'Merge from master for release.'
This commit is contained in:
commit
61e14aa827
|
|
@ -17,6 +17,7 @@
|
|||
README
|
||||
TAGS
|
||||
autom4te.cache
|
||||
compile_commands.json
|
||||
config.cache
|
||||
config.status
|
||||
configure
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ env:
|
|||
- VERILATOR_ROOT=$PWD
|
||||
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
|
||||
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
|
||||
- VERILATOR_AUTHOR_SITE=1
|
||||
- OBJCACHE=ccache
|
||||
|
||||
cache:
|
||||
|
|
@ -26,6 +27,7 @@ before_install:
|
|||
# Perl modules needed for testing
|
||||
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker Bit::Vector
|
||||
- sudo apt-get install gdb gtkwave
|
||||
- sudo apt-get install libgoogle-perftools-dev
|
||||
before_script:
|
||||
- bash -x ci/build_vcddiff.sh
|
||||
- bash -x ci/build_verilator.sh
|
||||
|
|
|
|||
50
Changes
50
Changes
|
|
@ -2,6 +2,50 @@ Revision history for Verilator
|
|||
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
* Verilator 4.028 2020-02-08
|
||||
|
||||
** Support attributes (public, isolate_assignments, etc.) in configuration files.
|
||||
|
||||
** Add -match to lint_off to waive warnings. [Philipp Wagner]
|
||||
|
||||
*** Link Verilator binary partially statically, #2146. [Geza Lore]
|
||||
|
||||
*** Verilation speed improvements, #2133, #2138. [Geza Lore]
|
||||
|
||||
*** Support libgoogle-perftools-dev's libtcmalloc if available, #2137. [Geza Lore]
|
||||
|
||||
*** Support $readmem/$writemem with assoc arrarys, #2100. [agrobman]
|
||||
|
||||
**** Support type(expression) operator and $typename, #1650.
|
||||
|
||||
**** Support left justified $display, #2101. [Pieter Kapsenberg]
|
||||
|
||||
**** Support string character access via indexing.
|
||||
|
||||
**** Support enum.next(k) with constant k > 1, #2125. [Tobias Rosenkranz]
|
||||
|
||||
**** Support parameter access from arrays of interfaces, #2155. [Todd Strader]
|
||||
|
||||
**** Add parameter values in XML. #2110. [Pieter Kapsenberg]
|
||||
|
||||
**** Add loc column location in XML (replaces fl), #2122. [Pieter Kapsenberg]
|
||||
|
||||
**** Add error on misused define. [Topa Tota]
|
||||
|
||||
**** Add parameter to set maximum signal width, #2082. [Øyvind Harboe]
|
||||
|
||||
**** Add warning on genvar in normal for loop, #2143. [yurivict]
|
||||
|
||||
**** Fix VPI scope naming for public modules. [Nandu Raj]
|
||||
|
||||
**** Fix FST tracing of enums inside structs. [fsiegle]
|
||||
|
||||
**** Fix WIDTH warning on </<= of narrower value, #2141. [agrobman]
|
||||
|
||||
**** Fix OpenSolaris issues, #2154. [brancoliticus]
|
||||
|
||||
|
||||
* Verilator 4.026 2020-01-11
|
||||
|
||||
** Docker images are now available for Verilator releases.
|
||||
|
|
@ -128,10 +172,10 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
|||
|
||||
* Verilator 4.020 2019-10-06
|
||||
|
||||
*** Support $fseek, $ftell, $frewind, #1496. [Howard Su]
|
||||
|
||||
*** Add --public-flat-rw, #1511. [Stefan Wallentowitz]
|
||||
|
||||
*** Support $fseek, $ftell, $frewind, #1496. [Howard Su]
|
||||
|
||||
*** Support vpiModule, #1469. [Stefan Wallentowitz]
|
||||
|
||||
**** Make Syms file honor --output-split-cfuncs, #1499. [Todd Strader]
|
||||
|
|
@ -152,6 +196,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
|||
|
||||
**** Fix case statements with strings, #1536. [Philipp Wagner]
|
||||
|
||||
**** Fix some coverage lost when multithreaded, #2151.
|
||||
|
||||
|
||||
* Verilator 4.018 2019-08-29
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@
|
|||
\.codacy\.yml
|
||||
\.travis\.yml
|
||||
/build/
|
||||
/obj_dir/
|
||||
/obj_dbg/
|
||||
/obj_dir/
|
||||
/obj_dist/
|
||||
/obj_iv/
|
||||
/obj_nc/
|
||||
/obj_opt/
|
||||
/obj_vcs/
|
||||
/obj_vlt/
|
||||
/obj_vltmt/
|
||||
/obj_dist/
|
||||
/INCA_libs/
|
||||
/cov_work/
|
||||
/logs/
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ DISTFILES_INC = $(INFOS) .gitignore \
|
|||
docs/install.adoc \
|
||||
docs/internals.adoc \
|
||||
docs/verilator_logo.png \
|
||||
docs/xml.adoc \
|
||||
install-sh configure *.pod \
|
||||
include/*.[chv]* \
|
||||
include/*.in \
|
||||
|
|
|
|||
17
README.adoc
17
README.adoc
|
|
@ -16,6 +16,7 @@ ifndef::env-github[]
|
|||
:link_verilator_contributing: https://github.com/verilator/verilator/blob/master/docs/CONTRIBUTING.adoc
|
||||
:link_verilator_install: https://verilator.org/install
|
||||
endif::[]
|
||||
:link_verilator_commercial_support: https://verilator.org/verilator_commercial_support
|
||||
|
||||
== Welcome to Verilator
|
||||
|
||||
|
|
@ -38,12 +39,18 @@ endif::[]
|
|||
+++ <br/> +++ • Out-of-the-box support from Arm, and RISC-V vendor IP
|
||||
<.^|image:https://www.veripool.org/img/verilator_usage_400x200-min.png[,400,200]
|
||||
|
||||
>.^|image:https://www.veripool.org/img/chips_alliance_logo_225x75-min.png[CHIPS Alliance,link=https://chipsalliance.org]
|
||||
image:https://www.veripool.org/img/osi_logo_125x125-min.png[,125,125]
|
||||
>.^|image:https://www.veripool.org/img/verilator_community_400x125-min.png[,400,125]
|
||||
^.^| *Community Driven & Openly Licensed*
|
||||
+++ <br/> +++ • Guided by the https://chipsalliance.org/[CHIPS Alliance] and https://www.linuxfoundation.org/[Linux Foundation]
|
||||
+++ <br/> +++ • Open, and free as in both speech and beer
|
||||
+++ <br/> +++ • More simulation for your verification budget
|
||||
|
||||
^.^| *Commercial Support Available*
|
||||
+++ <br/> +++ • Commercial support contracts
|
||||
+++ <br/> +++ • Design support contracts
|
||||
+++ <br/> +++ • Enhancement contracts
|
||||
<.^|image:https://www.veripool.org/img/verilator_support_400x125-min.png[,400,125]
|
||||
|
||||
|===
|
||||
|
||||
== What Verilator Does
|
||||
|
|
@ -109,7 +116,7 @@ or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
|
|||
|
||||
* https://verilator.org/issues[Verilator Issues]
|
||||
|
||||
== Community Supported
|
||||
== Support
|
||||
|
||||
Verilator is a community project, guided by the
|
||||
https://chipsalliance.org/[CHIPS Alliance] under the
|
||||
|
|
@ -120,6 +127,10 @@ We appreciate and welcome your contributions in whatever form; please see
|
|||
https://verilator.org/verilator_doc.html#CONTRIBUTORS[Contributors and
|
||||
Sponsors].
|
||||
|
||||
Verilator also supports and encourages commercial support models and
|
||||
organizations; please see {link_verilator_commercial_support}[Verilator
|
||||
Commercial Support].
|
||||
|
||||
== Related Projects
|
||||
|
||||
* http://gtkwave.sourceforge.net/[GTKwave] - Waveform viewer for Verilator
|
||||
|
|
|
|||
217
bin/verilator
217
bin/verilator
|
|
@ -323,6 +323,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
|
|||
--language <lang> Default language standard to parse
|
||||
+libext+<ext>+[ext]... Extensions for finding modules
|
||||
--lint-only Lint, but do not make output
|
||||
--max-num-width <value> Maximum number width (default: 64K)
|
||||
--MMD Create .d dependency files
|
||||
--MP Create phony dependency targets
|
||||
--Mdir <directory> Name of output object directory
|
||||
|
|
@ -968,6 +969,11 @@ stylistic and not enabled by default.
|
|||
If the design is not to be completely Verilated see also the --bbox-sys and
|
||||
--bbox-unsup options.
|
||||
|
||||
=item --max-num-width I<value>
|
||||
|
||||
Set the maximum number literal width (e.g. in 1024'd22 this it the 1024).
|
||||
Defaults to 64K.
|
||||
|
||||
=item --MMD
|
||||
=item --no-MMD
|
||||
|
||||
|
|
@ -2769,6 +2775,8 @@ purposes.
|
|||
|
||||
=item lint_off [-rule <message>] [-file "<filename>" [-lines <line> [ - <line>]]]
|
||||
|
||||
=item lint_off [-rule <message>] [-file "<filename>"] [-match "<string>"]
|
||||
|
||||
Enable/disables the specified lint warning, in the specified filename (or
|
||||
wildcard with '*' or '?', or all files if omitted) and range of line
|
||||
numbers (or all lines if omitted).
|
||||
|
|
@ -2780,6 +2788,10 @@ If the -rule is omitted, all lint warnings (see list in -Wno-lint) are
|
|||
enabled/disabled. This will override all later lint warning enables for
|
||||
the specified region.
|
||||
|
||||
If -match is set the linter warnings are matched against this (wildcard)
|
||||
string and are waived in case they match iff rule and file (with wildcard)
|
||||
also match.
|
||||
|
||||
In previous versions -rule was named -msg. The latter is deprecated, but
|
||||
still works with a deprecation info, it may be removed in future versions.
|
||||
|
||||
|
|
@ -2794,6 +2806,124 @@ and range of line numbers (or all lines if omitted).
|
|||
For tracing_off, cells below any module in the files/ranges specified will
|
||||
also not be traced.
|
||||
|
||||
=item clock_enable -module "<modulename>" -signal "<signame>"
|
||||
|
||||
Indicate the signal is used to gate a clock, and the user takes responsibility
|
||||
for insuring there are no races related to it.
|
||||
|
||||
Same as /*verilator clock_enable*/, see L</"LANGUAGE EXTENSIONS"> for
|
||||
more information and an example.
|
||||
|
||||
=item clocker -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
|
||||
|
||||
=item clocker -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
|
||||
|
||||
=item no_clocker -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
|
||||
|
||||
=item no_clocker -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
|
||||
|
||||
Indicate the signal is used as clock or not. This information is used by
|
||||
Verilator to mark the signal as clocker and propagate the clocker attribute
|
||||
automatically to derived signals. See C<--clk> for more information.
|
||||
|
||||
Same as /*verilator clocker*/, see L</"LANGUAGE EXTENSIONS"> for more
|
||||
information.
|
||||
|
||||
=item coverage_block_off -module "<modulename>" -block "<blockname>"
|
||||
|
||||
=item coverage_block_off -file "<filename>" -line <lineno>
|
||||
|
||||
Specifies the entire begin/end block should be ignored for coverage
|
||||
analysis purposes. Can either be specified as a named block or as a
|
||||
filename and line number.
|
||||
|
||||
Same as /*verilator coverage_block_off*/, see L</"LANGUAGE
|
||||
EXTENSIONS"> for more information.
|
||||
|
||||
=item full_case -file "<filename>" -lines <lineno>
|
||||
|
||||
=item parallel_case -file "<filename>" -lines <lineno>
|
||||
|
||||
Same as "//synopsys full_case" and "//synopsys parallel_case". When
|
||||
these synthesis directives are discovered, Verilator will either
|
||||
formally prove the directive to be true, or failing that, will insert
|
||||
the appropriate code to detect failing cases at simulation runtime and
|
||||
print an "Assertion failed" error message.
|
||||
|
||||
=item inline -module "<modulename>"
|
||||
|
||||
Specifies the module may be inlined into any modules that use this
|
||||
module. This is useful to speed up simulation runtime with some small
|
||||
loss of trace visibility and modularity. Note signals under inlined
|
||||
submodules will be named I<submodule>__DOT__I<subsignal> as C++ does
|
||||
not allow "." in signal names. When tracing such signals the tracing
|
||||
routines will replace the __DOT__ with the period.
|
||||
|
||||
Same as /*verilator inline_module*/, see L</"LANGUAGE EXTENSIONS"> for
|
||||
more information.
|
||||
|
||||
=item isolate_assignments -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
|
||||
|
||||
=item isolate_assignments -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
|
||||
|
||||
=item isolate_assignments -module "<modulename>" -function "<fname>"
|
||||
|
||||
Used to indicate the assignments to this signal in any blocks should be
|
||||
isolated into new blocks. When there is a large combinatorial block that
|
||||
is resulting in a UNOPTFLAT warning, attaching this to the signal causing
|
||||
a false loop may clear up the problem.
|
||||
|
||||
Same as /* verilator isolate_assignments */, see L</"LANGUAGE
|
||||
EXTENSIONS"> for more information.
|
||||
|
||||
=item no_inline -module "<modulename>"
|
||||
|
||||
Specifies the module should not be inlined into any modules that use
|
||||
this module. This is useful especially at the top level module to
|
||||
reduce the size of the interface class, to aid compile time at a small
|
||||
performance loss.
|
||||
|
||||
Same as /*verilator no_inline_module*/, see L</"LANGUAGE EXTENSIONS">
|
||||
for more information.
|
||||
|
||||
=item no_inline [-module "<modulename>"] -task "<taskname>"
|
||||
|
||||
=item no_inline [-module "<modulename>"] -function "<funcname>"
|
||||
|
||||
Specify the function or task should not be inlined into where it is
|
||||
used. This may reduce the size of the final executable when a task is
|
||||
used a very large number of times. For this flag to work, the task
|
||||
and tasks below it must be pure; they cannot reference any variables
|
||||
outside the task itself.
|
||||
|
||||
Same as /*verilator no_inline_task*/, see L</"LANGUAGE EXTENSIONS">
|
||||
for more information.
|
||||
|
||||
=item sc_bv -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
|
||||
|
||||
=item sc_bv -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
|
||||
|
||||
Sets the port to be of sc_bv<I<width>> type, instead of bool, vluint32_t or
|
||||
vluint64_t. This may be useful if the port width is parameterized and
|
||||
different of such modules interface a templated module (such as a transactor)
|
||||
or for other reasons. In general you should avoid using this attribute when
|
||||
not necessary as with increasing usage of sc_bv the performance decreases
|
||||
significantly.
|
||||
|
||||
Same as /*verilator sc_bv*/, see L</"LANGUAGE EXTENSIONS"> for more
|
||||
information.
|
||||
|
||||
=item sformat [-module "<modulename>"] [-task "<taskname>"] -signal "<signame>"
|
||||
|
||||
=item sformat [-module "<modulename>"] [-function "<funcname>"] -signal "<signame>"
|
||||
|
||||
Final input of a function or task "input string" to indicate the
|
||||
function or task should pass all remaining arguments through
|
||||
$sformatf. This allows creation of DPI functions with $display like
|
||||
behavior. See the test_regress/t/t_dpi_display.v file for an example.
|
||||
|
||||
Same as /*verilator sformat*/, see L</"LANGUAGE EXTENSIONS"> for more
|
||||
information.
|
||||
|
||||
=back
|
||||
|
||||
|
|
@ -2929,7 +3059,8 @@ per the C standard (it's unspecified in Verilog).
|
|||
|
||||
Specifies the entire begin/end block should be ignored for coverage
|
||||
analysis. Must be inside a basic block, e.g. within a begin/end pair.
|
||||
Same as /* verilator coverage_block_off */.
|
||||
Same as /* verilator coverage_block_off */ and C<coverage_block_off> in
|
||||
L</"CONFIGURATION FILES">.
|
||||
|
||||
=item `systemc_header
|
||||
|
||||
|
|
@ -3019,7 +3150,10 @@ analysis.) For example:
|
|||
The clock_enable attribute will cause the clock gate to be ignored in the
|
||||
scheduling algorithm, sometimes required for correct clock behavior, and
|
||||
always improving performance. It's also a good idea to enable the
|
||||
IMPERFECTSCH warning, to insure all clock enables are properly recognized.
|
||||
IMPERFECTSCH warning, to ensure all clock enables are properly recognized.
|
||||
|
||||
Same as C<clock_enable> in configuration files, see L</"CONFIGURATION
|
||||
FILES"> for more information.
|
||||
|
||||
=item /*verilator clocker*/
|
||||
|
||||
|
|
@ -3030,11 +3164,17 @@ not. This information is used by Verilator to mark the signal as clocker
|
|||
and propagate the clocker attribute automatically to derived signals. See
|
||||
C<--clk> for more information.
|
||||
|
||||
Same as C<clocker> and C<no_clocker> in configuration files, see
|
||||
L</"CONFIGURATION FILES"> for more information.
|
||||
|
||||
=item /*verilator coverage_block_off*/
|
||||
|
||||
Specifies the entire begin/end block should be ignored for coverage
|
||||
analysis purposes.
|
||||
|
||||
Same as C<coverage_block_off> in configuration files, see
|
||||
L</"CONFIGURATION FILES"> for more information.
|
||||
|
||||
=item /*verilator coverage_off*/
|
||||
|
||||
Specifies that following lines of code should have coverage disabled.
|
||||
|
|
@ -3055,6 +3195,9 @@ submodules will be named I<submodule>__DOT__I<subsignal> as C++ does not
|
|||
allow "." in signal names. When tracing such signals the tracing routines
|
||||
will replace the __DOT__ with the period.
|
||||
|
||||
Same as C<inline> in configuration files, see L</"CONFIGURATION FILES">
|
||||
for more information.
|
||||
|
||||
=item /*verilator isolate_assignments*/
|
||||
|
||||
Used after a signal declaration to indicate the assignments to this signal
|
||||
|
|
@ -3091,6 +3234,9 @@ It would then internally break it into (sort of):
|
|||
end
|
||||
end
|
||||
|
||||
Same as C<isolate_assignments> in configuration files, see
|
||||
L</"CONFIGURATION FILES"> for more information.
|
||||
|
||||
=item /*verilator lint_off I<msg>*/
|
||||
|
||||
Disable the specified warning message for any warnings following the comment.
|
||||
|
|
@ -3126,6 +3272,9 @@ modules that use this module. This is useful especially at the top level
|
|||
module to reduce the size of the interface class, to aid compile time at a
|
||||
small performance loss.
|
||||
|
||||
Same as C<no_inline> in configuration files, see L</"CONFIGURATION
|
||||
FILES"> for more information.
|
||||
|
||||
=item /*verilator no_inline_task*/
|
||||
|
||||
Used in a function or task variable definition section to specify the
|
||||
|
|
@ -3134,6 +3283,9 @@ reduce the size of the final executable when a task is used a very large
|
|||
number of times. For this flag to work, the task and tasks below it must
|
||||
be pure; they cannot reference any variables outside the task itself.
|
||||
|
||||
Same as C<no_inline> in configuration files, see L</"CONFIGURATION
|
||||
FILES"> for more information.
|
||||
|
||||
=item /*verilator public*/ (parameter)
|
||||
|
||||
Used after a parameter declaration to indicate the emitted C code should
|
||||
|
|
@ -3161,6 +3313,9 @@ Instead of using public variables, consider instead making a DPI or public
|
|||
function that accesses the variable. This is nicer as it provides an
|
||||
obvious entry point that is also compatible across simulators.
|
||||
|
||||
Same as C<public> in configuration files, see L</"CONFIGURATION FILES">
|
||||
for more information.
|
||||
|
||||
=item /*verilator public*/ (task/function)
|
||||
|
||||
Used inside the declaration section of a function or task declaration to
|
||||
|
|
@ -3183,6 +3338,9 @@ the model will NOT notice changes made to variables in these functions.
|
|||
You may want to use DPI exports instead, as it's compatible with other
|
||||
simulators.
|
||||
|
||||
Same as C<public> in configuration files, see L</"CONFIGURATION FILES">
|
||||
for more information.
|
||||
|
||||
=item /*verilator public_flat*/ (variable)
|
||||
|
||||
Used after an input, output, register, or wire declaration to indicate the
|
||||
|
|
@ -3191,11 +3349,17 @@ signal. This will not declare this module public, which means the name of
|
|||
the signal or path to it may change based upon the module inlining which
|
||||
takes place.
|
||||
|
||||
Same as C<public_flat> in configuration files, see L</"CONFIGURATION
|
||||
FILES"> for more information.
|
||||
|
||||
=item /*verilator public_flat_rd*/ (variable)
|
||||
|
||||
Used after an input, output, register, or wire declaration to indicate the
|
||||
signal should be declared public_flat (see above), but read-only.
|
||||
|
||||
Same as C<public_flat_rd> in configuration files, see L</"CONFIGURATION
|
||||
FILES"> for more information.
|
||||
|
||||
=item /*verilator public_flat_rw @(<edge_list>) */ (variable)
|
||||
|
||||
Used after an input, output, register, or wire declaration to indicate the
|
||||
|
|
@ -3204,6 +3368,9 @@ where writes should be considered to have the timing specified by the given
|
|||
sensitivity edge list. Set for all variables, ports and wires using the
|
||||
--public-flat-rw switch.
|
||||
|
||||
Same as C<public_flat_rw> in configuration files, see L</"CONFIGURATION
|
||||
FILES"> for more information.
|
||||
|
||||
=item /*verilator public_module*/
|
||||
|
||||
Used after a module statement to indicate the module should not be inlined
|
||||
|
|
@ -3212,9 +3379,12 @@ Verilator automatically sets this attribute when the module contains any
|
|||
public signals or `systemc_ directives. Also set for all modules when
|
||||
using the --public switch.
|
||||
|
||||
Same as C<public> in configuration files, see L</"CONFIGURATION FILES">
|
||||
for more information.
|
||||
|
||||
=item /*verilator sc_clock*/
|
||||
|
||||
Rarely needed. Used after an input declaration to indicate the signal
|
||||
Deprecated. Used after an input declaration to indicate the signal
|
||||
should be declared in SystemC as a sc_clock instead of a bool. This was
|
||||
needed in SystemC 1.1 and 1.2 only; versions 2.0 and later do not require
|
||||
clock pins to be sc_clocks and this is no longer needed.
|
||||
|
|
@ -3226,7 +3396,10 @@ type, instead of bool, vluint32_t or vluint64_t. This may be useful if
|
|||
the port width is parameterized and different of such modules interface
|
||||
a templated module (such as a transactor) or for other reasons. In general
|
||||
you should avoid using this attribute when not necessary as with increasing
|
||||
usage of sc_bv the performance increases significantly.
|
||||
usage of sc_bv the performance decreases significantly.
|
||||
|
||||
Same as C<sc_bv> in configuration files, see L</"CONFIGURATION FILES">
|
||||
for more information.
|
||||
|
||||
=item /*verilator sformat*/
|
||||
|
||||
|
|
@ -3235,6 +3408,9 @@ indicate the function or task should pass all remaining arguments through
|
|||
$sformatf. This allows creation of DPI functions with $display like
|
||||
behavior. See the test_regress/t/t_dpi_display.v file for an example.
|
||||
|
||||
Same as C<sformat> in configuration files, see L</"CONFIGURATION FILES">
|
||||
for more information.
|
||||
|
||||
=item /*verilator tag <text...>*/
|
||||
|
||||
Attached after a variable or structure member to indicate opaque (to
|
||||
|
|
@ -4476,6 +4652,37 @@ that is not yet supported in Verilator. See the Limitations chapter.
|
|||
=back
|
||||
|
||||
|
||||
=head1 DEPRECATIONS
|
||||
|
||||
The following deprecated items are scheduled for future removal:
|
||||
|
||||
=over 4
|
||||
|
||||
=item Pre-C++11 compiler support
|
||||
|
||||
Verilator supports pre-C++11 compilers for non-threaded models when
|
||||
configured with --enable-prec11. This flag will be removed and C++11
|
||||
compilers will be required for both compiling Verilator and compiling
|
||||
Verilated models no sooner than September 2020.
|
||||
|
||||
=item SystemC 2.1 and earlier support
|
||||
|
||||
Support for SystemC versions 2.1 and earlier and the related sc_clock
|
||||
variable attribute will be removed no sooner than July 2020.
|
||||
|
||||
=item Configuration File -msg
|
||||
|
||||
The -msg argument to lint_off has been replaced with -rule. -msg is
|
||||
planned for removal no sooner than January 2021.
|
||||
|
||||
=item XML locations
|
||||
|
||||
The XML C<fl> attribute has been replaced with C<loc>. C<fl> is planned
|
||||
for removal no sooner than January 2021.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 FAQ/FREQUENTLY ASKED QUESTIONS
|
||||
|
||||
=over 4
|
||||
|
|
@ -4707,7 +4914,7 @@ Most synthesis tools similarly define SYNTHESIS for you.
|
|||
=item Why do I get "unexpected `do'" or "unexpected `bit'" errors?
|
||||
|
||||
Do, bit, ref, return, and other words are now SystemVerilog keywords. You
|
||||
should change your code to not use them to insure it works with newer
|
||||
should change your code to not use them to ensure it works with newer
|
||||
tools. Alternatively, surround them by the Verilog 2005/SystemVerilog
|
||||
begin_keywords pragma to indicate Verilog 2001 code.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
# DESCRIPTION: Docker hub hook to tag the latest release (stable)
|
||||
#
|
||||
# Copyright 2020 by Stefan Wallentowitz. This program is free
|
||||
# software; you can redistribute it and/or modify it under the terms
|
||||
# of either the GNU Lesser General Public License Version 3 or the
|
||||
# Perl Artistic License Version 2.0.FROM ubuntu:18.04
|
||||
|
||||
if [ "$SOURCE_BRANCH"="stable" ]; then
|
||||
docker tag $IMAGE_NAME $DOCKER_REPO:latest
|
||||
docker push $DOCKER_REPO:latest
|
||||
fi
|
||||
96
configure.ac
96
configure.ac
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.026 2020-01-11],
|
||||
AC_INIT([Verilator],[4.028 2020-02-06],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
|
|
@ -25,11 +25,43 @@ AC_ARG_ENABLE([maintainer-mode],
|
|||
AC_ARG_ENABLE([silent-rules],
|
||||
[AS_HELP_STRING([--disable-silent-rules], [ignored])])
|
||||
|
||||
# Flag to enable linking specific libraries statically
|
||||
AC_MSG_CHECKING(whether to perform partial static linking of Verilator binary)
|
||||
AC_ARG_ENABLE([partial-static],
|
||||
[AS_HELP_STRING([--disable-partial-static],
|
||||
[By default, for Verilation peformance, Verilator
|
||||
is linked against some of its dependencies
|
||||
statically. Use this to link the Verilator binary
|
||||
fully dynamically.])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_ENABLE_PARTIAL_STATIC=yes ;;
|
||||
no) CFG_ENABLE_PARTIAL_STATIC=no ;;
|
||||
*) AC_MSG_ERROR([bad value '${enableval}' for --disable-partial-static]) ;;
|
||||
esac],
|
||||
CFG_ENABLE_PARTIAL_STATIC=yes)
|
||||
AC_MSG_RESULT($CFG_ENABLE_PARTIAL_STATIC)
|
||||
|
||||
# Flag to enable linking Verilator with tcmalloc if available
|
||||
AC_MSG_CHECKING(whether to use tcmalloc)
|
||||
AC_ARG_ENABLE([tcmalloc],
|
||||
[AS_HELP_STRING([--enable-tcmalloc],
|
||||
[Use libtcmalloc_minimal for faster dynamic memory
|
||||
management in Verilator binary@<:@default=check@:>@])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_TCMALLOC=yes ;;
|
||||
no) CFG_WITH_TCMALLOC=no ;;
|
||||
*) AC_MSG_ERROR([bad value '${enableval}' for --enable-tcmalloc]) ;;
|
||||
esac],
|
||||
[CFG_WITH_TCMALLOC=check;])
|
||||
AC_MSG_RESULT($CFG_WITH_TCMALLOC)
|
||||
|
||||
# Special Substitutions - CFG_WITH_DEFENV
|
||||
AC_MSG_CHECKING(whether to use hardcoded paths)
|
||||
AC_ARG_ENABLE([defenv],
|
||||
[AS_HELP_STRING([--disable-defenv],
|
||||
[disable using some hardcoded data paths extracted from some default environment variables (the default is to use hardcoded paths)])],
|
||||
[disable using some hardcoded data paths extracted
|
||||
from some default environment variables (the default
|
||||
is to use hardcoded paths) in Verilator binary])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_DEFENV=yes ;;
|
||||
no) CFG_WITH_DEFENV=no ;;
|
||||
|
|
@ -43,7 +75,8 @@ AC_MSG_RESULT($CFG_WITH_DEFENV)
|
|||
AC_MSG_CHECKING(whether to show and stop on compilation warnings)
|
||||
AC_ARG_ENABLE([ccwarn],
|
||||
[AS_HELP_STRING([--enable-ccwarn],
|
||||
[enable showing and stopping on compilation warnings])],
|
||||
[enable showing and stopping on compilation warnings
|
||||
in Verilator binrary and Verilated makefiles])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_CCWARN=yes ;;
|
||||
no) CFG_WITH_CCWARN=no ;;
|
||||
|
|
@ -79,7 +112,8 @@ AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
|||
AC_MSG_CHECKING(whether allow pre-C++11)
|
||||
AC_ARG_ENABLE([prec11],
|
||||
[AS_HELP_STRING([--enable-prec11],
|
||||
[enable pre-C++11 compilers])],
|
||||
[enable pre-C++11 compilers for Verilator binary
|
||||
and Verilated makefiles])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_PREC11=yes ;;
|
||||
no) CFG_WITH_PREC11=no ;;
|
||||
|
|
@ -209,15 +243,26 @@ AC_DEFUN([_MY_LDLIBS_CHECK_FLAG],
|
|||
LIBS="$ACO_SAVE_LIBS"
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_LDLIBS_CHECK_OPT],
|
||||
[# _MY_LDLIBS_CHECK_OPT(flag) -- Check if linker supports specific options
|
||||
# If it does, append flag to variable
|
||||
_MY_LDLIBS_CHECK_FLAG($2)
|
||||
AC_DEFUN([_MY_LDLIBS_CHECK_IFELSE],
|
||||
[# _MY_LDLIBS_CHECK_IFELSE(flag,action-if-supported,action-if-not-supported)
|
||||
# Check if linker supports specific flag, if it does do action-if-supported
|
||||
# otherwise do action-if-not-supported
|
||||
_MY_LDLIBS_CHECK_FLAG($1)
|
||||
if test "$_my_result" = "yes" ; then
|
||||
$1="$$1 $2"
|
||||
true
|
||||
$2
|
||||
else
|
||||
true
|
||||
$3
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_LDLIBS_CHECK_OPT],
|
||||
[# _MY_LDLIBS_CHECK_OPT(variable, flag) -- Check if linker supports specific
|
||||
# options. If it does, append flag to variable.
|
||||
_MY_LDLIBS_CHECK_IFELSE($2, $1="$$1 $2")
|
||||
])
|
||||
|
||||
# Flag to select newest language standard supported
|
||||
# Macros work such that first option that passes is the one we take
|
||||
# gnu++17 code is clean, but SystemC in 2018 doesn't link with it (bug1339)
|
||||
|
|
@ -310,6 +355,39 @@ m4_foreach([ldflag], [
|
|||
AC_SUBST(CFG_LDLIBS_THREADS)
|
||||
AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE)
|
||||
|
||||
# When linking partially statically
|
||||
if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc)
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libstdc++)
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -Xlinker -gc-sections)
|
||||
LTCMALLOC=-l:libtcmalloc_minimal.a
|
||||
else
|
||||
LTCMALLOC=-ltcmalloc_minimal
|
||||
fi
|
||||
AC_SUBST(CFG_LDFLAGS_SRC)
|
||||
|
||||
# The pthread library is required by tcmalloc, so add it if it exists. If it
|
||||
# does not, the tcmalloc check below will fail anyway, and linking against
|
||||
# pthreads is harmless otherwise.
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread)
|
||||
|
||||
# Check if tcmalloc is available based on --enable-tcmalloc
|
||||
_MY_LDLIBS_CHECK_IFELSE(
|
||||
$LTCMALLOC,
|
||||
[if test "$CFG_WITH_TCMALLOC" != "no"; then
|
||||
CFG_LIBS="$LTCMALLOC $CFG_LIBS";
|
||||
# If using tcmalloc, add some extra options to make the compiler not assume
|
||||
# it is using it's own versions of the standard library functions
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-free)
|
||||
fi],
|
||||
[if test "$CFG_WITH_TCMALLOC" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-tcmalloc was given but test for ${LTCMALLOC} failed])
|
||||
fi])
|
||||
AC_SUBST(CFG_LIBS)
|
||||
|
||||
# Set CFG_WITH_THREADED if can support threading
|
||||
AC_MSG_CHECKING(whether $CXX supports Verilated threads)
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ contributions flow more efficiently.
|
|||
https://verilator.org/issues[Verilator Issues].
|
||||
|
||||
* If you're unable to find an open issue addressing the problem,
|
||||
https://verilator.org/issues/new[open a new issue].
|
||||
https://verilator.org/issues/new[open a new Verilator issue].
|
||||
|
||||
** Be sure to include a **code sample** or an **executable test case**
|
||||
demonstrating the bug and expected behavior that is not occurring.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ Chris Randall
|
|||
Driss Hafdi
|
||||
Eric Rippey
|
||||
Garrett Smith
|
||||
Geza Lore
|
||||
Gianfranco Costamagna
|
||||
Howard Su
|
||||
Iztok Jeras
|
||||
|
|
@ -24,12 +25,14 @@ Lukasz Dalek
|
|||
Maarten De Braekeleer
|
||||
Matthew Ballance
|
||||
Mike Popoloski
|
||||
Peter Monsson
|
||||
Patrick Stewart
|
||||
Peter Monsson
|
||||
Philipp Wagner
|
||||
Pieter Kapsenberg
|
||||
Richard Myers
|
||||
Sebastien Van Cauwenberghe
|
||||
Stefan Wallentowitz
|
||||
Tobias Rosenkranz
|
||||
Todd Strader
|
||||
Wilson Snyder
|
||||
Yutetsu TAKATSUKASA
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ To build Verilator you will need to install some standard packages:
|
|||
sudo apt-get install autoconf
|
||||
sudo apt-get install flex bison
|
||||
|
||||
The following are optional, but improve compilation speed:
|
||||
|
||||
sudo apt-get install libgoogle-perftools-dev
|
||||
|
||||
Additionally, to build or run Verilator you need these standard packages:
|
||||
|
||||
sudo apt-get install perl python3
|
||||
|
|
|
|||
|
|
@ -70,7 +70,10 @@ The AST is represented at the top level by the class `AstNode`. This
|
|||
abstract class has derived classes for the individual components
|
||||
(e.g. `AstGenerate` for a generate block) or groups of components
|
||||
(e.g. `AstNodeFTask` for functions and tasks, which in turn has `AstFunc`
|
||||
and `AstTask` as derived classes).
|
||||
and `AstTask` as derived classes). An important property of the `AstNode`
|
||||
type hierarchy is that all non-final subclasses of `AstNode` (i.e.: those
|
||||
which themselves have subclasses) must be abstract as well, and be named
|
||||
with the prefix `AstNode*`. The `astgen` (see below) script relies on this.
|
||||
|
||||
Each `AstNode` has pointers to up to four children, accessed by the `op1p`
|
||||
through `op4p` methods. These methods are then abstracted in a specific
|
||||
|
|
@ -394,7 +397,7 @@ e.g. threads.
|
|||
We will work with contributors to fix up indentation style issues, but it
|
||||
is appreciated if you could match our style:
|
||||
|
||||
* All files should contain the magic header to insure standard indentation:
|
||||
* All files should contain the magic header to ensure standard indentation:
|
||||
+
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
+
|
||||
|
|
@ -959,7 +962,8 @@ src/VParseGrammar.y, as this grammar supports the full SystemVerilog
|
|||
language and has a lot of back-and-forth with Verilator's grammar. Copy
|
||||
the appropriate rules to src/verilog.y and modify the productions.
|
||||
|
||||
. If a new Ast type is needed, add it to V3AstNodes.h.
|
||||
. If a new Ast type is needed, add it to V3AstNodes.h. Follow the convention
|
||||
described above about the AstNode type hierarchy.
|
||||
|
||||
. Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
|
||||
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
= Verilator XML Output
|
||||
:toc: right
|
||||
|
||||
// Github doesn't render unless absolute URL
|
||||
image::https://www.veripool.org/img/verilator_256_200_min.png[Logo,256,200,role="right"]
|
||||
|
||||
== Introduction
|
||||
|
||||
This document describes Verilator's XML output. For more general information
|
||||
please see https://verilator.org[verilator.org].
|
||||
|
||||
== General
|
||||
|
||||
Verilator's XML output is enabled with the `--xml-only` flag. It contains
|
||||
limited information about the elaborated design including files, modules,
|
||||
instance hierarchy, logic and data types. There is no formal schema since part
|
||||
of the structure of the XML document matches the compiled code which would
|
||||
require the schema to describe legal SystemVerilog structure. The intended
|
||||
usage is to enable other downstream tools to take advantage of Verilator's
|
||||
parser.
|
||||
|
||||
== Structure
|
||||
|
||||
The XML document is consists of 4 sections within the top level `verilator_xml`
|
||||
element:
|
||||
|
||||
`<files>`...`</files>`::
|
||||
|
||||
This section contains a list of all design files read, including the
|
||||
built-in constructs and the command line as their own entries. Each
|
||||
`<file>` has an attribute `id` which is a short ASCII string unique to that
|
||||
file. Other elements' `loc` attributes use this id to refer to a particular
|
||||
file.
|
||||
|
||||
`<module_files>`...`</module_files>`::
|
||||
|
||||
All files containing Verilog module definitions are listed in this section.
|
||||
This element's contents is a subset of the `<files>` element's contents.
|
||||
|
||||
`<cells>`...`</cells>`::
|
||||
|
||||
The cells section of the XML document contains the design instance
|
||||
hierarchy. Each instance is represented with the `<cell>` element with the
|
||||
following attributes:
|
||||
|
||||
* `fl` (deprecated): The file id and line number where the module was
|
||||
instanced. Use `loc` instead.
|
||||
|
||||
* `loc`: The file id, first line number, last line number, first column
|
||||
number and last column number of the identifier where the module was
|
||||
instanced, separated by commas.
|
||||
|
||||
* `name`: The instance name.
|
||||
|
||||
* `submodname`: The module name uniquified with particular parameter values (if any).
|
||||
|
||||
* `hier`: The full hierarchy path.
|
||||
|
||||
`<netlist>`...`</netlist>`::
|
||||
|
||||
The netlist section contains a number of `<module>`...`</module>` elements,
|
||||
each describing the contents of that module, and a single `<typetable>`...
|
||||
`</typetable>` element which lists all used types used within the
|
||||
modules. Each type has a numeric `id` attribute that is referred to by
|
||||
elements in the `<module>` elements using the `dtype_id` attribute.
|
||||
|
|
@ -418,9 +418,7 @@ static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void
|
|||
const flzuint8* ip = (const flzuint8*) input;
|
||||
const flzuint8* ip_limit = ip + length;
|
||||
flzuint8* op = (flzuint8*) output;
|
||||
#ifdef FASTLZ_SAFE
|
||||
flzuint8* op_limit = op + maxout;
|
||||
#endif
|
||||
flzuint32 ctrl = (*ip++) & 31;
|
||||
int loop = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,9 +33,6 @@
|
|||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#include <malloc.h>
|
||||
#define alloca _alloca
|
||||
#endif
|
||||
#define wave_alloca alloca
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -618,7 +618,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
const char* pctp = NULL; // Most recent %##.##g format
|
||||
bool inPct = false;
|
||||
bool widthSet = false;
|
||||
int width = 0;
|
||||
bool left = false;
|
||||
size_t width = 0;
|
||||
for (const char* pos = formatp; *pos; ++pos) {
|
||||
if (!inPct && pos[0]=='%') {
|
||||
pctp = pos;
|
||||
|
|
@ -643,6 +644,10 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
widthSet = true;
|
||||
width = width*10 + (fmt - '0');
|
||||
break;
|
||||
case '-':
|
||||
left = true;
|
||||
inPct = true; // Get more digits
|
||||
break;
|
||||
case '.':
|
||||
inPct = true; // Get more digits
|
||||
break;
|
||||
|
|
@ -662,8 +667,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
case '@': { // Verilog/C++ string
|
||||
va_arg(ap, int); // # bits is ignored
|
||||
const std::string* cstrp = va_arg(ap, const std::string*);
|
||||
if (width > cstrp->size()) output += std::string(width - cstrp->size(), ' ');
|
||||
output += *cstrp;
|
||||
std::string padding;
|
||||
if (width > cstrp->size()) padding.append(width - cstrp->size(), ' ');
|
||||
output += left ? (*cstrp + padding) : (padding + *cstrp);
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
|
|
@ -721,8 +727,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||
field += (charval==0)?' ':charval;
|
||||
}
|
||||
if (width > field.size()) output += std::string(width - field.size(), ' ');
|
||||
output += field;
|
||||
std::string padding;
|
||||
if (width > field.size()) padding.append(width - field.size(), ' ');
|
||||
output += left ? (field + padding) : (padding + field);
|
||||
break;
|
||||
}
|
||||
case 'd': { // Signed decimal
|
||||
|
|
@ -743,14 +750,15 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
digits = append.length();
|
||||
}
|
||||
int needmore = width-digits;
|
||||
std::string padding;
|
||||
if (needmore>0) {
|
||||
if (pctp && pctp[0] && pctp[1]=='0') { // %0
|
||||
output.append(needmore, '0'); // Pre-pad zero
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
} else {
|
||||
output.append(needmore, ' '); // Pre-pad spaces
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
}
|
||||
}
|
||||
output += append;
|
||||
output += left ? (append + padding) : (padding + append);
|
||||
break;
|
||||
}
|
||||
case '#': { // Unsigned decimal
|
||||
|
|
@ -764,14 +772,15 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
digits = append.length();
|
||||
}
|
||||
int needmore = width-digits;
|
||||
std::string padding;
|
||||
if (needmore>0) {
|
||||
if (pctp && pctp[0] && pctp[1]=='0') { // %0
|
||||
output.append(needmore, '0'); // Pre-pad zero
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
} else {
|
||||
output.append(needmore, ' '); // Pre-pad spaces
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
}
|
||||
}
|
||||
output += append;
|
||||
output += left ? (append + padding) : (padding + append);
|
||||
break;
|
||||
}
|
||||
case 't': { // Time
|
||||
|
|
@ -786,8 +795,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
VL_FATAL_MT(__FILE__, __LINE__, "", "Unsupported VL_TIME_MULTIPLIER");
|
||||
}
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore, ' '); // Pre-pad spaces
|
||||
output += tmp;
|
||||
std::string padding;
|
||||
if (needmore>0) padding.append(needmore, ' '); // Pad with spaces
|
||||
output += left ? (tmp + padding) : (padding + tmp);
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
|
|
@ -1320,146 +1330,6 @@ 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 filename, const void* memp, IData start,
|
||||
IData end) VL_MT_SAFE {
|
||||
WData fnw[VL_WQ_WORDS_E]; VL_SET_WQ(fnw, filename);
|
||||
return VL_WRITEMEM_W(hex, width, depth, array_lsb, VL_WQ_WORDS_E, fnw, memp, start, end);
|
||||
}
|
||||
|
||||
void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP filenamep, const void* memp, IData start,
|
||||
IData end) VL_MT_SAFE {
|
||||
char filenamez[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
|
||||
_VL_VINT_TO_STRING(fnwords * VL_EDATASIZE, filenamez, filenamep);
|
||||
std::string filenames(filenamez);
|
||||
return VL_WRITEMEM_N(hex, width, depth, array_lsb, filenames, 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; // LCOV_EXCL_LINE
|
||||
}
|
||||
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& filename, // Output file name
|
||||
const void* memp, // Array state
|
||||
IData start, // First array row address to write
|
||||
IData end // Last address to write, or ~0 when not specified
|
||||
) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!hex)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "",
|
||||
"VL_WRITEMEM_N only supports hex format for now, sorry!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate row address limits
|
||||
size_t row_min = array_lsb;
|
||||
size_t row_max = row_min + depth - 1;
|
||||
|
||||
// Normalize the last address argument: ~0 => row_max
|
||||
size_t nend = (end == ~0u) ? row_max : end;
|
||||
|
||||
// Bounds check the write address range
|
||||
if (VL_UNLIKELY((start < row_min) || (start > row_max)
|
||||
|| (nend < row_min) || (nend > row_max))) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "",
|
||||
"$writemem specified address out-of-bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (VL_UNLIKELY(start > nend)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "",
|
||||
"$writemem invalid address range");
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate row offset range
|
||||
size_t row_start = start - row_min;
|
||||
size_t row_end = nend - row_min;
|
||||
|
||||
// Bail out on possible 32-bit size_t overflow
|
||||
if (VL_UNLIKELY(row_end + 1 == 0)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem address is too large");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(filename.c_str(), "w");
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
|
||||
// cppcheck-suppress resourceLeak // fp is NULL - bug in cppcheck
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t row_offset = row_start; row_offset <= row_end; ++row_offset) {
|
||||
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_EDATASIZE'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_EDATASIZE);
|
||||
bool first = true;
|
||||
while (word_idx >= 0) {
|
||||
EData data = datap[word_idx];
|
||||
if (first) {
|
||||
data &= VL_MASK_E(width);
|
||||
int top_word_nbits = ((width - 1) & (VL_EDATASIZE - 1)) + 1;
|
||||
fprintf(fp, memhFormat(top_word_nbits), data);
|
||||
} else {
|
||||
fprintf(fp, "%08x", data);
|
||||
}
|
||||
word_idx--;
|
||||
first = false;
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
IData VL_FREAD_I(int width, int array_lsb, int array_size,
|
||||
void* memp, IData fpi, IData start, IData count) VL_MT_SAFE {
|
||||
// While threadsafe, each thread can only access different file handles
|
||||
|
|
@ -1469,14 +1339,14 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size,
|
|||
// Prep for reading
|
||||
IData read_count = 0;
|
||||
IData read_elements = 0;
|
||||
int start_shift = (width-1) & ~7; // bit+7:bit gets first character
|
||||
int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
|
||||
int shift = start_shift;
|
||||
// Read the data
|
||||
// We process a character at a time, as then we don't need to deal
|
||||
// with changing buffer sizes dynamically, etc.
|
||||
while (1) {
|
||||
int c = fgetc(fp);
|
||||
if (VL_UNLIKELY(c==EOF)) break;
|
||||
if (VL_UNLIKELY(c == EOF)) break;
|
||||
// Shift value in
|
||||
IData entry = read_elements + start - array_lsb;
|
||||
if (width <= 8) {
|
||||
|
|
@ -1513,144 +1383,6 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size,
|
|||
return read_count;
|
||||
}
|
||||
|
||||
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
|
||||
QData filename, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
WData fnw[VL_WQ_WORDS_E]; VL_SET_WQ(fnw, filename);
|
||||
return VL_READMEM_W(hex, width, depth, array_lsb, VL_WQ_WORDS_E, fnw, memp, start, end);
|
||||
}
|
||||
|
||||
void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP filenamep, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
char filenamez[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
|
||||
_VL_VINT_TO_STRING(fnwords * VL_EDATASIZE, filenamez, filenamep);
|
||||
std::string filenames(filenamez);
|
||||
return VL_READMEM_N(hex, width, depth, array_lsb, filenames, memp, start, end);
|
||||
}
|
||||
|
||||
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& filename, // 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(filename.c_str(), "r");
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
|
||||
// cppcheck-suppress resourceLeak // fp is NULL - bug in cppcheck
|
||||
return;
|
||||
}
|
||||
// Prep for reading
|
||||
IData addr = start;
|
||||
int linenum = 1;
|
||||
bool innum = false;
|
||||
bool ignore_to_eol = false;
|
||||
bool ignore_to_cmt = false;
|
||||
bool needinc = false;
|
||||
bool reading_addr = false;
|
||||
int lastc = ' ';
|
||||
// Read the data
|
||||
// We process a character at a time, as then we don't need to deal
|
||||
// with changing buffer sizes dynamically, etc.
|
||||
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);
|
||||
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
|
||||
else if (ignore_to_cmt && lastc=='*' && c=='/') {
|
||||
ignore_to_cmt = false; if (innum) reading_addr=false; innum=false;
|
||||
} else if (!ignore_to_eol && !ignore_to_cmt) {
|
||||
if (lastc=='/' && c=='*') { ignore_to_cmt = true; }
|
||||
else if (lastc=='/' && c=='/') { ignore_to_eol = true; }
|
||||
else if (c=='/') {} // Part of /* or //
|
||||
else if (c=='#') { ignore_to_eol = true; }
|
||||
else if (c=='_') {}
|
||||
else if (c=='@') { reading_addr = true; innum=false; needinc=false; }
|
||||
// Check for hex or binary digits as file format requests
|
||||
else if (isxdigit(c) || (!reading_addr && (c=='x' || c=='X'))) {
|
||||
c = tolower(c);
|
||||
int value = (c >= 'a' ? (c=='x' ? VL_RAND_RESET_I(4) : (c-'a'+10)) : (c-'0'));
|
||||
if (!innum) { // Prep for next number
|
||||
if (needinc) { addr++; needinc=false; }
|
||||
}
|
||||
if (reading_addr) {
|
||||
// Decode @ addresses
|
||||
if (!innum) addr=0;
|
||||
addr = (addr<<4) + value;
|
||||
} else {
|
||||
needinc = true;
|
||||
//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(filename.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);
|
||||
// Shift value in
|
||||
if (width<=8) {
|
||||
CData* datap = &(reinterpret_cast<CData*>(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
||||
} else if (width<=16) {
|
||||
SData* datap = &(reinterpret_cast<SData*>(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
||||
} else if (width <= VL_IDATASIZE) {
|
||||
IData* datap = &(reinterpret_cast<IData*>(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
||||
} else if (width<=VL_QUADSIZE) {
|
||||
QData* datap = &(reinterpret_cast<QData*>(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << static_cast<QData>(shift))
|
||||
+ static_cast<QData>(value)) & VL_MASK_Q(width);
|
||||
} else {
|
||||
WDataOutP datap = &(reinterpret_cast<WDataOutP>(memp))
|
||||
[ entry*VL_WORDS_I(width) ];
|
||||
if (!innum) { VL_ZERO_RESET_W(width, datap); }
|
||||
_VL_SHIFTL_INPLACE_W(width, datap, static_cast<IData>(shift));
|
||||
datap[0] |= value;
|
||||
}
|
||||
if (VL_UNLIKELY(value>=(1<<shift))) {
|
||||
VL_FATAL_MT(filename.c_str(), linenum, "",
|
||||
"$readmemb (binary) file contains hex characters");
|
||||
}
|
||||
}
|
||||
}
|
||||
innum = true;
|
||||
}
|
||||
else {
|
||||
VL_FATAL_MT(filename.c_str(), linenum, "", "$readmem file syntax error");
|
||||
}
|
||||
}
|
||||
lastc = c;
|
||||
}
|
||||
if (needinc) { addr++; }
|
||||
|
||||
// Final checks
|
||||
fclose(fp);
|
||||
if (VL_UNLIKELY(end != VL_UL(0xffffffff) && addr != (end+1))) {
|
||||
VL_FATAL_MT(filename.c_str(), linenum, "",
|
||||
"$readmem file ended before specified ending-address");
|
||||
}
|
||||
}
|
||||
|
||||
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
||||
WData lhsw[VL_WQ_WORDS_E]; VL_SET_WQ(lhsw, lhs);
|
||||
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
|
||||
|
|
@ -1795,6 +1527,9 @@ std::string VL_TO_STRING(IData lhs) {
|
|||
std::string VL_TO_STRING(QData lhs) {
|
||||
return VL_SFORMATF_NX("'h%0x", 64, lhs);
|
||||
}
|
||||
std::string VL_TO_STRING_W(int words, WDataInP obj) {
|
||||
return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj);
|
||||
}
|
||||
|
||||
std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE {
|
||||
std::string out = ld;
|
||||
|
|
@ -1867,6 +1602,315 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
|
|||
return static_cast<IData>(v);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Readmem/writemem
|
||||
|
||||
static 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; // LCOV_EXCL_LINE
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
|
||||
: m_hex(hex)
|
||||
, m_bits(bits)
|
||||
, m_filename(filename)
|
||||
, m_end(end)
|
||||
, m_addr(start)
|
||||
, m_linenum(0) {
|
||||
m_fp = fopen(filename.c_str(), "r");
|
||||
if (VL_UNLIKELY(!m_fp)) {
|
||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
|
||||
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
|
||||
return;
|
||||
}
|
||||
}
|
||||
VlReadMem::~VlReadMem() {
|
||||
if (m_fp) { fclose(m_fp); m_fp = NULL; }
|
||||
}
|
||||
bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
||||
if (VL_UNLIKELY(!m_fp)) return false;
|
||||
valuer = "";
|
||||
// Prep for reading
|
||||
bool indata = false;
|
||||
bool ignore_to_eol = false;
|
||||
bool ignore_to_cmt = false;
|
||||
bool reading_addr = false;
|
||||
int lastc = ' ';
|
||||
// Read the data
|
||||
// We process a character at a time, as then we don't need to deal
|
||||
// with changing buffer sizes dynamically, etc.
|
||||
while (1) {
|
||||
int c = fgetc(m_fp);
|
||||
if (VL_UNLIKELY(c == EOF)) break;
|
||||
// printf("%d: Got '%c' Addr%lx IN%d IgE%d IgC%d\n",
|
||||
// m_linenum, c, m_addr, indata, ignore_to_eol, ignore_to_cmt);
|
||||
// See if previous data value has completed, and if so return
|
||||
if (c == '_') continue; // Ignore _ e.g. inside a number
|
||||
if (indata && !isxdigit(c) && c != 'x' && c != 'X') {
|
||||
// printf("Got data @%lx = %s\n", m_addr, valuer.c_str());
|
||||
indata = false;
|
||||
ungetc(c, m_fp);
|
||||
addrr = m_addr;
|
||||
++m_addr;
|
||||
return true;
|
||||
}
|
||||
// Parse line
|
||||
if (c == '\n') {
|
||||
++m_linenum; ignore_to_eol = false;
|
||||
reading_addr = false;
|
||||
} else if (c == '\t' || c == ' ' || c == '\r' || c == '\f') {
|
||||
reading_addr = false;
|
||||
}
|
||||
// Skip // comments and detect /* comments
|
||||
else if (ignore_to_cmt && lastc == '*' && c == '/') {
|
||||
ignore_to_cmt = false;
|
||||
reading_addr = false;
|
||||
} else if (!ignore_to_eol && !ignore_to_cmt) {
|
||||
if (lastc == '/' && c == '*') { ignore_to_cmt = true; }
|
||||
else if (lastc == '/' && c == '/') { ignore_to_eol = true; }
|
||||
else if (c == '/') {} // Part of /* or //
|
||||
else if (c == '#') { ignore_to_eol = true; }
|
||||
else if (c == '@') { reading_addr = true; m_addr = 0; }
|
||||
// Check for hex or binary digits as file format requests
|
||||
else if (isxdigit(c) || (!reading_addr && (c == 'x' || c == 'X'))) {
|
||||
c = tolower(c);
|
||||
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c-'a'+10)) : (c-'0'));
|
||||
if (reading_addr) {
|
||||
// Decode @ addresses
|
||||
m_addr = (m_addr << 4) + value;
|
||||
} else {
|
||||
indata = true;
|
||||
valuer += c;
|
||||
// printf(" Value width=%d @%x = %c\n", width, m_addr, c);
|
||||
if (VL_UNLIKELY(value > 1 && !m_hex)) {
|
||||
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
||||
"$readmemb (binary) file contains hex characters");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VL_FATAL_MT(m_filename.c_str(), m_linenum, "", "$readmem file syntax error");
|
||||
}
|
||||
}
|
||||
lastc = c;
|
||||
}
|
||||
|
||||
if (VL_UNLIKELY(m_end != ~VL_ULL(0) && m_addr <= m_end)) {
|
||||
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
||||
"$readmem file ended before specified final address (IEEE 2017 21.4)");
|
||||
}
|
||||
|
||||
return false; // EOF
|
||||
}
|
||||
void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
||||
QData shift = m_hex ? VL_ULL(4) : VL_ULL(1);
|
||||
bool innum = false;
|
||||
// Shift value in
|
||||
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
|
||||
char c = tolower(*it);
|
||||
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
|
||||
if (m_bits <= 8) {
|
||||
CData* datap = reinterpret_cast<CData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
|
||||
} else if (m_bits <= 16) {
|
||||
SData* datap = reinterpret_cast<SData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
|
||||
} else if (m_bits <= VL_IDATASIZE) {
|
||||
IData* datap = reinterpret_cast<IData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
|
||||
} else if (m_bits <= VL_QUADSIZE) {
|
||||
QData* datap = reinterpret_cast<QData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << static_cast<QData>(shift)) + static_cast<QData>(value))
|
||||
& VL_MASK_Q(m_bits);
|
||||
} else {
|
||||
WDataOutP datap = reinterpret_cast<WDataOutP>(valuep);
|
||||
if (!innum) { VL_ZERO_RESET_W(m_bits, datap); }
|
||||
_VL_SHIFTL_INPLACE_W(m_bits, datap, static_cast<IData>(shift));
|
||||
datap[0] |= value;
|
||||
}
|
||||
innum = true;
|
||||
}
|
||||
}
|
||||
|
||||
VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end)
|
||||
: m_bits(bits)
|
||||
, m_addr(0) {
|
||||
if (VL_UNLIKELY(!hex)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "",
|
||||
"Unsupported: $writemem binary format (suggest hex format)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (VL_UNLIKELY(start > end)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range");
|
||||
return;
|
||||
}
|
||||
|
||||
m_fp = fopen(filename.c_str(), "w");
|
||||
if (VL_UNLIKELY(!m_fp)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
|
||||
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
|
||||
return;
|
||||
}
|
||||
}
|
||||
VlWriteMem::~VlWriteMem() {
|
||||
if (m_fp) { fclose(m_fp); m_fp = NULL; }
|
||||
}
|
||||
void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
|
||||
if (VL_UNLIKELY(!m_fp)) return;
|
||||
if (addr != m_addr && addrstamp) { // Only assoc has time stamps
|
||||
fprintf(m_fp, "@%" VL_PRI64 "x\n", addr);
|
||||
}
|
||||
m_addr = addr + 1;
|
||||
if (m_bits <= 8) {
|
||||
const CData* datap = reinterpret_cast<const CData*>(valuep);
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
} else if (m_bits <= 16) {
|
||||
const SData* datap = reinterpret_cast<const SData*>(valuep);
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
} else if (m_bits <= 32) {
|
||||
const IData* datap = reinterpret_cast<const IData*>(valuep);
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
} else if (m_bits <= 64) {
|
||||
const QData* datap = reinterpret_cast<const QData*>(valuep);
|
||||
vluint64_t value = VL_MASK_Q(m_bits) & *datap;
|
||||
vluint32_t lo = value & 0xffffffff;
|
||||
vluint32_t hi = value >> 32;
|
||||
fprintf(m_fp, memhFormat(m_bits - 32), hi);
|
||||
fprintf(m_fp, "%08x\n", lo);
|
||||
} else {
|
||||
WDataInP datap = reinterpret_cast<WDataInP>(valuep);
|
||||
// output as a sequence of VL_EDATASIZE'd words
|
||||
// from MSB to LSB. Mask off the MSB word which could
|
||||
// contain junk above the top of valid data.
|
||||
int word_idx = ((m_bits - 1) / VL_EDATASIZE);
|
||||
bool first = true;
|
||||
while (word_idx >= 0) {
|
||||
EData data = datap[word_idx];
|
||||
if (first) {
|
||||
data &= VL_MASK_E(m_bits);
|
||||
int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1;
|
||||
fprintf(m_fp, memhFormat(top_word_nbits), data);
|
||||
} else {
|
||||
fprintf(m_fp, "%08x", data);
|
||||
}
|
||||
word_idx--;
|
||||
first = false;
|
||||
}
|
||||
fprintf(m_fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void VL_READMEM_N(bool hex, // Hex format, else binary
|
||||
int bits, // M_Bits of each array row
|
||||
QData 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& filename, // Input file name
|
||||
void* memp, // Array state
|
||||
QData start, // First array row address to read
|
||||
QData end // Last row address to read
|
||||
) VL_MT_SAFE {
|
||||
QData addr_max = array_lsb + depth - 1;
|
||||
if (start < array_lsb) start = array_lsb;
|
||||
QData addr_end = end;
|
||||
if (addr_end > addr_max) addr_end = addr_max;
|
||||
|
||||
VlReadMem rmem(hex, bits, filename, start, end);
|
||||
if (VL_UNLIKELY(!rmem.isOpen())) return;
|
||||
while (1) {
|
||||
QData addr;
|
||||
std::string value;
|
||||
if (rmem.get(addr /*ref*/, value/*ref*/)) {
|
||||
if (VL_UNLIKELY(addr < static_cast<QData>(array_lsb)
|
||||
|| addr >= static_cast<QData>(array_lsb + depth))) {
|
||||
VL_FATAL_MT(filename.c_str(), rmem.linenum(), "",
|
||||
"$readmem file address beyond bounds of array");
|
||||
} else {
|
||||
QData entry = addr - array_lsb;
|
||||
if (bits <= 8) {
|
||||
CData* datap = &(reinterpret_cast<CData*>(memp))[entry];
|
||||
rmem.setData(datap, value);
|
||||
} else if (bits <= 16) {
|
||||
SData* datap = &(reinterpret_cast<SData*>(memp))[entry];
|
||||
rmem.setData(datap, value);
|
||||
} else if (bits <= VL_IDATASIZE) {
|
||||
IData* datap = &(reinterpret_cast<IData*>(memp))[entry];
|
||||
rmem.setData(datap, value);
|
||||
} else if (bits <= VL_QUADSIZE) {
|
||||
QData* datap = &(reinterpret_cast<QData*>(memp))[entry];
|
||||
rmem.setData(datap, value);
|
||||
} else {
|
||||
WDataOutP datap = &(reinterpret_cast<WDataOutP>(memp))
|
||||
[ entry*VL_WORDS_I(bits) ];
|
||||
rmem.setData(datap, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VL_WRITEMEM_N(bool hex, // Hex format, else binary
|
||||
int bits, // Width of each array row
|
||||
QData 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& filename, // Output file name
|
||||
const void* memp, // Array state
|
||||
QData start, // First array row address to write
|
||||
QData end // Last address to write, or ~0 when not specified
|
||||
) VL_MT_SAFE {
|
||||
QData addr_max = array_lsb + depth - 1;
|
||||
if (start < array_lsb) start = array_lsb;
|
||||
if (end > addr_max) end = addr_max;
|
||||
|
||||
VlWriteMem wmem(hex, bits, filename, start, end);
|
||||
if (VL_UNLIKELY(!wmem.isOpen())) return;
|
||||
|
||||
for (QData addr = start; addr <= end; ++addr) {
|
||||
QData row_offset = addr - array_lsb;
|
||||
if (bits <= 8) {
|
||||
const CData* datap = &(reinterpret_cast<const CData*>(memp))[row_offset];
|
||||
wmem.print(addr, false, datap);
|
||||
} else if (bits <= 16) {
|
||||
const SData* datap = &(reinterpret_cast<const SData*>(memp))[row_offset];
|
||||
wmem.print(addr, false, datap);
|
||||
} else if (bits <= 32) {
|
||||
const IData* datap = &(reinterpret_cast<const IData*>(memp))[row_offset];
|
||||
wmem.print(addr, false, datap);
|
||||
} else if (bits <= 64) {
|
||||
const QData* datap = &(reinterpret_cast<const QData*>(memp))[row_offset];
|
||||
wmem.print(addr, false, datap);
|
||||
} else {
|
||||
WDataInP memDatap = reinterpret_cast<WDataInP>(memp);
|
||||
WDataInP datap = &memDatap[row_offset * VL_WORDS_I(bits)];
|
||||
wmem.print(addr, false, datap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Timescale conversion
|
||||
|
||||
|
|
@ -2352,9 +2396,9 @@ VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTIN
|
|||
|
||||
void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath - Called only when find has failed
|
||||
std::string msg = (std::string("Testbench C called '")
|
||||
+VerilatedImp::exportName(funcnum)
|
||||
+"' but scope wasn't set, perhaps due to dpi import call without 'context'");
|
||||
std::string msg = (std::string("Testbench C called '") + VerilatedImp::exportName(funcnum)
|
||||
+ "' but scope wasn't set, perhaps due to dpi import call without "
|
||||
+ "'context', or missing svSetScope. See IEEE 1800-2017 35.5.3.");
|
||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -630,22 +630,6 @@ extern void VL_FCLOSE_I(IData fdi);
|
|||
extern IData VL_FREAD_I(int width, int array_lsb, int array_size,
|
||||
void* memp, IData fpi, IData start, IData count);
|
||||
|
||||
extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP filenamep, void* memp, IData start, IData end);
|
||||
extern void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
QData filename, void* memp, IData start, IData end);
|
||||
inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
IData filename, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
VL_READMEM_Q(hex, width, depth, array_lsb, fnwords, filename, memp, start, end); }
|
||||
|
||||
extern void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP filenamep, const void* memp, IData start, IData end);
|
||||
extern void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
QData filename, const void* memp, IData start, IData end);
|
||||
inline void VL_WRITEMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
IData filename, const void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
VL_WRITEMEM_Q(hex, width, depth, array_lsb, fnwords, filename, memp, start, end); }
|
||||
|
||||
extern void VL_WRITEF(const char* formatp, ...);
|
||||
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
|
||||
|
||||
|
|
|
|||
|
|
@ -73,12 +73,12 @@ private:
|
|||
public:
|
||||
// METHODS
|
||||
// cppcheck-suppress truncLongCastReturn
|
||||
virtual vluint64_t count() const { return *m_countp; }
|
||||
virtual void zero() const { *m_countp = 0; }
|
||||
virtual vluint64_t count() const VL_OVERRIDE { return *m_countp; }
|
||||
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
|
||||
// CONSTRUCTORS
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VerilatedCoverItemSpec(T* countp) : m_countp(countp) { *m_countp = 0; }
|
||||
virtual ~VerilatedCoverItemSpec() {}
|
||||
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
|
@ -222,7 +222,7 @@ private:
|
|||
void clearGuts() VL_REQUIRES(m_mutex) {
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
delete itemp;
|
||||
VL_DO_DANGLING(delete itemp, itemp);
|
||||
}
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
|
|
@ -244,7 +244,7 @@ public:
|
|||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
if (!itemMatchesString(itemp, matchp)) {
|
||||
delete itemp;
|
||||
VL_DO_DANGLING(delete itemp, itemp);
|
||||
} else {
|
||||
newlist.push_back(itemp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#define __STDC_LIMIT_MACROS // UINT64_MAX
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_fst_c.h"
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,38 @@ extern std::string VL_TO_STRING(SData obj);
|
|||
extern std::string VL_TO_STRING(IData obj);
|
||||
extern std::string VL_TO_STRING(QData obj);
|
||||
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
|
||||
extern std::string VL_TO_STRING_W(int words, WDataInP obj);
|
||||
|
||||
//===================================================================
|
||||
// Readmem/Writemem operation classes
|
||||
|
||||
class VlReadMem {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
const std::string& m_filename; // Filename
|
||||
QData m_end; // End address (as specified by user)
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to read
|
||||
int m_linenum; // Line number last read from file
|
||||
public:
|
||||
VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlReadMem();
|
||||
bool isOpen() const { return m_fp != NULL; }
|
||||
int linenum() const { return m_linenum; }
|
||||
bool get(QData& addrr, std::string& valuer);
|
||||
void setData(void* valuep, const std::string& rhs);
|
||||
};
|
||||
|
||||
class VlWriteMem {
|
||||
int m_bits; // Bit width of values
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to write
|
||||
public:
|
||||
VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlWriteMem();
|
||||
bool isOpen() const { return m_fp != NULL; }
|
||||
void print(QData addr, bool addrstamp, const void* valuep);
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Verilog array container
|
||||
|
|
@ -72,6 +104,10 @@ VlWide<T_Words>& VL_CVT_W_A(WDataInP inp, const VlWide<T_Words>&) {
|
|||
return *((VlWide<T_Words>*)inp);
|
||||
}
|
||||
|
||||
template <std::size_t T_Words>
|
||||
std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
|
||||
return VL_TO_STRING_W(T_Words, obj.data());
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog associative array container
|
||||
|
|
@ -180,6 +216,34 @@ std::string VL_TO_STRING(const VlAssocArray<T_Key, T_Value>& obj) {
|
|||
return obj.to_string();
|
||||
}
|
||||
|
||||
template <class T_Key, class T_Value>
|
||||
void VL_READMEM_N(bool hex, int bits, const std::string& filename,
|
||||
VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
|
||||
VlReadMem rmem(hex, bits, filename, start, end);
|
||||
if (VL_UNLIKELY(!rmem.isOpen())) return;
|
||||
while (1) {
|
||||
QData addr;
|
||||
std::string data;
|
||||
if (rmem.get(addr /*ref*/, data /*ref*/)) {
|
||||
rmem.setData(&(obj.at(addr)), data);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T_Key, class T_Value>
|
||||
void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
const VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
|
||||
VlWriteMem wmem(hex, bits, filename, start, end);
|
||||
if (VL_UNLIKELY(!wmem.isOpen())) return;
|
||||
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = obj.begin(); it != obj.end();
|
||||
++it) {
|
||||
QData addr = it->first;
|
||||
if (addr >= start && addr <= end) wmem.print(addr, true, &(it->second));
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog queue container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
|
|
@ -312,12 +376,12 @@ extern std::string VL_TOLOWER_NN(const std::string& ld);
|
|||
extern std::string VL_TOUPPER_NN(const std::string& ld);
|
||||
|
||||
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,
|
||||
const std::string& filename,
|
||||
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& filename,
|
||||
const void* memp, IData start, IData end) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||
const std::string& filename, void* memp, QData start,
|
||||
QData end) VL_MT_SAFE;
|
||||
extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||
const std::string& filename, const void* memp, QData start,
|
||||
QData 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,
|
||||
|
|
|
|||
|
|
@ -164,12 +164,12 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSave() { m_fd = -1; }
|
||||
virtual ~VerilatedSave() { close(); }
|
||||
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
|
||||
// METHODS
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_MT_UNSAFE_ONE;
|
||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
|
@ -183,14 +183,14 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedRestore() { m_fd = -1; }
|
||||
virtual ~VerilatedRestore() { close(); }
|
||||
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
|
||||
|
||||
// METHODS
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() VL_MT_UNSAFE_ONE;
|
||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ public:
|
|||
}
|
||||
}
|
||||
~vl_unordered_set() {
|
||||
delete [] m_bucketsp; VL_DANGLING(m_bucketsp);
|
||||
VL_DO_DANGLING(delete [] m_bucketsp, m_bucketsp);
|
||||
}
|
||||
|
||||
vl_unordered_set& operator=(const vl_unordered_set& other) {
|
||||
|
|
|
|||
|
|
@ -1993,7 +1993,7 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
|
|||
}
|
||||
if (!_error_info_p) return 0; // no error occured
|
||||
return _error_info_p->level; // return error severity level
|
||||
};
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_free_object(vpiHandle object) {
|
||||
VerilatedVpiImp::assertOneCheck();
|
||||
|
|
@ -2008,7 +2008,7 @@ PLI_INT32 vpi_release_handle(vpiHandle object) {
|
|||
_VL_VPI_ERROR_RESET();
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
vpi_remove_cb(object); // May not be a callback, but that's ok
|
||||
delete vop;
|
||||
VL_DO_DANGLING(delete vop, vop);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,11 +154,19 @@
|
|||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
||||
# define VL_DANGLING(v)
|
||||
# define VL_DANGLING(var)
|
||||
#else
|
||||
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||
///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||
# define VL_DANGLING(var) do { (var) = NULL; } while(0)
|
||||
#endif
|
||||
|
||||
///< Perform an e.g. delete, then set variable to NULL to indicate must not use later.
|
||||
///< Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
|
||||
#define VL_DO_DANGLING(stmt, var) do { do { stmt; } while(0); VL_DANGLING(var); } while(0)
|
||||
|
||||
///< Perform an e.g. delete, then set variable to NULL as a requirement
|
||||
#define VL_DO_CLEAR(stmt, stmt2) do { do { stmt; } while(0); do { stmt2; } while(0); } while(0)
|
||||
|
||||
//=========================================================================
|
||||
// C++-2011
|
||||
|
||||
|
|
@ -176,11 +184,15 @@
|
|||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# endif
|
||||
# define VL_FINAL final
|
||||
# define VL_OVERRIDE override
|
||||
#else
|
||||
# define VL_EQ_DELETE
|
||||
# define vl_unique_ptr std::auto_ptr
|
||||
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
||||
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
||||
# define VL_FINAL
|
||||
# define VL_OVERRIDE
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
|
@ -261,6 +273,10 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
|
|||
|
||||
#else // Linux or compliant Unix flavors, -m64
|
||||
|
||||
// The inttypes supplied with some GCC versions requires STDC_FORMAT_MACROS
|
||||
// to be declared in order to get the PRIxx macros used by fstapi.c
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
# include <inttypes.h> // Solaris
|
||||
# include <stdint.h> // Linux and most flavors
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
|
|
@ -324,6 +340,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
||||
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
|
||||
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
|
||||
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
|
||||
|
||||
/// Bytes this number of bits needs (1 bit=1 byte)
|
||||
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ CFG_CXXFLAGS_SRC = @CFG_CXXFLAGS_SRC@
|
|||
CFG_CXXFLAGS_PARSER = @CFG_CXXFLAGS_PARSER@
|
||||
# Compiler flags that turn on extra warnings
|
||||
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
||||
CFG_LDFLAGS_SRC = @CFG_LDFLAGS_SRC@
|
||||
CFG_LIBS = @CFG_LIBS@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
|
|
@ -91,8 +93,7 @@ endif
|
|||
#CCMALLOC = /usr/local/lib/ccmalloc-gcc.o -lccmalloc -ldl
|
||||
|
||||
# -lfl not needed as Flex invoked with %nowrap option
|
||||
# -lstdc++ needed for clang, believed harmless with gcc
|
||||
LIBS = -lm -lstdc++
|
||||
LIBS = $(CFG_LIBS) -lm
|
||||
|
||||
CPPFLAGS += -MMD
|
||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
||||
|
|
@ -106,6 +107,7 @@ CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
|
|||
else
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_SRC)
|
||||
endif
|
||||
LDFLAGS += $(CFG_LDFLAGS_SRC)
|
||||
|
||||
CPPFLAGSWALL = $(CPPFLAGS)
|
||||
CPPFLAGSPARSER = $(CPPFLAGS) $(CFG_CXXFLAGS_PARSER)
|
||||
|
|
@ -164,6 +166,7 @@ RAW_OBJS = \
|
|||
V3Branch.o \
|
||||
V3Broken.o \
|
||||
V3CCtors.o \
|
||||
V3CUse.o \
|
||||
V3Case.o \
|
||||
V3Cast.o \
|
||||
V3Cdc.o \
|
||||
|
|
@ -193,6 +196,7 @@ RAW_OBJS = \
|
|||
V3FileLine.o \
|
||||
V3Gate.o \
|
||||
V3GenClk.o \
|
||||
V3Global.o \
|
||||
V3Graph.o \
|
||||
V3GraphAlg.o \
|
||||
V3GraphAcyc.o \
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ private:
|
|||
m_scopep->addActivep(nodep);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
m_scopep = nodep;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
|
|
@ -79,15 +79,15 @@ private:
|
|||
iterateChildren(nodep);
|
||||
// Don't clear scopep, the namer persists beyond this visit
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) {
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
// Simplify sensitivity list
|
||||
V3Const::constifyExpensiveEdit(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep);
|
||||
}
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeStmt* nodep) { }
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE { }
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -163,7 +163,7 @@ private:
|
|||
AstNode* m_alwaysp; // Always we're under
|
||||
AstNode* m_assignp; // In assign
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
if (m_check != CT_SEQ) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
|
|
@ -181,10 +181,10 @@ private:
|
|||
nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssign* nodep) {
|
||||
virtual void visit(AstAssign* nodep) VL_OVERRIDE {
|
||||
if (m_check == CT_SEQ) {
|
||||
AstNode* las = m_assignp;
|
||||
m_assignp = nodep;
|
||||
|
|
@ -192,7 +192,7 @@ private:
|
|||
m_assignp = las;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
AstVar* varp = nodep->varp();
|
||||
if (m_check == CT_SEQ
|
||||
&& m_assignp
|
||||
|
|
@ -210,7 +210,7 @@ private:
|
|||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -240,7 +240,7 @@ private:
|
|||
bool m_itemSequent; // Found a SenItem sequential
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
// Create required actives and add to scope
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
// Clear last scope's names, and collect this scope's existing names
|
||||
|
|
@ -248,10 +248,10 @@ private:
|
|||
m_scopeFinalp = NULL;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// Actives are being formed, so we can ignore any already made
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
// Relink to IACTIVE, unless already under it
|
||||
UINFO(4," INITIAL "<<nodep<<endl);
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
|
|
@ -259,32 +259,32 @@ private:
|
|||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) {
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," COVERTOGGLE "<<nodep<<endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) {
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
// Relink to CFUNC for the final
|
||||
UINFO(4," FINAL "<<nodep<<endl);
|
||||
if (!nodep->bodysp()) { // Empty, Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
|
|
@ -303,7 +303,7 @@ private:
|
|||
nodep->unlinkFrBack();
|
||||
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName(), true));
|
||||
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext());
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
|
|
@ -316,7 +316,7 @@ private:
|
|||
// Never executing. Kill it.
|
||||
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
|
||||
"Never senitem should be alone, else the never should be eliminated.");
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +353,7 @@ private:
|
|||
|
||||
// Delete sensitivity list
|
||||
if (oldsensesp) {
|
||||
oldsensesp->unlinkFrBackWithNext()->deleteTree(); VL_DANGLING(oldsensesp);
|
||||
VL_DO_DANGLING(oldsensesp->unlinkFrBackWithNext()->deleteTree(), oldsensesp);
|
||||
}
|
||||
|
||||
// Move node to new active
|
||||
|
|
@ -372,25 +372,25 @@ private:
|
|||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALWPub "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
||||
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
AstSenItem* subitemp = nodep->sensesp();
|
||||
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|
||||
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
|
|
@ -398,12 +398,12 @@ private:
|
|||
nodep, "Strange activity type under SenGate");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
|
||||
m_itemCombo = true;
|
||||
// Delete the sensitivity
|
||||
// We'll add it as a generic COMBO SenItem in a moment.
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else if (nodep->varrefp()) {
|
||||
// V3LinkResolve should have cleaned most of these up
|
||||
if (!nodep->varrefp()->width1()) {
|
||||
|
|
@ -416,10 +416,10 @@ private:
|
|||
}
|
||||
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstVarScope* nodep) {}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -56,19 +56,19 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
m_topscopep = nodep;
|
||||
m_finder.main(m_topscopep);
|
||||
iterateChildren(nodep);
|
||||
m_topscopep = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Create required actives and add to module
|
||||
// We can start ordering at a module, or a scope
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
||||
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
|
||||
AstSenTree* sensesp = nodep->sensesp();
|
||||
|
|
@ -79,7 +79,7 @@ private:
|
|||
// Never executing. Kill it.
|
||||
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
|
||||
"Never senitem should be alone, else the never should be eliminated.");
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
// Copy combo tree to settlement tree with duplicated statements
|
||||
|
|
@ -113,29 +113,29 @@ private:
|
|||
// No need to do statements under it, they're already moved.
|
||||
//iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been deleted");
|
||||
}
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstVarScope* nodep) {}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -115,9 +115,9 @@ private:
|
|||
if (failsp) failsp->unlinkFrBackWithNext();
|
||||
|
||||
if (nodep->immediate()) {
|
||||
UASSERT_OBJ(!sentreep, nodep, "Immediate assertions don't have sensivity");
|
||||
UASSERT_OBJ(!sentreep, nodep, "Immediate assertions don't have sensitivity");
|
||||
} else {
|
||||
UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensivity");
|
||||
UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensitivity");
|
||||
sentreep->unlinkFrBack();
|
||||
}
|
||||
//
|
||||
|
|
@ -164,17 +164,17 @@ private:
|
|||
if (selfDestruct) {
|
||||
// Delete it after making the tree. This way we can tell the user
|
||||
// if it wasn't constructed nicely or has other errors without needing --coverage.
|
||||
newp->deleteTree();
|
||||
VL_DO_DANGLING(newp->deleteTree(), newp);
|
||||
nodep->unlinkFrBack();
|
||||
} else {
|
||||
nodep->replaceWith(newp);
|
||||
}
|
||||
// Bye
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstIf* nodep) {
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
AstNodeIf* ifp = nodep;
|
||||
|
|
@ -234,7 +234,7 @@ private:
|
|||
}
|
||||
|
||||
//========== Case assertions
|
||||
virtual void visit(AstCase* nodep) {
|
||||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
bool has_default = false;
|
||||
|
|
@ -296,7 +296,7 @@ private:
|
|||
}
|
||||
|
||||
//========== Past
|
||||
virtual void visit(AstPast* nodep) {
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
uint32_t ticks = 1;
|
||||
if (nodep->ticksp()) {
|
||||
|
|
@ -326,9 +326,13 @@ private:
|
|||
}
|
||||
nodep->replaceWith(inp);
|
||||
}
|
||||
virtual void visit(AstSampled* nodep) VL_OVERRIDE {
|
||||
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
//========== Statements
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Replace the special types with standard text
|
||||
if (nodep->displayType()==AstDisplayType::DT_INFO) {
|
||||
|
|
@ -341,29 +345,32 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAssert* nodep) {
|
||||
virtual void visit(AstAssert* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nodep->failsp());
|
||||
}
|
||||
virtual void visit(AstCover* nodep) {
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, NULL);
|
||||
}
|
||||
virtual void visit(AstRestrict* nodep) {
|
||||
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// IEEE says simulator ignores these
|
||||
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
//
|
||||
iterateChildren(nodep);
|
||||
// Reset defaults
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
unsigned origPastNum = m_modPastNum;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_modPastNum = origPastNum;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
// This code is needed rather than a visitor in V3Begin,
|
||||
// because V3Assert is called before V3Begin
|
||||
AstBegin* lastp = m_beginp;
|
||||
|
|
@ -374,7 +381,7 @@ private:
|
|||
m_beginp = lastp;
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ private:
|
|||
|
||||
// VISITORS
|
||||
//========== Statements
|
||||
virtual void visit(AstClocking* nodep) {
|
||||
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
|
||||
UINFO(8," CLOCKING"<<nodep<<endl);
|
||||
// Store the new default clock, reset on new module
|
||||
m_seniDefaultp = nodep->sensesp();
|
||||
|
|
@ -81,9 +81,9 @@ private:
|
|||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (nodep->sensesp()) {
|
||||
m_seniAlwaysp = nodep->sensesp()->sensesp();
|
||||
|
|
@ -92,7 +92,7 @@ private:
|
|||
m_seniAlwaysp = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) {
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) VL_OVERRIDE {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
// Find Clocking's buried under nodep->exprsp
|
||||
|
|
@ -102,12 +102,12 @@ private:
|
|||
}
|
||||
clearAssertInfo();
|
||||
}
|
||||
virtual void visit(AstPast* nodep) {
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
virtual void visit(AstPropClocked* nodep) {
|
||||
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
|
||||
// No need to iterate the body, once replace will get iterated
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (m_senip) {
|
||||
|
|
@ -130,14 +130,14 @@ private:
|
|||
// Unlink and just keep a pointer to it, convert to sentree as needed
|
||||
m_senip = nodep->sensesp();
|
||||
nodep->replaceWith(blockp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Reset defaults
|
||||
m_seniDefaultp = NULL;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -865,10 +865,10 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||
// track, then delete it on completion
|
||||
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
||||
{
|
||||
tempp->stmtsp()->accept(v); VL_DANGLING(nodep); // nodep to null as may be replaced
|
||||
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced
|
||||
}
|
||||
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
tempp->deleteTree(); VL_DANGLING(tempp);
|
||||
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
||||
} else {
|
||||
// Use back to determine who's pointing at us (IE assume new node
|
||||
// grafts into same place as old one)
|
||||
|
|
@ -880,7 +880,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
|
||||
UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself");
|
||||
{
|
||||
nodep->accept(v); VL_DANGLING(nodep); // nodep to null as may be replaced
|
||||
VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced
|
||||
}
|
||||
nodep = *nextnodepp; // Grab new node from point where old was connected
|
||||
}
|
||||
|
|
|
|||
418
src/V3Ast.h
418
src/V3Ast.h
|
|
@ -51,15 +51,18 @@ typedef std::set<int> MTaskIdSet; // Set of mtaskIds for Var sorting
|
|||
//######################################################################
|
||||
|
||||
// For broken() function, return error string if have a match
|
||||
#define BROKEN_RTN(test) do { if (VL_UNCOVERABLE(test)) return # test; } while(0)
|
||||
#define BROKEN_RTN(test) \
|
||||
do { \
|
||||
if (VL_UNCOVERABLE(test)) return #test; \
|
||||
} while (0)
|
||||
|
||||
// (V)erilator (N)ode is: True if AstNode is of a a given AstType
|
||||
#define VN_IS(nodep,nodetypename) (AstNode::privateIs ## nodetypename(nodep))
|
||||
#define VN_IS(nodep,nodetypename) (AstNode::privateIs<Ast ## nodetypename>(nodep))
|
||||
|
||||
// (V)erilator (N)ode cast: Cast to given type if can; effectively
|
||||
// dynamic_cast<nodetypename>(nodep)
|
||||
#define VN_CAST(nodep,nodetypename) (AstNode::privateCast ## nodetypename(nodep))
|
||||
#define VN_CAST_CONST(nodep,nodetypename) (AstNode::privateConstCast ## nodetypename(nodep) )
|
||||
#define VN_CAST(nodep,nodetypename) (AstNode::privateCast<Ast ## nodetypename>(nodep))
|
||||
#define VN_CAST_CONST(nodep,nodetypename) (AstNode::privateConstCast<Ast ## nodetypename>(nodep))
|
||||
|
||||
// (V)erilator (N)ode deleted: Reference to deleted child (for assertions only)
|
||||
#define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
|
||||
|
|
@ -79,11 +82,11 @@ public:
|
|||
inline AstType(en _e) : m_e(_e) {}
|
||||
explicit inline AstType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(AstType lhs, AstType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstType lhs, AstType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstType::en lhs, AstType rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const AstType& lhs, const AstType& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const AstType& lhs, AstType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(AstType::en lhs, const AstType& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return os << rhs.ascii(); }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -108,7 +111,7 @@ public:
|
|||
"UNSIGNED", "SIGNED", "NOSIGN"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
inline AstNumeric() : m_e(UNSIGNED) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline AstNumeric(en _e) : m_e(_e) {}
|
||||
|
|
@ -125,11 +128,13 @@ public:
|
|||
inline bool isSigned() const { return m_e==SIGNED; }
|
||||
inline bool isNosign() const { return m_e==NOSIGN; }
|
||||
// No isUnsigned() as it's ambiguous if NOSIGN should be included or not.
|
||||
};
|
||||
inline bool operator==(AstNumeric lhs, AstNumeric rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstNumeric lhs, AstNumeric::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstNumeric::en lhs, AstNumeric rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstNumeric& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const AstNumeric& lhs, const AstNumeric& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const AstNumeric& lhs, AstNumeric::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(AstNumeric::en lhs, const AstNumeric& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstNumeric& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -142,7 +147,10 @@ public:
|
|||
NO_INLINE_MODULE,
|
||||
NO_INLINE_TASK,
|
||||
PUBLIC_MODULE,
|
||||
PUBLIC_TASK
|
||||
PUBLIC_TASK,
|
||||
FULL_CASE,
|
||||
PARALLEL_CASE,
|
||||
ENUM_SIZE
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstPragmaType() : m_e(ILLEGAL) {}
|
||||
|
|
@ -150,10 +158,12 @@ public:
|
|||
inline AstPragmaType(en _e) : m_e(_e) {}
|
||||
explicit inline AstPragmaType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(AstPragmaType lhs, AstPragmaType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstPragmaType lhs, AstPragmaType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstPragmaType::en lhs, AstPragmaType rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const AstPragmaType& lhs, const AstPragmaType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const AstPragmaType& lhs, AstPragmaType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(AstPragmaType::en lhs, const AstPragmaType& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -178,10 +188,12 @@ public:
|
|||
bool isTrace() const { return (m_e==TRACE_INIT || m_e==TRACE_INIT_SUB
|
||||
|| m_e==TRACE_FULL || m_e==TRACE_FULL_SUB
|
||||
|| m_e==TRACE_CHANGE || m_e==TRACE_CHANGE_SUB); }
|
||||
};
|
||||
inline bool operator==(AstCFuncType lhs, AstCFuncType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstCFuncType lhs, AstCFuncType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstCFuncType::en lhs, AstCFuncType rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const AstCFuncType& lhs, AstCFuncType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(AstCFuncType::en lhs, const AstCFuncType& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -267,10 +279,10 @@ public:
|
|||
inline VEdgeType(en _e) : m_e(_e) {}
|
||||
explicit inline VEdgeType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(VEdgeType lhs, VEdgeType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VEdgeType lhs, VEdgeType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VEdgeType::en lhs, VEdgeType rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const VEdgeType& lhs, VEdgeType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -301,6 +313,8 @@ public:
|
|||
//
|
||||
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
//
|
||||
TYPENAME, // V3Width processes
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked
|
||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||
|
|
@ -324,22 +338,25 @@ public:
|
|||
"ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
|
||||
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME",
|
||||
"MEMBER_BASE",
|
||||
"TYPENAME",
|
||||
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
||||
"VAR_NO_CLOCKER"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
inline AstAttrType() : m_e(ILLEGAL) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline AstAttrType(en _e) : m_e(_e) {}
|
||||
explicit inline AstAttrType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(AstAttrType lhs, AstAttrType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstAttrType lhs, AstAttrType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstAttrType::en lhs, AstAttrType rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const AstAttrType& lhs, const AstAttrType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const AstAttrType& lhs, AstAttrType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(AstAttrType::en lhs, const AstAttrType& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -373,7 +390,7 @@ public:
|
|||
" MAX"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
const char* dpiType() const {
|
||||
static const char* const names[] = {
|
||||
"%E-unk",
|
||||
|
|
@ -386,7 +403,7 @@ public:
|
|||
" MAX"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
static void selfTest() {
|
||||
UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), "SelfTest: Enum mismatch");
|
||||
UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), "SelfTest: Enum mismatch");
|
||||
|
|
@ -463,10 +480,16 @@ public:
|
|||
}
|
||||
bool isDouble() const { return m_e==DOUBLE; }
|
||||
bool isString() const { return m_e==STRING; }
|
||||
};
|
||||
inline bool operator==(AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstBasicDTypeKwd::en lhs, AstBasicDTypeKwd rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const AstBasicDTypeKwd& lhs, const AstBasicDTypeKwd& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const AstBasicDTypeKwd& lhs, AstBasicDTypeKwd::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
inline bool operator==(AstBasicDTypeKwd::en lhs, const AstBasicDTypeKwd& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -508,11 +531,13 @@ public:
|
|||
bool isWritable() const { return m_e == OUTPUT || m_e == INOUT
|
||||
|| m_e == REF; }
|
||||
bool isRefOrConstRef() const { return m_e == REF || m_e == CONSTREF; }
|
||||
};
|
||||
inline bool operator==(VDirection lhs, VDirection rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VDirection lhs, VDirection::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VDirection::en lhs, VDirection rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const VDirection& lhs, const VDirection& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const VDirection& lhs, VDirection::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VDirection::en lhs, const VDirection& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -535,14 +560,25 @@ public:
|
|||
static const char* const names[] = {
|
||||
"FALSE", "TRUE", "UNK"};
|
||||
return names[m_e]; }
|
||||
bool trueU() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; }
|
||||
bool falseU() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; }
|
||||
bool trueKnown() const { return m_e == BU_TRUE; }
|
||||
bool trueUnknown() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; }
|
||||
bool falseKnown() const { return m_e == BU_FALSE; }
|
||||
bool falseUnknown() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; }
|
||||
bool unknown() const { return m_e == BU_UNKNOWN; }
|
||||
};
|
||||
inline bool operator==(VBoolOrUnknown lhs, VBoolOrUnknown rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VBoolOrUnknown lhs, VBoolOrUnknown::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VBoolOrUnknown::en lhs, VBoolOrUnknown rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) { return os<<rhs.ascii(); }
|
||||
void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; }
|
||||
};
|
||||
inline bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
inline bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -607,11 +643,13 @@ public:
|
|||
bool isTemp() const {
|
||||
return (m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP || m_e==XTEMP);
|
||||
}
|
||||
};
|
||||
inline bool operator==(AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstVarType lhs, AstVarType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstVarType::en lhs, AstVarType rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const AstVarType& lhs, const AstVarType& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const AstVarType& lhs, AstVarType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(AstVarType::en lhs, const AstVarType& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -642,11 +680,15 @@ public:
|
|||
static const char* const names[] = {
|
||||
"", "VL_LIKELY", "VL_UNLIKELY"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
inline bool operator==(VBranchPred lhs, VBranchPred rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VBranchPred lhs, VBranchPred::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VBranchPred::en lhs, VBranchPred rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const VBranchPred& lhs, VBranchPred::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VBranchPred::en lhs, const VBranchPred& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -675,11 +717,19 @@ public:
|
|||
static const char* const names[] = {
|
||||
"", "clker", "non_clker"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
inline bool operator==(VVarAttrClocker lhs, VVarAttrClocker rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VVarAttrClocker lhs, VVarAttrClocker::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VVarAttrClocker::en lhs, VVarAttrClocker rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const VVarAttrClocker& lhs, VVarAttrClocker::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
inline bool operator==(VVarAttrClocker::en lhs, const VVarAttrClocker& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -701,10 +751,10 @@ public:
|
|||
static const char* const names[] = {
|
||||
"always", "always_ff", "always_latch", "always_comb"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
inline bool operator==(VAlwaysKwd lhs, VAlwaysKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VAlwaysKwd lhs, VAlwaysKwd::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VAlwaysKwd::en lhs, VAlwaysKwd rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -722,10 +772,10 @@ public:
|
|||
inline VCaseType(en _e) : m_e(_e) {}
|
||||
explicit inline VCaseType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(VCaseType lhs, VCaseType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VCaseType lhs, VCaseType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VCaseType::en lhs, VCaseType rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const VCaseType& lhs, const VCaseType& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const VCaseType& lhs, VCaseType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -751,10 +801,16 @@ public:
|
|||
static const char* const names[] = {
|
||||
"display", "write", "info", "error", "warning", "fatal"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
inline bool operator==(AstDisplayType lhs, AstDisplayType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(AstDisplayType lhs, AstDisplayType::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(AstDisplayType::en lhs, AstDisplayType rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const AstDisplayType& lhs, const AstDisplayType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const AstDisplayType& lhs, AstDisplayType::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -774,11 +830,15 @@ public:
|
|||
static const char* const names[] = {
|
||||
"", "TEXT", "PREDOT"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
inline bool operator==(VParseRefExp lhs, VParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VParseRefExp lhs, VParseRefExp::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VParseRefExp::en lhs, VParseRefExp rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const VParseRefExp& lhs, VParseRefExp::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VParseRefExp::en lhs, const VParseRefExp& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// VNumRange - Structure containing numeric range information
|
||||
|
|
@ -840,6 +900,36 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) { rhs.du
|
|||
|
||||
//######################################################################
|
||||
|
||||
class VUseType {
|
||||
public:
|
||||
enum en {
|
||||
IMP_INCLUDE, // Implementation (.cpp) needs an include
|
||||
INT_INCLUDE, // Interface (.h) needs an include
|
||||
IMP_FWD_CLASS, // Implementation (.cpp) needs a forward class declaration
|
||||
INT_FWD_CLASS, // Interface (.h) needs a forward class declaration
|
||||
};
|
||||
enum en m_e;
|
||||
inline VUseType() : m_e(IMP_FWD_CLASS) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline VUseType(en _e) : m_e(_e) {}
|
||||
explicit inline VUseType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; }
|
||||
bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; }
|
||||
operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"};
|
||||
return names[m_e];
|
||||
}
|
||||
};
|
||||
inline bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VBasicTypeKey {
|
||||
public:
|
||||
int m_width; // From AstNodeDType: Bit width of operation
|
||||
|
|
@ -934,14 +1024,14 @@ protected:
|
|||
clearcnt(id, cntGblRef, userBusyRef); // Includes a checkUse for us
|
||||
userBusyRef = false;
|
||||
}
|
||||
static void clearcnt(int id, uint32_t& cntGblRef, bool& userBusyRef) {
|
||||
static void clearcnt(int id, uint32_t& cntGblRef, const bool& userBusyRef) {
|
||||
UASSERT_STATIC(userBusyRef, "Clear of User"+cvtToStr(id)+"() not under AstUserInUse");
|
||||
// If this really fires and is real (after 2^32 edits???)
|
||||
// we could just walk the tree and clear manually
|
||||
++cntGblRef;
|
||||
UASSERT_STATIC(cntGblRef, "User*() overflowed!");
|
||||
}
|
||||
static void checkcnt(int id, uint32_t&, bool& userBusyRef) {
|
||||
static void checkcnt(int id, uint32_t&, const bool& userBusyRef) {
|
||||
UASSERT_STATIC(userBusyRef, "Check of User"+cvtToStr(id)+"() failed, not under AstUserInUse");
|
||||
}
|
||||
};
|
||||
|
|
@ -1106,7 +1196,7 @@ public:
|
|||
explicit V3Hash(VNUser u) { m_both = u.toInt(); }
|
||||
V3Hash operator+= (const V3Hash& rh) {
|
||||
setBoth(depth()+rh.depth(), (hshval()*31+rh.hshval()));
|
||||
return *this; };
|
||||
return *this; }
|
||||
// Creating from raw data (sameHash functions)
|
||||
V3Hash() { setBoth(1, 0); }
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
|
|
@ -1153,6 +1243,8 @@ class AstNode {
|
|||
|
||||
AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list
|
||||
|
||||
const AstType m_type; // Node sub-type identifier
|
||||
|
||||
FileLine* m_fileline; // Where it was declared
|
||||
vluint64_t m_editCount; // When it was last edited
|
||||
static vluint64_t s_editCntGbl; // Global edit counter
|
||||
|
|
@ -1207,8 +1299,10 @@ public:
|
|||
|
||||
protected:
|
||||
// CONSTRUCTORS
|
||||
AstNode() { init(); }
|
||||
explicit AstNode(FileLine* fileline) {init(); m_fileline = fileline; }
|
||||
AstNode(AstType t)
|
||||
: m_type(t) { init(); }
|
||||
AstNode(AstType t, FileLine* fl)
|
||||
: m_type(t) { init(); m_fileline = fl; }
|
||||
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
|
||||
virtual void cloneRelink() {}
|
||||
void cloneRelinkTree();
|
||||
|
|
@ -1239,7 +1333,7 @@ protected:
|
|||
|
||||
public:
|
||||
// ACCESSORS
|
||||
virtual AstType type() const = 0;
|
||||
inline AstType type() const { return m_type; }
|
||||
const char* typeName() const { return type().ascii(); } // See also prettyTypeName
|
||||
AstNode* nextp() const { return m_nextp; }
|
||||
AstNode* backp() const { return m_backp; }
|
||||
|
|
@ -1295,7 +1389,7 @@ public:
|
|||
static string vcdName(const string& namein); // Name for printing out to vcd files
|
||||
string prettyName() const { return prettyName(name()); }
|
||||
string prettyNameQ() const { return prettyNameQ(name()); }
|
||||
string prettyTypeName() const; // "VARREF" for error messages
|
||||
string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name)
|
||||
virtual string prettyOperatorName() const { return "operator "+prettyTypeName(); }
|
||||
FileLine* fileline() const { return m_fileline; }
|
||||
void fileline(FileLine* fl) { m_fileline = fl; }
|
||||
|
|
@ -1529,11 +1623,22 @@ private:
|
|||
|
||||
// CONVERSION
|
||||
public:
|
||||
#include "V3Ast__gen_interface.h" // From ./astgen
|
||||
// Things like:
|
||||
// AstAlways* castAlways();
|
||||
// These for use by VN_IS macro only
|
||||
template<class T>
|
||||
static bool privateIs(const AstNode* nodep);
|
||||
|
||||
// These for use by VN_CAST macro only
|
||||
template<class T>
|
||||
static T* privateCast(AstNode* nodep);
|
||||
|
||||
// These for use by VN_CAST_CONST macro only
|
||||
template<class T>
|
||||
static const T* privateConstCast(const AstNode* nodep);
|
||||
};
|
||||
|
||||
// Specialisations of privateIs/privateCast
|
||||
#include "V3Ast__gen_impl.h" // From ./astgen
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
|
||||
if (!rhs) os<<"NULL"; else rhs->dump(os); return os;
|
||||
}
|
||||
|
|
@ -1553,8 +1658,8 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
|
|||
class AstNodeMath : public AstNode {
|
||||
// Math -- anything that's part of an expression tree
|
||||
public:
|
||||
explicit AstNodeMath(FileLine* fl)
|
||||
: AstNode(fl) {}
|
||||
AstNodeMath(AstType t, FileLine* fl)
|
||||
: AstNode(t, fl) {}
|
||||
ASTNODE_BASE_FUNCS(NodeMath)
|
||||
// METHODS
|
||||
virtual bool hasDType() const { return true; }
|
||||
|
|
@ -1570,8 +1675,8 @@ public:
|
|||
class AstNodeTermop : public AstNodeMath {
|
||||
// Terminal operator -- a operator with no "inputs"
|
||||
public:
|
||||
explicit AstNodeTermop(FileLine* fl)
|
||||
: AstNodeMath(fl) {}
|
||||
AstNodeTermop(AstType t, FileLine* fl)
|
||||
: AstNodeMath(t, fl) {}
|
||||
ASTNODE_BASE_FUNCS(NodeTermop)
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// See checkTreeIter also that asserts no children
|
||||
|
|
@ -1582,8 +1687,8 @@ public:
|
|||
class AstNodeUniop : public AstNodeMath {
|
||||
// Unary math
|
||||
public:
|
||||
AstNodeUniop(FileLine* fl, AstNode* lhsp)
|
||||
: AstNodeMath(fl) {
|
||||
AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp)
|
||||
: AstNodeMath(t, fl) {
|
||||
dtypeFrom(lhsp);
|
||||
setOp1p(lhsp); }
|
||||
ASTNODE_BASE_FUNCS(NodeUniop)
|
||||
|
|
@ -1604,8 +1709,8 @@ public:
|
|||
class AstNodeBiop : public AstNodeMath {
|
||||
// Binary math
|
||||
public:
|
||||
AstNodeBiop(FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: AstNodeMath(fl) {
|
||||
AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: AstNodeMath(t, fl) {
|
||||
setOp1p(lhs); setOp2p(rhs); }
|
||||
ASTNODE_BASE_FUNCS(NodeBiop)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; // Clone single node, just get same type back.
|
||||
|
|
@ -1631,8 +1736,8 @@ public:
|
|||
class AstNodeTriop : public AstNodeMath {
|
||||
// Trinary math
|
||||
public:
|
||||
AstNodeTriop(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
|
||||
: AstNodeMath(fl) {
|
||||
AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
|
||||
: AstNodeMath(t, fl) {
|
||||
setOp1p(lhs); setOp2p(rhs); setOp3p(ths); }
|
||||
ASTNODE_BASE_FUNCS(NodeTriop)
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
|
|
@ -1659,22 +1764,22 @@ public:
|
|||
class AstNodeBiCom : public AstNodeBiop {
|
||||
// Binary math with commutative properties
|
||||
public:
|
||||
AstNodeBiCom(FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: AstNodeBiop(fl, lhs, rhs) {}
|
||||
AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: AstNodeBiop(t, fl, lhs, rhs) {}
|
||||
ASTNODE_BASE_FUNCS(NodeBiCom)
|
||||
};
|
||||
|
||||
class AstNodeBiComAsv : public AstNodeBiCom {
|
||||
// Binary math with commutative & associative properties
|
||||
public:
|
||||
AstNodeBiComAsv(FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: AstNodeBiCom(fl, lhs, rhs) {}
|
||||
AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: AstNodeBiCom(t, fl, lhs, rhs) {}
|
||||
ASTNODE_BASE_FUNCS(NodeBiComAsv)
|
||||
};
|
||||
class AstNodeCond : public AstNodeTriop {
|
||||
public:
|
||||
AstNodeCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
|
||||
: AstNodeTriop(fl, condp, expr1p, expr2p) {
|
||||
AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
|
||||
: AstNodeTriop(t, fl, condp, expr1p, expr2p) {
|
||||
if (expr1p) dtypeFrom(expr1p);
|
||||
else if (expr2p) dtypeFrom(expr2p);
|
||||
}
|
||||
|
|
@ -1700,8 +1805,8 @@ public:
|
|||
class AstNodePreSel : public AstNode {
|
||||
// Something that becomes an AstSel
|
||||
public:
|
||||
AstNodePreSel(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
|
||||
: AstNode(fl) {
|
||||
AstNodePreSel(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
|
||||
: AstNode(t, fl) {
|
||||
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
|
||||
ASTNODE_BASE_FUNCS(NodePreSel)
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
|
|
@ -1720,20 +1825,23 @@ public:
|
|||
|
||||
class AstNodeStmt : public AstNode {
|
||||
// Statement -- anything that's directly under a function
|
||||
bool m_statement; // Really a statement (e.g. not a function with return)
|
||||
public:
|
||||
explicit AstNodeStmt(FileLine* fl)
|
||||
: AstNode(fl) {}
|
||||
AstNodeStmt(AstType t, FileLine* fl, bool statement = true)
|
||||
: AstNode(t, fl)
|
||||
, m_statement(statement) {}
|
||||
ASTNODE_BASE_FUNCS(NodeStmt)
|
||||
// METHODS
|
||||
virtual bool isStatement() const { return true; } // Really a statement
|
||||
bool isStatement() const { return m_statement; } // Really a statement
|
||||
void statement(bool flag) { m_statement = flag; }
|
||||
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||
};
|
||||
|
||||
class AstNodeAssign : public AstNodeStmt {
|
||||
public:
|
||||
AstNodeAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: AstNodeStmt(fl) {
|
||||
AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: AstNodeStmt(t, fl) {
|
||||
setOp1p(rhsp); setOp2p(lhsp);
|
||||
dtypeFrom(lhsp);
|
||||
}
|
||||
|
|
@ -1755,9 +1863,9 @@ public:
|
|||
|
||||
class AstNodeFor : public AstNodeStmt {
|
||||
public:
|
||||
AstNodeFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
||||
AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp,
|
||||
AstNode* incsp, AstNode* bodysp)
|
||||
: AstNodeStmt(fileline) {
|
||||
: AstNodeStmt(t, fl) {
|
||||
addNOp1p(initsp); setOp2p(condp); addNOp3p(incsp); addNOp4p(bodysp);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeFor)
|
||||
|
|
@ -1775,8 +1883,8 @@ class AstNodeIf : public AstNodeStmt {
|
|||
private:
|
||||
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
|
||||
public:
|
||||
AstNodeIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
||||
: AstNodeStmt(fl) {
|
||||
AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
||||
: AstNodeStmt(t, fl) {
|
||||
setOp1p(condp); addNOp2p(ifsp); addNOp3p(elsesp);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeIf)
|
||||
|
|
@ -1797,8 +1905,8 @@ public:
|
|||
|
||||
class AstNodeCase : public AstNodeStmt {
|
||||
public:
|
||||
AstNodeCase(FileLine* fl, AstNode* exprp, AstNode* casesp)
|
||||
: AstNodeStmt(fl) {
|
||||
AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp)
|
||||
: AstNodeStmt(t, fl) {
|
||||
setOp1p(exprp); addNOp2p(casesp);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeCase)
|
||||
|
|
@ -1813,7 +1921,8 @@ public:
|
|||
class AstNodeSenItem : public AstNode {
|
||||
// An AstSenItem or AstSenGate
|
||||
public:
|
||||
explicit AstNodeSenItem(FileLine* fl) : AstNode(fl) {}
|
||||
AstNodeSenItem(AstType t, FileLine* fl)
|
||||
: AstNode(t, fl) {}
|
||||
ASTNODE_BASE_FUNCS(NodeSenItem)
|
||||
virtual bool isClocked() const = 0;
|
||||
virtual bool isCombo() const = 0;
|
||||
|
|
@ -1834,14 +1943,14 @@ private:
|
|||
bool m_hierThis; // Hiername points to "this" function
|
||||
void init();
|
||||
public:
|
||||
AstNodeVarRef(FileLine* fl, const string& name, bool lvalue)
|
||||
: AstNodeMath(fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL),
|
||||
m_packagep(NULL), m_name(name), m_hierThis(false) {
|
||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
|
||||
: AstNodeMath(t, fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL)
|
||||
, m_packagep(NULL), m_name(name), m_hierThis(false) {
|
||||
init();
|
||||
}
|
||||
AstNodeVarRef(FileLine* fl, const string& name, AstVar* varp, bool lvalue)
|
||||
: AstNodeMath(fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL),
|
||||
m_packagep(NULL), m_name(name), m_hierThis(false) {
|
||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
|
||||
: AstNodeMath(t, fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL)
|
||||
, m_packagep(NULL), m_name(name), m_hierThis(false) {
|
||||
// May have varp==NULL
|
||||
init();
|
||||
}
|
||||
|
|
@ -1876,8 +1985,8 @@ private:
|
|||
string m_text;
|
||||
public:
|
||||
// Node that simply puts text into the output stream
|
||||
AstNodeText(FileLine* fileline, const string& textp)
|
||||
: AstNode(fileline) {
|
||||
AstNodeText(AstType t, FileLine* fl, const string& textp)
|
||||
: AstNode(t, fl) {
|
||||
m_text = textp; // Copy it
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeText)
|
||||
|
|
@ -1902,7 +2011,8 @@ private:
|
|||
static int s_uniqueNum; // Unique number assigned to each dtype during creation for IEEE matching
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit AstNodeDType(FileLine* fl) : AstNode(fl) {
|
||||
AstNodeDType(AstType t, FileLine* fl)
|
||||
: AstNode(t, fl) {
|
||||
m_width = 0; m_widthMin = 0; m_generic = false;
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeDType)
|
||||
|
|
@ -1924,6 +2034,8 @@ public:
|
|||
virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
virtual AstNodeDType* subDTypep() const { return NULL; } // Iff has a non-null subDTypep(), as generic node function
|
||||
virtual bool isFourstate() const;
|
||||
virtual string prettyDTypeName() const { return prettyTypeName(); } // Ideally an IEEE $typename
|
||||
string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; }
|
||||
//
|
||||
// Changing the width may confuse the data type resolution, so must clear
|
||||
// TypeTable cache after use.
|
||||
|
|
@ -1962,8 +2074,8 @@ private:
|
|||
bool m_isFourstate;
|
||||
MemberNameMap m_members;
|
||||
public:
|
||||
AstNodeUOrStructDType(FileLine* fl, AstNumeric numericUnpack)
|
||||
: AstNodeDType(fl) {
|
||||
AstNodeUOrStructDType(AstType t, FileLine* fl, AstNumeric numericUnpack)
|
||||
: AstNodeDType(t, fl) {
|
||||
// AstNumeric::NOSIGN overloaded to indicate not packed
|
||||
m_packed = (numericUnpack != AstNumeric::NOSIGN);
|
||||
m_isFourstate = false; // V3Width computes
|
||||
|
|
@ -2013,7 +2125,8 @@ private:
|
|||
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
|
||||
AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable
|
||||
public:
|
||||
explicit AstNodeArrayDType(FileLine* fl) : AstNodeDType(fl) {
|
||||
AstNodeArrayDType(AstType t, FileLine* fl)
|
||||
: AstNodeDType(t, fl) {
|
||||
m_refDTypep = NULL;
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeArrayDType)
|
||||
|
|
@ -2064,8 +2177,8 @@ public:
|
|||
class AstNodeSel : public AstNodeBiop {
|
||||
// Single bit range extraction, perhaps with non-constant selection or array selection
|
||||
public:
|
||||
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
: AstNodeBiop(fl, fromp, bitp) {}
|
||||
AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
: AstNodeBiop(t, fl, fromp, bitp) {}
|
||||
ASTNODE_BASE_FUNCS(NodeSel)
|
||||
AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
|
|
@ -2078,7 +2191,8 @@ public:
|
|||
class AstNodeStream : public AstNodeBiop {
|
||||
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
|
||||
public:
|
||||
AstNodeStream(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: AstNodeBiop(t, fl, lhsp, rhsp) {
|
||||
if (lhsp->dtypep()) {
|
||||
dtypeSetLogicSized(lhsp->dtypep()->width(), AstNumeric::UNSIGNED);
|
||||
}
|
||||
|
|
@ -2104,8 +2218,8 @@ private:
|
|||
bool m_dpiTask:1; // DPI import task (vs. void function)
|
||||
bool m_pure:1; // DPI import pure
|
||||
public:
|
||||
AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp)
|
||||
: AstNode(fileline)
|
||||
AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
||||
: AstNode(t, fl)
|
||||
, m_name(name)
|
||||
, m_dpiOpenParent(0), m_taskPublic(false)
|
||||
, m_attrIsolateAssign(false), m_prototype(false)
|
||||
|
|
@ -2167,13 +2281,13 @@ private:
|
|||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
AstPackage* m_packagep; // Package hierarchy
|
||||
public:
|
||||
AstNodeFTaskRef(FileLine* fl, AstNode* namep, AstNode* pinsp)
|
||||
: AstNodeStmt(fl)
|
||||
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
|
||||
: AstNodeStmt(t, fl, statement)
|
||||
, m_taskp(NULL), m_packagep(NULL) {
|
||||
setOp1p(namep); addNOp2p(pinsp);
|
||||
}
|
||||
AstNodeFTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
: AstNodeStmt(fl)
|
||||
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp)
|
||||
: AstNodeStmt(t, fl, statement)
|
||||
, m_taskp(NULL), m_name(name), m_packagep(NULL) {
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
|
|
@ -2224,8 +2338,8 @@ private:
|
|||
int m_varNum; // Incrementing variable number
|
||||
int m_typeNum; // Incrementing implicit type number
|
||||
public:
|
||||
AstNodeModule(FileLine* fl, const string& name)
|
||||
: AstNode(fl)
|
||||
AstNodeModule(AstType t, FileLine* fl, const string& name)
|
||||
: AstNode(t, fl)
|
||||
, m_name(name), m_origName(name)
|
||||
, m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false)
|
||||
, m_internal(false), m_recursive(false), m_recursiveClone(false)
|
||||
|
|
@ -2238,7 +2352,7 @@ public:
|
|||
AstActive* activesp() const { return VN_CAST(op3p(), Active); } // op3 = List of i/sblocks
|
||||
// METHODS
|
||||
void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
|
||||
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
|
||||
void addStmtp(AstNode* nodep) { addNOp2p(nodep); }
|
||||
void addActivep(AstNode* nodep) { addOp3p(nodep); }
|
||||
// ACCESSORS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
|
|
@ -2269,18 +2383,14 @@ public:
|
|||
class AstNodeRange : public AstNode {
|
||||
// A range, sized or unsized
|
||||
public:
|
||||
explicit AstNodeRange(FileLine* fl) : AstNode(fl) { }
|
||||
AstNodeRange(AstType t, FileLine* fl)
|
||||
: AstNode(t, fl) {}
|
||||
ASTNODE_BASE_FUNCS(NodeRange)
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#include "V3AstNodes.h"
|
||||
|
||||
#include "V3Ast__gen_impl.h" // From ./astgen
|
||||
// Things like:
|
||||
// inline AstAlways* AstNode::castAlways() { return dynamic_cast<AstAlways*>(this); }
|
||||
// inline bool AstNode::privateIsaAlways(const AstNode* nodep) { return nodep && nodep->type() == AstType::atAlways; }
|
||||
#include "V3AstNodes__gen.h"
|
||||
|
||||
//######################################################################
|
||||
// Inline AstNVisitor METHODS
|
||||
|
|
|
|||
|
|
@ -168,11 +168,11 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
|||
}
|
||||
|
||||
AstExecGraph::AstExecGraph(FileLine* fileline)
|
||||
: AstNode(fileline) {
|
||||
: AstNode(AstType::atExecGraph, fileline) {
|
||||
m_depGraphp = new V3Graph;
|
||||
}
|
||||
AstExecGraph::~AstExecGraph() {
|
||||
delete m_depGraphp; VL_DANGLING(m_depGraphp);
|
||||
VL_DO_DANGLING(delete m_depGraphp, m_depGraphp);
|
||||
}
|
||||
|
||||
bool AstVar::isSigPublic() const {
|
||||
|
|
@ -630,7 +630,7 @@ std::pair<uint32_t,uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
|||
else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
|
||||
}
|
||||
else if (const AstStructDType* sdtypep = VN_CAST(dtypep, StructDType)) {
|
||||
else if (VN_IS(dtypep, StructDType)) {
|
||||
packed++;
|
||||
}
|
||||
break;
|
||||
|
|
@ -798,7 +798,7 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd)
|
|||
// check the detailed map for this same node
|
||||
// Also adds this new node to the detailed map
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) new1p->deleteTree();
|
||||
if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
||||
else addTypesp(newp);
|
||||
//
|
||||
m_basicps[kwd] = newp;
|
||||
|
|
@ -809,7 +809,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
|
|||
int width, int widthMin, AstNumeric numeric) {
|
||||
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) new1p->deleteTree();
|
||||
if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
||||
else addTypesp(newp);
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -818,7 +818,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
|
|||
VNumRange range, int widthMin, AstNumeric numeric) {
|
||||
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) new1p->deleteTree();
|
||||
if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
||||
else addTypesp(newp);
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -943,6 +943,14 @@ void AstBasicDType::dump(std::ostream& str) const {
|
|||
str<<" kwd="<<keyword().ascii();
|
||||
if (isRanged() && !rangep()) str<<" range=["<<left()<<":"<<right()<<"]";
|
||||
}
|
||||
string AstBasicDType::prettyDTypeName() const {
|
||||
std::ostringstream os;
|
||||
os << keyword().ascii();
|
||||
if (isRanged() && !rangep() && keyword().width() <= 1) {
|
||||
os << "[" << left() << ":" << right() << "]";
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
void AstCCast::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str<<" sz"<<size();
|
||||
|
|
@ -999,6 +1007,12 @@ void AstJumpGo::dump(std::ostream& str) const {
|
|||
if (labelp()) { labelp()->dump(str); }
|
||||
else { str<<"%Error:UNLINKED"; }
|
||||
}
|
||||
void AstMemberSel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> ";
|
||||
if (varp()) { varp()->dump(str); }
|
||||
else { str << "%Error:UNLINKED"; }
|
||||
}
|
||||
void AstModportFTaskRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isExport()) str<<" EXPORT";
|
||||
|
|
@ -1073,6 +1087,24 @@ void AstNodeArrayDType::dump(std::ostream& str) const {
|
|||
this->AstNodeDType::dump(str);
|
||||
str<<" "<<declRange();
|
||||
}
|
||||
string AstPackArrayDType::prettyDTypeName() const {
|
||||
std::ostringstream os;
|
||||
os << subDTypep()->prettyDTypeName() << declRange();
|
||||
return os.str();
|
||||
}
|
||||
string AstUnpackArrayDType::prettyDTypeName() const {
|
||||
std::ostringstream os;
|
||||
string ranges = cvtToStr(declRange());
|
||||
// Unfortunately we need a single $ for the first unpacked, and all
|
||||
// dimensions shown in "reverse" order
|
||||
AstNodeDType* subp = subDTypep()->skipRefp();
|
||||
while (AstUnpackArrayDType* adtypep = VN_CAST(subp, UnpackArrayDType)) {
|
||||
ranges += cvtToStr(adtypep->declRange());
|
||||
subp = adtypep->subDTypep()->skipRefp();
|
||||
}
|
||||
os << subp->prettyDTypeName() << "$" << ranges;
|
||||
return os.str();
|
||||
}
|
||||
void AstNodeModule::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str<<" L"<<level();
|
||||
|
|
@ -1133,10 +1165,18 @@ void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
|||
this->AstNodeDType::dumpSmall(str);
|
||||
str<<"[assoc-"<<(void*)keyDTypep()<<"]";
|
||||
}
|
||||
string AstAssocArrayDType::prettyDTypeName() const {
|
||||
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
|
||||
}
|
||||
void AstQueueDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str<<"[queue]";
|
||||
}
|
||||
string AstQueueDType::prettyDTypeName() const {
|
||||
string str = subDTypep()->prettyDTypeName() + "[$";
|
||||
if (boundConst()) str += ":" + cvtToStr(boundConst());
|
||||
return str + "]";
|
||||
}
|
||||
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str<<"[]";
|
||||
|
|
@ -1296,8 +1336,15 @@ void AstCFunc::dump(std::ostream& str) const {
|
|||
if (slow()) str<<" [SLOW]";
|
||||
if (pure()) str<<" [PURE]";
|
||||
if (isStatic().unknown()) str<<" [STATICU]";
|
||||
else if (isStatic().trueU()) str<<" [STATIC]";
|
||||
else if (isStatic().trueUnknown()) str<<" [STATIC]";
|
||||
if (dpiImport()) str<<" [DPII]";
|
||||
if (dpiExport()) str<<" [DPIX]";
|
||||
if (dpiExportWrapper()) str<<" [DPIXWR]";
|
||||
if (isConstructor()) str<<" [CTOR]";
|
||||
if (isDestructor()) str<<" [DTOR]";
|
||||
if (isVirtual()) str<<" [VIRT]";
|
||||
}
|
||||
void AstCUse::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [" << useType() << "]";
|
||||
}
|
||||
|
|
|
|||
1265
src/V3AstNodes.h
1265
src/V3AstNodes.h
File diff suppressed because it is too large
Load Diff
|
|
@ -72,20 +72,21 @@ private:
|
|||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_repeatNum; // Repeat counter
|
||||
int m_ifDepth; // Current if depth
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_repeatNum = 0;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
// Rename it
|
||||
if (m_unnamedScope != "") {
|
||||
|
|
@ -110,7 +111,7 @@ private:
|
|||
m_namedScope = oldScope;
|
||||
m_unnamedScope = oldUnnamed;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
string oldScope = m_namedScope;
|
||||
|
|
@ -157,9 +158,9 @@ private:
|
|||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
||||
|
|
@ -170,7 +171,7 @@ private:
|
|||
else m_modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(8," CELL "<<nodep<<endl);
|
||||
if (m_namedScope != "") {
|
||||
m_statep->userMarkChanged(nodep);
|
||||
|
|
@ -183,14 +184,14 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
UINFO(9, " VARXREF "<<nodep<<endl);
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "") {
|
||||
nodep->inlinedDots(m_namedScope);
|
||||
UINFO(9, " rescope to "<<nodep<<endl);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Inline
|
||||
if (nodep->user1SetOnce()) return; // Don't double-add text's
|
||||
|
|
@ -203,13 +204,13 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) {
|
||||
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
|
||||
// Don't need to fix path in coverage statements, they're not under
|
||||
// any BEGINs, but V3Coverage adds them all under the module itself.
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
// VISITORS - LINT CHECK
|
||||
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered
|
||||
// Check IFDEPTH warning - could be in other transform files if desire
|
||||
int prevIfDepth = m_ifDepth;
|
||||
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
|
||||
|
|
@ -223,7 +224,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_ifDepth = prevIfDepth;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -232,7 +233,6 @@ public:
|
|||
m_statep = statep;
|
||||
m_modp = NULL;
|
||||
m_ftaskp = NULL;
|
||||
m_repeatNum = 0;
|
||||
m_ifDepth = 0;
|
||||
iterate(nodep);
|
||||
}
|
||||
|
|
@ -249,21 +249,21 @@ private:
|
|||
// AstNodeFTask::user1p // Node replaced, rename it
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->taskp()->user1()) { // It was converted
|
||||
UINFO(9, " relinkFTask "<<nodep<<endl);
|
||||
nodep->name(nodep->taskp()->name());
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp()->user1()) { // It was converted
|
||||
UINFO(9, " relinVarRef "<<nodep<<endl);
|
||||
nodep->name(nodep->varp()->name());
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstIfaceRefDType* nodep) {
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
// May have changed cell names
|
||||
// TypeTable is always after all modules, so names are stable
|
||||
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
|
||||
|
|
@ -272,7 +272,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
UINFO(4," IF: "<<nodep<<endl);
|
||||
int lastLikely = m_likely;
|
||||
int lastUnlikely = m_unlikely;
|
||||
|
|
@ -96,17 +96,17 @@ private:
|
|||
m_likely = lastLikely;
|
||||
m_unlikely = lastUnlikely;
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
checkUnlikely(nodep);
|
||||
nodep->funcp()->user1Inc();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
checkUnlikely(nodep);
|
||||
m_cfuncsp.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
checkUnlikely(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ private:
|
|||
iterateChildrenConst(nodep);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -257,7 +257,7 @@ private:
|
|||
iterateChildrenConst(nodep);
|
||||
BrokenTable::setUnder(nodep, false);
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
processAndIterate(nodep);
|
||||
UASSERT_OBJ(!(v3Global.assertDTypesResolved()
|
||||
&& nodep->brokeLhsMustBeLvalue()
|
||||
|
|
@ -265,7 +265,7 @@ private:
|
|||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
|
||||
nodep, "Assignment LHS is not an lvalue");
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Handle SV classes
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Class's Transformations:
|
||||
//
|
||||
// Each module:
|
||||
// Each cell:
|
||||
// Create CUse for cell forward declaration
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3CUse.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CUseState {
|
||||
private:
|
||||
// MEMBERS
|
||||
AstNodeModule* m_modInsertp; // Current module to insert AstCUse under
|
||||
typedef std::pair<VUseType, string> UseString;
|
||||
std::map<UseString, AstCUse*> m_didUse; // What we already used
|
||||
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstClass::user1() -> bool. True if class needs to_string dumper
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
public:
|
||||
AstCUse* newUse(AstNode* nodep, VUseType useType, const string& name) {
|
||||
UseString key(useType, name);
|
||||
if (m_didUse.find(key) == m_didUse.end()) {
|
||||
AstCUse* newp = new AstCUse(nodep->fileline(), useType, name);
|
||||
m_modInsertp->addStmtp(newp);
|
||||
UINFO(8, "Insert " << newp << endl);
|
||||
m_didUse[key] = newp;
|
||||
}
|
||||
return m_didUse[key];
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit CUseState(AstNodeModule* nodep)
|
||||
: m_modInsertp(nodep) {}
|
||||
virtual ~CUseState() {}
|
||||
VL_UNCOPYABLE(CUseState);
|
||||
};
|
||||
|
||||
class CUseVisitor : public AstNVisitor {
|
||||
// MEMBERS
|
||||
CUseState m_state; // Inserter state
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// Module use builders
|
||||
void makeUseCells(AstNodeModule* nodep) {
|
||||
for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCell* cellp = VN_CAST(itemp, Cell)) {
|
||||
// Currently no include because we include __Syms which has them all
|
||||
m_state.newUse(nodep, VUseType::INT_FWD_CLASS, cellp->modp()->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
if (v3Global.opt.trace()) {
|
||||
AstCUse* usep
|
||||
= m_state.newUse(nodep, VUseType::INT_FWD_CLASS, v3Global.opt.traceClassBase());
|
||||
usep->protect(false);
|
||||
}
|
||||
makeUseCells(nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {} // All in AstNodeModule
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CUseVisitor(AstNodeModule* nodep)
|
||||
: m_state(nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CUseVisitor() {}
|
||||
VL_UNCOPYABLE(CUseVisitor);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Class class functions
|
||||
|
||||
void V3CUse::cUseAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// Call visitor separately for each module, so visitor state is cleared
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
// Insert under this module; someday we should e.g. make Ast
|
||||
// for each output file and put under that
|
||||
CUseVisitor visitor(modp);
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("cuse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Pre C-Emit stage changes
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3CUSE_H_
|
||||
#define _V3CUSE_H_ 1
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CUse {
|
||||
public:
|
||||
static void cUseAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -62,7 +62,7 @@ private:
|
|||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
virtual void visit(AstNodeCase* nodep) {
|
||||
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
|
||||
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
|
||||
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ private:
|
|||
m_caseExprp = NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConst* nodep) {
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
// See also neverItem
|
||||
if (m_caseExprp && nodep->num().isFourState()) {
|
||||
if (VN_IS(m_caseExprp, GenCase)) {
|
||||
|
|
@ -106,7 +106,7 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -250,7 +250,7 @@ private:
|
|||
if (m_valueItem[a] != m_valueItem[b]) { same = false; break; }
|
||||
}
|
||||
if (same) {
|
||||
tree1p->deleteTree(); VL_DANGLING(tree1p);
|
||||
VL_DO_DANGLING(tree1p->deleteTree(), tree1p);
|
||||
return tree0p;
|
||||
}
|
||||
|
||||
|
|
@ -299,8 +299,8 @@ private:
|
|||
|
||||
if (ifrootp) nodep->replaceWith(ifrootp);
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
cexprp->deleteTree(); VL_DANGLING(cexprp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
|
||||
if (debug()>=9) ifrootp->dumpTree(cout, " _simp: ");
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +331,7 @@ private:
|
|||
AstConst* iconstp = VN_CAST(icondp, Const);
|
||||
if (iconstp && neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
|
||||
// For simplicity, make expression that is not equal, and let later
|
||||
// optimizations remove it
|
||||
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
|
||||
|
|
@ -357,7 +357,7 @@ private:
|
|||
AstNode* and2p = new AstAnd(itemp->fileline(),
|
||||
new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
|
||||
|
|
@ -375,7 +375,7 @@ private:
|
|||
itemp->condsp(ifexprp);
|
||||
}
|
||||
}
|
||||
cexprp->deleteTree(); VL_DANGLING(cexprp);
|
||||
VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
|
||||
if (!hadDefault) {
|
||||
// If there was no default, add a empty one, this greatly simplifies below code
|
||||
// and constant propagation will just eliminate it for us later.
|
||||
|
|
@ -418,7 +418,7 @@ private:
|
|||
{ // Make the new lower IF and attach in the tree
|
||||
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
|
||||
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
|
||||
itemexprp->deleteTree(); VL_DANGLING(itemexprp);
|
||||
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
|
||||
|
|
@ -434,7 +434,7 @@ private:
|
|||
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
|
||||
if (grouprootp) nodep->replaceWith(grouprootp);
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
void replaceCaseParallel(AstCase* nodep, bool noOverlapsAllCovered) {
|
||||
|
|
@ -460,7 +460,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCase* nodep) {
|
||||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
V3Case::caseLint(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (debug()>=9) nodep->dumpTree(cout, " case_old: ");
|
||||
|
|
@ -468,15 +468,15 @@ private:
|
|||
// It's a simple priority encoder or complete statement
|
||||
// we can make a tree of statements to avoid extra comparisons
|
||||
++m_statCaseFast;
|
||||
replaceCaseFast(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceCaseFast(nodep), nodep);
|
||||
} else {
|
||||
++m_statCaseSlow;
|
||||
replaceCaseComplicated(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceCaseComplicated(nodep), nodep);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ private:
|
|||
relinkHandle.relink(castp);
|
||||
//if (debug()>8) castp->dumpTree(cout, "-castins: ");
|
||||
//
|
||||
insureLower32Cast(castp);
|
||||
ensureLower32Cast(castp);
|
||||
nodep->user1(1); // Now must be of known size
|
||||
}
|
||||
int castSize(AstNode* nodep) {
|
||||
|
|
@ -84,13 +84,13 @@ private:
|
|||
else if (nodep->width() <= 16) return 16;
|
||||
else return VL_IDATASIZE;
|
||||
}
|
||||
void insureCast(AstNode* nodep) {
|
||||
void ensureCast(AstNode* nodep) {
|
||||
if (castSize(nodep->backp()) != castSize(nodep)
|
||||
|| !nodep->user1()) {
|
||||
insertCast(nodep, castSize(nodep->backp()));
|
||||
}
|
||||
}
|
||||
void insureLower32Cast(AstCCast* nodep) {
|
||||
void ensureLower32Cast(AstCCast* nodep) {
|
||||
// If we have uint64 = CAST(uint64(x)) then the upcasting
|
||||
// really needs to be CAST(uint64(CAST(uint32(x))).
|
||||
// Otherwise a (uint64)(a>b) would return wrong value, as
|
||||
|
|
@ -102,33 +102,33 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeUniop* nodep) {
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) {
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1()
|
||||
| nodep->rhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep) {
|
||||
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1()
|
||||
| nodep->rhsp()->user1()
|
||||
| nodep->thsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) insureCast(nodep->thsp());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstCCast* nodep) {
|
||||
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureLower32Cast(nodep);
|
||||
ensureLower32Cast(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstNegate* nodep) {
|
||||
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->lhsp()->widthMin()==1) {
|
||||
|
|
@ -137,10 +137,10 @@ private:
|
|||
// out = {32{a<b}} => out = - (a<b)
|
||||
insertCast(nodep->lhsp(), castSize(nodep));
|
||||
} else {
|
||||
insureCast(nodep->lhsp());
|
||||
ensureCast(nodep->lhsp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->lvalue()
|
||||
&& !VN_IS(nodep->backp(), CCast)
|
||||
&& VN_IS(nodep->backp(), NodeMath)
|
||||
|
|
@ -153,7 +153,7 @@ private:
|
|||
}
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstConst* nodep) {
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
// Constants are of unknown size if smaller than 33 bits, because
|
||||
// we're too lazy to wrap every constant in the universe in
|
||||
// ((IData)#).
|
||||
|
|
@ -161,11 +161,11 @@ private:
|
|||
}
|
||||
|
||||
// NOPs
|
||||
virtual void visit(AstVar* nodep) {}
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ private:
|
|||
std::ofstream* m_ofp; // Output file
|
||||
string m_prefix;
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
*m_ofp<<m_prefix;
|
||||
if (nodep->user3()) *m_ofp<<" %%";
|
||||
else *m_ofp<<" ";
|
||||
|
|
@ -170,7 +170,7 @@ private:
|
|||
int m_maxLineno;
|
||||
size_t m_maxFilenameLen;
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Keeping line+filename lengths separate is much faster than calling ascii().length()
|
||||
if (nodep->fileline()->lineno() >= m_maxLineno) {
|
||||
|
|
@ -608,19 +608,22 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4," BLOCK "<<nodep<<endl);
|
||||
AstNode::user2ClearTree();
|
||||
|
|
@ -631,7 +634,7 @@ private:
|
|||
m_domainp = NULL;
|
||||
AstNode::user2ClearTree();
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
|
|
@ -659,72 +662,72 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
m_inDly = true;
|
||||
iterateChildren(nodep);
|
||||
m_inDly = false;
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
// Note we look at only AstSenItems, not AstSenGate's
|
||||
// The gating term of a AstSenGate is normal logic
|
||||
m_inSenItem = true;
|
||||
iterateChildren(nodep);
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
// CDC doesn't care about public variables
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is dealt with as logic
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
|
||||
// Math that shouldn't cause us to clear hazard
|
||||
virtual void visit(AstConst* nodep) { }
|
||||
virtual void visit(AstReplicate* nodep) {
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE { }
|
||||
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNot* nodep) {
|
||||
virtual void visit(AstNot* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) {
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeSel* nodep) {
|
||||
virtual void visit(AstNodeSel* nodep) VL_OVERRIDE {
|
||||
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Ignores
|
||||
virtual void visit(AstInitial* nodep) { }
|
||||
virtual void visit(AstTraceInc* nodep) { }
|
||||
virtual void visit(AstCoverToggle* nodep) { }
|
||||
virtual void visit(AstNodeDType* nodep) { }
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE { }
|
||||
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE { }
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { }
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { }
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +764,7 @@ public:
|
|||
}
|
||||
}
|
||||
virtual ~CdcVisitor() {
|
||||
if (m_ofp) { delete m_ofp; m_ofp = NULL; }
|
||||
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public:
|
|||
new AstLogOr(m_scopetopp->fileline(), callp,
|
||||
returnp->lhsp()->unlinkFrBack()));
|
||||
returnp->replaceWith(newp);
|
||||
returnp->deleteTree(); VL_DANGLING(returnp);
|
||||
VL_DO_DANGLING(returnp->deleteTree(), returnp);
|
||||
}
|
||||
m_numStmts = 0;
|
||||
}
|
||||
|
|
@ -148,13 +148,13 @@ private:
|
|||
m_statep->m_numStmts += visitor.count();
|
||||
}
|
||||
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstPackArrayDType* nodep) {
|
||||
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE {
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstUnpackArrayDType* nodep) {
|
||||
virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE {
|
||||
for (int index=0; index < nodep->elementsConst(); ++index) {
|
||||
AstNode* origVEp = m_varEqnp;
|
||||
AstNode* origNLEp = m_newLvEqnp;
|
||||
|
|
@ -175,7 +175,7 @@ private:
|
|||
m_newRvEqnp = origNREp;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) {
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->packedUnsup()) {
|
||||
newChangeDet();
|
||||
} else {
|
||||
|
|
@ -185,7 +185,7 @@ private:
|
|||
<<m_vscp->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
|
||||
|
|
@ -247,7 +247,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
if (nodep->isTop()) {
|
||||
m_statep->m_topModp = nodep;
|
||||
|
|
@ -255,7 +255,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," TS "<<nodep<<endl);
|
||||
// Clearing
|
||||
AstNode::user1ClearTree();
|
||||
|
|
@ -279,7 +279,7 @@ private:
|
|||
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
if (nodep->isCircular()) {
|
||||
UINFO(8," CIRC "<<nodep<<endl);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
|
|
@ -287,12 +287,12 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
// Short-circuit
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,15 +135,15 @@ private:
|
|||
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
|
||||
relinkHandle.relink(cleanp);
|
||||
}
|
||||
void insureClean(AstNode* nodep) {
|
||||
void ensureClean(AstNode* nodep) {
|
||||
computeCppWidth(nodep);
|
||||
if (!isClean(nodep)) insertClean(nodep);
|
||||
}
|
||||
void insureCleanAndNext(AstNode* nodep) {
|
||||
void ensureCleanAndNext(AstNode* nodep) {
|
||||
// Editing list, careful looping!
|
||||
for (AstNode* exprp = nodep; exprp; ) {
|
||||
AstNode* nextp = exprp->nextp();
|
||||
insureClean(exprp);
|
||||
ensureClean(exprp);
|
||||
exprp = nextp;
|
||||
}
|
||||
}
|
||||
|
|
@ -153,10 +153,10 @@ private:
|
|||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
insureClean(nodep->lhsp());
|
||||
ensureClean(nodep->lhsp());
|
||||
}
|
||||
if (nodep->cleanRhs()) {
|
||||
insureClean(nodep->rhsp());
|
||||
ensureClean(nodep->rhsp());
|
||||
}
|
||||
//no setClean.. must do it in each user routine.
|
||||
}
|
||||
|
|
@ -164,70 +164,73 @@ private:
|
|||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
insureClean(nodep->lhsp());
|
||||
ensureClean(nodep->lhsp());
|
||||
}
|
||||
if (nodep->cleanRhs()) {
|
||||
insureClean(nodep->rhsp());
|
||||
ensureClean(nodep->rhsp());
|
||||
}
|
||||
if (nodep->cleanThs()) {
|
||||
insureClean(nodep->thsp());
|
||||
ensureClean(nodep->thsp());
|
||||
}
|
||||
//no setClean.. must do it in each user routine.
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstNodeUniop* nodep) {
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
insureClean(nodep->lhsp());
|
||||
ensureClean(nodep->lhsp());
|
||||
}
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) {
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstAnd* nodep) {
|
||||
virtual void visit(AstAnd* nodep) VL_OVERRIDE {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstXor* nodep) {
|
||||
virtual void visit(AstXor* nodep) VL_OVERRIDE {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstOr* nodep) {
|
||||
virtual void visit(AstOr* nodep) VL_OVERRIDE {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanRhs()) {
|
||||
insureClean(nodep->rhsp());
|
||||
ensureClean(nodep->rhsp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstText* nodep) {
|
||||
virtual void visit(AstText* nodep) VL_OVERRIDE {
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) {
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
operandTriop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) {
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
setClean(nodep, false);
|
||||
|
|
@ -235,66 +238,66 @@ private:
|
|||
if (!VN_IS(nodep->backp(), And)) {
|
||||
insertClean(nodep);
|
||||
}
|
||||
insureCleanAndNext(nodep->bodysp());
|
||||
ensureCleanAndNext(nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstTraceDecl* nodep) {
|
||||
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstTraceInc* nodep) {
|
||||
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureCleanAndNext(nodep->valuep());
|
||||
ensureCleanAndNext(nodep->valuep());
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstParamTypeDType* nodep) {
|
||||
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Control flow operators
|
||||
virtual void visit(AstNodeCond* nodep) {
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureClean(nodep->condp());
|
||||
ensureClean(nodep->condp());
|
||||
setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p()));
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureClean(nodep->condp());
|
||||
ensureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureClean(nodep->condp());
|
||||
ensureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureCleanAndNext(nodep->exprsp());
|
||||
ensureCleanAndNext(nodep->exprsp());
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) {
|
||||
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureCleanAndNext(nodep->bodysp());
|
||||
ensureCleanAndNext(nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureCleanAndNext(nodep->argsp());
|
||||
ensureCleanAndNext(nodep->argsp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstCMethodCall* nodep) {
|
||||
virtual void visit(AstCMethodHard* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
insureCleanAndNext(nodep->pinsp());
|
||||
ensureCleanAndNext(nodep->pinsp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstIntfRef* nodep) {
|
||||
virtual void visit(AstIntfRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," TOPSCOPE "<<nodep<<endl);
|
||||
m_topScopep = nodep;
|
||||
m_scopep = nodep->scopep();
|
||||
|
|
@ -254,13 +254,16 @@ private:
|
|||
m_topScopep = NULL;
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp= NULL;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," SCOPE "<<nodep<<endl);
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -271,25 +274,25 @@ private:
|
|||
}
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPost* nodep) {
|
||||
virtual void visit(AstAlwaysPost* nodep) VL_OVERRIDE {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) {
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
//nodep->dumpTree(cout, "ct:");
|
||||
//COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
|
|
@ -307,18 +310,18 @@ private:
|
|||
newp->addIfsp(new AstAssign(nodep->fileline(),
|
||||
changep->cloneTree(false),
|
||||
origp->cloneTree(false)));
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Link to global function
|
||||
if (nodep->formCallTree()) {
|
||||
|
|
@ -328,7 +331,7 @@ private:
|
|||
m_finalFuncp->addStmtsp(callp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) {
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
// Delete it later; Actives still pointing to it
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep);
|
||||
|
|
@ -342,14 +345,14 @@ private:
|
|||
void addToInitial(AstNode* stmtsp) {
|
||||
m_initFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// Careful if adding variables here, ACTIVES can be under other ACTIVES
|
||||
// Need to save and restore any member state in AstUntilStable block
|
||||
if (!m_topScopep || !nodep->stmtsp()) {
|
||||
// Not at the top or empty block...
|
||||
// Only empty blocks should be leftover on the non-top. Killem.
|
||||
UASSERT_OBJ(!nodep->stmtsp(), nodep, "Non-empty lower active");
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else if (m_mtaskBodyp) {
|
||||
UINFO(4," TR ACTIVE "<<nodep<<endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
|
|
@ -374,7 +377,7 @@ private:
|
|||
clearLastSen();
|
||||
m_mtaskBodyp->addStmtsp(stmtsp);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else {
|
||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
|
|
@ -407,10 +410,10 @@ private:
|
|||
// Move statements to function
|
||||
addToEvalLoop(stmtsp);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) {
|
||||
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
|
||||
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody);
|
||||
m_mtaskBodyp;
|
||||
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
|
||||
|
|
@ -427,7 +430,7 @@ private:
|
|||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ protected:
|
|||
static bool emptyFunctionDeletion() { return true; }
|
||||
static bool duplicateFunctionCombine() { return true; }
|
||||
// Note this is disabled, it still needed work
|
||||
// Also repair it for DPI functions; when make __common need to insure proper
|
||||
// Also repair it for DPI functions; when make __common need to ensure proper
|
||||
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
|
||||
// get split between functions causing the text to have a dangling reference.
|
||||
bool statementCombine() { return false; } // duplicateFunctionCombine();
|
||||
|
|
@ -107,7 +107,7 @@ public:
|
|||
callp->unlinkFrBack();
|
||||
}
|
||||
callp->user3(true); // Dead now
|
||||
pushDeletep(callp); VL_DANGLING(callp);
|
||||
VL_DO_DANGLING(pushDeletep(callp), callp);
|
||||
m_callMmap.erase(eqit); // Fix the table
|
||||
}
|
||||
}
|
||||
|
|
@ -131,13 +131,13 @@ public:
|
|||
}
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
addCall(nodep);
|
||||
}
|
||||
// Speed things up
|
||||
virtual void visit(AstNodeAssign* nodep) {}
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -160,7 +160,7 @@ private:
|
|||
// OUTPUT:
|
||||
// AstNode::user3() -> bool. True to indicate duplicated
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
nodep->user3(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ private:
|
|||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, NULL);
|
||||
oldfuncp->unlinkFrBack();
|
||||
pushDeletep(oldfuncp); VL_DANGLING(oldfuncp);
|
||||
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -260,7 +260,7 @@ private:
|
|||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, newfuncp);
|
||||
oldfuncp->unlinkFrBack();
|
||||
pushDeletep(oldfuncp); VL_DANGLING(oldfuncp);
|
||||
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
|
||||
}
|
||||
void replaceOnlyCallFunc(AstCCall* nodep) {
|
||||
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
|
||||
|
|
@ -272,7 +272,7 @@ private:
|
|||
UINFO(9," Function only has call "<<oldfuncp<<endl);
|
||||
m_call.deleteCall(nodep);
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
replaceFuncWFunc(oldfuncp, nodep->funcp()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -384,12 +384,12 @@ private:
|
|||
m_call.addCall(call2p);
|
||||
// If either new statement makes a func with only a single call, replace
|
||||
// the above callers to call it directly
|
||||
replaceOnlyCallFunc(call1p); VL_DANGLING(call1p);
|
||||
replaceOnlyCallFunc(call2p); VL_DANGLING(call2p);
|
||||
VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p);
|
||||
VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Track all callers of each function
|
||||
m_call.main(nodep);
|
||||
//
|
||||
|
|
@ -398,7 +398,7 @@ private:
|
|||
// Required so that a module instantiating another can benefit from collapsing.
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_modNFuncs = 0;
|
||||
|
|
@ -427,7 +427,7 @@ private:
|
|||
}
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
m_funcp = nodep;
|
||||
if (!nodep->dontCombine()) {
|
||||
if (m_state == STATE_HASH) {
|
||||
|
|
@ -438,7 +438,7 @@ private:
|
|||
}
|
||||
m_funcp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
|
|
@ -453,10 +453,10 @@ private:
|
|||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar*) {}
|
||||
virtual void visit(AstTraceDecl*) {}
|
||||
virtual void visit(AstTraceInc*) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
542
src/V3Config.cpp
542
src/V3Config.cpp
|
|
@ -30,133 +30,489 @@
|
|||
#include <string>
|
||||
|
||||
//######################################################################
|
||||
// Resolve wildcards in files, modules, ftasks or variables
|
||||
|
||||
class V3ConfigLine {
|
||||
// Template for a class that serves as a map for entities that can be specified
|
||||
// as wildcards and are accessed by a resolved name. It rebuilds a name lookup
|
||||
// cache of resolved entities. Entities stored in this container need an update
|
||||
// function that takes a reference of this type to join multiple entities into one.
|
||||
template <typename T> class V3ConfigWildcardResolver {
|
||||
typedef std::map<string, T> Map;
|
||||
|
||||
Map m_mapWildcard; // Wildcard strings to entities
|
||||
Map m_mapResolved; // Resolved strings to converged entities
|
||||
public:
|
||||
int m_lineno; // Line number to make change at
|
||||
V3ErrorCode m_code; // Error code
|
||||
bool m_on; // True to enable message
|
||||
V3ConfigLine(V3ErrorCode code, int lineno, bool on)
|
||||
: m_lineno(lineno), m_code(code), m_on(on) {}
|
||||
~V3ConfigLine() {}
|
||||
inline bool operator< (const V3ConfigLine& rh) const {
|
||||
if (m_lineno<rh.m_lineno) return true;
|
||||
if (m_lineno>rh.m_lineno) return false;
|
||||
if (m_code<rh.m_code) return true;
|
||||
if (m_code>rh.m_code) return false;
|
||||
V3ConfigWildcardResolver() {}
|
||||
~V3ConfigWildcardResolver() {}
|
||||
|
||||
/// Update into maps from other
|
||||
void update(const V3ConfigWildcardResolver& other) {
|
||||
typename Map::const_iterator it;
|
||||
for (it = other.m_mapResolved.begin(); it != other.m_mapResolved.end(); ++it) {
|
||||
m_mapResolved[it->first].update(it->second);
|
||||
}
|
||||
for (it = other.m_mapWildcard.begin(); it != other.m_mapWildcard.end(); ++it) {
|
||||
m_mapWildcard[it->first].update(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Access and create a (wildcard) entity
|
||||
T& at(const string& name) {
|
||||
// Don't store into wildcards if the name is not a wildcard string
|
||||
return m_mapWildcard[name];
|
||||
}
|
||||
// Access an entity and resolve wildcards that match it
|
||||
T* resolve(const string& name) {
|
||||
// Lookup if it was resolved before, typically not
|
||||
typename Map::iterator it = m_mapResolved.find(name);
|
||||
if (VL_UNLIKELY(it != m_mapResolved.end())) { return &it->second; }
|
||||
|
||||
T* newp = NULL;
|
||||
// Cannot be resolved, create if matched
|
||||
|
||||
// Update this entity with all matches in the wildcards
|
||||
for (it = m_mapWildcard.begin(); it != m_mapWildcard.end(); ++it) {
|
||||
if (VString::wildmatch(name, it->first)) {
|
||||
if (!newp) {
|
||||
newp = &m_mapResolved[name]; // Emplace and get pointer
|
||||
}
|
||||
newp->update(it->second);
|
||||
}
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
// Flush on update
|
||||
void flush() { m_mapResolved.clear(); }
|
||||
};
|
||||
|
||||
// Only public_flat_rw has the sensitity tree
|
||||
class V3ConfigVarAttr {
|
||||
public:
|
||||
AstAttrType m_type; // Type of attribute
|
||||
AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw
|
||||
V3ConfigVarAttr(AstAttrType type, AstSenTree* sentreep)
|
||||
: m_type(type)
|
||||
, m_sentreep(sentreep) {}
|
||||
};
|
||||
|
||||
// Overload vector with the required update function and to apply all entries
|
||||
class V3ConfigVar : public std::vector<V3ConfigVarAttr> {
|
||||
public:
|
||||
// Update from other by copying all attributes
|
||||
void update(const V3ConfigVar& node) {
|
||||
reserve(size() + node.size());
|
||||
insert(end(), node.begin(), node.end());
|
||||
}
|
||||
// Apply all attributes to the variable
|
||||
void apply(AstVar* varp) {
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
|
||||
varp->addAttrsp(newp);
|
||||
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
|
||||
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef V3ConfigWildcardResolver<V3ConfigVar> V3ConfigVarResolver;
|
||||
|
||||
//######################################################################
|
||||
// Function or task: Have variables and properties
|
||||
|
||||
class V3ConfigFTask {
|
||||
V3ConfigVarResolver m_vars; // Variables in function/task
|
||||
bool m_isolate; // Isolate function return
|
||||
bool m_noinline; // Don't inline function/task
|
||||
bool m_public; // Public function/task
|
||||
|
||||
public:
|
||||
V3ConfigFTask()
|
||||
: m_isolate(false)
|
||||
, m_noinline(false)
|
||||
, m_public(false) {}
|
||||
void update(const V3ConfigFTask& f) {
|
||||
// Don't overwrite true with false
|
||||
if (f.m_isolate) m_isolate = true;
|
||||
if (f.m_noinline) m_noinline = true;
|
||||
if (f.m_public) m_public = true;
|
||||
m_vars.update(f.m_vars);
|
||||
}
|
||||
|
||||
V3ConfigVarResolver& vars() { return m_vars; }
|
||||
|
||||
void setIsolate(bool set) { m_isolate = set; }
|
||||
void setNoInline(bool set) { m_noinline = set; }
|
||||
void setPublic(bool set) { m_public = set; }
|
||||
|
||||
void apply(AstNodeFTask* ftaskp) {
|
||||
if (m_noinline)
|
||||
ftaskp->addStmtsp(new AstPragma(ftaskp->fileline(), AstPragmaType::NO_INLINE_TASK));
|
||||
if (m_public)
|
||||
ftaskp->addStmtsp(new AstPragma(ftaskp->fileline(), AstPragmaType::PUBLIC_TASK));
|
||||
// Only functions can have isolate (return value)
|
||||
if (VN_IS(ftaskp, Func)) ftaskp->attrIsolateAssign(m_isolate);
|
||||
}
|
||||
};
|
||||
|
||||
typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
|
||||
|
||||
//######################################################################
|
||||
// Modules have tasks, variables, named blocks and properties
|
||||
|
||||
class V3ConfigModule {
|
||||
typedef vl_unordered_set<string> StringSet;
|
||||
|
||||
V3ConfigFTaskResolver m_tasks; // Functions/tasks in module
|
||||
V3ConfigVarResolver m_vars; // Variables in module
|
||||
StringSet m_coverageOffBlocks; // List of block names for coverage_off
|
||||
bool m_inline; // Whether to force the inline
|
||||
bool m_inlineValue; // The inline value (on/off)
|
||||
bool m_public; // Public module
|
||||
|
||||
public:
|
||||
V3ConfigModule()
|
||||
: m_inline(false)
|
||||
, m_inlineValue(false)
|
||||
, m_public(false) {}
|
||||
|
||||
void update(const V3ConfigModule& m) {
|
||||
m_tasks.update(m.m_tasks);
|
||||
m_vars.update(m.m_vars);
|
||||
for (StringSet::const_iterator it = m.m_coverageOffBlocks.begin();
|
||||
it != m.m_coverageOffBlocks.end(); ++it) {
|
||||
m_coverageOffBlocks.insert(*it);
|
||||
}
|
||||
if (!m_inline) {
|
||||
m_inline = m.m_inline;
|
||||
m_inlineValue = m.m_inlineValue;
|
||||
}
|
||||
if (!m_public) m_public = m.m_public;
|
||||
}
|
||||
|
||||
V3ConfigFTaskResolver& ftasks() { return m_tasks; }
|
||||
V3ConfigVarResolver& vars() { return m_vars; }
|
||||
|
||||
void addCoverageBlockOff(const string& name) { m_coverageOffBlocks.insert(name); }
|
||||
void setInline(bool set) {
|
||||
m_inline = true;
|
||||
m_inlineValue = set;
|
||||
}
|
||||
void setPublic(bool set) { m_public = set; }
|
||||
|
||||
void apply(AstNodeModule* modp) {
|
||||
if (m_inline) {
|
||||
AstPragmaType type
|
||||
= m_inlineValue ? AstPragmaType::INLINE_MODULE : AstPragmaType::NO_INLINE_MODULE;
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), type);
|
||||
modp->addStmtp(nodep);
|
||||
}
|
||||
if (m_public) {
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), AstPragmaType::PUBLIC_MODULE);
|
||||
modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
void applyBlock(AstBegin* nodep) {
|
||||
AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF;
|
||||
if (!nodep->unnamed()) {
|
||||
for (StringSet::const_iterator it = m_coverageOffBlocks.begin();
|
||||
it != m_coverageOffBlocks.end(); ++it) {
|
||||
if (VString::wildmatch(nodep->name(), *it)) {
|
||||
nodep->addStmtsp(new AstPragma(nodep->fileline(), pragma));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef V3ConfigWildcardResolver<V3ConfigModule> V3ConfigModuleResolver;
|
||||
|
||||
//######################################################################
|
||||
// Files have:
|
||||
// - Line ignores (lint/coverage/tracing on/off)
|
||||
// - Line attributes: Attributes attached to lines
|
||||
|
||||
// lint/coverage/tracing on/off
|
||||
class V3ConfigIgnoresLine {
|
||||
public:
|
||||
int m_lineno; // Line number to make change at
|
||||
V3ErrorCode m_code; // Error code
|
||||
bool m_on; // True to enable message
|
||||
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
|
||||
: m_lineno(lineno)
|
||||
, m_code(code)
|
||||
, m_on(on) {}
|
||||
~V3ConfigIgnoresLine() {}
|
||||
inline bool operator<(const V3ConfigIgnoresLine& rh) const {
|
||||
if (m_lineno < rh.m_lineno) return true;
|
||||
if (m_lineno > rh.m_lineno) return false;
|
||||
if (m_code < rh.m_code) return true;
|
||||
if (m_code > rh.m_code) return false;
|
||||
// Always turn "on" before "off" so that overlapping lines will end
|
||||
// up finally with the error "off"
|
||||
return (m_on>rh.m_on);
|
||||
return (m_on > rh.m_on);
|
||||
}
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, V3ConfigLine rhs) {
|
||||
return os<<rhs.m_lineno<<", "<<rhs.m_code<<", "<<rhs.m_on; }
|
||||
std::ostream& operator<<(std::ostream& os, V3ConfigIgnoresLine rhs) {
|
||||
return os << rhs.m_lineno << ", " << rhs.m_code << ", " << rhs.m_on;
|
||||
}
|
||||
|
||||
class V3ConfigIgnores {
|
||||
typedef std::multiset<V3ConfigLine> IgnLines; // list of {line,code,on}
|
||||
typedef std::map<string,IgnLines> IgnFiles; // {filename} => list of {line,code,on}
|
||||
// Some attributes are attached to entities of the occur on a fileline
|
||||
// and multiple attributes can be attached to a line
|
||||
typedef std::bitset<AstPragmaType::ENUM_SIZE> V3ConfigLineAttribute;
|
||||
|
||||
// MEMBERS
|
||||
string m_lastFilename; // Last filename looked up
|
||||
int m_lastLineno; // Last linenumber looked up
|
||||
// File entity
|
||||
class V3ConfigFile {
|
||||
typedef std::map<int, V3ConfigLineAttribute> LineAttrMap; // Map line->bitset of attributes
|
||||
typedef std::multiset<V3ConfigIgnoresLine> IgnLines; // list of {line,code,on}
|
||||
typedef std::pair<V3ErrorCode, string> WaiverSetting; // Waive code if string matches
|
||||
typedef std::vector<WaiverSetting> Waivers; // List of {code,wildcard string}
|
||||
|
||||
IgnLines::const_iterator m_lastIt; // Point with next linenumber > current line number
|
||||
IgnLines::const_iterator m_lastEnd; // Point with end()
|
||||
LineAttrMap m_lineAttrs; // Atributes to line mapping
|
||||
IgnLines m_ignLines; // Ignore line settings
|
||||
Waivers m_waivers; // Waive messages
|
||||
|
||||
IgnFiles m_ignWilds; // Ignores for each wildcarded filename
|
||||
IgnFiles m_ignFiles; // Ignores for each non-wildcarded filename
|
||||
struct {
|
||||
int lineno; // Last line number
|
||||
IgnLines::const_iterator it; // Point with next linenumber > current line number
|
||||
} m_lastIgnore; // Last ignore line run
|
||||
|
||||
static V3ConfigIgnores s_singleton; // Singleton (not via local static, as that's slow)
|
||||
|
||||
V3ConfigIgnores() { m_lastLineno = -1; }
|
||||
~V3ConfigIgnores() {}
|
||||
|
||||
// METHODS
|
||||
inline IgnLines* findWilds(const string& wildname) {
|
||||
IgnFiles::iterator it = m_ignWilds.find(wildname);
|
||||
if (it != m_ignWilds.end()) {
|
||||
return &(it->second);
|
||||
} else {
|
||||
m_ignWilds.insert(make_pair(wildname, IgnLines()));
|
||||
it = m_ignWilds.find(wildname);
|
||||
return &(it->second);
|
||||
}
|
||||
}
|
||||
inline void absBuild(const string& filename) {
|
||||
// Given a filename, find all wildcard matches against it and build
|
||||
// hash with the specific filename. This avoids having to wildmatch
|
||||
// more than once against any filename.
|
||||
IgnFiles::iterator it = m_ignFiles.find(filename);
|
||||
if (it == m_ignFiles.end()) {
|
||||
// Haven't seen this filename before
|
||||
m_ignFiles.insert(make_pair(filename, IgnLines()));
|
||||
it = m_ignFiles.find(filename);
|
||||
// Make new list for this file of all matches
|
||||
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
|
||||
if (VString::wildmatch(filename.c_str(), fnit->first.c_str())) {
|
||||
for (IgnLines::iterator lit = fnit->second.begin();
|
||||
lit != fnit->second.end(); ++lit) {
|
||||
it->second.insert(*lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_lastIt = it->second.begin();
|
||||
m_lastEnd = it->second.end();
|
||||
// Match a given line and attribute to the map, line 0 is any
|
||||
bool lineMatch(int lineno, AstPragmaType type) {
|
||||
if (m_lineAttrs.find(0) != m_lineAttrs.end() && m_lineAttrs[0][type]) return true;
|
||||
if (m_lineAttrs.find(lineno) == m_lineAttrs.end()) return false;
|
||||
return m_lineAttrs[lineno][type];
|
||||
}
|
||||
|
||||
public:
|
||||
inline static V3ConfigIgnores& singleton() { return s_singleton; }
|
||||
V3ConfigFile() {
|
||||
m_lastIgnore.lineno = -1;
|
||||
m_lastIgnore.it = m_ignLines.begin();
|
||||
}
|
||||
void update(const V3ConfigFile& file) {
|
||||
// Copy in all Attributes
|
||||
for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin();
|
||||
it != file.m_lineAttrs.end(); ++it) {
|
||||
m_lineAttrs[it->first] |= it->second;
|
||||
}
|
||||
// Copy in all ignores
|
||||
for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end();
|
||||
++it) {
|
||||
m_ignLines.insert(*it);
|
||||
}
|
||||
// Update the iterator after the list has changed
|
||||
m_lastIgnore.it = m_ignLines.begin();
|
||||
m_waivers.reserve(m_waivers.size() + file.m_waivers.size());
|
||||
m_waivers.insert(m_waivers.end(), file.m_waivers.begin(), file.m_waivers.end());
|
||||
}
|
||||
void addLineAttribute(int lineno, AstPragmaType attr) { m_lineAttrs[lineno].set(attr); }
|
||||
void addIgnore(V3ErrorCode code, int lineno, bool on) {
|
||||
m_ignLines.insert(V3ConfigIgnoresLine(code, lineno, on));
|
||||
m_lastIgnore.it = m_ignLines.begin();
|
||||
}
|
||||
void addWaiver(V3ErrorCode code, const string& match) {
|
||||
m_waivers.push_back(make_pair(code, match));
|
||||
}
|
||||
|
||||
void addIgnore(V3ErrorCode code, const string& wildname, int lineno, bool on) {
|
||||
// Insert
|
||||
IgnLines* linesp = findWilds(wildname);
|
||||
UINFO(9,"config addIgnore "<<wildname<<":"<<lineno<<", "<<code<<", "<<on<<endl);
|
||||
linesp->insert(V3ConfigLine(code, lineno, on));
|
||||
// Flush the match cache, due to a change in the rules.
|
||||
m_ignFiles.clear();
|
||||
m_lastFilename = " ";
|
||||
void applyBlock(AstBegin* nodep) {
|
||||
// Apply to block at this line
|
||||
AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF;
|
||||
if (lineMatch(nodep->fileline()->lineno(), pragma)) {
|
||||
nodep->addStmtsp(new AstPragma(nodep->fileline(), pragma));
|
||||
}
|
||||
}
|
||||
void applyCase(AstCase* nodep) {
|
||||
// Apply to this case at this line
|
||||
int lineno = nodep->fileline()->lineno();
|
||||
if (lineMatch(lineno, AstPragmaType::FULL_CASE)) nodep->fullPragma(true);
|
||||
if (lineMatch(lineno, AstPragmaType::PARALLEL_CASE)) nodep->parallelPragma(true);
|
||||
}
|
||||
inline void applyIgnores(FileLine* filelinep) {
|
||||
// HOT routine, called each parsed token line
|
||||
if (m_lastLineno != filelinep->lastLineno()
|
||||
|| m_lastFilename != filelinep->filename()) {
|
||||
//UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
|
||||
if (VL_UNLIKELY(m_lastFilename != filelinep->filename())) {
|
||||
absBuild(filelinep->filename());
|
||||
m_lastFilename = filelinep->filename();
|
||||
}
|
||||
// HOT routine, called each parsed token line of this filename
|
||||
if (m_lastIgnore.lineno != filelinep->lineno()) {
|
||||
// UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
|
||||
// Process all on/offs for lines up to and including the current line
|
||||
int curlineno = filelinep->lastLineno();
|
||||
for (; m_lastIt != m_lastEnd; ++m_lastIt) {
|
||||
if (m_lastIt->m_lineno > curlineno) break;
|
||||
//UINFO(9," Hit "<<*m_lastIt<<endl);
|
||||
filelinep->warnOn(m_lastIt->m_code, m_lastIt->m_on);
|
||||
for (; m_lastIgnore.it != m_ignLines.end(); ++m_lastIgnore.it) {
|
||||
if (m_lastIgnore.it->m_lineno > curlineno) break;
|
||||
// UINFO(9," Hit "<<*m_lastIt<<endl);
|
||||
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
|
||||
}
|
||||
if (0 && debug() >= 9) {
|
||||
for (IgnLines::const_iterator it=m_lastIt; it != m_lastEnd; ++it) {
|
||||
UINFO(9," NXT "<<*it<<endl);
|
||||
for (IgnLines::const_iterator it = m_lastIgnore.it; it != m_ignLines.end(); ++it) {
|
||||
UINFO(9, " NXT " << *it << endl);
|
||||
}
|
||||
}
|
||||
m_lastLineno = filelinep->lastLineno();
|
||||
m_lastIgnore.lineno = filelinep->lastLineno();
|
||||
}
|
||||
}
|
||||
bool waive(V3ErrorCode code, const string& match) {
|
||||
for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) {
|
||||
if (((it->first == code) || (it->first == V3ErrorCode::I_LINT))
|
||||
&& VString::wildmatch(match, it->second)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
V3ConfigIgnores V3ConfigIgnores::s_singleton;
|
||||
typedef V3ConfigWildcardResolver<V3ConfigFile> V3ConfigFileResolver;
|
||||
|
||||
//######################################################################
|
||||
// Resolve modules and files in the design
|
||||
|
||||
class V3ConfigResolver {
|
||||
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
|
||||
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
|
||||
|
||||
static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow)
|
||||
V3ConfigResolver() {}
|
||||
~V3ConfigResolver() {}
|
||||
|
||||
public:
|
||||
inline static V3ConfigResolver& s() { return s_singleton; }
|
||||
|
||||
V3ConfigModuleResolver& modules() { return m_modules; }
|
||||
V3ConfigFileResolver& files() { return m_files; }
|
||||
};
|
||||
|
||||
V3ConfigResolver V3ConfigResolver::s_singleton;
|
||||
|
||||
//######################################################################
|
||||
// V3Config
|
||||
|
||||
void V3Config::addCaseFull(const string& filename, int lineno) {
|
||||
V3ConfigFile& file = V3ConfigResolver::s().files().at(filename);
|
||||
file.addLineAttribute(lineno, AstPragmaType::FULL_CASE);
|
||||
}
|
||||
|
||||
void V3Config::addCaseParallel(const string& filename, int lineno) {
|
||||
V3ConfigFile& file = V3ConfigResolver::s().files().at(filename);
|
||||
file.addLineAttribute(lineno, AstPragmaType::PARALLEL_CASE);
|
||||
}
|
||||
|
||||
void V3Config::addCoverageBlockOff(const string& filename, int lineno) {
|
||||
V3ConfigFile& file = V3ConfigResolver::s().files().at(filename);
|
||||
file.addLineAttribute(lineno, AstPragmaType::COVERAGE_BLOCK_OFF);
|
||||
}
|
||||
|
||||
void V3Config::addCoverageBlockOff(const string& module, const string& blockname) {
|
||||
V3ConfigResolver::s().modules().at(module).addCoverageBlockOff(blockname);
|
||||
}
|
||||
|
||||
void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max) {
|
||||
if (filename=="*") {
|
||||
FileLine::globalWarnOff(code,!on);
|
||||
if (filename == "*") {
|
||||
FileLine::globalWarnOff(code, !on);
|
||||
} else {
|
||||
V3ConfigIgnores::singleton().addIgnore(code, filename, min, on);
|
||||
if (max) V3ConfigIgnores::singleton().addIgnore(code, filename, max, !on);
|
||||
V3ConfigResolver::s().files().at(filename).addIgnore(code, min, on);
|
||||
if (max) V3ConfigResolver::s().files().at(filename).addIgnore(code, max, !on);
|
||||
V3ConfigResolver::s().files().flush();
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::applyIgnores(FileLine* filelinep) {
|
||||
V3ConfigIgnores::singleton().applyIgnores(filelinep);
|
||||
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
|
||||
if (ftask.empty()) {
|
||||
V3ConfigResolver::s().modules().at(module).setInline(on);
|
||||
} else {
|
||||
if (!on) {
|
||||
fl->v3error("no_inline not supported for tasks" << endl);
|
||||
} else {
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setNoInline(on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftask,
|
||||
const string& var, AstAttrType attr, AstSenTree* sensep) {
|
||||
// Semantics: sensep only if public_flat_rw
|
||||
if ((attr != AstAttrType::VAR_PUBLIC_FLAT_RW) && sensep) {
|
||||
sensep->v3error("sensitivity not expected for attribute" << endl);
|
||||
return;
|
||||
}
|
||||
// Semantics: Most of the attributes operate on signals
|
||||
if (var.empty()) {
|
||||
if (attr == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||
if (ftask.empty()) {
|
||||
fl->v3error("isolate_assignments only applies to signals or functions/tasks"
|
||||
<< endl);
|
||||
} else {
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setIsolate(true);
|
||||
}
|
||||
} else if (attr == AstAttrType::VAR_PUBLIC) {
|
||||
if (ftask.empty()) {
|
||||
// public module, this is the only exception from var here
|
||||
V3ConfigResolver::s().modules().at(module).setPublic(true);
|
||||
} else {
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
|
||||
}
|
||||
} else {
|
||||
fl->v3error("missing -signal" << endl);
|
||||
}
|
||||
} else {
|
||||
V3ConfigModule& mod = V3ConfigResolver::s().modules().at(module);
|
||||
if (ftask.empty()) {
|
||||
mod.vars().at(var).push_back(V3ConfigVarAttr(attr, sensep));
|
||||
} else {
|
||||
mod.ftasks().at(ftask).vars().at(var).push_back(V3ConfigVarAttr(attr, sensep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& match) {
|
||||
V3ConfigResolver::s().files().at(filename).addWaiver(code, match);
|
||||
}
|
||||
|
||||
void V3Config::applyCase(AstCase* nodep) {
|
||||
const string& filename = nodep->fileline()->filename();
|
||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
|
||||
if (filep) filep->applyCase(nodep);
|
||||
}
|
||||
|
||||
void V3Config::applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep) {
|
||||
const string& filename = nodep->fileline()->filename();
|
||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
|
||||
if (filep) filep->applyBlock(nodep);
|
||||
const string& modname = modulep->name();
|
||||
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
|
||||
if (modp) modp->applyBlock(nodep);
|
||||
}
|
||||
|
||||
void V3Config::applyIgnores(FileLine* filelinep) {
|
||||
const string& filename = filelinep->filename();
|
||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
|
||||
if (filep) filep->applyIgnores(filelinep);
|
||||
}
|
||||
|
||||
void V3Config::applyModule(AstNodeModule* modulep) {
|
||||
const string& modname = modulep->name();
|
||||
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
|
||||
if (modp) modp->apply(modulep);
|
||||
}
|
||||
|
||||
void V3Config::applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp) {
|
||||
const string& modname = modulep->name();
|
||||
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
|
||||
if (!modp) return;
|
||||
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
|
||||
if (ftp) ftp->apply(ftaskp);
|
||||
}
|
||||
|
||||
void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp) {
|
||||
V3ConfigVar* vp;
|
||||
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modulep->name());
|
||||
if (!modp) return;
|
||||
if (ftaskp) {
|
||||
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
|
||||
if (!ftp) return;
|
||||
vp = ftp->vars().resolve(varp->name());
|
||||
} else {
|
||||
vp = modp->vars().resolve(varp->name());
|
||||
}
|
||||
if (vp) vp->apply(varp);
|
||||
}
|
||||
|
||||
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
|
||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());
|
||||
if (!filep) return false;
|
||||
return filep->waive(code, message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,27 @@
|
|||
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3Config {
|
||||
public:
|
||||
static void addCaseFull(const string& file, int lineno);
|
||||
static void addCaseParallel(const string& file, int lineno);
|
||||
static void addCoverageBlockOff(const string& file, int lineno);
|
||||
static void addCoverageBlockOff(const string& module, const string& blockname);
|
||||
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
|
||||
static void addWaiver(V3ErrorCode code, const string& filename, const string& msg);
|
||||
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
|
||||
static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, AstAttrType type, AstSenTree* nodep);
|
||||
static void applyCase(AstCase* nodep);
|
||||
static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep);
|
||||
static void applyIgnores(FileLine* filelinep);
|
||||
static void applyModule(AstNodeModule* nodep);
|
||||
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
|
||||
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
|
||||
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& match);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
278
src/V3Const.cpp
278
src/V3Const.cpp
|
|
@ -46,10 +46,10 @@ class ConstVarMarkVisitor : public AstNVisitor {
|
|||
// AstVar::user4p -> bool, Var marked, 0=not set yet
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp()) nodep->varp()->user4(1);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -68,10 +68,10 @@ class ConstVarFindVisitor : public AstNVisitor {
|
|||
bool m_found;
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp() && nodep->varp()->user4()) m_found = true;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -212,7 +212,7 @@ private:
|
|||
if (!operandsSame(ap, bp)) return false;
|
||||
// Do it
|
||||
cp->unlinkFrBack();
|
||||
andp->unlinkFrBack()->deleteTree(); VL_DANGLING(andp); VL_DANGLING(notp);
|
||||
VL_DO_DANGLING(andp->unlinkFrBack()->deleteTree(), andp); VL_DANGLING(notp);
|
||||
// Replace whichever branch is now dangling
|
||||
if (nodep->rhsp()) nodep->lhsp(cp);
|
||||
else nodep->rhsp(cp);
|
||||
|
|
@ -240,7 +240,7 @@ private:
|
|||
newp->dtypeFrom(nodep);
|
||||
newp->expr1p()->dtypeFrom(nodep); // As And might have been to change widths
|
||||
newp->expr2p()->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
static bool operandShiftSame(const AstNode* nodep) {
|
||||
|
|
@ -343,7 +343,7 @@ private:
|
|||
&& nodep->lsbConst()==0
|
||||
&& static_cast<int>(nodep->widthConst()) == extendp->lhsp()->width()
|
||||
)) return false;
|
||||
replaceWChild(nodep, extendp->lhsp()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWChild(nodep, extendp->lhsp()), nodep);
|
||||
return true;
|
||||
}
|
||||
bool operandSelBiLower(AstSel* nodep) {
|
||||
|
|
@ -362,7 +362,7 @@ private:
|
|||
bip->lhsp(new AstSel(nodep->fileline(), bilhsp, 0, nodep->widthConst()));
|
||||
bip->rhsp(new AstSel(nodep->fileline(), birhsp, 0, nodep->widthConst()));
|
||||
if (debug()>=9) bip->dumpTree(cout, "SEL(BI)-ou:");
|
||||
replaceWChild(nodep, bip); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWChild(nodep, bip), nodep);
|
||||
return true;
|
||||
}
|
||||
bool operandSelShiftLower(AstSel* nodep) {
|
||||
|
|
@ -390,7 +390,7 @@ private:
|
|||
newLsb, nodep->widthConst());
|
||||
newp->dtypeFrom(nodep);
|
||||
if (debug()>=9) newp->dumpTree(cout, "SEL(SH)-ou:");
|
||||
nodep->replaceWith(newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->replaceWith(newp), nodep);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -409,14 +409,14 @@ private:
|
|||
//
|
||||
if (debug()>=9) nodep->dumpTree(cout, "BI(EXTEND)-in:");
|
||||
smallerp->unlinkFrBack();
|
||||
extendp->unlinkFrBack()->deleteTree(); // aka nodep->lhsp.
|
||||
VL_DO_DANGLING(extendp->unlinkFrBack()->deleteTree(), extendp); // aka nodep->lhsp.
|
||||
nodep->rhsp(smallerp);
|
||||
|
||||
constp->unlinkFrBack();
|
||||
V3Number num (constp, subsize);
|
||||
num.opAssign(constp->num());
|
||||
nodep->lhsp(new AstConst(constp->fileline(), num));
|
||||
constp->deleteTree(); VL_DANGLING(constp);
|
||||
VL_DO_DANGLING(constp->deleteTree(), constp);
|
||||
if (debug()>=9) nodep->dumpTree(cout, "BI(EXTEND)-ou:");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -622,11 +622,11 @@ private:
|
|||
if (debug()>5) oldp->dumpTree(cout, " const_old: ");
|
||||
if (debug()>5) newp->dumpTree(cout, " _new: ");
|
||||
oldp->replaceWith(newp);
|
||||
oldp->deleteTree(); VL_DANGLING(oldp);
|
||||
VL_DO_DANGLING(oldp->deleteTree(), oldp);
|
||||
}
|
||||
void replaceNum(AstNode* nodep, uint32_t val) {
|
||||
V3Number num (nodep, nodep->width(), val);
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
}
|
||||
void replaceNumSigned(AstNodeBiop* nodep, uint32_t val) {
|
||||
// We allow both sides to be constant, as one may have come from
|
||||
|
|
@ -634,48 +634,48 @@ private:
|
|||
if (m_warn && !(VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const))) {
|
||||
nodep->v3warn(UNSIGNED, "Comparison is constant due to unsigned arithmetic");
|
||||
}
|
||||
replaceNum(nodep, val); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, val), nodep);
|
||||
}
|
||||
void replaceNumLimited(AstNodeBiop* nodep, uint32_t val) {
|
||||
// Avoids gcc warning about same
|
||||
if (m_warn) nodep->v3warn(CMPCONST, "Comparison is constant due to limited range");
|
||||
replaceNum(nodep, val); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, val), nodep);
|
||||
}
|
||||
void replaceZero(AstNode* nodep) {
|
||||
replaceNum(nodep, 0); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, 0), nodep);
|
||||
}
|
||||
void replaceZeroChkPure(AstNode* nodep, AstNode* checkp) {
|
||||
// For example, "0 * n" -> 0 if n has no side effects
|
||||
// Else strength reduce it to 0 & n.
|
||||
// If ever change the operation note AstAnd rule specially ignores this created pattern
|
||||
if (isTPure(checkp)) {
|
||||
replaceNum(nodep, 0); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, 0), nodep);
|
||||
} else {
|
||||
AstNode* newp = new AstAnd(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), 0),
|
||||
checkp->unlinkFrBack());
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
void replaceAllOnes(AstNode* nodep) {
|
||||
V3Number ones (nodep, nodep->width(), 0);
|
||||
ones.setMask(nodep->width());
|
||||
replaceNum(nodep, ones); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, ones), nodep);
|
||||
}
|
||||
void replaceConst(AstNodeUniop* nodep) {
|
||||
V3Number num (nodep, nodep->width());
|
||||
nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num());
|
||||
UINFO(4,"UNICONST -> "<<num<<endl);
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
}
|
||||
void replaceConst(AstNodeBiop* nodep) {
|
||||
V3Number num (nodep, nodep->width());
|
||||
nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num(),
|
||||
VN_CAST(nodep->rhsp(), Const)->num());
|
||||
UINFO(4,"BICONST -> "<<num<<endl);
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
}
|
||||
void replaceConst(AstNodeTriop* nodep) {
|
||||
V3Number num (nodep, nodep->width());
|
||||
|
|
@ -683,7 +683,7 @@ private:
|
|||
VN_CAST(nodep->rhsp(), Const)->num(),
|
||||
VN_CAST(nodep->thsp(), Const)->num());
|
||||
UINFO(4,"TRICONST -> "<<num<<endl);
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
}
|
||||
|
||||
void replaceConstString(AstNode* oldp, const string& num) {
|
||||
|
|
@ -693,7 +693,7 @@ private:
|
|||
if (debug()>5) oldp->dumpTree(cout, " const_old: ");
|
||||
if (debug()>5) newp->dumpTree(cout, " _new: ");
|
||||
oldp->replaceWith(newp);
|
||||
oldp->deleteTree(); VL_DANGLING(oldp);
|
||||
VL_DO_DANGLING(oldp->deleteTree(), oldp);
|
||||
}
|
||||
//----------------------------------------
|
||||
// Replacement functions.
|
||||
|
|
@ -706,7 +706,7 @@ private:
|
|||
// This may adversely affect the operation of the node being replaced.
|
||||
childp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(childp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
//! Replace a ternary node with its RHS after iterating
|
||||
|
|
@ -794,15 +794,15 @@ private:
|
|||
lp->rhsp(nodep);
|
||||
nodep->lhsp(lrp);
|
||||
nodep->rhsp(rrp);
|
||||
rp->deleteTree();
|
||||
rlp->deleteTree();
|
||||
VL_DO_DANGLING(rp->deleteTree(), rp);
|
||||
VL_DO_DANGLING(rlp->deleteTree(), rlp);
|
||||
} else if (operandsSame(lrp, rrp)) {
|
||||
lp->lhsp(nodep);
|
||||
lp->rhsp(rrp);
|
||||
nodep->lhsp(llp);
|
||||
nodep->rhsp(rlp);
|
||||
rp->deleteTree();
|
||||
lrp->deleteTree();
|
||||
VL_DO_DANGLING(rp->deleteTree(), rp);
|
||||
VL_DO_DANGLING(lrp->deleteTree(), lrp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("replaceAndOr on something operandAndOrSame shouldn't have matched");
|
||||
}
|
||||
|
|
@ -822,8 +822,8 @@ private:
|
|||
lp->rhsp(lrp);
|
||||
nodep->lhsp(llp);
|
||||
nodep->rhsp(rlp);
|
||||
rp->deleteTree();
|
||||
rrp->deleteTree();
|
||||
VL_DO_DANGLING(rp->deleteTree(), rp);
|
||||
VL_DO_DANGLING(rrp->deleteTree(), rrp);
|
||||
//nodep->dumpTree(cout, " repShiftSame_new: ");
|
||||
}
|
||||
void replaceConcatSel(AstConcat* nodep) {
|
||||
|
|
@ -842,9 +842,9 @@ private:
|
|||
UINFO(5, "merged two adjacent sel "<<lselp <<" and "<<rselp<< " to one "<<newselp<<endl);
|
||||
|
||||
nodep->replaceWith(newselp);
|
||||
lselp->deleteTree(); VL_DANGLING(lselp);
|
||||
rselp->deleteTree(); VL_DANGLING(rselp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(lselp->deleteTree(), lselp);
|
||||
VL_DO_DANGLING(rselp->deleteTree(), rselp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceConcatMerge(AstConcat* nodep) {
|
||||
AstNodeBiop* lp = VN_CAST(nodep->lhsp(), NodeBiop);
|
||||
|
|
@ -861,8 +861,8 @@ private:
|
|||
lp->rhsp()->replaceWith(newrp);
|
||||
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::UNSIGNED);
|
||||
UINFO(5, "merged "<< nodep <<endl);
|
||||
rp->unlinkFrBack()->deleteTree(); VL_DANGLING(rp);
|
||||
nodep->replaceWith(lp->unlinkFrBack()); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(rp->unlinkFrBack()->deleteTree(), rp);
|
||||
nodep->replaceWith(lp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
iterate(lp->lhsp());
|
||||
iterate(lp->rhsp());
|
||||
} else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
|
||||
|
|
@ -875,7 +875,7 @@ private:
|
|||
? static_cast<AstNode*>(new AstExtendS(nodep->fileline(), arg0p))
|
||||
: static_cast<AstNode*>(new AstExtend (nodep->fileline(), arg0p)));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replacePowShift(AstNodeBiop* nodep) { // Pow or PowS
|
||||
UINFO(5,"POW(2,b)->SHIFTL(1,b) "<<nodep<<endl);
|
||||
|
|
@ -885,7 +885,7 @@ private:
|
|||
rhsp);
|
||||
newp->dtypeFrom(nodep);
|
||||
newp->lhsp()->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceMulShift(AstMul* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5,"MUL(2^n,b)->SHIFTL(b,n) "<<nodep<<endl);
|
||||
|
|
@ -894,7 +894,7 @@ private:
|
|||
AstShiftL* newp = new AstShiftL(nodep->fileline(),
|
||||
opp, new AstConst(nodep->fileline(), amount));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceDivShift(AstDiv* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5,"DIV(b,2^n)->SHIFTR(b,n) "<<nodep<<endl);
|
||||
|
|
@ -903,7 +903,7 @@ private:
|
|||
AstShiftR* newp = new AstShiftR(nodep->fileline(),
|
||||
opp, new AstConst(nodep->fileline(), amount));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceModAnd(AstModDiv* nodep) { // Mod, but not ModS as not simple shift
|
||||
UINFO(5,"MOD(b,2^n)->AND(b,2^n-1) "<<nodep<<endl);
|
||||
|
|
@ -914,7 +914,7 @@ private:
|
|||
AstAnd* newp = new AstAnd(nodep->fileline(),
|
||||
opp, new AstConst(nodep->fileline(), mask));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceShiftOp(AstNodeBiop* nodep) {
|
||||
UINFO(5,"SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) "<<nodep<<endl);
|
||||
|
|
@ -946,8 +946,8 @@ private:
|
|||
int shift1 = VN_CAST(shift1p, Const)->toUInt();
|
||||
int shift2 = VN_CAST(shift2p, Const)->toUInt();
|
||||
int newshift = shift1+shift2;
|
||||
shift1p->deleteTree(); VL_DANGLING(shift1p);
|
||||
shift2p->deleteTree(); VL_DANGLING(shift2p);
|
||||
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
|
||||
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
|
||||
nodep->lhsp(ap);
|
||||
nodep->rhsp(new AstConst(nodep->fileline(), newshift));
|
||||
iterate(nodep); // Further reduce, either node may have more reductions.
|
||||
|
|
@ -958,8 +958,8 @@ private:
|
|||
int shift2 = VN_CAST(shift2p, Const)->toUInt();
|
||||
if (VN_IS(nodep, ShiftR)) shift2=-shift2;
|
||||
int newshift = shift1+shift2;
|
||||
shift1p->deleteTree(); VL_DANGLING(shift1p);
|
||||
shift2p->deleteTree(); VL_DANGLING(shift2p);
|
||||
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
|
||||
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
|
||||
AstNode* newp;
|
||||
V3Number mask1 (nodep, nodep->width());
|
||||
V3Number ones (nodep, nodep->width());
|
||||
|
|
@ -987,11 +987,11 @@ private:
|
|||
newp,
|
||||
new AstConst(nodep->fileline(), mask));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
//newp->dumpTree(cout, " repShiftShift_new: ");
|
||||
iterate(newp); // Further reduce, either node may have more reductions.
|
||||
}
|
||||
lhsp->deleteTree(); VL_DANGLING(lhsp);
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
|
||||
}
|
||||
|
||||
bool replaceAssignMultiSel(AstNodeAssign* nodep) {
|
||||
|
|
@ -1033,8 +1033,9 @@ private:
|
|||
new AstConcat(rhs1p->fileline(), rhs1p, rhs2p));
|
||||
}
|
||||
//pnewp->dumpTree(cout, "conew: ");
|
||||
nodep->replaceWith(newp); nodep->deleteTree();
|
||||
nextp->unlinkFrBack()->deleteTree();
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(nextp->unlinkFrBack()->deleteTree(), nextp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1062,7 +1063,7 @@ private:
|
|||
nodep->v3error("Wire inputs its own output, creating circular logic (wire x=x)");
|
||||
return false; // Don't delete the assign, or V3Gate will freak out
|
||||
} else {
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1156,8 +1157,8 @@ private:
|
|||
if (debug()>=9 && newp) newp->dumpTreeAndNext(cout, " _new: ");
|
||||
nodep->addNextHere(newp);
|
||||
// Cleanup
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
conp->deleteTree(); VL_DANGLING(conp);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(conp->deleteTree(), conp);
|
||||
// Further reduce, either node may have more reductions.
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1170,8 +1171,8 @@ private:
|
|||
AstNode* streamp = VN_CAST(nodep->rhsp(), StreamR)->unlinkFrBack();
|
||||
nodep->rhsp(srcp);
|
||||
// Cleanup
|
||||
sizep->deleteTree(); VL_DANGLING(sizep);
|
||||
streamp->deleteTree(); VL_DANGLING(streamp);
|
||||
VL_DO_DANGLING(sizep->deleteTree(), sizep);
|
||||
VL_DO_DANGLING(streamp->deleteTree(), streamp);
|
||||
// Further reduce, any of the nodes may have more reductions.
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1213,8 +1214,8 @@ private:
|
|||
nodep->lhsp(dstp);
|
||||
nodep->rhsp(srcp);
|
||||
// Cleanup
|
||||
sizep->deleteTree(); VL_DANGLING(sizep);
|
||||
streamp->deleteTree(); VL_DANGLING(streamp);
|
||||
VL_DO_DANGLING(sizep->deleteTree(), sizep);
|
||||
VL_DO_DANGLING(streamp->deleteTree(), streamp);
|
||||
// Further reduce, any of the nodes may have more reductions.
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1250,7 +1251,7 @@ private:
|
|||
// widthMin no longer applicable if different C-expanded width
|
||||
newp->dtypeSetLogicSized(nodep->width(), AstNumeric::UNSIGNED);
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (debug()>=9) newp->dumpTree(cout, " _new: ");
|
||||
}
|
||||
|
||||
|
|
@ -1264,7 +1265,7 @@ private:
|
|||
<<nodep->prettyTypeName()<<endl
|
||||
<<errorp->warnOther()<<"... Location of non-constant "
|
||||
<<errorp->prettyTypeName()<<": "<<simvis.whyNotMessage());
|
||||
replaceZero(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceZero(nodep), nodep);
|
||||
} else {
|
||||
// Fetch the result
|
||||
AstNode* valuep = simvis.fetchValueNull(nodep); // valuep is owned by Simulate
|
||||
|
|
@ -1274,30 +1275,33 @@ private:
|
|||
newp->dtypeFrom(nodep);
|
||||
newp->fileline(nodep->fileline());
|
||||
UINFO(4, "Simulate->"<<newp<<endl);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Iterate modules backwards, in bottom-up order. That's faster
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
// No ASSIGNW removals under funcs, we've long eliminated INITIALs
|
||||
// (We should perhaps rename the assignw's to just assigns)
|
||||
m_wremove = false;
|
||||
iterateChildren(nodep);
|
||||
m_wremove = true;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
// No ASSIGNW removals under scope, we've long eliminated INITIALs
|
||||
m_scopep = nodep;
|
||||
m_wremove = false;
|
||||
|
|
@ -1354,7 +1358,7 @@ private:
|
|||
// If bp was a concat, then we have this exact same form again!
|
||||
// Recurse rather then calling node->iterate to prevent 2^n recursion!
|
||||
if (operandConcatMove(abConcp)) moveConcat(abConcp);
|
||||
bcConcp->deleteTree(); VL_DANGLING(bcConcp);
|
||||
VL_DO_DANGLING(bcConcp->deleteTree(), bcConcp);
|
||||
} else {
|
||||
AstConcat* abConcp = VN_CAST(nodep->lhsp(), Concat); abConcp->unlinkFrBack();
|
||||
AstNode* ap = abConcp->lhsp()->unlinkFrBack();
|
||||
|
|
@ -1365,21 +1369,21 @@ private:
|
|||
nodep->lhsp(ap);
|
||||
nodep->rhsp(bcConcp);
|
||||
if (operandConcatMove(bcConcp)) moveConcat(bcConcp);
|
||||
abConcp->deleteTree(); VL_DANGLING(abConcp);
|
||||
VL_DO_DANGLING(abConcp->deleteTree(), abConcp);
|
||||
}
|
||||
}
|
||||
|
||||
// Special cases
|
||||
virtual void visit(AstConst* nodep) {} // Already constant
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {} // Already constant
|
||||
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
if (m_params) {
|
||||
iterateAndNextNull(nodep->paramsp());
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -1397,7 +1401,7 @@ private:
|
|||
rhsp->cloneTree(false)),
|
||||
lhsp->cloneTree(false)));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
void replaceSelSel(AstSel* nodep) {
|
||||
|
|
@ -1414,8 +1418,8 @@ private:
|
|||
newlsbp = new AstConst(lsb1p->fileline(),
|
||||
VN_CAST(lsb1p, Const)->toUInt()
|
||||
+ VN_CAST(lsb2p, Const)->toUInt());
|
||||
lsb1p->deleteTree(); VL_DANGLING(lsb1p);
|
||||
lsb2p->deleteTree(); VL_DANGLING(lsb2p);
|
||||
VL_DO_DANGLING(lsb1p->deleteTree(), lsb1p);
|
||||
VL_DO_DANGLING(lsb2p->deleteTree(), lsb2p);
|
||||
} else {
|
||||
// Width is important, we need the width of the fromp's
|
||||
// expression, not the potentially smaller lsb1p's width
|
||||
|
|
@ -1429,7 +1433,7 @@ private:
|
|||
newlsbp,
|
||||
widthp);
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
void replaceSelConcat(AstSel* nodep) {
|
||||
|
|
@ -1469,7 +1473,7 @@ private:
|
|||
conRhsp->width()-nodep->lsbConst()));
|
||||
nodep->replaceWith(newp);
|
||||
}
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
bool operandSelReplicate(AstSel* nodep) {
|
||||
// SEL(REPLICATE(from,rep),lsb,width) => SEL(from,0,width) as long
|
||||
|
|
@ -1489,7 +1493,7 @@ private:
|
|||
new AstConst(lsbp->fileline(), lsbp->toUInt() % fromp->width()),
|
||||
widthp);
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
bool operandRepRep(AstReplicate* nodep) {
|
||||
|
|
@ -1505,7 +1509,7 @@ private:
|
|||
AstReplicate* newp = new AstReplicate(nodep->fileline(),
|
||||
from2p, cnt1p->toUInt()*cnt2p->toUInt());
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
bool operandConcatSame(AstConcat* nodep) {
|
||||
|
|
@ -1532,7 +1536,7 @@ private:
|
|||
from1p->unlinkFrBack();
|
||||
AstReplicate* newp = new AstReplicate(nodep->fileline(), from1p, cnt1+cnt2);
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
void replaceSelIntoBiop(AstSel* nodep) {
|
||||
|
|
@ -1550,7 +1554,7 @@ private:
|
|||
fromp->rhsp(new AstSel(nodep->fileline(),
|
||||
birhsp, lsbp, widthp));
|
||||
fromp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(fromp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(fromp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceSelIntoUniop(AstSel* nodep) {
|
||||
// SEL(NOT(a),1,bit) => NOT(SEL(a,bit))
|
||||
|
|
@ -1564,17 +1568,17 @@ private:
|
|||
fromp->lhsp(new AstSel(nodep->fileline(),
|
||||
bilhsp, lsbp, widthp));
|
||||
fromp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(fromp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(fromp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstAttrOf* nodep) {
|
||||
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
|
||||
AstAttrOf* oldAttr = m_attrp;
|
||||
m_attrp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_attrp = oldAttr;
|
||||
}
|
||||
|
||||
virtual void visit(AstArraySel* nodep) {
|
||||
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
if (VN_IS(nodep->bitp(), Const)
|
||||
&& VN_IS(nodep->fromp(), VarRef)
|
||||
|
|
@ -1595,12 +1599,12 @@ private:
|
|||
fromp->dtypeFrom(VN_CAST(fromp->dtypep()->skipRefp(),
|
||||
NodeArrayDType)->subDTypep());
|
||||
}
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
m_selp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->varp(), nodep, "Not linked");
|
||||
bool did = false;
|
||||
|
|
@ -1621,7 +1625,7 @@ private:
|
|||
if (operandConst(valuep)) {
|
||||
const V3Number& num = VN_CAST(valuep, Const)->num();
|
||||
//UINFO(2,"constVisit "<<cvtToHex(valuep)<<" "<<num<<endl);
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
did = true;
|
||||
}
|
||||
else if (m_selp && VN_IS(valuep, InitArray)) {
|
||||
|
|
@ -1631,7 +1635,7 @@ private:
|
|||
if (VN_IS(itemp, Const)) {
|
||||
const V3Number& num = VN_CAST(itemp, Const)->num();
|
||||
//UINFO(2,"constVisit "<<cvtToHex(valuep)<<" "<<num<<endl);
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
did = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1641,7 +1645,7 @@ private:
|
|||
// This exception is fairly fragile, i.e. doesn't
|
||||
// support arrays of arrays or other stuff
|
||||
AstNode* newp = valuep->cloneTree(false);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
did = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1651,7 +1655,7 @@ private:
|
|||
<<nodep->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) {
|
||||
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
|
||||
bool did = false;
|
||||
|
|
@ -1666,7 +1670,7 @@ private:
|
|||
}
|
||||
if (AstConst* valuep = VN_CAST(nodep->itemp()->valuep(), Const)) {
|
||||
const V3Number& num = valuep->num();
|
||||
replaceNum(nodep, num); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
did = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1676,7 +1680,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// virtual void visit(AstCvtPackString* nodep) {
|
||||
// virtual void visit(AstCvtPackString* nodep) VL_OVERRIDE {
|
||||
// Not constant propagated (for today) because AstNodeMath::isOpaque is set
|
||||
// Someday if lower is constant, convert to quoted "string".
|
||||
|
||||
|
|
@ -1684,7 +1688,7 @@ private:
|
|||
// Only one if it's not in a list
|
||||
return (!nodep->nextp() && nodep->backp()->nextp() != nodep);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst
|
||||
&& (VN_IS(nodep->sensp(), Const)
|
||||
|
|
@ -1694,13 +1698,13 @@ private:
|
|||
if (nodep->isClocked()) { // A constant can never get a pos/negedge
|
||||
if (onlySenItemInSenTree(nodep)) {
|
||||
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else {
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
} else { // Otherwise it may compute a result that needs to settle out
|
||||
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
} else if (m_doNConst && VN_IS(nodep->sensp(), Not)) {
|
||||
// V3Gate may propagate NOTs into clocks... Just deal with it
|
||||
|
|
@ -1716,7 +1720,7 @@ private:
|
|||
AstNodeVarRef* senvarp = VN_CAST(lastSensp->unlinkFrBack(), NodeVarRef);
|
||||
UASSERT_OBJ(senvarp, sensp, "Non-varref sensitivity variable");
|
||||
sensp->replaceWith(senvarp);
|
||||
sensp->deleteTree(); VL_DANGLING(sensp);
|
||||
VL_DO_DANGLING(sensp->deleteTree(), sensp);
|
||||
} else if (!m_doNConst // Deal with later when doNConst missing
|
||||
&& (VN_IS(nodep->sensp(), EnumItemRef)
|
||||
|| VN_IS(nodep->sensp(), Const))) {
|
||||
|
|
@ -1726,22 +1730,22 @@ private:
|
|||
"Null sensitivity variable");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) {
|
||||
if (constp->isZero()) {
|
||||
UINFO(4,"SENGATE(...,0)->NEVER"<<endl);
|
||||
if (onlySenItemInSenTree(nodep)) {
|
||||
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else {
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
} else {
|
||||
UINFO(4,"SENGATE(SENITEM,0)->ALWAYS SENITEM"<<endl);
|
||||
AstNode* senitemp = nodep->sensesp()->unlinkFrBack();
|
||||
nodep->replaceWith(senitemp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1778,7 +1782,7 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
virtual void visit(AstSenTree* nodep) {
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_doExpensive) {
|
||||
//cout<<endl; nodep->dumpTree(cout, "ssin: ");
|
||||
|
|
@ -1787,7 +1791,7 @@ private:
|
|||
|
||||
// SENTREE(... SENITEM(x), SENGATE(SENITEM(x),*) ...) => SENITEM(x)
|
||||
// Do we need the SENITEM's to be identical? No because we're
|
||||
// ORing between them; we just need to insure that the result is at
|
||||
// ORing between them; we just need to ensure that the result is at
|
||||
// least as frequently activating. So we simply
|
||||
// SENGATE(SENITEM(x)) -> SENITEM(x), then let it collapse with the
|
||||
// other SENITEM(x).
|
||||
|
|
@ -1813,7 +1817,8 @@ private:
|
|||
// Found, push this item up to the top
|
||||
itemp->unlinkFrBack();
|
||||
nodep->addSensesp(itemp);
|
||||
gatep->unlinkFrBack()->deleteTree(); VL_DANGLING(gatep); VL_DANGLING(senp);
|
||||
VL_DO_DANGLING(gatep->unlinkFrBack()->deleteTree(), gatep);
|
||||
VL_DANGLING(senp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1874,7 +1879,8 @@ private:
|
|||
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|
||||
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
// Remove redundant node
|
||||
ritemp->unlinkFrBack()->deleteTree(); VL_DANGLING(ritemp); VL_DANGLING(cmpp);
|
||||
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
|
||||
VL_DANGLING(cmpp);
|
||||
// Try to collapse again
|
||||
nextp = litemp;
|
||||
}
|
||||
|
|
@ -1887,17 +1893,17 @@ private:
|
|||
|
||||
//-----
|
||||
// Zero elimination
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst && replaceNodeAssign(nodep)) return;
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
// Don't perform any optimizations, keep the alias around
|
||||
}
|
||||
virtual void visit(AstAssignVarScope* nodep) {
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
|
||||
// Don't perform any optimizations, the node won't be linked yet
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst && replaceNodeAssign(nodep)) return;
|
||||
AstNodeVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); // Not VarXRef, as different refs may set different values to each hierarchy
|
||||
|
|
@ -1917,14 +1923,14 @@ private:
|
|||
new AstAssign(nodep->fileline(),
|
||||
varrefp, exprp));
|
||||
m_modp->addStmtp(newinitp);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
// Set the initial value right in the variable so we can constant propagate
|
||||
AstNode* initvaluep = exprp->cloneTree(false);
|
||||
varrefp->varp()->valuep(initvaluep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst) {
|
||||
if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) {
|
||||
|
|
@ -1942,13 +1948,13 @@ private:
|
|||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) {
|
||||
// Empty block, remove it
|
||||
// Note if we support more C++ then there might be side
|
||||
// effects in the condition itself
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (!afterComment(nodep->ifsp())) {
|
||||
UINFO(4,"IF({x}) NULL {...} => IF(NOT{x}}: "<<nodep<<endl);
|
||||
|
|
@ -1970,7 +1976,7 @@ private:
|
|||
AstIf* ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp);
|
||||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
else if (ifSameAssign(nodep)) {
|
||||
UINFO(4,"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"<<endl);
|
||||
|
|
@ -1983,7 +1989,7 @@ private:
|
|||
ifp->rhsp(new AstCond(truep->fileline(),
|
||||
condp, truep, falsep));
|
||||
nodep->replaceWith(ifp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
|
||||
&& operandIfIf(nodep)) {
|
||||
|
|
@ -1995,7 +2001,7 @@ private:
|
|||
nodep->condp(new AstLogAnd(lowerIfp->fileline(),
|
||||
condp, lowerCondp));
|
||||
lowerIfp->replaceWith(lowerIfsp);
|
||||
lowerIfp->deleteTree(); VL_DANGLING(lowerIfp);
|
||||
VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp);
|
||||
}
|
||||
else if (operandBoolShift(nodep->condp())) {
|
||||
replaceBoolShift(nodep->condp());
|
||||
|
|
@ -2003,7 +2009,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
|
||||
iterateChildren(nodep);
|
||||
if (stmtDisplayDisplay(nodep)) return;
|
||||
|
|
@ -2045,10 +2051,10 @@ private:
|
|||
if (!prevp->addNewline() && nodep->addNewline()) {
|
||||
pformatp->text(pformatp->text()+"\n");
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
// Substitute constants into displays. The main point of this is to
|
||||
// simplify assertion methodologies which call functions with display's.
|
||||
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
|
||||
|
|
@ -2069,7 +2075,7 @@ private:
|
|||
if (!inPct && ch=='%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
} else if (inPct && (isdigit(ch) || ch=='.')) {
|
||||
} else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
|
|
@ -2081,13 +2087,13 @@ private:
|
|||
default: // Most operators, just move to next argument
|
||||
if (argp) {
|
||||
AstNode* nextp = argp->nextp();
|
||||
if (argp && VN_IS(argp, Const)) { // Convert it
|
||||
if (VN_IS(argp, Const)) { // Convert it
|
||||
string out = VN_CAST(argp, Const)->num().displayed(nodep, fmt);
|
||||
UINFO(9," DispConst: "<<fmt<<" -> "<<out
|
||||
<<" for "<<argp<<endl);
|
||||
// fmt = out w/ replace % with %% as it must be literal.
|
||||
fmt = VString::quotePercent(out);
|
||||
argp->unlinkFrBack()->deleteTree(); VL_DANGLING(argp);
|
||||
VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp);
|
||||
}
|
||||
argp = nextp;
|
||||
}
|
||||
|
|
@ -2107,21 +2113,21 @@ private:
|
|||
&& nodep->name().find('%') == string::npos
|
||||
&& !nodep->hidden()) {
|
||||
// Just a simple constant string - the formatting is pointless
|
||||
replaceConstString(nodep, nodep->name()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceConstString(nodep, nodep->name()), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstFuncRef* nodep) {
|
||||
virtual void visit(AstFuncRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_params) { // Only parameters force us to do constant function call propagation
|
||||
replaceWithSimulation(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstArg* nodep) {
|
||||
virtual void visit(AstArg* nodep) VL_OVERRIDE {
|
||||
// replaceWithSimulation on the Arg's parent FuncRef replaces these
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
bool oldHasJumpGo = m_hasJumpGo;
|
||||
m_hasJumpGo = false;
|
||||
{
|
||||
|
|
@ -2134,7 +2140,7 @@ private:
|
|||
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
||||
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->condp()->isNeqZero()) {
|
||||
if (!thisWhileHasJumpGo) {
|
||||
|
|
@ -2147,27 +2153,27 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep) {
|
||||
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstInitItem* nodep) {
|
||||
virtual void visit(AstInitItem* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
// These are converted by V3Param. Don't constify as we don't want the
|
||||
// from() VARREF to disappear, if any.
|
||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||
virtual void visit(AstNodePreSel* nodep) {}
|
||||
virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE {}
|
||||
|
||||
// Ignored, can eliminate early
|
||||
virtual void visit(AstSysIgnore* nodep) {
|
||||
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst) {
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
// Simplify
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->cvtRangeConst();
|
||||
}
|
||||
|
|
@ -2175,7 +2181,7 @@ private:
|
|||
//-----
|
||||
// Jump elimination
|
||||
|
||||
virtual void visit(AstJumpGo* nodep) {
|
||||
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
m_hasJumpGo = true;
|
||||
if (m_doExpensive) {
|
||||
|
|
@ -2185,7 +2191,7 @@ private:
|
|||
if (AstJumpLabel* aboveLabelp = VN_CAST(nodep->abovep(), JumpLabel)) {
|
||||
if (aboveLabelp == nodep->labelp()) {
|
||||
UINFO(4, "JUMPGO => last remove "<<nodep<<endl);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2194,7 +2200,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstJumpLabel* nodep) {
|
||||
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
|
||||
// Because JumpLabels disable many optimizations,
|
||||
// remove JumpLabels that are not pointed to by any AstJumpGos
|
||||
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
|
||||
|
|
@ -2206,7 +2212,7 @@ private:
|
|||
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (underp) nodep->replaceWith(underp);
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2540,7 +2546,7 @@ private:
|
|||
// Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
if (m_required) {
|
||||
if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range)) {
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ private:
|
|||
: m_comment(comment), m_varRefp(vp), m_chgRefp(cp) {}
|
||||
~ToggleEnt() {}
|
||||
void cleanup() {
|
||||
m_varRefp->deleteTree(); m_varRefp = NULL;
|
||||
m_chgRefp->deleteTree(); m_chgRefp = NULL;
|
||||
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = NULL);
|
||||
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -149,17 +149,21 @@ private:
|
|||
+"_"+type;
|
||||
}
|
||||
// VISITORS - BOTH
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
|
||||
m_fileps.clear();
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
m_inModOff = true;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
bool origInModOff = m_inModOff;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
|
||||
m_fileps.clear();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_inModOff = origInModOff;
|
||||
}
|
||||
|
||||
// VISITORS - TOGGLE COVERAGE
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
bool oldtog = m_inToggleOff;
|
||||
{
|
||||
m_inToggleOff = true;
|
||||
|
|
@ -167,7 +171,7 @@ private:
|
|||
}
|
||||
m_inToggleOff = oldtog;
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_modp && !m_inModOff && !m_inToggleOff
|
||||
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) {
|
||||
|
|
@ -303,7 +307,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS - LINE COVERAGE
|
||||
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered
|
||||
UINFO(4," IF: "<<nodep<<endl);
|
||||
if (m_checkBlock) {
|
||||
// An else-if. When we iterate the if, use "elsif" marking
|
||||
|
|
@ -340,7 +344,7 @@ private:
|
|||
m_checkBlock = true; // Reset as a child may have cleared it
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCaseItem* nodep) {
|
||||
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
|
||||
UINFO(4," CASEI: "<<nodep<<endl);
|
||||
if (m_checkBlock && !m_inModOff
|
||||
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) {
|
||||
|
|
@ -353,7 +357,7 @@ private:
|
|||
m_checkBlock = true; // Reset as a child may have cleared it
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCover* nodep) {
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
UINFO(4," COVER: "<<nodep<<endl);
|
||||
m_checkBlock = true; // Always do cover blocks, even if there's a $stop
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -364,21 +368,21 @@ private:
|
|||
}
|
||||
m_checkBlock = true; // Reset as a child may have cleared it
|
||||
}
|
||||
virtual void visit(AstStop* nodep) {
|
||||
virtual void visit(AstStop* nodep) VL_OVERRIDE {
|
||||
UINFO(4," STOP: "<<nodep<<endl);
|
||||
m_checkBlock = false;
|
||||
}
|
||||
virtual void visit(AstPragma* nodep) {
|
||||
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
|
||||
if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
|
||||
// Skip all NEXT nodes under this block, and skip this if/case branch
|
||||
UINFO(4," OFF: "<<nodep<<endl);
|
||||
m_checkBlock = false;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else {
|
||||
if (m_checkBlock) iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
// Record the hierarchy of any named begins, so we can apply to user
|
||||
// coverage points. This is because there may be cov points inside
|
||||
// generate blocks; each point should get separate consideration.
|
||||
|
|
@ -398,7 +402,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS - BOTH
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
if (m_checkBlock) {
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ private:
|
|||
UINFO(8," new "<<removep->incp()->declp()<<endl);
|
||||
// Mark the found node as a duplicate of the first node
|
||||
// (Not vice-versa as we have the iterator for the found node)
|
||||
removep->unlinkFrBack(); pushDeletep(removep); VL_DANGLING(removep);
|
||||
removep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(removep), removep);
|
||||
// Remove node from comparison so don't hit it again
|
||||
hashed.erase(dupit);
|
||||
++m_statToggleJoins;
|
||||
|
|
@ -102,19 +102,19 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Find all Coverage's
|
||||
iterateChildren(nodep);
|
||||
// Simplify
|
||||
detectDuplicates();
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) {
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
m_toggleps.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath* nodep) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,13 +57,13 @@ private:
|
|||
// NODE STATE
|
||||
// ** Shared with DeadVisitor **
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->modp()->user1Inc(-1);
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNodeMath* nodep) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -133,20 +133,23 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
if (!nodep->dead()) {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
if (!nodep->dead()) {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
}
|
||||
}
|
||||
m_modp = NULL;
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->scopep()) nodep->scopep()->user1Inc();
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc();
|
||||
|
|
@ -155,14 +158,14 @@ private:
|
|||
m_scopesp.push_back(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
m_cellsp.push_back(nodep);
|
||||
nodep->modp()->user1Inc();
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->varScopep()) {
|
||||
|
|
@ -177,7 +180,7 @@ private:
|
|||
else nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
|
|
@ -185,7 +188,7 @@ private:
|
|||
else nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep) {
|
||||
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
|
|
@ -194,12 +197,12 @@ private:
|
|||
else nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) {
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) {
|
||||
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
|
|
@ -208,20 +211,20 @@ private:
|
|||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstModport* nodep) {
|
||||
virtual void visit(AstModport* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_elimCells) {
|
||||
if (!nodep->varsp()) {
|
||||
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_elimCells && !nodep->attrPublic()) {
|
||||
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
checkAll(nodep);
|
||||
|
|
@ -229,7 +232,7 @@ private:
|
|||
// Normal modules may disappear, e.g. if they are parameterized then removed
|
||||
if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->scopep()) nodep->scopep()->user1Inc();
|
||||
|
|
@ -237,7 +240,7 @@ private:
|
|||
m_vscsp.push_back(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
|
||||
|
|
@ -245,7 +248,7 @@ private:
|
|||
m_varsp.push_back(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
// See if simple assignments to variables may be eliminated because
|
||||
// that variable is never used.
|
||||
// Similar code in V3Life
|
||||
|
|
@ -265,7 +268,7 @@ private:
|
|||
}
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
if (nodep->isOutputter()) m_sideEffect = true;
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
|
|
@ -289,7 +292,7 @@ private:
|
|||
if (!modp->dead()) { // If was dead didn't increment user1's
|
||||
DeadModVisitor visitor(modp);
|
||||
}
|
||||
modp->unlinkFrBack()->deleteTree(); VL_DANGLING(modp);
|
||||
VL_DO_DANGLING(modp->unlinkFrBack()->deleteTree(), modp);
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +302,7 @@ private:
|
|||
return (!nodep->isSigPublic() // Can't elim publics!
|
||||
&& !nodep->isIO()
|
||||
&& ((nodep->isTemp() && !nodep->isTrace())
|
||||
|| (nodep->isParam() && !nodep->isTrace())
|
||||
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|
||||
|| m_elimUserVars)); // Post-Trace can kill most anything
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +320,7 @@ private:
|
|||
if (scp->dtypep()) {
|
||||
scp->dtypep()->user1Inc(-1);
|
||||
}
|
||||
scp->unlinkFrBack()->deleteTree(); VL_DANGLING(scp);
|
||||
VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp);
|
||||
*it = NULL;
|
||||
retry = true;
|
||||
}
|
||||
|
|
@ -330,7 +333,7 @@ private:
|
|||
AstCell* cellp = *it;
|
||||
if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) {
|
||||
cellp->modp()->user1Inc(-1);
|
||||
cellp->unlinkFrBack()->deleteTree(); VL_DANGLING(cellp);
|
||||
VL_DO_DANGLING(cellp->unlinkFrBack()->deleteTree(), cellp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -347,11 +350,11 @@ private:
|
|||
AstNodeAssign* assp = itr->second;
|
||||
UINFO(4," Dead assign "<<assp<<endl);
|
||||
assp->dtypep()->user1Inc(-1);
|
||||
assp->unlinkFrBack()->deleteTree(); VL_DANGLING(assp);
|
||||
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
|
||||
}
|
||||
if (vscp->scopep()) vscp->scopep()->user1Inc(-1);
|
||||
vscp->dtypep()->user1Inc(-1);
|
||||
vscp->unlinkFrBack()->deleteTree(); VL_DANGLING(vscp);
|
||||
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
|
||||
}
|
||||
}
|
||||
for (bool retry=true; retry; ) {
|
||||
|
|
@ -365,7 +368,7 @@ private:
|
|||
if (varp->dtypep()) {
|
||||
varp->dtypep()->user1Inc(-1);
|
||||
}
|
||||
varp->unlinkFrBack()->deleteTree(); VL_DANGLING(varp);
|
||||
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
|
||||
*it = NULL;
|
||||
retry = true;
|
||||
}
|
||||
|
|
@ -389,7 +392,7 @@ private:
|
|||
if (!cont)
|
||||
continue;
|
||||
}
|
||||
(*it)->unlinkFrBack()->deleteTree(); VL_DANGLING(*it);
|
||||
VL_DO_DANGLING((*it)->unlinkFrBack()->deleteTree(), *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,22 +348,22 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
//VV***** We reset all userp() on the netlist
|
||||
m_modVarMap.clear();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
AstNode::user3ClearTree();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_cfuncp = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
m_activep = nodep;
|
||||
bool oldinit = m_inInitial;
|
||||
m_inInitial = nodep->hasInitial();
|
||||
|
|
@ -371,7 +371,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_inInitial = oldinit;
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
m_inDly = true;
|
||||
m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
|
||||
if (m_cfuncp) nodep->v3error("Unsupported: Delayed assignment inside public function/task");
|
||||
|
|
@ -384,9 +384,9 @@ private:
|
|||
if (newlhsp) {
|
||||
nodep->lhsp(newlhsp);
|
||||
} else {
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
lhsp->deleteTree(); VL_DANGLING(lhsp);
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
|
||||
}
|
||||
else {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -395,7 +395,7 @@ private:
|
|||
m_nextDlyp = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user2Inc()) { // Not done yet
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
UINFO(4,"AssignDlyVar: "<<nodep<<endl);
|
||||
|
|
@ -432,7 +432,7 @@ private:
|
|||
}
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
|
||||
newrefp->user2(true); // No reason to do it again
|
||||
nodep->replaceWith(newrefp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
else if (!m_inDly && nodep->lvalue()) {
|
||||
//UINFO(9,"NBA "<<nodep<<endl);
|
||||
|
|
@ -444,10 +444,10 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep) {
|
||||
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
bool oldloop = m_inLoop;
|
||||
m_inLoop = true;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -456,7 +456,7 @@ private:
|
|||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,14 +82,17 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_funcp = NULL;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_funcp = NULL;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
m_funcp = nodep;
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
|
|
@ -103,7 +106,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_stmtp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
} else {
|
||||
|
|
@ -111,9 +114,9 @@ private:
|
|||
}
|
||||
}
|
||||
// Operators
|
||||
virtual void visit(AstNodeTermop* nodep) {
|
||||
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
// We have some operator defines that use 2 parens, so += 2.
|
||||
m_depth += 2;
|
||||
if (m_depth>m_maxdepth) m_maxdepth = m_depth;
|
||||
|
|
@ -135,24 +138,24 @@ private:
|
|||
// (Here instead of new visitor after V3Descope just to avoid another visitor)
|
||||
void needNonStaticFunc(AstNode* nodep) {
|
||||
UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function");
|
||||
if (m_funcp->isStatic().trueU()) {
|
||||
if (m_funcp->isStatic().trueUnknown()) {
|
||||
UINFO(5,"Mark non-public due to "<<nodep<<endl);
|
||||
m_funcp->isStatic(false);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) {
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
needNonStaticFunc(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) {
|
||||
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
|
||||
needNonStaticFunc(nodep);
|
||||
visitStmt(nodep);
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar* nodep) {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,14 +71,17 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_deepNum = 0;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_deepNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
// We recurse into this.
|
||||
int lastDepth = m_depth;
|
||||
AstCFunc* lastFuncp = m_funcp;
|
||||
|
|
@ -106,7 +109,7 @@ private:
|
|||
}
|
||||
m_depth--;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
} else {
|
||||
|
|
@ -114,11 +117,11 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeMath* nodep) {} // Accelerate
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar* nodep) {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,18 +44,18 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared entire netlist
|
||||
// AstCFunc::user() // bool. Indicates processing completed
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
typedef std::multimap<string,AstCFunc*> FuncMmap;
|
||||
typedef std::multimap<string, AstCFunc*> FuncMmap;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope
|
||||
bool m_modSingleton; // m_modp is only instanced once
|
||||
bool m_allowThis; // Allow function non-static
|
||||
bool m_needThis; // Make function non-static
|
||||
FuncMmap m_modFuncs; // Name of public functions added
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope
|
||||
bool m_modSingleton; // m_modp is only instanced once
|
||||
bool m_allowThis; // Allow function non-static
|
||||
bool m_needThis; // Make function non-static
|
||||
FuncMmap m_modFuncs; // Name of public functions added
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -63,7 +63,7 @@ private:
|
|||
static bool modIsSingleton(AstNodeModule* modp) {
|
||||
// True iff there's exactly one instance of this module in the design.
|
||||
int instances = 0;
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (VN_IS(stmtp, Scope)) {
|
||||
if (++instances > 1) { return false; }
|
||||
}
|
||||
|
|
@ -81,8 +81,7 @@ private:
|
|||
// Sets 'hierThisr' true if the object is local to this scope
|
||||
// (and could be made into a function-local later in V3Localize),
|
||||
// false if the object is in another scope.
|
||||
string descopedName(const AstScope* scopep, bool& hierThisr,
|
||||
const AstVar* varp=NULL) {
|
||||
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = NULL) {
|
||||
UASSERT(scopep, "Var/Func not scoped");
|
||||
hierThisr = (scopep == m_scopep);
|
||||
|
||||
|
|
@ -97,7 +96,6 @@ private:
|
|||
//
|
||||
// Static functions can't use this
|
||||
if (!m_allowThis) relativeRefOk = false;
|
||||
|
||||
//
|
||||
// Use absolute refs in top-scoped routines, keep them static.
|
||||
// The DPI callback registration depends on representing top-level
|
||||
|
|
@ -106,18 +104,15 @@ private:
|
|||
//
|
||||
// V3Combine wouldn't likely be able to combine top-level
|
||||
// routines anyway, so there's no harm in keeping these static.
|
||||
if (m_modp->isTop()) {
|
||||
relativeRefOk = false;
|
||||
}
|
||||
UASSERT_OBJ(m_modp, scopep, "Scope not under module");
|
||||
if (m_modp->isTop()) relativeRefOk = false;
|
||||
//
|
||||
// Use absolute refs if this scope is the only instance of the module.
|
||||
// Saves a bit of overhead on passing the 'this' pointer, and there's no
|
||||
// need to be nice to V3Combine when we have only a single instance.
|
||||
// The risk that this prevents combining identical logic from differently-
|
||||
// named but identical modules seems low.
|
||||
if (m_modSingleton) {
|
||||
relativeRefOk = false;
|
||||
}
|
||||
if (m_modSingleton) relativeRefOk = false;
|
||||
|
||||
if (varp && varp->isFuncLocal()) {
|
||||
hierThisr = true;
|
||||
|
|
@ -130,23 +125,21 @@ private:
|
|||
// Reference to scope of cell directly under this module, can just "cell->"
|
||||
string name = scopep->name();
|
||||
string::size_type pos;
|
||||
if ((pos = name.rfind('.')) != string::npos) {
|
||||
name.erase(0, pos+1);
|
||||
}
|
||||
if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1);
|
||||
m_needThis = true;
|
||||
return name+"->";
|
||||
return name + "->";
|
||||
} else {
|
||||
// Reference to something elsewhere, or relative references
|
||||
// are disabled. Use global variable
|
||||
UINFO(8," Descope "<<scopep<<endl);
|
||||
UINFO(8," to "<<scopep->name()<<endl);
|
||||
UINFO(8," under "<<m_scopep->name()<<endl);
|
||||
UINFO(8, " Descope " << scopep << endl);
|
||||
UINFO(8, " to " << scopep->name() << endl);
|
||||
UINFO(8, " under " << m_scopep->name() << endl);
|
||||
if (!scopep->aboveScopep()) { // Top
|
||||
// We could also return "vlSymsp->TOPp->" here, but GCC would
|
||||
// suspect aliases.
|
||||
return "vlTOPp->";
|
||||
} else {
|
||||
return scopep->nameVlSym()+".";
|
||||
return scopep->nameVlSym() + ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -155,64 +148,64 @@ private:
|
|||
// We recorded all public functions in m_modFuncs.
|
||||
// If for any given name only one function exists, we can use that function directly.
|
||||
// If multiple functions exist, we need to select the appropriate scope.
|
||||
for (FuncMmap::iterator it = m_modFuncs.begin(); it!=m_modFuncs.end(); ++it) {
|
||||
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
|
||||
string name = it->first;
|
||||
AstCFunc* topFuncp = it->second;
|
||||
FuncMmap::iterator nextIt1 = it; ++nextIt1;
|
||||
bool moreOfSame1 = (nextIt1!=m_modFuncs.end() && nextIt1->first == name);
|
||||
FuncMmap::iterator nextIt1 = it;
|
||||
++nextIt1;
|
||||
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
|
||||
if (moreOfSame1) {
|
||||
// Multiple functions under this name, need a wrapper function
|
||||
UINFO(6," Wrapping "<<name<<" multifuncs\n");
|
||||
UINFO(6, " Wrapping " << name << " multifuncs\n");
|
||||
AstCFunc* newfuncp = topFuncp->cloneTree(false);
|
||||
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
newfuncp->name(name);
|
||||
newfuncp->isStatic(false);
|
||||
newfuncp->addInitsp(
|
||||
new AstCStmt(newfuncp->fileline(),
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(),
|
||||
EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
EmitCBaseVisitor::symClassVar() + " = this->__VlSymsp;\n"));
|
||||
newfuncp->addInitsp(
|
||||
new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
|
||||
topFuncp->addNextHere(newfuncp);
|
||||
// In the body, call each function if it matches the given scope
|
||||
for (FuncMmap::iterator eachIt = it;
|
||||
eachIt != m_modFuncs.end() && eachIt->first==name; ++eachIt) {
|
||||
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
|
||||
it = eachIt;
|
||||
AstCFunc* funcp = eachIt->second;
|
||||
FuncMmap::iterator nextIt2 = eachIt; ++nextIt2;
|
||||
bool moreOfSame = (nextIt2!=m_modFuncs.end() && nextIt2->first == name);
|
||||
FuncMmap::iterator nextIt2 = eachIt;
|
||||
++nextIt2;
|
||||
bool moreOfSame = (nextIt2 != m_modFuncs.end() && nextIt2->first == name);
|
||||
UASSERT_OBJ(funcp->scopep(), funcp, "Not scoped");
|
||||
|
||||
UINFO(6," Wrapping "<<name<<" "<<funcp<<endl);
|
||||
UINFO(6," at "<<newfuncp->argTypes()<<" und "<<funcp->argTypes()<<endl);
|
||||
UINFO(6, " Wrapping " << name << " " << funcp << endl);
|
||||
UINFO(6, " at " << newfuncp->argTypes()
|
||||
<< " und " << funcp->argTypes() << endl);
|
||||
funcp->declPrivate(true);
|
||||
AstNode* argsp = NULL;
|
||||
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
AstNode* newp = new AstVarRef(portp->fileline(),
|
||||
portp, portp->isWritable());
|
||||
if (argsp) argsp = argsp->addNextNull(newp);
|
||||
else argsp = newp;
|
||||
AstNode* newp
|
||||
= new AstVarRef(portp->fileline(), portp, portp->isWritable());
|
||||
argsp = argsp ? argsp->addNextNull(newp) : newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* returnp = new AstCReturn(funcp->fileline(),
|
||||
new AstCCall(funcp->fileline(),
|
||||
funcp, argsp));
|
||||
AstNode* returnp = new AstCReturn(
|
||||
funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp));
|
||||
|
||||
if (moreOfSame) {
|
||||
AstIf* ifp = new AstIf(funcp->fileline(),
|
||||
new AstEq(funcp->fileline(),
|
||||
new AstCMath(funcp->fileline(),
|
||||
"this", 64),
|
||||
new AstCMath(funcp->fileline(),
|
||||
string("&(")
|
||||
+funcp->scopep()->nameVlSym()
|
||||
+")", 64)),
|
||||
returnp, NULL);
|
||||
AstIf* ifp = new AstIf(
|
||||
funcp->fileline(),
|
||||
new AstEq(
|
||||
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64),
|
||||
new AstCMath(funcp->fileline(),
|
||||
string("&(") + funcp->scopep()->nameVlSym() + ")",
|
||||
64)),
|
||||
returnp, NULL);
|
||||
newfuncp->addStmtsp(ifp);
|
||||
} else {
|
||||
newfuncp->addStmtsp(returnp);
|
||||
|
|
@ -220,68 +213,70 @@ private:
|
|||
}
|
||||
// Not really any way the user could do this, and we'd need
|
||||
// to come up with some return value
|
||||
//newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
|
||||
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
|
||||
// AstDisplayType::DT_WARNING,
|
||||
// string("%%Error: ")+name+"() called with bad scope", NULL));
|
||||
//newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
||||
if (debug()>=9) newfuncp->dumpTree(cout, " newfunc: ");
|
||||
// string("%%Error: ")+name+"() called with bad
|
||||
// scope", NULL));
|
||||
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
||||
if (debug() >= 9) newfuncp->dumpTree(cout, " newfunc: ");
|
||||
} else {
|
||||
// Only a single function under this name, we can simply rename it
|
||||
UINFO(6," Wrapping "<<name<<" just one "<<topFuncp<<endl);
|
||||
UINFO(6, " Wrapping " << name << " just one " << topFuncp << endl);
|
||||
topFuncp->name(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_modFuncs.clear();
|
||||
m_modSingleton = modIsSingleton(m_modp);
|
||||
iterateChildren(nodep);
|
||||
makePublicFuncWrappers();
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modFuncs.clear();
|
||||
m_modSingleton = modIsSingleton(m_modp);
|
||||
iterateChildren(nodep);
|
||||
makePublicFuncWrappers();
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
// Delete the varscope when we're finished
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Convert the hierch name
|
||||
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
|
||||
bool hierThis;
|
||||
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis/*ref*/,
|
||||
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis /*ref*/,
|
||||
nodep->varScopep()->varp()));
|
||||
nodep->hierThis(hierThis);
|
||||
nodep->varScopep(NULL);
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
//UINFO(9," "<<nodep<<endl);
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
// UINFO(9," "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
// Convert the hierch name
|
||||
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
|
||||
UASSERT_OBJ(nodep->funcp()->scopep(), nodep, "CFunc not under scope");
|
||||
bool hierThis;
|
||||
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis/*ref*/));
|
||||
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis /*ref*/));
|
||||
// Can't do this, as we may have more calls later
|
||||
// nodep->funcp()->scopep(NULL);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1()) {
|
||||
m_needThis = false;
|
||||
m_allowThis = nodep->isStatic().falseU(); // Non-static or unknown if static
|
||||
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(true);
|
||||
if (m_needThis) {
|
||||
nodep->isStatic(false);
|
||||
}
|
||||
if (m_needThis) nodep->isStatic(false);
|
||||
// If it's under a scope, move it up to the top
|
||||
if (m_scopep) {
|
||||
nodep->unlinkFrBack();
|
||||
|
|
@ -291,23 +286,22 @@ private:
|
|||
// There may be multiple public functions by the same name;
|
||||
// record for later correction or making of shells
|
||||
m_modFuncs.insert(make_pair(nodep->name(), nodep));
|
||||
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
|
||||
nodep->name(m_scopep->nameDotless() + "__" + nodep->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar*) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DescopeVisitor(AstNetlist* nodep)
|
||||
: m_modp(NULL),
|
||||
m_scopep(NULL),
|
||||
m_modSingleton(false),
|
||||
m_allowThis(false),
|
||||
m_needThis(false) {
|
||||
: m_modp(NULL)
|
||||
, m_scopep(NULL)
|
||||
, m_modSingleton(false)
|
||||
, m_allowThis(false)
|
||||
, m_needThis(false) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~DescopeVisitor() {}
|
||||
|
|
|
|||
804
src/V3EmitC.cpp
804
src/V3EmitC.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -56,11 +56,17 @@ public:
|
|||
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
|
||||
static string symTopAssign() {
|
||||
return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
|
||||
static string modClassName(AstNodeModule* modp) { // Return name of current module being processed
|
||||
if (modp->isTop()) {
|
||||
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
||||
if (nodep->isConstructor()) return prefixNameProtect(modp);
|
||||
else if (nodep->isDestructor()) return string("~") + prefixNameProtect(modp);
|
||||
else return nodep->nameProtect();
|
||||
}
|
||||
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
|
||||
const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule);
|
||||
if (modp && modp->isTop()) {
|
||||
return v3Global.opt.prefix();
|
||||
} else {
|
||||
return v3Global.opt.modPrefix()+"_"+protect(modp->name());
|
||||
return v3Global.opt.modPrefix() + "_" + protect(nodep->name());
|
||||
}
|
||||
}
|
||||
static string topClassName() { // Return name of top wrapper module
|
||||
|
|
@ -108,7 +114,7 @@ private:
|
|||
// MEMBERS
|
||||
int m_count; // Number of statements
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
m_count++;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,47 +40,55 @@ class EmitCInlines : EmitCBaseVisitor {
|
|||
void emitInt();
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->keyword() == AstBasicDTypeKwd::STRING) {
|
||||
// Request #include <string> via verilated_heavy.h when we create symbol file
|
||||
v3Global.needHeavy(true);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssocArrayDType* nodep) {
|
||||
virtual void visit(AstAssocArrayDType* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstQueueDType* nodep) {
|
||||
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstAtoN* nodep) {
|
||||
virtual void visit(AstValuePlusArgs* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstPutcN* nodep) {
|
||||
virtual void visit(AstAtoN* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstGetcN* nodep) {
|
||||
virtual void visit(AstPutcN* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSubstrN* nodep) {
|
||||
virtual void visit(AstGetcN* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCompareNN* nodep) {
|
||||
virtual void visit(AstGetcRefN* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSubstrN* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCompareNN* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//---------------------------------------
|
||||
|
|
|
|||
|
|
@ -125,8 +125,8 @@ class CMakeEmitter {
|
|||
|
||||
*of << "\n### Sources...\n";
|
||||
std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global;
|
||||
for (AstFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), File)) {
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(nodep, CFile);
|
||||
if (cfilep && cfilep->source()) {
|
||||
if (cfilep->support()) {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,10 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
|
||||
void nameCheck(AstNode* nodep) {
|
||||
// Prevent GCC compile time error; name check all things that reach C++ code
|
||||
if (nodep->name() != "") {
|
||||
if (nodep->name() != ""
|
||||
&& !(VN_IS(nodep, CFunc)
|
||||
&& (VN_CAST(nodep, CFunc)->isConstructor()
|
||||
|| VN_CAST(nodep, CFunc)->isDestructor()))) {
|
||||
string rsvd = m_words.isKeyword(nodep->name());
|
||||
if (rsvd != "") {
|
||||
// Generally V3Name should find all of these and throw SYMRSVDWORD.
|
||||
|
|
@ -244,7 +247,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Collect list of scopes
|
||||
iterateChildren(nodep);
|
||||
varsExpand();
|
||||
|
|
@ -268,13 +271,16 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
if (!m_dpiHdrOnly) emitDpiImp();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
nameCheck(nodep);
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCellInline* nodep) {
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
|
||||
if (v3Global.opt.vpi()) {
|
||||
string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER"
|
||||
: "SCOPE_MODULE";
|
||||
|
|
@ -284,18 +290,19 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
name_dedot, type)));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
nameCheck(nodep);
|
||||
|
||||
m_scopes.push_back(make_pair(nodep, m_modp));
|
||||
|
||||
if (v3Global.opt.vpi() && !nodep->isTop()) {
|
||||
string name_dedot = AstNode::dedotName(nodep->shortName());
|
||||
m_vpiScopeCandidates.insert(make_pair(nodep->name(),
|
||||
ScopeData(scopeSymString(nodep->name()),
|
||||
nodep->name(), "SCOPE_MODULE")));
|
||||
name_dedot, "SCOPE_MODULE")));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
string name = nodep->scopeSymName();
|
||||
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()<<" ss "<<name<<endl);
|
||||
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
||||
|
|
@ -315,7 +322,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
nameCheck(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isSigUserRdPublic()
|
||||
|
|
@ -323,13 +330,13 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
m_modVars.push_back(make_pair(m_modp, nodep));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) {
|
||||
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
|
||||
// Assign numbers to all bins, so we know how big of an array to use
|
||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||
nodep->binNum(m_coverBins++);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
nameCheck(nodep);
|
||||
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
|
||||
m_dpis.push_back(nodep);
|
||||
|
|
@ -339,9 +346,9 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
m_funcp = NULL;
|
||||
}
|
||||
// NOPs
|
||||
virtual void visit(AstConst*) {}
|
||||
virtual void visit(AstConst*) VL_OVERRIDE {}
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//---------------------------------------
|
||||
|
|
@ -383,11 +390,10 @@ void EmitCSyms::emitSymHdr() {
|
|||
puts("#include \"verilated.h\"\n");
|
||||
}
|
||||
|
||||
// for
|
||||
puts("\n// INCLUDE MODULE CLASSES\n");
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
|
||||
nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) {
|
||||
puts("#include \""+modClassName(nodep)+".h\"\n");
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
|
||||
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
|
||||
}
|
||||
|
||||
if (v3Global.dpi()) {
|
||||
|
|
@ -418,20 +424,23 @@ void EmitCSyms::emitSymHdr() {
|
|||
|
||||
puts("\n// SUBCELL STATE\n");
|
||||
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
|
||||
AstScope* scopep = it->first;
|
||||
AstNodeModule* modp = it->second;
|
||||
if (modp->isTop()) {
|
||||
ofp()->printf("%-30s ", (modClassName(modp)+"*").c_str());
|
||||
puts(protectIf(scopep->nameDotless()+"p", scopep->protect())+";\n");
|
||||
}
|
||||
else {
|
||||
ofp()->printf("%-30s ", (modClassName(modp)+"").c_str());
|
||||
puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n");
|
||||
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str());
|
||||
puts(protectIf(scopep->nameDotless() + "p", scopep->protect()) + ";\n");
|
||||
} else {
|
||||
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "").c_str());
|
||||
puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_coverBins) {
|
||||
puts("\n// COVERAGE\n");
|
||||
puts("uint32_t __Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
|
||||
puts(v3Global.opt.threads() ? "std::atomic<uint32_t>" : "uint32_t");
|
||||
puts(" __Vcoverage[");
|
||||
puts(cvtToStr(m_coverBins));
|
||||
puts("];\n");
|
||||
}
|
||||
|
||||
if (!m_scopeNames.empty()) { // Scope names
|
||||
|
|
@ -471,7 +480,7 @@ void EmitCSyms::emitSymHdr() {
|
|||
puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n");
|
||||
}
|
||||
puts("\n");
|
||||
puts("} VL_ATTR_ALIGNED(64);\n");
|
||||
puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n");
|
||||
|
||||
ofp()->putsEndGuard();
|
||||
}
|
||||
|
|
@ -480,8 +489,7 @@ void EmitCSyms::closeSplit() {
|
|||
if (!m_ofp || m_ofp == m_ofpBase) return;
|
||||
|
||||
puts("}\n");
|
||||
delete m_ofp;
|
||||
m_ofp = NULL;
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
|
||||
}
|
||||
|
||||
void EmitCSyms::checkSplit(bool usesVfinal) {
|
||||
|
|
@ -522,9 +530,9 @@ void EmitCSyms::emitSymImpPreamble() {
|
|||
|
||||
// Includes
|
||||
puts("#include \""+symClassName()+".h\"\n");
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
|
||||
nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) {
|
||||
puts("#include \""+modClassName(nodep)+".h\"\n");
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
|
||||
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -580,13 +588,14 @@ void EmitCSyms::emitSymImp() {
|
|||
}
|
||||
puts(" , __Vm_didInit(false)\n");
|
||||
puts(" // Setup submodule names\n");
|
||||
char comma=',';
|
||||
char comma = ',';
|
||||
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
|
||||
AstScope* scopep = it->first;
|
||||
AstNodeModule* modp = it->second;
|
||||
if (modp->isTop()) {
|
||||
} else {
|
||||
puts(string(" ")+comma+" "+protect(scopep->nameDotless()));
|
||||
puts("(Verilated::catName(topp->name(),");
|
||||
puts(string(" ") + comma + " " + protect(scopep->nameDotless()));
|
||||
puts("(Verilated::catName(topp->name(), ");
|
||||
// The "." is added by catName
|
||||
putsQuoted(protectWordsIf(scopep->prettyName(), scopep->protect()));
|
||||
puts("))\n");
|
||||
|
|
@ -600,7 +609,8 @@ void EmitCSyms::emitSymImp() {
|
|||
puts("TOPp = topp;\n");
|
||||
puts("// Setup each module's pointers to their submodules\n");
|
||||
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
|
||||
AstScope* scopep = it->first;
|
||||
AstNodeModule* modp = it->second;
|
||||
if (!modp->isTop()) {
|
||||
checkSplit(false);
|
||||
string arrow = scopep->name();
|
||||
|
|
@ -609,10 +619,9 @@ void EmitCSyms::emitSymImp() {
|
|||
arrow.replace(pos, 1, "->");
|
||||
}
|
||||
if (arrow.substr(0, 5) == "TOP->") arrow.replace(0, 5, "TOPp->");
|
||||
string arrowProt = protectWordsIf(arrow, scopep->protect());
|
||||
ofp()->printf("%-30s ", arrowProt.c_str());
|
||||
ofp()->puts(protectWordsIf(arrow, scopep->protect()));
|
||||
puts(" = &");
|
||||
puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n");
|
||||
puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
|
||||
++m_numStmts;
|
||||
}
|
||||
}
|
||||
|
|
@ -620,7 +629,8 @@ void EmitCSyms::emitSymImp() {
|
|||
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
|
||||
puts("TOPp->"+protect("__Vconfigure")+"(this, true);\n");
|
||||
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
|
||||
AstScope* scopep = it->first;
|
||||
AstNodeModule* modp = it->second;
|
||||
if (!modp->isTop()) {
|
||||
checkSplit(false);
|
||||
// first is used by AstCoverDecl's call to __vlCoverInsert
|
||||
|
|
@ -693,7 +703,7 @@ void EmitCSyms::emitSymImp() {
|
|||
puts(protect("__Vscope_"+scopep->scopeSymName())+".exportInsert(__Vfinal, ");
|
||||
putsQuoted(funcp->cname()); // Not protected - user asked for import/export
|
||||
puts(", (void*)(&");
|
||||
puts(modClassName(modp));
|
||||
puts(prefixNameProtect(modp));
|
||||
puts("::");
|
||||
puts(funcp->nameProtect());
|
||||
puts("));\n");
|
||||
|
|
@ -775,7 +785,7 @@ void EmitCSyms::emitDpiHdr() {
|
|||
puts("// DESCR" "IPTION: Verilator output: Prototypes for DPI import and export functions.\n");
|
||||
puts("//\n");
|
||||
puts("// Verilator includes this file in all generated .cpp files that use DPI functions.\n");
|
||||
puts("// Manually include this file where DPI .c import functions are declared to insure\n");
|
||||
puts("// Manually include this file where DPI .c import functions are declared to ensure\n");
|
||||
puts("// the C functions match the expectations of the DPI imports.\n");
|
||||
puts("\n");
|
||||
puts("#include \"svdpi.h\"\n");
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public:
|
|||
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
|
||||
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
|
||||
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
|
||||
of.puts("# Tracing threadeds output mode? 0/1 (from --trace-fst-thread)\n");
|
||||
of.puts("# Tracing threaded output mode? 0/1 (from --trace-fst-thread)\n");
|
||||
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
|
||||
?"1":"0"); of.puts("\n");
|
||||
|
||||
|
|
@ -101,8 +101,8 @@ public:
|
|||
else if (support==2 && slow) {
|
||||
}
|
||||
else {
|
||||
for (AstFile* nodep = v3Global.rootp()->filesp();
|
||||
nodep; nodep = VN_CAST(nodep->nextp(), File)) {
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp();
|
||||
nodep; nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(nodep, CFile);
|
||||
if (cfilep && cfilep->source()
|
||||
&& cfilep->slow()==(slow!=0)
|
||||
|
|
@ -189,7 +189,7 @@ public:
|
|||
string cppfile = *it;
|
||||
of.puts("\t"+V3Os::filenameNonExt(cppfile)+" \\\n");
|
||||
string dir = V3Os::filenameDir(cppfile);
|
||||
if (dirs.find(dir) == dirs.end()) dirs.insert(dir);
|
||||
dirs.insert(dir);
|
||||
}
|
||||
of.puts("\n");
|
||||
|
||||
|
|
|
|||
192
src/V3EmitV.cpp
192
src/V3EmitV.cpp
|
|
@ -57,15 +57,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
putfs(nodep, nodep->verilogKwd()+" "+modClassName(nodep)+";\n");
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end"+nodep->verilogKwd()+"\n");
|
||||
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->isFunction() ? "function":"task");
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
|
|
@ -75,7 +75,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
putqs(nodep, "end\n");
|
||||
}
|
||||
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
if (nodep->unnamed()) {
|
||||
putbs("begin\n");
|
||||
} else {
|
||||
|
|
@ -84,22 +84,22 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateChildren(nodep);
|
||||
puts("end\n");
|
||||
}
|
||||
virtual void visit(AstGenerate* nodep) {
|
||||
virtual void visit(AstGenerate* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "generate\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) {
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "final begin\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "initial begin\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "always ");
|
||||
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
|
||||
else iterateAndNextNull(nodep->sensesp());
|
||||
|
|
@ -107,7 +107,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "/*verilator public_flat_rw ");
|
||||
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
|
||||
else iterateAndNextNull(nodep->sensesp());
|
||||
|
|
@ -115,37 +115,37 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "*/\n");
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " "+nodep->verilogKwd()+" ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " <= ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
putbs("alias ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " = ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "assign ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putbs(" = ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstBreak* nodep) {
|
||||
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
|
||||
putbs("break");
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) {
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
// AstSenItem is called for dumping in isolation by V3Order
|
||||
putfs(nodep, "@(");
|
||||
for (AstNode* expp=nodep->sensesp(); expp; expp = expp->nextp()) {
|
||||
|
|
@ -154,16 +154,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "");
|
||||
puts(nodep->edgeType().verilogKwd());
|
||||
if (nodep->sensp()) puts(" ");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeCase* nodep) {
|
||||
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "");
|
||||
if (const AstCase* casep = VN_CAST(nodep, Case)) {
|
||||
if (casep->priorityPragma()) puts("priority ");
|
||||
|
|
@ -184,7 +184,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->itemsp());
|
||||
putqs(nodep, "endcase\n");
|
||||
}
|
||||
virtual void visit(AstCaseItem* nodep) {
|
||||
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
|
||||
if (nodep->condsp()) {
|
||||
iterateAndNextNull(nodep->condsp());
|
||||
} else putbs("default");
|
||||
|
|
@ -192,17 +192,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstComment* nodep) {
|
||||
virtual void visit(AstComment* nodep) VL_OVERRIDE {
|
||||
puts(string("// ")+nodep->name()+"\n");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstContinue* nodep) {
|
||||
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
|
||||
putbs("continue");
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstCoverDecl*) {} // N/A
|
||||
virtual void visit(AstCoverInc*) {} // N/A
|
||||
virtual void visit(AstCoverToggle*) {} // N/A
|
||||
virtual void visit(AstCoverDecl*) VL_OVERRIDE {} // N/A
|
||||
virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A
|
||||
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A
|
||||
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp,
|
||||
const string& text, AstNode* exprsp) {
|
||||
|
|
@ -216,28 +216,28 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstDisable* nodep) {
|
||||
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
|
||||
putbs("disable "+nodep->name()+";\n");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
virtual void visit(AstElabDisplay* nodep) {
|
||||
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, NULL, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) {
|
||||
virtual void visit(AstFScanF* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstSScanF* nodep) {
|
||||
virtual void visit(AstSScanF* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep) {
|
||||
virtual void visit(AstSFormat* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstFOpen* nodep) {
|
||||
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
|
|
@ -247,27 +247,27 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
if (nodep->modep()) iterateAndNextNull(nodep->modep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFClose* nodep) {
|
||||
virtual void visit(AstFClose* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFFlush* nodep) {
|
||||
virtual void visit(AstFFlush* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstJumpGo* nodep) {
|
||||
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
||||
putbs("disable "+cvtToHex(nodep->labelp())+";\n");
|
||||
}
|
||||
virtual void visit(AstJumpLabel* nodep) {
|
||||
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
|
||||
putbs("begin : "+cvtToHex(nodep)+"\n");
|
||||
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
|
||||
puts("end\n");
|
||||
}
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
|
||||
|
|
@ -277,17 +277,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
if (nodep->msbp()) { putbs(","); iterateAndNextNull(nodep->msbp()); }
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) {
|
||||
virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstSysIgnore* nodep) {
|
||||
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstNodeFor* nodep) {
|
||||
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "for (");
|
||||
m_suppressSemi = true;
|
||||
iterateAndNextNull(nodep->initsp());
|
||||
|
|
@ -300,14 +300,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep) {
|
||||
virtual void visit(AstRepeat* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "repeat (");
|
||||
iterateAndNextNull(nodep->countp());
|
||||
puts(") begin\n");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putfs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
putfs(nodep, "while (");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
|
|
@ -317,7 +317,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
putfs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "");
|
||||
if (const AstIf* ifp = VN_CAST(nodep, If)) {
|
||||
if (ifp->priorityPragma()) puts("priority ");
|
||||
|
|
@ -335,7 +335,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstPast* nodep) {
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$past(");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
if (nodep->ticksp()) {
|
||||
|
|
@ -344,49 +344,49 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstReturn* nodep) {
|
||||
virtual void visit(AstReturn* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "return ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstStop* nodep) {
|
||||
virtual void visit(AstStop* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$stop;\n");
|
||||
}
|
||||
virtual void visit(AstFinish* nodep) {
|
||||
virtual void visit(AstFinish* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$finish;\n");
|
||||
}
|
||||
virtual void visit(AstText* nodep) {
|
||||
virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE {
|
||||
if (nodep->tracking() || m_trackText) {
|
||||
puts(nodep->text());
|
||||
} else {
|
||||
putsNoTracking(nodep->text());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTextBlock* nodep) {
|
||||
visit(VN_CAST(nodep, Text));
|
||||
virtual void visit(AstTextBlock* nodep) VL_OVERRIDE {
|
||||
visit(VN_CAST(nodep, NodeSimpleText));
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterate(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
}
|
||||
virtual void visit(AstCStmt* nodep) {
|
||||
virtual void visit(AstCStmt* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$_CSTMT(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstCMath* nodep) {
|
||||
virtual void visit(AstCMath* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$_CMATH(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) {
|
||||
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$c(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) {
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$c(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(")");
|
||||
|
|
@ -444,19 +444,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeTermop* nodep) {
|
||||
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog());
|
||||
}
|
||||
virtual void visit(AstNodeUniop* nodep) {
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) {
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep) {
|
||||
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep) {
|
||||
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$_ATTROF(");
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
if (nodep->dimp()) {
|
||||
|
|
@ -465,7 +465,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep) {
|
||||
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "`{");
|
||||
int comma = 0;
|
||||
const AstInitArray::KeyItemMap& mapr = nodep->map();
|
||||
|
|
@ -479,13 +479,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstNodeCond* nodep) {
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->condp()); putfs(nodep, " ? ");
|
||||
iterateAndNextNull(nodep->expr1p()); putbs(" : ");
|
||||
iterateAndNextNull(nodep->expr2p()); puts(")");
|
||||
}
|
||||
virtual void visit(AstRange* nodep) {
|
||||
virtual void visit(AstRange* nodep) VL_OVERRIDE {
|
||||
puts("[");
|
||||
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
|
||||
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
|
||||
|
|
@ -496,7 +496,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->rightp()); puts("]");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSel* nodep) {
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->fromp()); puts("[");
|
||||
if (VN_IS(nodep->lsbp(), Const)) {
|
||||
if (nodep->widthp()->isOne()) {
|
||||
|
|
@ -518,44 +518,44 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
puts("]");
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
virtual void visit(AstSliceSel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
puts(cvtToStr(nodep->declRange()));
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "typedef ");
|
||||
iterateAndNextNull(nodep->dtypep()); puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->isSigned()) putfs(nodep, "signed ");
|
||||
putfs(nodep, nodep->prettyName());
|
||||
if (nodep->rangep()) { puts(" "); iterateAndNextNull(nodep->rangep()); puts(" "); }
|
||||
else if (nodep->isRanged()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); }
|
||||
}
|
||||
virtual void visit(AstConstDType* nodep) {
|
||||
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "const ");
|
||||
iterate(nodep->subDTypep());
|
||||
}
|
||||
virtual void visit(AstNodeArrayDType* nodep) {
|
||||
virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE {
|
||||
iterate(nodep->subDTypep());
|
||||
iterateAndNextNull(nodep->rangep());
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) {
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
puts(nodep->verilogKwd()+" ");
|
||||
if (nodep->packed()) puts("packed ");
|
||||
puts("\n");
|
||||
iterateAndNextNull(nodep->membersp());
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstMemberDType* nodep) {
|
||||
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
|
||||
iterate(nodep->subDTypep());
|
||||
puts(" ");
|
||||
puts(nodep->name());
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->dotted()!="") {
|
||||
putfs(nodep, nodep->dotted()); puts("."); puts(nodep->prettyName());
|
||||
} else { putfs(nodep, nodep->prettyName()); }
|
||||
|
|
@ -563,11 +563,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->pinsp());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstArg* nodep) {
|
||||
virtual void visit(AstArg* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
}
|
||||
// Terminals
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varScopep()) {
|
||||
putfs(nodep, nodep->varScopep()->prettyName());
|
||||
} else {
|
||||
|
|
@ -575,43 +575,43 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
puts(nodep->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->dotted());
|
||||
puts(".");
|
||||
puts(nodep->varp()->prettyName());
|
||||
}
|
||||
virtual void visit(AstConst* nodep) {
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->num().ascii(true, true));
|
||||
}
|
||||
|
||||
// Just iterate
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
puts(" ");
|
||||
iterate(nodep->dtypep()); puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
if (!m_suppressVarSemi) puts(";\n"); else puts("\n");
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
m_sensesp = nodep->sensesp();
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
m_sensesp = NULL;
|
||||
}
|
||||
virtual void visit(AstVarScope*) {}
|
||||
virtual void visit(AstNodeText*) {}
|
||||
virtual void visit(AstTraceDecl*) {}
|
||||
virtual void visit(AstTraceInc*) {}
|
||||
virtual void visit(AstVarScope*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeText*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
|
||||
// NOPs
|
||||
virtual void visit(AstPragma*) {}
|
||||
virtual void visit(AstCell*) {} // Handled outside the Visit class
|
||||
virtual void visit(AstPragma*) VL_OVERRIDE {}
|
||||
virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
|
||||
iterateChildren(nodep);
|
||||
// Not v3fatalSrc so we keep processing
|
||||
|
|
@ -757,12 +757,12 @@ void V3EmitV::emitv() {
|
|||
EmitVFileVisitor visitor (v3Global.rootp(), &of);
|
||||
} else {
|
||||
// Process each module in turn
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp();
|
||||
modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
|
||||
V3OutVFile of (v3Global.opt.makeDir()
|
||||
+"/"+EmitCBaseVisitor::modClassName(modp)+"__Vout.v");
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
V3OutVFile of(v3Global.opt.makeDir() + "/" + EmitCBaseVisitor::prefixNameProtect(modp)
|
||||
+ "__Vout.v");
|
||||
of.putsHeader();
|
||||
EmitVFileVisitor visitor (modp, &of);
|
||||
EmitVFileVisitor visitor(modp, &of);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -779,8 +779,8 @@ void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os,
|
|||
|
||||
void V3EmitV::emitvFiles() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
for (AstFile* filep = v3Global.rootp()->filesp(); filep;
|
||||
filep = VN_CAST(filep->nextp(), File)) {
|
||||
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
|
||||
filep = VN_CAST(filep->nextp(), NodeFile)) {
|
||||
AstVFile* vfilep = VN_CAST(filep, VFile);
|
||||
if (vfilep && vfilep->tblockp()) {
|
||||
V3OutVFile of(vfilep->name());
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
void outputTag(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||
puts("<"+tag+" "+nodep->fileline()->xml());
|
||||
puts(" "+nodep->fileline()->xmlDetailedLocation());
|
||||
if (VN_IS(nodep, NodeDType)) { puts(" id="); outputId(nodep); }
|
||||
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
|
||||
if (nodep->tag()!="") { puts(" tag="); putsQuoted(nodep->tag()); }
|
||||
|
|
@ -94,22 +95,22 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "contassign"); // IEEE: vpiContAssign
|
||||
outputChildrenEnd(nodep, "contassign");
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "instance"); // IEEE: vpiInstance
|
||||
puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName
|
||||
puts(" origName="); putsQuoted(nodep->origName());
|
||||
outputChildrenEnd(nodep, "instance");
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
puts("<netlist>\n");
|
||||
iterateChildren(nodep);
|
||||
puts("</netlist>\n");
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" origName="); putsQuoted(nodep->origName());
|
||||
if (nodep->level()==1 || nodep->level()==2) // ==2 because we don't add wrapper when in XML mode
|
||||
|
|
@ -117,7 +118,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
if (nodep->modPublic()) puts(" public=\"true\"");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
AstVarType typ = nodep->varType();
|
||||
string kw = nodep->verilogKwd();
|
||||
string vt = nodep->dtypep()->name();
|
||||
|
|
@ -131,18 +132,23 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
}
|
||||
puts(" origName="); putsQuoted(nodep->origName());
|
||||
// Attributes
|
||||
if (nodep->attrClocker()) puts(" clocker=\"true\"");
|
||||
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES)
|
||||
puts(" clocker=\"true\"");
|
||||
else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO)
|
||||
puts(" clocker=\"false\"");
|
||||
if (nodep->attrClockEn()) puts(" clock_enable=\"true\"");
|
||||
if (nodep->attrIsolateAssign()) puts(" isolate_assignments=\"true\"");
|
||||
if (nodep->isSigPublic()) puts(" public=\"true\"");
|
||||
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
|
||||
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
|
||||
if (nodep->isGParam()) puts(" param=\"true\"");
|
||||
else if (nodep->isParam()) puts(" localparam=\"true\"");
|
||||
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
|
||||
if (nodep->attrScClocked()) puts(" sc_clock=\"true\"");
|
||||
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
// What we call a pin in verilator is a port in the IEEE spec.
|
||||
outputTag(nodep, "port"); // IEEE: vpiPort
|
||||
if (nodep->modVarp()->isIO()) {
|
||||
|
|
@ -152,26 +158,26 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
||||
outputChildrenEnd(nodep, "port");
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" edgeType=\""+cvtToStr(nodep->edgeType().ascii())+"\""); // IEEE vpiTopModule
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstModportVarRef* nodep) {
|
||||
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
|
||||
// Dump direction for Modport references
|
||||
string kw = nodep->direction().xmlKwd();
|
||||
outputTag(nodep, "");
|
||||
puts(" direction="); putsQuoted(kw);
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" dotted="); putsQuoted(nodep->dotted());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
|
||||
// Data types
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "basicdtype");
|
||||
if (nodep->isRanged()) {
|
||||
puts(" left=\""+cvtToStr(nodep->left())+"\"");
|
||||
|
|
@ -179,30 +185,30 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
}
|
||||
puts("/>\n");
|
||||
}
|
||||
virtual void visit(AstIfaceRefDType* nodep) {
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
string mpn;
|
||||
outputTag(nodep, "");
|
||||
if (nodep->isModport()) mpn = nodep->modportName();
|
||||
puts(" modportname="); putsQuoted(mpn);
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstElabDisplay* nodep) {
|
||||
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstExtend* nodep) {
|
||||
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
|
||||
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstExtendS* nodep) {
|
||||
virtual void visit(AstExtendS* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
|
||||
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
|
|
@ -210,7 +216,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
}
|
||||
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
|
|
@ -237,11 +243,11 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Children are iterated backwards to ensure correct compilation order
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Only list modules and interfaces
|
||||
// Assumes modules and interfaces list is already sorted level wise
|
||||
if (!nodep->dead()
|
||||
|
|
@ -251,7 +257,7 @@ private:
|
|||
}
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// All modules are present at root so no need to iterate on children
|
||||
}
|
||||
|
||||
|
|
@ -288,11 +294,12 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
if (nodep->level() >= 0
|
||||
&& nodep->level() <=2 ) { // ==2 because we don't add wrapper when in XML mode
|
||||
m_os<<"<cells>\n";
|
||||
m_os<<"<cell "<<nodep->fileline()->xml()
|
||||
<<" "<<nodep->fileline()->xmlDetailedLocation()
|
||||
<<" name=\""<<nodep->name()<<"\""
|
||||
<<" submodname=\""<<nodep->name()<<"\""
|
||||
<<" hier=\""<<nodep->name()<<"\"";
|
||||
|
|
@ -307,12 +314,13 @@ private:
|
|||
m_os<<"</cells>\n";
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
if (nodep->modp()->dead()) {
|
||||
return;
|
||||
}
|
||||
if (!m_hasChildren) m_os<<">\n";
|
||||
m_os<<"<cell "<<nodep->fileline()->xml()
|
||||
<<" "<<nodep->fileline()->xmlDetailedLocation()
|
||||
<<" name=\""<<nodep->name()<<"\""
|
||||
<<" submodname=\""<<nodep->modName()<<"\""
|
||||
<<" hier=\""<<m_hier+nodep->name()<<"\"";
|
||||
|
|
@ -329,7 +337,7 @@ private:
|
|||
m_hasChildren = true;
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -205,11 +205,15 @@ public:
|
|||
|| m_e==UNDRIVEN
|
||||
|| m_e==UNUSED
|
||||
|| m_e==VARHIDDEN ); }
|
||||
};
|
||||
inline bool operator==(V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(V3ErrorCode::en lhs, V3ErrorCode rhs) { return (lhs == rhs.m_e); }
|
||||
inline std::ostream& operator<<(std::ostream& os, V3ErrorCode rhs) { return os<<rhs.ascii(); }
|
||||
};
|
||||
inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -291,8 +295,8 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
|
|||
|
||||
// Theses allow errors using << operators: v3error("foo"<<"bar");
|
||||
// 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.
|
||||
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
|
||||
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
|
||||
#define v3warnCode(code,msg) \
|
||||
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
|
||||
#define v3warnCodeFatal(code,msg) \
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ private:
|
|||
void replaceWithDelete(AstNode* nodep, AstNode* newp) {
|
||||
newp->user1(1); // Already processed, don't need to re-iterate
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
AstNode* newWordAssign(AstNodeAssign* placep, int word, AstNode* lhsp, AstNode* rhsp) {
|
||||
AstAssign* newp = new AstAssign(placep->fileline(),
|
||||
|
|
@ -306,7 +306,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstExtend* nodep) {
|
||||
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isWide()) {
|
||||
|
|
@ -328,7 +328,7 @@ private:
|
|||
"extending larger thing into smaller?");
|
||||
lhsp->dtypeFrom(nodep); // Just mark it, else nop
|
||||
}
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) {
|
||||
|
|
@ -343,7 +343,7 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual void visit(AstSel* nodep) {
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
||||
|
|
@ -443,7 +443,7 @@ private:
|
|||
if (midp) newp = new AstOr(nodep->fileline(), midp, newp);
|
||||
if (hip) newp = new AstOr(nodep->fileline(), hip, newp);
|
||||
newp->dtypeFrom(nodep);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
else { // Long/Quad from Long/Quad
|
||||
UINFO(8," SEL->SHIFT "<<nodep<<endl);
|
||||
|
|
@ -461,7 +461,7 @@ private:
|
|||
newp = new AstCCast(newp->fileline(), newp, nodep);
|
||||
}
|
||||
newp->dtypeFrom(nodep);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -553,8 +553,8 @@ private:
|
|||
rhsp, lsb)));
|
||||
}
|
||||
}
|
||||
rhsp->deleteTree(); VL_DANGLING(rhsp);
|
||||
destp->deleteTree(); VL_DANGLING(destp);
|
||||
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
|
||||
VL_DO_DANGLING(destp->deleteTree(), destp);
|
||||
} else {
|
||||
UINFO(8," ASSIGNSEL(const,narrow) "<<nodep<<endl);
|
||||
if (destp->isQuad() && !rhsp->isQuad()) {
|
||||
|
|
@ -670,7 +670,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isWide()) {
|
||||
|
|
@ -693,7 +693,7 @@ private:
|
|||
nodep->width()),
|
||||
rhsp);
|
||||
newp->dtypeFrom(nodep); // Unsigned
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) {
|
||||
|
|
@ -714,7 +714,7 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual void visit(AstReplicate* nodep) {
|
||||
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isWide()) {
|
||||
|
|
@ -746,10 +746,10 @@ private:
|
|||
newp);
|
||||
newp->dtypeFrom(nodep); // Unsigned
|
||||
}
|
||||
lhsp->deleteTree(); // Never used
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp); // Never used
|
||||
}
|
||||
newp->dtypeFrom(nodep); // Unsigned
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) {
|
||||
|
|
@ -779,7 +779,7 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual void visit(AstChangeXor* nodep) {
|
||||
virtual void visit(AstChangeXor* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
|
||||
|
|
@ -791,7 +791,7 @@ private:
|
|||
newAstWordSelClone(nodep->rhsp(), w));
|
||||
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
|
||||
void visitEqNeq(AstNodeBiop* nodep) {
|
||||
|
|
@ -816,13 +816,13 @@ private:
|
|||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
|
||||
newp);
|
||||
}
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEq* nodep) { visitEqNeq(nodep); }
|
||||
virtual void visit(AstNeq* nodep) { visitEqNeq(nodep); }
|
||||
virtual void visit(AstEq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
|
||||
virtual void visit(AstNeq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
|
||||
|
||||
virtual void visit(AstRedOr* nodep) {
|
||||
virtual void visit(AstRedOr* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
|
|
@ -836,7 +836,7 @@ private:
|
|||
newp = new AstNeq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
|
||||
newp);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
} else {
|
||||
UINFO(8," REDOR->EQ "<<nodep<<endl);
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
|
@ -844,10 +844,10 @@ private:
|
|||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
longOrQuadWidth(nodep), 0),
|
||||
lhsp);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRedAnd* nodep) {
|
||||
virtual void visit(AstRedAnd* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
|
|
@ -870,17 +870,17 @@ private:
|
|||
newp = new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(),
|
||||
~VL_MASK_E(0)), newp);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
} else {
|
||||
UINFO(8," REDAND->EQ "<<nodep<<endl);
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newp = new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), wordMask(lhsp)),
|
||||
lhsp);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRedXor* nodep) {
|
||||
virtual void visit(AstRedXor* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
|
|
@ -893,13 +893,13 @@ private:
|
|||
}
|
||||
newp = new AstRedXor(nodep->fileline(), newp);
|
||||
UINFO(8," Wordize REDXORnew "<<newp<<endl);
|
||||
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
|
||||
// which the inlined function does nicely.
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -909,7 +909,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_stmtp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
m_stmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -948,15 +948,15 @@ private:
|
|||
}
|
||||
// Cleanup common code
|
||||
if (did) {
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
m_stmtp = NULL;
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar*) {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -594,7 +594,7 @@ protected:
|
|||
// Just dispatch to the implementation
|
||||
|
||||
VInFilter::VInFilter(const string& command) { m_impp = new VInFilterImp(command); }
|
||||
VInFilter::~VInFilter() { if (m_impp) delete m_impp; m_impp = NULL; }
|
||||
VInFilter::~VInFilter() { if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = NULL); }
|
||||
|
||||
bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) {
|
||||
if (!m_impp) v3fatalSrc("readWholefile on invalid filter");
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ void VFileContent::pushText(const string& text) {
|
|||
|
||||
string VFileContent::getLine(int lineno) const {
|
||||
// Return error text rather than asserting so the user isn't left without a message
|
||||
// cppcheck-suppress negativeContainerIndex
|
||||
if (VL_UNCOVERABLE(lineno < 0 || lineno >= (int)m_lines.size())) {
|
||||
if (debug() || v3Global.opt.debugCheck()) {
|
||||
return ("%Error-internal-contents-bad-ct"+cvtToStr(m_id)
|
||||
|
|
@ -158,6 +159,15 @@ FileLine::FileLine(FileLine::EmptySecret) {
|
|||
}
|
||||
}
|
||||
|
||||
const string FileLine::xmlDetailedLocation() const {
|
||||
return "loc=\"" +
|
||||
cvtToStr(filenameLetters()) + "," +
|
||||
cvtToStr(firstLineno()) + "," +
|
||||
cvtToStr(firstColumn()) + "," +
|
||||
cvtToStr(lastLineno()) + "," +
|
||||
cvtToStr(lastColumn()) + "\"";
|
||||
}
|
||||
|
||||
string FileLine::lineDirectiveStrg(int enterExit) const {
|
||||
char numbuf[20]; sprintf(numbuf, "%d", lastLineno());
|
||||
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
|
||||
|
|
@ -341,7 +351,10 @@ void FileLine::v3errorEnd(std::ostringstream& str, const string& locationStr) {
|
|||
if (!locationStr.empty()) {
|
||||
lstr<<std::setw(ascii().length())<<" "<<": "<<locationStr;
|
||||
}
|
||||
if (warnIsOff(V3Error::errorCode())) V3Error::suppressThisWarning();
|
||||
if (warnIsOff(V3Error::errorCode())
|
||||
|| V3Config::waive(this, V3Error::errorCode(), str.str())) {
|
||||
V3Error::suppressThisWarning();
|
||||
}
|
||||
else if (!V3Error::errorContexted()) nsstr<<warnContextPrimary();
|
||||
V3Error::v3errorEnd(nsstr, lstr.str());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ private:
|
|||
return *defFilelinep;
|
||||
}
|
||||
public:
|
||||
FileLine(const string& filename) {
|
||||
explicit FileLine(const string& filename) {
|
||||
m_lastLineno = m_firstLineno = 0;
|
||||
m_lastColumn = m_firstColumn = 0;
|
||||
m_filenameno = singleton().nameToNumber(filename);
|
||||
|
|
@ -183,6 +183,7 @@ public:
|
|||
const string filebasenameNoExt() const;
|
||||
const string profileFuncname() const;
|
||||
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lastLineno())+"\""; }
|
||||
const string xmlDetailedLocation() const;
|
||||
string lineDirectiveStrg(int enterExit) const;
|
||||
|
||||
// Turn on/off warning messages on this line.
|
||||
|
|
@ -239,7 +240,7 @@ public:
|
|||
/// When building an error, additional location for additional references
|
||||
/// Simplified information vs warnContextPrimary() to make dump clearer
|
||||
string warnContextSecondary() const { return warnContext(true); }
|
||||
bool operator==(FileLine rhs) const {
|
||||
bool operator==(const FileLine& rhs) const {
|
||||
return (m_firstLineno == rhs.m_firstLineno
|
||||
&& m_firstColumn == rhs.m_firstColumn
|
||||
&& m_lastLineno == rhs.m_lastLineno
|
||||
|
|
|
|||
121
src/V3Gate.cpp
121
src/V3Gate.cpp
|
|
@ -207,7 +207,7 @@ private:
|
|||
}
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
++m_ops;
|
||||
iterateChildren(nodep);
|
||||
// We only allow a LHS ref for the var being set, and a RHS ref for
|
||||
|
|
@ -235,7 +235,7 @@ private:
|
|||
m_rhsVarRefs.push_back(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
m_substTreep = nodep->rhsp();
|
||||
if (!VN_IS(nodep->lhsp(), NodeVarRef)) {
|
||||
clearSimple("ASSIGN(non-VARREF)");
|
||||
|
|
@ -258,7 +258,7 @@ private:
|
|||
}
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// *** Special iterator
|
||||
if (!m_isSimple) return; // Fastpath
|
||||
if (++m_ops > v3Global.opt.gateStmts()) {
|
||||
|
|
@ -388,7 +388,7 @@ private:
|
|||
void decomposeClkVectors();
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
//if (debug()>6) m_graph.dump();
|
||||
if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre");
|
||||
|
|
@ -419,20 +419,23 @@ private:
|
|||
consumedMove();
|
||||
replaceAssigns();
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_activeReducible = true;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_activeReducible = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4," BLOCK "<<nodep<<endl);
|
||||
m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible
|
||||
|
|
@ -443,16 +446,18 @@ private:
|
|||
m_activep = NULL;
|
||||
m_activeReducible = true;
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
GateVarVertex* vvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
if (m_inSenItem) vvertexp->setIsClock();
|
||||
// For SYNCASYNCNET
|
||||
if (m_inSenItem) varscp->user2(true);
|
||||
if (m_inSenItem) {
|
||||
vvertexp->setIsClock();
|
||||
// For SYNCASYNCNET
|
||||
varscp->user2(true);
|
||||
}
|
||||
else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) {
|
||||
if (varscp->user2()) {
|
||||
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
|
||||
|
|
@ -469,19 +474,19 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "AlwaysPublic", NULL);
|
||||
m_inSlow = lastslow;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep, "User C Function", "User C Function");
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
// Note we look at only AstSenItems, not AstSenGate's
|
||||
// The gating term of a AstSenGate is normal logic
|
||||
m_inSenItem = true;
|
||||
|
|
@ -492,33 +497,33 @@ private:
|
|||
}
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is dealt with as logic
|
||||
iterateNewStmt(nodep, "Clock gater", "Clock gater");
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
|
||||
m_inSlow = lastslow;
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep, NULL, NULL);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep, NULL, NULL);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) {
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep, "CoverToggle", "CoverToggle");
|
||||
}
|
||||
virtual void visit(AstTraceInc* nodep) {
|
||||
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE {
|
||||
bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "Tracing", "Tracing");
|
||||
m_inSlow = lastslow;
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)
|
||||
&& VN_CAST(nodep->backp(), NodeAssign)->lhsp()==nodep),
|
||||
nodep, "Concat on LHS of assignment; V3Const should have deleted it");
|
||||
|
|
@ -527,7 +532,7 @@ private:
|
|||
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isOutputter() && m_logicVertexp) m_logicVertexp->setConsumed("outputter");
|
||||
}
|
||||
|
|
@ -666,7 +671,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
varvertexp->propagateAttrClocksFrom(vvertexp);
|
||||
}
|
||||
// Remove the edge
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
++m_statRefs;
|
||||
edgep = vvertexp->outBeginp();
|
||||
}
|
||||
|
|
@ -674,7 +679,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
if (removedAllUsages) {
|
||||
// Remove input links
|
||||
while (V3GraphEdge* edgep = vvertexp->inBeginp()) {
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
// Clone tree so we remember it for tracing, and keep the pointer
|
||||
// to the "ALWAYS" part of the tree as part of this statement
|
||||
|
|
@ -709,7 +714,7 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
|
|||
for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
|
||||
it != rhsVarRefs.end(); ++it) {
|
||||
AstVarScope* vscp = (*it)->varScopep();
|
||||
if (varscopes.find(vscp) == varscopes.end()) varscopes.insert(vscp);
|
||||
varscopes.insert(vscp);
|
||||
}
|
||||
for (V3GraphEdge* edgep = consumeVertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
GateVarVertex* consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top());
|
||||
|
|
@ -731,25 +736,25 @@ void GateVisitor::replaceAssigns() {
|
|||
if (vscp->valuep() && !VN_IS(vscp->valuep(), NodeMath)) {
|
||||
//if (debug()>9) vscp->dumpTree(cout, "-vscPre: ");
|
||||
while (AstNode* delp = VN_CAST(vscp->valuep(), Comment)) {
|
||||
delp->unlinkFrBack()->deleteTree(); VL_DANGLING(delp);
|
||||
VL_DO_DANGLING(delp->unlinkFrBack()->deleteTree(), delp);
|
||||
}
|
||||
if (AstInitial* delp = VN_CAST(vscp->valuep(), Initial)) {
|
||||
AstNode* bodyp = delp->bodysp();
|
||||
bodyp->unlinkFrBackWithNext();
|
||||
delp->replaceWith(bodyp);
|
||||
delp->deleteTree(); VL_DANGLING(delp);
|
||||
VL_DO_DANGLING(delp->deleteTree(), delp);
|
||||
}
|
||||
if (AstAlways* delp = VN_CAST(vscp->valuep(), Always)) {
|
||||
AstNode* bodyp = delp->bodysp();
|
||||
bodyp->unlinkFrBackWithNext();
|
||||
delp->replaceWith(bodyp);
|
||||
delp->deleteTree(); VL_DANGLING(delp);
|
||||
VL_DO_DANGLING(delp->deleteTree(), delp);
|
||||
}
|
||||
if (AstNodeAssign* delp = VN_CAST(vscp->valuep(), NodeAssign)) {
|
||||
AstNode* rhsp = delp->rhsp();
|
||||
rhsp->unlinkFrBack();
|
||||
delp->replaceWith(rhsp);
|
||||
delp->deleteTree(); VL_DANGLING(delp);
|
||||
VL_DO_DANGLING(delp->deleteTree(), delp);
|
||||
}
|
||||
//if (debug()>9) {vscp->dumpTree(cout, "-vscDone: "); cout<<endl;}
|
||||
if (!VN_IS(vscp->valuep(), NodeMath)
|
||||
|
|
@ -805,7 +810,7 @@ void GateVisitor::consumedMove() {
|
|||
// with "tracing-on" sensitivity
|
||||
UINFO(8," Remove unconsumed "<<nodep<<endl);
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -860,7 +865,7 @@ private:
|
|||
void hashReplace(AstNode* oldp, AstNode* newp);
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varScopep() == m_elimVarScp) {
|
||||
// Substitute in the new tree
|
||||
// It's possible we substitute into something that will be reduced more later,
|
||||
|
|
@ -884,10 +889,10 @@ private:
|
|||
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false);
|
||||
hashReplace(nodep, substp);
|
||||
nodep->replaceWith(substp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -1066,7 +1071,7 @@ private:
|
|||
bool m_dedupable; // Determined the assign to be dedupable
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeAssign* assignp) {
|
||||
virtual void visit(AstNodeAssign* assignp) VL_OVERRIDE {
|
||||
if (m_dedupable) {
|
||||
// I think we could safely dedupe an always block with multiple
|
||||
// non-blocking statements, but erring on side of caution here
|
||||
|
|
@ -1077,7 +1082,7 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* alwaysp) {
|
||||
virtual void visit(AstAlways* alwaysp) VL_OVERRIDE {
|
||||
if (m_dedupable) {
|
||||
if (!m_always) {
|
||||
m_always = true;
|
||||
|
|
@ -1091,7 +1096,7 @@ private:
|
|||
// always @(...)
|
||||
// if (...)
|
||||
// foo = ...; // or foo <= ...;
|
||||
virtual void visit(AstNodeIf* ifp) {
|
||||
virtual void visit(AstNodeIf* ifp) VL_OVERRIDE {
|
||||
if (m_dedupable) {
|
||||
if (m_always && !m_ifCondp && !ifp->elsesp()) { //we're under an always, this is the first IF, and there's no else
|
||||
m_ifCondp = ifp->condp();
|
||||
|
|
@ -1102,10 +1107,10 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstComment*) {} // NOP
|
||||
virtual void visit(AstComment*) VL_OVERRIDE {} // NOP
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode*) {
|
||||
virtual void visit(AstNode*) VL_OVERRIDE {
|
||||
m_dedupable = false;
|
||||
}
|
||||
|
||||
|
|
@ -1207,7 +1212,7 @@ private:
|
|||
dupVvertexp->propagateAttrClocksFrom(vvertexp);
|
||||
// Remove inputs links
|
||||
while (V3GraphEdge* inedgep = vvertexp->inBeginp()) {
|
||||
inedgep->unlinkDelete(); VL_DANGLING(inedgep);
|
||||
VL_DO_DANGLING(inedgep->unlinkDelete(), inedgep);
|
||||
}
|
||||
// replaceAssigns() does the deleteTree on lvertexNodep in a later step
|
||||
AstNode* lvertexNodep = lvertexp->nodep();
|
||||
|
|
@ -1338,19 +1343,19 @@ private:
|
|||
UINFO(5, "assemble to new sel: "<<newselp<<endl);
|
||||
// replace preSel with newSel
|
||||
preselp->replaceWith(newselp);
|
||||
preselp->deleteTree(); VL_DANGLING(preselp);
|
||||
VL_DO_DANGLING(preselp->deleteTree(), preselp);
|
||||
// create new rhs for pre assignment
|
||||
AstNode* newrhsp = new AstConcat(
|
||||
m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false),
|
||||
assignp->rhsp()->cloneTree(false));
|
||||
AstNode* oldrhsp = m_assignp->rhsp();
|
||||
oldrhsp->replaceWith(newrhsp);
|
||||
oldrhsp->deleteTree(); VL_DANGLING(oldrhsp);
|
||||
VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp);
|
||||
m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(),
|
||||
m_assignp->width()+assignp->width(),
|
||||
AstNumeric::SIGNED);
|
||||
// don't need to delete, will be handled
|
||||
//assignp->unlinkFrBack(); assignp->deleteTree(); VL_DANGLING(assignp);
|
||||
//assignp->unlinkFrBack(); VL_DO_DANGLING(assignp->deleteTree(), assignp);
|
||||
|
||||
// update the graph
|
||||
{
|
||||
|
|
@ -1362,11 +1367,11 @@ private:
|
|||
GateEitherVertex* fromvp
|
||||
= dynamic_cast<GateEitherVertex*>(oedgep->fromp());
|
||||
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
|
||||
oedgep->unlinkDelete(); VL_DANGLING(oedgep);
|
||||
VL_DO_DANGLING(oedgep->unlinkDelete(), oedgep);
|
||||
}
|
||||
}
|
||||
// delete all outedges to lvertexp, only one
|
||||
oldedgep->unlinkDelete(); VL_DANGLING(oldedgep);
|
||||
VL_DO_DANGLING(oldedgep->unlinkDelete(), oldedgep);
|
||||
}
|
||||
++m_numMergedAssigns;
|
||||
} else {
|
||||
|
|
@ -1425,7 +1430,7 @@ private:
|
|||
bool m_found; // Offset found
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
UINFO(9,"CLK DECOMP Concat search var (off = "<<m_offset<<") - "<<nodep<<endl);
|
||||
if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) {
|
||||
// A concatenation may use the same var multiple times
|
||||
|
|
@ -1437,14 +1442,14 @@ private:
|
|||
}
|
||||
m_offset += nodep->dtypep()->width();
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
UINFO(9,"CLK DECOMP Concat search (off = "<<m_offset<<") - "<<nodep<<endl);
|
||||
iterate(nodep->rhsp());
|
||||
iterate(nodep->lhsp());
|
||||
}
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -1556,7 +1561,7 @@ private:
|
|||
AstNode* rhsp = assignp->rhsp();
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
|
||||
for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep; ) {
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1);
|
||||
m_total_decomposed_clk_vectors++;
|
||||
|
|
@ -1617,19 +1622,19 @@ void GateVisitor::decomposeClkVectors() {
|
|||
class GateDeassignVisitor : public GateBaseVisitor {
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
if (AstNodeAssign* assp = VN_CAST(nodep->valuep(), NodeAssign)) {
|
||||
UINFO(5," Removeassign "<<assp<<endl);
|
||||
AstNode* valuep = assp->rhsp();
|
||||
valuep->unlinkFrBack();
|
||||
assp->replaceWith(valuep);
|
||||
assp->deleteTree(); VL_DANGLING(assp);
|
||||
VL_DO_DANGLING(assp->deleteTree(), assp);
|
||||
}
|
||||
}
|
||||
// Speedups
|
||||
virtual void visit(AstVar* nodep) {}
|
||||
virtual void visit(AstActive* nodep) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
AstNode::user2ClearTree(); // user2p() used on entire tree
|
||||
|
||||
AstScope* scopep = nodep->scopep();
|
||||
|
|
@ -93,7 +93,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
//----
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
|
|
@ -105,23 +105,23 @@ private:
|
|||
AstVarScope* newvscp = genInpClk(vscp);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
nodep->replaceWith(newrefp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
iterateChildren(nodep->sensesp()); // iterateAndNext?
|
||||
m_activep = NULL;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -152,7 +152,7 @@ private:
|
|||
AstNodeModule* m_topModp; // Top module
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||
iterateChildren(nodep);
|
||||
{
|
||||
|
|
@ -161,14 +161,14 @@ private:
|
|||
GenClkRenameVisitor visitor (nodep, m_topModp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Only track the top scopes, not lower level functions
|
||||
if (nodep->isTop()) {
|
||||
m_topModp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->funcp()->entryPoint()) {
|
||||
// Enter the function and trace it
|
||||
|
|
@ -176,7 +176,7 @@ private:
|
|||
iterate(nodep->funcp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (!m_tracingCall && !nodep->entryPoint()) {
|
||||
// Only consider logic within a CFunc when looking
|
||||
// at the call to it, and not when scanning whatever
|
||||
|
|
@ -188,7 +188,7 @@ private:
|
|||
}
|
||||
//----
|
||||
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
|
|
@ -203,13 +203,13 @@ private:
|
|||
vscp->circular(true);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
//UINFO(8,"ASS "<<nodep<<endl);
|
||||
m_assignp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_assignp = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
UINFO(8,"ACTIVE "<<nodep<<endl);
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
|
|
@ -219,8 +219,8 @@ private:
|
|||
}
|
||||
|
||||
//-----
|
||||
virtual void visit(AstVar*) {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Common implemenetations
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2020 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3File.h"
|
||||
#include "V3LinkCells.h"
|
||||
#include "V3Parse.h"
|
||||
#include "V3ParseSym.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
//######################################################################
|
||||
// V3 Class -- top level
|
||||
|
||||
AstNetlist* V3Global::makeNetlist() {
|
||||
AstNetlist* newp = new AstNetlist();
|
||||
newp->addTypeTablep(new AstTypeTable(newp->fileline()));
|
||||
return newp;
|
||||
}
|
||||
|
||||
void V3Global::checkTree() { rootp()->checkTree(); }
|
||||
|
||||
void V3Global::clear() {
|
||||
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = NULL);
|
||||
}
|
||||
|
||||
void V3Global::readFiles() {
|
||||
// NODE STATE
|
||||
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
|
||||
AstUser4InUse inuser4;
|
||||
|
||||
VInFilter filter(v3Global.opt.pipeFilter());
|
||||
V3ParseSym parseSyms(v3Global.rootp()); // Symbol table must be common across all parsing
|
||||
|
||||
V3Parse parser(v3Global.rootp(), &filter, &parseSyms);
|
||||
// Read top module
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (V3StringList::const_iterator it = vFiles.begin(); it != vFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, false,
|
||||
"Cannot find file containing module: ");
|
||||
}
|
||||
|
||||
// Read libraries
|
||||
// To be compatible with other simulators,
|
||||
// this needs to be done after the top file is read
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
for (V3StringSet::const_iterator it = libraryFiles.begin(); it != libraryFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, true,
|
||||
"Cannot find file containing library module: ");
|
||||
}
|
||||
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree"));
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
if (!v3Global.opt.preprocOnly()) {
|
||||
// Resolve all modules cells refer to
|
||||
V3LinkCells::link(v3Global.rootp(), &filter, &parseSyms);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool doDump) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(stagename + ".tree", newNumber),
|
||||
false, doDump);
|
||||
if (v3Global.opt.stats()) V3Stats::statsStage(stagename);
|
||||
}
|
||||
|
|
@ -55,10 +55,16 @@ public:
|
|||
inline VWidthMinUsage(en _e) : m_e(_e) {}
|
||||
explicit inline VWidthMinUsage(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(VWidthMinUsage lhs, VWidthMinUsage rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(VWidthMinUsage lhs, VWidthMinUsage::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(VWidthMinUsage::en lhs, VWidthMinUsage rhs) { return (lhs == rhs.m_e); }
|
||||
};
|
||||
inline bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
inline bool operator==(const VWidthMinUsage& lhs, VWidthMinUsage::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3Global - The top level class for the entire program
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ void V3Graph::clear() {
|
|||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) {
|
||||
V3GraphEdge* nextp = edgep->outNextp();
|
||||
delete edgep;
|
||||
VL_DO_DANGLING(delete edgep, edgep);
|
||||
edgep = nextp;
|
||||
}
|
||||
vertexp->outUnlink();
|
||||
|
|
@ -232,7 +232,7 @@ void V3Graph::clear() {
|
|||
// Delete the old vertices
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; /*BELOW*/) {
|
||||
V3GraphVertex* nextp = vertexp->verticesNextp();
|
||||
delete vertexp;
|
||||
VL_DO_DANGLING(delete vertexp, vertexp);
|
||||
vertexp = nextp;
|
||||
}
|
||||
verticesUnlink();
|
||||
|
|
|
|||
|
|
@ -65,15 +65,15 @@ public:
|
|||
const char* ascii() const {
|
||||
static const char* const names[] = { "FORWARD", "REVERSE" };
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
// METHODS unique to this class
|
||||
GraphWay invert() const { return m_e == FORWARD ? REVERSE : FORWARD; }
|
||||
bool forward() const { return m_e == FORWARD; }
|
||||
bool reverse() const { return m_e != FORWARD; }
|
||||
};
|
||||
inline bool operator==(GraphWay lhs, GraphWay rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator==(GraphWay lhs, GraphWay::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator==(GraphWay::en lhs, GraphWay rhs) { return (lhs == rhs.m_e); }
|
||||
inline bool operator==(const GraphWay& lhs, const GraphWay& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
inline bool operator==(const GraphWay& lhs, GraphWay::en rhs) { return lhs.m_e == rhs; }
|
||||
inline bool operator==(GraphWay::en lhs, const GraphWay& rhs) { return lhs == rhs.m_e; }
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
|
@ -104,6 +104,7 @@ public:
|
|||
// METHODS
|
||||
void clear(); // Empty it of all vertices/edges, as if making a new object
|
||||
void clearColors();
|
||||
bool empty() const { return m_vertices.empty(); }
|
||||
|
||||
V3GraphVertex* verticesBeginp() const { return m_vertices.begin(); }
|
||||
|
||||
|
|
@ -270,7 +271,7 @@ class V3GraphEdge {
|
|||
// Wires/variables aren't edges. Edges have only a single to/from vertex
|
||||
public:
|
||||
// ENUMS
|
||||
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
|
||||
enum Cutable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
|
||||
protected:
|
||||
friend class V3Graph; friend class V3GraphVertex;
|
||||
friend class GraphAcyc; friend class GraphAcycEdge;
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ void GraphAcyc::deleteMarked() {
|
|||
nextp = vertexp->verticesNextp();
|
||||
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
|
||||
if (avertexp->isDelete()) {
|
||||
avertexp->unlinkDelete(&m_breakGraph); VL_DANGLING(avertexp);
|
||||
VL_DO_DANGLING(avertexp->unlinkDelete(&m_breakGraph), avertexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -291,13 +291,13 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) {
|
|||
while (V3GraphEdge* edgep = avertexp->outBeginp()) {
|
||||
V3GraphVertex* otherVertexp = edgep->top();
|
||||
//UINFO(9," out "<<otherVertexp<<endl);
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(otherVertexp);
|
||||
}
|
||||
while (V3GraphEdge* edgep = avertexp->inBeginp()) {
|
||||
V3GraphVertex* otherVertexp = edgep->fromp();
|
||||
//UINFO(9," in "<<otherVertexp<<endl);
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(otherVertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -328,8 +328,8 @@ void GraphAcyc::simplifyOne(GraphAcycVertex* avertexp) {
|
|||
// cppcheck-suppress leakReturnValNotUsed
|
||||
edgeFromEdge(templateEdgep, inVertexp, outVertexp);
|
||||
// Remove old edge
|
||||
inEdgep->unlinkDelete(); VL_DANGLING(inEdgep);
|
||||
outEdgep->unlinkDelete(); VL_DANGLING(outEdgep); VL_DANGLING(templateEdgep);
|
||||
VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep);
|
||||
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep); VL_DANGLING(templateEdgep);
|
||||
workPush(inVertexp);
|
||||
workPush(outVertexp);
|
||||
}
|
||||
|
|
@ -363,10 +363,10 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) {
|
|||
// cppcheck-suppress leakReturnValNotUsed
|
||||
edgeFromEdge(inEdgep, inVertexp, outVertexp);
|
||||
// Remove old edge
|
||||
inEdgep->unlinkDelete(); VL_DANGLING(inEdgep);
|
||||
VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep);
|
||||
workPush(inVertexp);
|
||||
}
|
||||
outEdgep->unlinkDelete(); VL_DANGLING(outEdgep);
|
||||
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep);
|
||||
workPush(outVertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -389,18 +389,18 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
|
|||
// !cutable duplicates prev !cutable: we can ignore it, redundant
|
||||
// cutable duplicates prev !cutable: know it's not a relevant loop, ignore it
|
||||
UINFO(8," DelDupEdge "<<avertexp<<" -> "<<edgep->top()<<endl);
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
} else if (!edgep->cutable()) {
|
||||
// !cutable duplicates prev cutable: delete the earlier cutable
|
||||
UINFO(8," DelDupPrev "<<avertexp<<" -> "<<prevEdgep->top()<<endl);
|
||||
prevEdgep->unlinkDelete(); VL_DANGLING(prevEdgep);
|
||||
VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep);
|
||||
outVertexp->userp(edgep);
|
||||
} else {
|
||||
// cutable duplicates prev cutable: combine weights
|
||||
UINFO(8," DelDupComb "<<avertexp<<" -> "<<edgep->top()<<endl);
|
||||
prevEdgep->weight(prevEdgep->weight() + edgep->weight());
|
||||
addOrigEdgep(prevEdgep, edgep);
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
workPush(outVertexp);
|
||||
workPush(avertexp);
|
||||
|
|
@ -418,7 +418,7 @@ void GraphAcyc::cutBasic(GraphAcycVertex* avertexp) {
|
|||
nextp = edgep->outNextp();
|
||||
if (edgep->cutable() && edgep->top()==avertexp) {
|
||||
cutOrigEdge(edgep, " Cut Basic");
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(avertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -439,7 +439,7 @@ void GraphAcyc::cutBackward(GraphAcycVertex* avertexp) {
|
|||
nextp = edgep->outNextp();
|
||||
if (edgep->cutable() && edgep->top()->user()) {
|
||||
cutOrigEdge(edgep, " Cut A->B->A");
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(avertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -506,7 +506,7 @@ void GraphAcyc::placeTryEdge(V3GraphEdge* edgep) {
|
|||
// Adding this edge would cause a loop, kill it
|
||||
edgep->cutable(true); // So graph still looks pretty
|
||||
cutOrigEdge(edgep, " Cut loop");
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
// Back out the ranks we calculated
|
||||
while (GraphAcycVertex* vertexp = workBeginp()) {
|
||||
workPop();
|
||||
|
|
|
|||
|
|
@ -110,10 +110,10 @@ private:
|
|||
}
|
||||
if (saveOld) {
|
||||
if (m_sumWeights) prevEdgep->weight(prevEdgep->weight() + edgep->weight());
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
} else {
|
||||
if (m_sumWeights) edgep->weight(prevEdgep->weight() + edgep->weight());
|
||||
prevEdgep->unlinkDelete(); VL_DANGLING(prevEdgep);
|
||||
VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep);
|
||||
outVertexp->userp(edgep);
|
||||
}
|
||||
}
|
||||
|
|
@ -150,9 +150,7 @@ public:
|
|||
V3GraphEdge* deletep = NULL;
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
if (deletep) {
|
||||
deletep->unlinkDelete(); deletep = NULL;
|
||||
}
|
||||
if (deletep) VL_DO_CLEAR(deletep->unlinkDelete(), deletep = NULL);
|
||||
// It should be safe to modify the graph, despite using
|
||||
// the GraphPathChecker, as none of the modifications will
|
||||
// change what can be reached from what, nor should they
|
||||
|
|
@ -162,7 +160,7 @@ public:
|
|||
}
|
||||
}
|
||||
if (deletep) {
|
||||
deletep->unlinkDelete(); VL_DANGLING(deletep);
|
||||
VL_DO_DANGLING(deletep->unlinkDelete(), deletep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ private:
|
|||
for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
if (nfaState(vertexp)) {
|
||||
vertexp->unlinkDelete(m_graphp); VL_DANGLING(vertexp);
|
||||
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +409,7 @@ private:
|
|||
if (vvertexp->accepting()) {
|
||||
for (V3GraphEdge* nextp,*edgep = vertexp->outBeginp(); edgep; edgep=nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -445,7 +445,7 @@ private:
|
|||
for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
if (!vertexp->user()) {
|
||||
vertexp->unlinkDelete(m_graphp); VL_DANGLING(vertexp);
|
||||
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -487,7 +487,7 @@ private:
|
|||
}
|
||||
}
|
||||
// Transitions to this state removed by the unlink function
|
||||
vertexp->unlinkDelete(m_graphp); VL_DANGLING(vertexp);
|
||||
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -566,7 +566,7 @@ private:
|
|||
DfaVertex* tovertexp = static_cast<DfaVertex*>(edgep->top());
|
||||
if (tovertexp->accepting()) {
|
||||
new DfaEdge(graphp(), vvertexp, m_tempNewerReject, vedgep);
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
|
||||
// NOT of all values goes to accept
|
||||
|
|
@ -595,10 +595,11 @@ public:
|
|||
add_complement_edges();
|
||||
if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_preswap");
|
||||
|
||||
m_tempNewerReject->unlinkDelete(graphp()); m_tempNewerReject = NULL;
|
||||
VL_DO_CLEAR(m_tempNewerReject->unlinkDelete(graphp()), m_tempNewerReject = NULL);
|
||||
if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_out");
|
||||
}
|
||||
~DfaGraphComplement() {}
|
||||
VL_UNCOPYABLE(DfaGraphComplement);
|
||||
};
|
||||
|
||||
void DfaGraph::dfaComplement() {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class DfaVertex : public V3GraphVertex {
|
|||
bool m_accepting; // Accepting state?
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false)
|
||||
explicit DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false)
|
||||
: V3GraphVertex(graphp)
|
||||
, m_start(start), m_accepting(accepting) {}
|
||||
using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ GraphPathChecker::~GraphPathChecker() {
|
|||
for (V3GraphVertex* vxp = m_graphp->verticesBeginp();
|
||||
vxp; vxp = vxp->verticesNextp()) {
|
||||
GraphPCNode* nodep = static_cast<GraphPCNode*>(vxp->userp());
|
||||
delete nodep; VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(delete nodep, nodep);
|
||||
vxp->userp(NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ class GraphPathChecker : GraphAlg<const V3Graph> {
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GraphPathChecker(const V3Graph* graphp,
|
||||
V3EdgeFuncP edgeFuncp = V3GraphEdge::followAlwaysTrue);
|
||||
explicit GraphPathChecker(const V3Graph* graphp,
|
||||
V3EdgeFuncP edgeFuncp = V3GraphEdge::followAlwaysTrue);
|
||||
~GraphPathChecker();
|
||||
|
||||
// METHODS
|
||||
|
|
|
|||
|
|
@ -95,9 +95,9 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GraphStream(const V3Graph* graphp,
|
||||
GraphWay way = GraphWay::FORWARD,
|
||||
const T_Compare& lessThan = T_Compare())
|
||||
explicit GraphStream(const V3Graph* graphp,
|
||||
GraphWay way = GraphWay::FORWARD,
|
||||
const T_Compare& lessThan = T_Compare())
|
||||
// NOTE: Perhaps REVERSE way should also reverse the sense of the
|
||||
// lessThan function? For now the only usage of REVERSE is not
|
||||
// sensitive to its lessThan at all, so it doesn't matter.
|
||||
|
|
|
|||
|
|
@ -88,10 +88,10 @@ private:
|
|||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar*) {}
|
||||
virtual void visit(AstTypedef*) {}
|
||||
virtual void visit(AstParamTypeDType*) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTypedef*) VL_OVERRIDE {}
|
||||
virtual void visit(AstParamTypeDType*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
nodeHashIterate(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
109
src/V3Inline.cpp
109
src/V3Inline.cpp
|
|
@ -100,7 +100,8 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UASSERT_OBJ(!m_modp, nodep, "Unsupported: Recursive modules");
|
||||
m_modp = nodep;
|
||||
m_allMods.push_back(nodep);
|
||||
m_modp->user2(CIL_MAYBE);
|
||||
|
|
@ -115,12 +116,12 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
nodep->modp()->user3Inc(); // Inc refs
|
||||
m_instances[m_modp][nodep->modp()]++;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstPragma* nodep) {
|
||||
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
|
||||
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
|
||||
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
|
||||
if (!m_modp) {
|
||||
|
|
@ -129,39 +130,41 @@ private:
|
|||
|| m_modp->user2() == CIL_NOTSOFT) {
|
||||
m_modp->user2(CIL_USER);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); // Remove so don't propagate to upper cell...
|
||||
// Remove so don't propagate to upper cell...
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
|
||||
if (!m_modp) {
|
||||
nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE
|
||||
} else {
|
||||
cantInline("Pragma NO_INLINE_MODULE", false);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); // Remove so don't propagate to upper cell...
|
||||
// Remove so don't propagate to upper cell...
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
// Cleanup link until V3LinkDot can correct it
|
||||
nodep->varp(NULL);
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
// Cleanup link until V3LinkDot can correct it
|
||||
if (!nodep->packagep()) nodep->taskp(NULL);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
m_modp->user4Inc(); // statement count
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
// Don't count assignments, as they'll likely flatten out
|
||||
// Still need to iterate though to nullify VarXRefs
|
||||
int oldcnt = m_modp->user4();
|
||||
iterateChildren(nodep);
|
||||
m_modp->user4(oldcnt);
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Build user2, user3, and user4 for all modules.
|
||||
// Also build m_allMods and m_instances.
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -175,10 +178,10 @@ private:
|
|||
// update user4 (statement count) to reflect that:
|
||||
int statements = modp->user4();
|
||||
LocalInstanceMap& localsr = m_instances[modp];
|
||||
for (LocalInstanceMap::iterator it = localsr.begin(); it != localsr.end(); ++it) {
|
||||
AstNodeModule* childp = it->first;
|
||||
for (LocalInstanceMap::iterator iti = localsr.begin(); iti != localsr.end(); ++iti) {
|
||||
AstNodeModule* childp = iti->first;
|
||||
if (childp->user1()) { // inlining child
|
||||
statements += (childp->user4() * it->second);
|
||||
statements += (childp->user4() * iti->second);
|
||||
}
|
||||
}
|
||||
modp->user4(statements);
|
||||
|
|
@ -204,7 +207,7 @@ private:
|
|||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_modp) {
|
||||
m_modp->user4Inc(); // Inc statement count
|
||||
|
|
@ -240,13 +243,13 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
nodep->user4p(nodep->clonep());
|
||||
}
|
||||
// Accelerate
|
||||
virtual void visit(AstNodeStmt* nodep) {}
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +281,7 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCellInline* nodep) {
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
|
||||
// Inlined cell under the inline cell, need to move to avoid conflicts
|
||||
nodep->unlinkFrBack();
|
||||
m_modp->addInlinesp(nodep);
|
||||
|
|
@ -289,17 +292,17 @@ private:
|
|||
// Do CellInlines under this, but don't move them
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
// Cell under the inline cell, need to rename to avoid conflicts
|
||||
string name = m_cellp->name() + "__DOT__" + nodep->name();
|
||||
nodep->name(name);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstModule* nodep) {
|
||||
virtual void visit(AstModule* nodep) VL_OVERRIDE {
|
||||
m_renamedInterfaces.clear();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (nodep->user2p()) {
|
||||
// Make an assignment, so we'll trace it properly
|
||||
// user2p is either a const or a var.
|
||||
|
|
@ -383,17 +386,17 @@ private:
|
|||
if (debug()>=9 && nodep->valuep()) { nodep->valuep()->dumpTree(cout, "varchangei:"); }
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
// Function under the inline cell, need to rename to avoid conflicts
|
||||
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
// Typedef under the inline cell, need to rename to avoid conflicts
|
||||
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp()->user2p() // It's being converted to an alias.
|
||||
&& !nodep->varp()->user3()
|
||||
&& !VN_IS(nodep->backp(), AssignAlias)) { // Don't constant propagate aliases (we just made)
|
||||
|
|
@ -401,7 +404,7 @@ private:
|
|||
AstVarRef* exprvarrefp = VN_CAST(nodep->varp()->user2p(), VarRef);
|
||||
if (exprconstp) {
|
||||
nodep->replaceWith(exprconstp->cloneTree(true));
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
else if (exprvarrefp) {
|
||||
|
|
@ -414,7 +417,7 @@ private:
|
|||
nodep->name(nodep->varp()->name());
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
// Track what scope it was originally under so V3LinkDot can resolve it
|
||||
string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots());
|
||||
nodep->inlinedDots(newdots);
|
||||
|
|
@ -433,7 +436,7 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
// Track what scope it was originally under so V3LinkDot can resolve it
|
||||
string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots());
|
||||
nodep->inlinedDots(newdots);
|
||||
|
|
@ -445,9 +448,9 @@ private:
|
|||
}
|
||||
|
||||
// Not needed, as V3LinkDot doesn't care about typedefs
|
||||
//virtual void visit(AstRefDType* nodep) {}
|
||||
//virtual void visit(AstRefDType* nodep) VL_OVERRIDE {}
|
||||
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Begin
|
||||
// To keep correct visual order, must add before other Text's
|
||||
|
|
@ -461,12 +464,12 @@ private:
|
|||
if (afterp) nodep->scopeEntrp(afterp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) {
|
||||
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
|
||||
// Fix path in coverage statements
|
||||
nodep->hier(VString::dot(m_cellp->prettyName(), ".", nodep->hier()));
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -510,11 +513,11 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Iterate modules backwards, in bottom-up order. Required!
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstIfaceRefDType* nodep) {
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->user5()) {
|
||||
// The cell has been removed so let's make sure we don't leave a reference to it
|
||||
// This dtype may still be in use by the AstAssignVarScope created earlier
|
||||
|
|
@ -522,11 +525,15 @@ private:
|
|||
nodep->cellp(NULL);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
if (nodep->modp()->user1()) { // Marked with inline request
|
||||
UINFO(5," Inline CELL "<<nodep<<endl);
|
||||
UINFO(5," To MOD "<<m_modp<<endl);
|
||||
|
|
@ -597,17 +604,17 @@ private:
|
|||
if (stmtsp) stmtsp->unlinkFrBackWithNext();
|
||||
if (stmtsp) m_modp->addStmtp(stmtsp);
|
||||
// Remove the cell
|
||||
newmodp->deleteTree(); VL_DANGLING(newmodp); // Clear any leftover ports, etc
|
||||
VL_DO_DANGLING(newmodp->deleteTree(), newmodp); // Clear any leftover ports, etc
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
if (debug()>=9) { m_modp->dumpTree(cout, "donemod:"); }
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath* nodep) {} // Accelerate
|
||||
virtual void visit(AstNodeStmt* nodep) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -638,17 +645,17 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstModule* nodep) {
|
||||
virtual void visit(AstModule* nodep) VL_OVERRIDE {
|
||||
if (nodep->isTop()) {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
string oldScope = m_scope;
|
||||
if (m_scope.empty()) {
|
||||
m_scope = nodep->name();
|
||||
|
|
@ -684,7 +691,7 @@ private:
|
|||
m_scope = oldScope;
|
||||
}
|
||||
|
||||
virtual void visit(AstAssignVarScope* nodep) {
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
|
||||
// Reference
|
||||
AstVarRef* reflp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
// What the reference refers to
|
||||
|
|
@ -710,9 +717,9 @@ private:
|
|||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) {} // Accelerate
|
||||
virtual void visit(AstNodeStmt*) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -746,7 +753,7 @@ void V3Inline::inlineAll(AstNetlist* nodep) {
|
|||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
|
||||
nextmodp = VN_CAST(modp->nextp(), NodeModule);
|
||||
if (modp->user1()) { // Was inlined
|
||||
modp->unlinkFrBack()->deleteTree(); VL_DANGLING(modp);
|
||||
VL_DO_DANGLING(modp->unlinkFrBack()->deleteTree(), modp);
|
||||
}
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
m_cellp = nodep;
|
||||
//VV***** We reset user1p() on each cell!!!
|
||||
|
|
@ -62,7 +62,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_cellp = NULL;
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
|
||||
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
|
||||
UINFO(4," PIN "<<nodep<<endl);
|
||||
|
|
@ -113,10 +113,10 @@ private:
|
|||
}
|
||||
|
||||
// We're done with the pin
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstUdpTable* nodep) {
|
||||
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
// If we support primitives, update V3Undriven to remove special case
|
||||
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables.");
|
||||
|
|
@ -124,13 +124,13 @@ private:
|
|||
}
|
||||
|
||||
// Save some time
|
||||
virtual void visit(AstNodeMath*) {}
|
||||
virtual void visit(AstNodeAssign*) {}
|
||||
virtual void visit(AstAlways*) {}
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeAssign*) VL_OVERRIDE {}
|
||||
virtual void visit(AstAlways*) VL_OVERRIDE {}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -155,7 +155,7 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
|
||||
UINFO(8," dm-1-VAR "<<nodep<<endl);
|
||||
insert(nodep);
|
||||
|
|
@ -163,9 +163,9 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
// Save some time
|
||||
virtual void visit(AstNodeMath*) {}
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -213,7 +213,7 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (VN_IS(nodep->dtypep(), UnpackArrayDType)
|
||||
&& VN_IS(VN_CAST(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
|
||||
UINFO(8," dv-vec-VAR "<<nodep<<endl);
|
||||
|
|
@ -246,7 +246,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
// Find submodule vars
|
||||
UASSERT_OBJ(nodep->modp(), nodep, "Unlinked");
|
||||
|
|
@ -303,16 +303,17 @@ private:
|
|||
// Done. Delete original
|
||||
m_cellRangep = NULL;
|
||||
if (isIface) {
|
||||
ifaceVarp->unlinkFrBack(); pushDeletep(ifaceVarp); VL_DANGLING(ifaceVarp);
|
||||
ifaceVarp->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(ifaceVarp), ifaceVarp);
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else {
|
||||
m_cellRangep = NULL;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
// Any non-direct pins need reconnection with a part-select
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
if (m_cellRangep) {
|
||||
|
|
@ -379,7 +380,7 @@ private:
|
|||
newp->dtypep(nodep->modVarp()->dtypep());
|
||||
newp->packagep(varrefp->packagep());
|
||||
arrselp->addNextHere(newp);
|
||||
arrselp->unlinkFrBack()->deleteTree();
|
||||
VL_DO_DANGLING(arrselp->unlinkFrBack()->deleteTree(), arrselp);
|
||||
}
|
||||
} else {
|
||||
AstVar* pinVarp = nodep->modVarp();
|
||||
|
|
@ -446,10 +447,10 @@ private:
|
|||
}
|
||||
|
||||
// Save some time
|
||||
virtual void visit(AstNodeMath*) {}
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeSel* nodep) {
|
||||
virtual void visit(AstNodeSel* nodep) VL_OVERRIDE {
|
||||
// This covers both AstArraySel and AstWordSel
|
||||
//
|
||||
// If some vector is a bazillion dwords long, and we're selecting 1
|
||||
|
|
@ -135,7 +135,7 @@ private:
|
|||
VisitBase vb(this, nodep);
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
}
|
||||
virtual void visit(AstSel* nodep) {
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
// Similar to AstNodeSel above, a small select into a large vector
|
||||
// is not expensive. Count the cost of the AstSel itself (scales with
|
||||
// its width) and the cost of the lsbp() and widthp() nodes, but not
|
||||
|
|
@ -144,13 +144,13 @@ private:
|
|||
iterateAndNextNull(nodep->lsbp());
|
||||
iterateAndNextNull(nodep->widthp());
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
virtual void visit(AstSliceSel* nodep) VL_OVERRIDE {
|
||||
nodep->v3fatalSrc("AstSliceSel unhandled");
|
||||
}
|
||||
virtual void visit(AstMemberSel* nodep) {
|
||||
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
|
||||
nodep->v3fatalSrc("AstMemberSel unhandled");
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
// Nop.
|
||||
//
|
||||
// Ignore concat. The problem with counting concat is that when we
|
||||
|
|
@ -170,7 +170,7 @@ private:
|
|||
// the widths of the operands (ignored here).
|
||||
markCost(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
VisitBase vb(this, nodep);
|
||||
iterateAndNextNull(nodep->condp());
|
||||
uint32_t savedCount = m_instrCount;
|
||||
|
|
@ -195,7 +195,7 @@ private:
|
|||
if (nodep->ifsp()) nodep->ifsp()->user4(0); // Don't dump it
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeCond* nodep) {
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
// Just like if/else above, the ternary operator only evaluates
|
||||
// one of the two expressions, so only count the max.
|
||||
VisitBase vb(this, nodep);
|
||||
|
|
@ -220,7 +220,7 @@ private:
|
|||
if (nodep->expr2p()) nodep->expr2p()->user4(0); // Don't dump it
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// You'd think that the OrderLogicVertex's would be disjoint trees
|
||||
// of stuff in the AST, but it isn't so: V3Order makes an
|
||||
// OrderLogicVertex for each ACTIVE, and then also makes an
|
||||
|
|
@ -236,14 +236,14 @@ private:
|
|||
markCost(nodep);
|
||||
UASSERT_OBJ(nodep == m_startNodep, nodep, "Multiple actives, or not start node");
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
VisitBase vb(this, nodep);
|
||||
iterateChildren(nodep);
|
||||
m_tracingCall = true;
|
||||
iterate(nodep->funcp());
|
||||
UASSERT_OBJ(!m_tracingCall, nodep, "visit(AstCFunc) should have cleared m_tracingCall.");
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
// Don't count a CFunc other than by tracing a call or counting it
|
||||
// from the root
|
||||
UASSERT_OBJ(m_tracingCall || nodep == m_startNodep, nodep,
|
||||
|
|
@ -257,7 +257,7 @@ private:
|
|||
}
|
||||
m_inCFunc = saved_inCFunc;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
VisitBase vb(this, nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -289,7 +289,7 @@ public:
|
|||
private:
|
||||
// METHODS
|
||||
string indent() { return string(m_depth, ':')+" "; }
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
++m_depth;
|
||||
if (unsigned costPlus1 = nodep->user4()) {
|
||||
*m_osp <<" "<<indent()
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public:
|
|||
"1800-2017"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
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; }
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ public:
|
|||
// above our current iteration point.
|
||||
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
|
||||
entp->complexAssign();
|
||||
m_statep->pushUnlinkDeletep(oldassp); VL_DANGLING(oldassp);
|
||||
VL_DO_DANGLING(m_statep->pushUnlinkDeletep(oldassp), oldassp);
|
||||
++m_statep->m_statAssnDel;
|
||||
}
|
||||
}
|
||||
|
|
@ -195,7 +195,7 @@ public:
|
|||
// We'll later constant propagate
|
||||
UINFO(4," replaceconst: "<<varrefp<<endl);
|
||||
varrefp->replaceWith(constp->cloneTree(false));
|
||||
varrefp->deleteTree(); VL_DANGLING(varrefp);
|
||||
VL_DO_DANGLING(varrefp->deleteTree(), varrefp);
|
||||
++m_statep->m_statAssnCon;
|
||||
return; // **DONE, no longer a var reference**
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
// Consumption/generation of a variable,
|
||||
// it's used so can't elim assignment before this use.
|
||||
UASSERT_OBJ(nodep->varScopep(), nodep, "NULL");
|
||||
|
|
@ -307,10 +307,10 @@ private:
|
|||
m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues
|
||||
m_lifep->complexAssign(vscp);
|
||||
} else {
|
||||
m_lifep->varUsageReplace(vscp, nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(m_lifep->varUsageReplace(vscp, nodep), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
// Collect any used variables first, as lhs may also be on rhs
|
||||
// Similar code in V3Dead
|
||||
vluint64_t lastEdit = AstNode::editCountGbl(); // When it was last edited
|
||||
|
|
@ -330,13 +330,13 @@ private:
|
|||
iterateAndNextNull(nodep->lhsp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
// Don't treat as normal assign; V3Life doesn't understand time sense
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
//---- Track control flow changes
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
UINFO(4," IF "<<nodep<<endl);
|
||||
// Condition is part of PREVIOUS block
|
||||
iterateAndNextNull(nodep->condp());
|
||||
|
|
@ -358,11 +358,11 @@ private:
|
|||
// For the next assignments, clear any variables that were read or written in the block
|
||||
ifLifep->lifeToAbove();
|
||||
elseLifep->lifeToAbove();
|
||||
delete ifLifep;
|
||||
delete elseLifep;
|
||||
VL_DO_DANGLING(delete ifLifep, ifLifep);
|
||||
VL_DO_DANGLING(delete elseLifep, elseLifep);
|
||||
}
|
||||
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
// While's are a problem, as we don't allow loops in the graph. We
|
||||
// may go around the cond/body multiple times. Thus a
|
||||
// lifelication just in the body is ok, but we can't delete an
|
||||
|
|
@ -388,10 +388,10 @@ private:
|
|||
// For the next assignments, clear any variables that were read or written in the block
|
||||
condLifep->lifeToAbove();
|
||||
bodyLifep->lifeToAbove();
|
||||
delete condLifep;
|
||||
delete bodyLifep;
|
||||
VL_DO_DANGLING(delete condLifep, condLifep);
|
||||
VL_DO_DANGLING(delete bodyLifep, bodyLifep);
|
||||
}
|
||||
virtual void visit(AstJumpLabel* nodep) {
|
||||
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
|
||||
// As with While's we can't predict if a JumpGo will kill us or not
|
||||
// It's worse though as an IF(..., JUMPGO) may change the control flow.
|
||||
// Just don't optimize blocks with labels; they're rare - so far.
|
||||
|
|
@ -408,9 +408,9 @@ private:
|
|||
UINFO(4," joinjump"<<endl);
|
||||
// For the next assignments, clear any variables that were read or written in the block
|
||||
bodyLifep->lifeToAbove();
|
||||
delete bodyLifep;
|
||||
VL_DO_DANGLING(delete bodyLifep, bodyLifep);
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," CCALL "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
// Enter the function and trace it
|
||||
|
|
@ -419,8 +419,8 @@ private:
|
|||
iterate(nodep->funcp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
//UINFO(4," CCALL "<<nodep<<endl);
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," CFUNC "<<nodep<<endl);
|
||||
if (!m_tracingCall && !nodep->entryPoint()) return;
|
||||
m_tracingCall = false;
|
||||
if (nodep->dpiImport() && !nodep->pure()) {
|
||||
|
|
@ -428,17 +428,17 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) {
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCMath* nodep) {
|
||||
virtual void visit(AstCMath* nodep) VL_OVERRIDE {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstVar*) {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -453,11 +453,11 @@ public:
|
|||
{
|
||||
m_lifep = new LifeBlock(NULL, m_statep);
|
||||
iterate(nodep);
|
||||
if (m_lifep) { delete m_lifep; m_lifep = NULL; }
|
||||
if (m_lifep) VL_DO_CLEAR(delete m_lifep, m_lifep = NULL);
|
||||
}
|
||||
}
|
||||
virtual ~LifeVisitor() {
|
||||
if (m_lifep) { delete m_lifep; m_lifep = NULL; }
|
||||
if (m_lifep) VL_DO_CLEAR(delete m_lifep, m_lifep = NULL);
|
||||
}
|
||||
VL_UNCOPYABLE(LifeVisitor);
|
||||
};
|
||||
|
|
@ -472,28 +472,28 @@ private:
|
|||
LifeState* m_statep; // Current state
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (nodep->entryPoint()) {
|
||||
// Usage model 1: Simulate all C code, doing lifetime analysis
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
// Usage model 2: Cleanup basic blocks
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
// Usage model 2: Cleanup basic blocks
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) {
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
// Usage model 2: Cleanup basic blocks
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
}
|
||||
virtual void visit(AstVar*) {} // Accelerate
|
||||
virtual void visit(AstNodeStmt*) {} // Accelerate
|
||||
virtual void visit(AstNodeMath*) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -58,21 +58,21 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
if (AstVarScope* newvscp = reinterpret_cast<AstVarScope*>(vscp->user4p())) {
|
||||
UINFO(9, " Replace "<<nodep<<" to "<<newvscp<<endl);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
nodep->replaceWith(newrefp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Only track the top scopes, not lower level functions
|
||||
if (nodep->isTop()) iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->funcp()->entryPoint()) {
|
||||
// Enter the function and trace it
|
||||
|
|
@ -80,18 +80,18 @@ private:
|
|||
iterate(nodep->funcp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) {
|
||||
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
|
||||
// Can just iterate across the MTask bodies in any order. Order
|
||||
// isn't important for LifePostElimVisitor's simple substitution.
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (!m_tracingCall && !nodep->entryPoint()) return;
|
||||
m_tracingCall = false;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVar*) {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -253,13 +253,13 @@ private:
|
|||
// Delete and mark so LifePostElimVisitor will get it
|
||||
UINFO(4," DELETE "<<app->nodep<<endl);
|
||||
dlyVarp->user4p(origVarp);
|
||||
app->nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(app->nodep);
|
||||
VL_DO_DANGLING(app->nodep->unlinkFrBack()->deleteTree(), app->nodep);
|
||||
++m_statAssnDel;
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
AstNode::user4ClearTree(); // user4p() used on entire tree
|
||||
|
||||
// First, build maps of every location (mtask and sequence
|
||||
|
|
@ -284,7 +284,7 @@ private:
|
|||
// Replace any node4p varscopes with the new scope
|
||||
LifePostElimVisitor visitor (nodep);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
|
|
@ -296,14 +296,14 @@ private:
|
|||
m_reads[vscp].insert(loc);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignPre* nodep) {
|
||||
virtual void visit(AstAssignPre* nodep) VL_OVERRIDE {
|
||||
// Do not record varrefs within assign pre.
|
||||
//
|
||||
// The pre-assignment into the dly var should not count as its
|
||||
// first write; we only want to consider reads and writes that
|
||||
// would still happen if the dly var were eliminated.
|
||||
}
|
||||
virtual void visit(AstAssignPost* nodep) {
|
||||
virtual void visit(AstAssignPost* nodep) VL_OVERRIDE {
|
||||
// Don't record ASSIGNPOST in the read/write maps, record them in a
|
||||
// separate map
|
||||
if (AstVarRef* rhsp = VN_CAST(nodep->rhsp(), VarRef)) {
|
||||
|
|
@ -315,11 +315,11 @@ private:
|
|||
m_assignposts[dlyVarp] = LifePostLocation(loc, nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Only track the top scopes, not lower level functions
|
||||
if (nodep->isTop()) iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->funcp()->entryPoint()) {
|
||||
// Enter the function and trace it
|
||||
|
|
@ -327,7 +327,7 @@ private:
|
|||
iterate(nodep->funcp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) {
|
||||
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
|
||||
// Treat the ExecGraph like a call to each mtask body
|
||||
m_mtasksGraphp = nodep->depGraphp();
|
||||
for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp();
|
||||
|
|
@ -339,14 +339,14 @@ private:
|
|||
}
|
||||
m_execMTaskp = NULL;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (!m_tracingCall && !nodep->entryPoint()) return;
|
||||
m_tracingCall = false;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstVar*) {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
AstNode::user1ClearTree();
|
||||
readModNames();
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -190,45 +190,49 @@ private:
|
|||
v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' was not found in design.");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Module: Pick up modnames, so we can resolve cells later
|
||||
m_modp = nodep;
|
||||
UINFO(2,"Link Module: "<<nodep<<endl);
|
||||
if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName()
|
||||
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename())
|
||||
&& !nodep->recursiveClone()
|
||||
&& !nodep->internal()) {
|
||||
// We only complain once per file, otherwise library-like files
|
||||
// have a huge mess of warnings
|
||||
if (m_declfnWarned.find(nodep->fileline()->filename()) == m_declfnWarned.end()) {
|
||||
m_declfnWarned.insert(nodep->fileline()->filename());
|
||||
nodep->v3warn(DECLFILENAME, "Filename '"<<nodep->fileline()->filebasenameNoExt()
|
||||
<<"' does not match "<<nodep->typeName()
|
||||
<<" name: "<<nodep->prettyNameQ());
|
||||
AstNodeModule* oldModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
UINFO(2, "Link Module: " << nodep << endl);
|
||||
if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName()
|
||||
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename())
|
||||
&& !nodep->recursiveClone() && !nodep->internal()) {
|
||||
// We only complain once per file, otherwise library-like files
|
||||
// have a huge mess of warnings
|
||||
if (m_declfnWarned.find(nodep->fileline()->filename()) == m_declfnWarned.end()) {
|
||||
m_declfnWarned.insert(nodep->fileline()->filename());
|
||||
nodep->v3warn(DECLFILENAME, "Filename '"
|
||||
<< nodep->fileline()->filebasenameNoExt()
|
||||
<< "' does not match " << nodep->typeName()
|
||||
<< " name: " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) {
|
||||
nodep->inLibrary(true); // Interfaces can't be at top, unless asked
|
||||
}
|
||||
bool topMatch = (v3Global.opt.topModule() == nodep->prettyName());
|
||||
if (topMatch) {
|
||||
m_topVertexp = vertex(nodep);
|
||||
UINFO(2, "Link --top-module: " << nodep << endl);
|
||||
nodep->inLibrary(false); // Safer to make sure it doesn't disappear
|
||||
}
|
||||
if (v3Global.opt.topModule() == "" ? nodep->inLibrary() // Library cells are lower
|
||||
: !topMatch) { // Any non-specified module is lower
|
||||
// Put under a fake vertex so that the graph ranking won't indicate
|
||||
// this is a top level module
|
||||
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
|
||||
new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false);
|
||||
}
|
||||
// Note AstBind also has iteration on cells
|
||||
iterateChildren(nodep);
|
||||
nodep->checkTree();
|
||||
}
|
||||
if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) nodep->inLibrary(true); // Interfaces can't be at top, unless asked
|
||||
bool topMatch = (v3Global.opt.topModule()==nodep->prettyName());
|
||||
if (topMatch) {
|
||||
m_topVertexp = vertex(nodep);
|
||||
UINFO(2,"Link --top-module: "<<nodep<<endl);
|
||||
nodep->inLibrary(false); // Safer to make sure it doesn't disappear
|
||||
}
|
||||
if (v3Global.opt.topModule()==""
|
||||
? nodep->inLibrary() // Library cells are lower
|
||||
: !topMatch) { // Any non-specified module is lower
|
||||
// Put under a fake vertex so that the graph ranking won't indicate
|
||||
// this is a top level module
|
||||
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
|
||||
new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false);
|
||||
}
|
||||
// Note AstBind also has iteration on cells
|
||||
iterateChildren(nodep);
|
||||
nodep->checkTree();
|
||||
m_modp = NULL;
|
||||
m_modp = oldModp;
|
||||
}
|
||||
|
||||
virtual void visit(AstIfaceRefDType* nodep) {
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
// Cell: Resolve its filename. If necessary, parse it.
|
||||
UINFO(4,"Link IfaceRef: "<<nodep<<endl);
|
||||
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
|
||||
|
|
@ -247,14 +251,14 @@ private:
|
|||
// Note cannot do modport resolution here; modports are allowed underneath generates
|
||||
}
|
||||
|
||||
virtual void visit(AstPackageImport* nodep) {
|
||||
virtual void visit(AstPackageImport* nodep) VL_OVERRIDE {
|
||||
// Package Import: We need to do the package before the use of a package
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->packagep(), nodep, "Unlinked package"); // Parser should set packagep
|
||||
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(nodep->packagep()), 1, false);
|
||||
}
|
||||
|
||||
virtual void visit(AstBind* nodep) {
|
||||
virtual void visit(AstBind* nodep) VL_OVERRIDE {
|
||||
// Bind: Has cells underneath that need to be put into the new
|
||||
// module, and cells which need resolution
|
||||
// TODO this doesn't allow bind to dotted hier names, that would require
|
||||
|
|
@ -276,7 +280,7 @@ private:
|
|||
pushDeletep(nodep->unlinkFrBack());
|
||||
}
|
||||
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
// Cell: Resolve its filename. If necessary, parse it.
|
||||
// Execute only once. Complication is that cloning may result in
|
||||
// user1 being set (for pre-clone) so check if user1() matches the
|
||||
|
|
@ -354,7 +358,7 @@ private:
|
|||
if (pinStar) pinp->v3error("Duplicate .* in a cell");
|
||||
pinStar = true;
|
||||
// Done with this fake pin
|
||||
pinp->unlinkFrBack()->deleteTree(); VL_DANGLING(pinp);
|
||||
VL_DO_DANGLING(pinp->unlinkFrBack()->deleteTree(), pinp);
|
||||
}
|
||||
}
|
||||
// Convert unnamed pins to pin number based assignments
|
||||
|
|
@ -381,9 +385,7 @@ private:
|
|||
<<pinp->prettyNameQ());
|
||||
}
|
||||
}
|
||||
if (ports.find(pinp->name()) == ports.end()) {
|
||||
ports.insert(pinp->name());
|
||||
}
|
||||
ports.insert(pinp->name());
|
||||
}
|
||||
// We search ports, rather than in/out declarations as they aren't resolved yet,
|
||||
// and it's easier to do it now than in V3LinkDot when we'd need to repeat steps.
|
||||
|
|
@ -448,8 +450,8 @@ private:
|
|||
|
||||
// Accelerate the recursion
|
||||
// Must do statements to support Generates, math though...
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -470,7 +472,7 @@ private:
|
|||
<<foundp->warnContextSecondary());
|
||||
}
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (!foundp) {
|
||||
m_mods.rootp()->insert(nodep->name(), new VSymEnt(&m_mods, nodep));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ public:
|
|||
VSymEnt* getScopeSym(AstScope* nodep) {
|
||||
NameScopeSymMap::iterator it = m_nameScopeSymMap.find(nodep->name());
|
||||
UASSERT_OBJ(it != m_nameScopeSymMap.end(), nodep,
|
||||
"Scope never assigned a symbol entry?");
|
||||
"Scope never assigned a symbol entry '" << nodep->name() << "'");
|
||||
return it->second;
|
||||
}
|
||||
void implicitOkAdd(AstNodeModule* nodep, const string& varname) {
|
||||
|
|
@ -726,7 +726,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Process $unit or other packages
|
||||
// Not needed - dotted references not allowed from inside packages
|
||||
//for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
|
||||
|
|
@ -758,8 +758,8 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
m_curSymp = m_modSymp = NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTypeTable* nodep) {}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstTypeTable* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Called on top module from Netlist, other modules from the cell creating them,
|
||||
// and packages
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
|
|
@ -821,12 +821,12 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
// Prep for next
|
||||
m_packagep = NULL;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UASSERT_OBJ(m_statep->forScopeCreation(), nodep,
|
||||
"Scopes should only exist right after V3Scope");
|
||||
// Ignored. Processed in next step
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(5," CELL under "<<m_scope<<" is "<<nodep<<endl);
|
||||
// Process XREFs/etc inside pins
|
||||
if (nodep->recursive() && m_inRecursion) return;
|
||||
|
|
@ -867,7 +867,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
m_paramNum = oldParamNum;
|
||||
m_inRecursion = oldRecursion;
|
||||
}
|
||||
virtual void visit(AstCellInline* nodep) {
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
|
||||
UINFO(5," CELLINLINE under "<<m_scope<<" is "<<nodep<<endl);
|
||||
VSymEnt* aboveSymp = m_curSymp;
|
||||
// If baz__DOT__foo__DOT__bar, we need to find baz__DOT__foo and add bar to it.
|
||||
|
|
@ -887,11 +887,11 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
m_statep->insertInline(aboveSymp, m_modSymp, nodep, nodep->name());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstDefParam* nodep) {
|
||||
virtual void visit(AstDefParam* nodep) VL_OVERRIDE {
|
||||
nodep->user1p(m_curSymp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstGenerate* nodep) {
|
||||
virtual void visit(AstGenerate* nodep) VL_OVERRIDE {
|
||||
// Begin: ... blocks often replicate under genif/genfor, so simply
|
||||
// suppress duplicate checks. See t_gen_forif.v for an example.
|
||||
bool lastInGen = m_inGenerate;
|
||||
|
|
@ -901,7 +901,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
}
|
||||
m_inGenerate = lastInGen;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
// Rename "genblk"s to include a number
|
||||
if (m_statep->forPrimary() && !nodep->user4SetOnce()) {
|
||||
|
|
@ -943,7 +943,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
m_beginp = oldbegin;
|
||||
m_beginNum = oldNum;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
// NodeTask: Remember its name for later resolution
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Function/Task not under module?");
|
||||
|
|
@ -979,13 +979,13 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
}
|
||||
m_curSymp = oldCurSymp;
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
// Var: Remember its name for later resolution
|
||||
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?");
|
||||
iterateChildren(nodep);
|
||||
if (m_ftaskp && nodep->isParam()) {
|
||||
nodep->v3error("Unsupported: Parameters in functions."); // Big3 unsupported too
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
|
|
@ -1020,7 +1020,8 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
nodep->v3error("Duplicate declaration of signal: "
|
||||
<<nodep->prettyNameQ()<<endl
|
||||
<<(ansiWarn
|
||||
? nodep->warnMore()+"... note: ANSI ports must have type declared with the I/O (IEEE 2017 23.2.2.2)\n"
|
||||
? nodep->warnMore() + "... note: ANSI ports must have"
|
||||
" type declared with the I/O (IEEE 1800-2017 23.2.2.2)\n"
|
||||
: "")
|
||||
<<nodep->warnContextPrimary()<<endl
|
||||
<<findvarp->warnOther()<<"... Location of original declaration"<<endl
|
||||
|
|
@ -1038,12 +1039,12 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
AstNodeDType* newdtypep = nodep->subDTypep();
|
||||
UASSERT_OBJ(newdtypep && nodep->childDTypep(), findvarp,
|
||||
"No child type?");
|
||||
bdtypep->unlinkFrBack()->deleteTree();
|
||||
VL_DO_DANGLING(bdtypep->unlinkFrBack()->deleteTree(), bdtypep);
|
||||
newdtypep->unlinkFrBack();
|
||||
findvarp->childDTypep(newdtypep);
|
||||
}
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else {
|
||||
// User can disable the message at either point
|
||||
if (!(m_ftaskp && m_ftaskp->dpiImport())
|
||||
|
|
@ -1075,7 +1076,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
newp->valuep(valuep);
|
||||
UINFO(9," replace parameter "<<nodep<<endl);
|
||||
UINFO(9," with "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep = newp;
|
||||
}
|
||||
}
|
||||
|
|
@ -1097,22 +1098,21 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
// Remember its name for later resolution
|
||||
UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module?");
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit");
|
||||
iterateChildren(nodep);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
|
||||
}
|
||||
virtual void visit(AstParamTypeDType* nodep) {
|
||||
UASSERT_OBJ(m_curSymp, nodep, "Parameter type not under module?");
|
||||
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
|
||||
UASSERT_OBJ(m_curSymp, nodep, "Parameter type not under module/package/$unit");
|
||||
iterateChildren(nodep);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
// For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist
|
||||
UASSERT_OBJ(!m_statep->forScopeCreation(), nodep, "No CFuncs expected in tree yet");
|
||||
}
|
||||
virtual void visit(AstEnumItem* nodep) {
|
||||
virtual void visit(AstEnumItem* nodep) VL_OVERRIDE {
|
||||
// EnumItem: Remember its name for later resolution
|
||||
iterateChildren(nodep);
|
||||
// Find under either a task or the module's vars
|
||||
|
|
@ -1150,7 +1150,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPackageImport* nodep) {
|
||||
virtual void visit(AstPackageImport* nodep) VL_OVERRIDE {
|
||||
UINFO(4," Link: "<<nodep<<endl);
|
||||
VSymEnt* srcp = m_statep->getNodeSym(nodep->packagep());
|
||||
if (nodep->name()=="*") {
|
||||
|
|
@ -1168,7 +1168,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
UINFO(9," Link Done: "<<nodep<<endl);
|
||||
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
||||
}
|
||||
virtual void visit(AstPackageExport* nodep) {
|
||||
virtual void visit(AstPackageExport* nodep) VL_OVERRIDE {
|
||||
UINFO(9," Link: "<<nodep<<endl);
|
||||
VSymEnt* srcp = m_statep->getNodeSym(nodep->packagep());
|
||||
if (nodep->name()!="*") {
|
||||
|
|
@ -1182,13 +1182,13 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
UINFO(9," Link Done: "<<nodep<<endl);
|
||||
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
||||
}
|
||||
virtual void visit(AstPackageExportStarStar* nodep) {
|
||||
virtual void visit(AstPackageExportStarStar* nodep) VL_OVERRIDE {
|
||||
UINFO(4," Link: "<<nodep<<endl);
|
||||
m_curSymp->exportStarStar(m_statep->symsp());
|
||||
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -1253,8 +1253,8 @@ private:
|
|||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstTypeTable* nodep) {}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstTypeTable* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
if (nodep->dead() || !nodep->user4()) {
|
||||
UINFO(4,"Mark dead module "<<nodep<<endl);
|
||||
|
|
@ -1271,7 +1271,7 @@ private:
|
|||
m_modp = NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
// Pin: Link to submodule's port
|
||||
// Deal with implicit definitions - do before Resolve visitor as may
|
||||
// be referenced above declaration
|
||||
|
|
@ -1280,7 +1280,7 @@ private:
|
|||
pinImplicitExprRecurse(nodep->exprp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstDefParam* nodep) {
|
||||
virtual void visit(AstDefParam* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->v3warn(DEFPARAM, "Suggest replace defparam assignment with Verilog 2001 #(."
|
||||
<<nodep->prettyName()<<"(...etc...))");
|
||||
|
|
@ -1299,10 +1299,10 @@ private:
|
|||
nodep->name(),
|
||||
exprp);
|
||||
cellp->addParamsp(pinp);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPort* nodep) {
|
||||
virtual void visit(AstPort* nodep) VL_OVERRIDE {
|
||||
// Port: Stash the pin number
|
||||
// Need to set pin numbers after varnames are created
|
||||
// But before we do the final resolution based on names
|
||||
|
|
@ -1327,16 +1327,16 @@ private:
|
|||
symp->exported(false);
|
||||
}
|
||||
// Ports not needed any more
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
// Deal with implicit definitions
|
||||
// We used to nodep->allowImplicit() here, but it turns out
|
||||
// normal "assigns" can also make implicit wires. Yuk.
|
||||
pinImplicitExprRecurse(nodep->lhsp());
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
// tran gates need implicit creation
|
||||
// As VarRefs don't exist in forPrimary, sanity check
|
||||
UASSERT_OBJ(!m_statep->forPrimary(), nodep, "Assign aliases unexpected pre-dot");
|
||||
|
|
@ -1348,13 +1348,13 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstImplicit* nodep) {
|
||||
virtual void visit(AstImplicit* nodep) VL_OVERRIDE {
|
||||
// Unsupported gates need implicit creation
|
||||
pinImplicitExprRecurse(nodep);
|
||||
// We're done with implicit gates
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -1384,11 +1384,11 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
|||
int debug() { return LinkDotState::debug(); }
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Recurse..., backward as must do packages before using packages
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(8," SCOPE "<<nodep<<endl);
|
||||
UASSERT_OBJ(m_statep->forScopeCreation(), nodep,
|
||||
"Scopes should only exist right after V3Scope");
|
||||
|
|
@ -1400,7 +1400,7 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
|||
m_modSymp = NULL;
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
if (!nodep->varp()->isFuncLocal()) {
|
||||
VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
|
||||
if (nodep->varp()->isIfaceRef()
|
||||
|
|
@ -1434,12 +1434,12 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
VSymEnt* symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, NULL);
|
||||
symp->fallbackp(m_modSymp);
|
||||
// No recursion, we don't want to pick up variables
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
|
||||
// we'll need to replace it with a VARXREF(aliased_to)
|
||||
if (debug()>=9) nodep->dumpTree(cout, "- alias: ");
|
||||
|
|
@ -1449,7 +1449,7 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
|||
fromVscp->user2p(toVscp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignVarScope* nodep) {
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
|
||||
UINFO(5,"ASSIGNVARSCOPE "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout, "- avs: ");
|
||||
VSymEnt* rhsSymp;
|
||||
|
|
@ -1497,14 +1497,14 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
|||
// or maybe an alias of an alias
|
||||
m_statep->insertScopeAlias(LinkDotState::SAMN_IFTOP, lhsSymp, rhsSymp);
|
||||
// We have stored the link, we don't need these any more
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
// For speed, don't recurse things that can't have scope
|
||||
// Note we allow AstNodeStmt's as generates may be under them
|
||||
virtual void visit(AstCell*) {}
|
||||
virtual void visit(AstVar*) {}
|
||||
virtual void visit(AstNodeMath*) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstCell*) VL_OVERRIDE {}
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -1534,7 +1534,7 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
|||
int debug() { return LinkDotState::debug(); }
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstModport* nodep) {
|
||||
virtual void visit(AstModport* nodep) VL_OVERRIDE {
|
||||
// Modport: Remember its name for later resolution
|
||||
UINFO(5," fiv: "<<nodep<<endl);
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
|
|
@ -1546,7 +1546,7 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
|||
}
|
||||
m_curSymp = oldCurSymp;
|
||||
}
|
||||
virtual void visit(AstModportFTaskRef* nodep) {
|
||||
virtual void visit(AstModportFTaskRef* nodep) VL_OVERRIDE {
|
||||
UINFO(5," fif: "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isExport()) nodep->v3error("Unsupported: modport export");
|
||||
|
|
@ -1565,10 +1565,10 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
|||
if (m_statep->forScopeCreation()) {
|
||||
// Done with AstModportFTaskRef.
|
||||
// Delete to prevent problems if we dead-delete pointed to ftask
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstModportVarRef* nodep) {
|
||||
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
|
||||
UINFO(5," fiv: "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
|
||||
|
|
@ -1589,10 +1589,10 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
|||
if (m_statep->forScopeCreation()) {
|
||||
// Done with AstModportVarRef.
|
||||
// Delete to prevent problems if we dead-delete pointed to variable
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -1769,12 +1769,12 @@ private:
|
|||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Recurse..., backward as must do packages before using packages
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstTypeTable* nodep) {}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstTypeTable* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
if (nodep->dead()) return;
|
||||
checkNoDot(nodep);
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
|
|
@ -1787,7 +1787,7 @@ private:
|
|||
m_modp = NULL;
|
||||
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
VSymEnt* oldModSymp = m_modSymp;
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
|
|
@ -1798,13 +1798,13 @@ private:
|
|||
m_modSymp = oldModSymp;
|
||||
m_curSymp = oldCurSymp;
|
||||
}
|
||||
virtual void visit(AstCellInline* nodep) {
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
|
||||
checkNoDot(nodep);
|
||||
if (m_statep->forScopeCreation() && !v3Global.opt.vpi()) {
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
// Cell: Recurse inside or cleanup not founds
|
||||
checkNoDot(nodep);
|
||||
m_cellp = nodep;
|
||||
|
|
@ -1833,7 +1833,7 @@ private:
|
|||
// Parent module inherits child's publicity
|
||||
// This is done bottom up in the LinkBotupVisitor stage
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
// Pin: Link to submodule's port
|
||||
checkNoDot(nodep);
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -1844,7 +1844,7 @@ private:
|
|||
if (!foundp) {
|
||||
if (nodep->name() == "__paramNumber1" && VN_IS(m_cellp->modp(), Primitive)) {
|
||||
// Primitive parameter is really a delay we can just ignore
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
string suggest
|
||||
|
|
@ -1875,7 +1875,7 @@ private:
|
|||
}
|
||||
// Early return() above when deleted
|
||||
}
|
||||
virtual void visit(AstDot* nodep) {
|
||||
virtual void visit(AstDot* nodep) VL_OVERRIDE {
|
||||
// Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel
|
||||
// also a DOT can be part of an expression, but only above plus
|
||||
// AstFTaskRef are legal children
|
||||
|
|
@ -1923,7 +1923,7 @@ private:
|
|||
}
|
||||
if (debug()>=9) newp->dumpTree("-dot-out: ");
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // Dot midpoint
|
||||
AstNode* newp = nodep->rhsp()->unlinkFrBack();
|
||||
if (m_ds.m_unresolved) {
|
||||
|
|
@ -1932,7 +1932,7 @@ private:
|
|||
newp = crp;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
if (start) {
|
||||
|
|
@ -1941,7 +1941,7 @@ private:
|
|||
m_ds.m_dotp = lastStates.m_dotp;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstParseRef* nodep) {
|
||||
virtual void visit(AstParseRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->user3SetOnce()) return;
|
||||
UINFO(9," linkPARSEREF "<<m_ds.ascii()<<" n="<<nodep<<endl);
|
||||
// m_curSymp is symbol table of outer expression
|
||||
|
|
@ -1963,7 +1963,7 @@ private:
|
|||
VFlagChildDType(), nodep->name());
|
||||
if (m_ds.m_dotErr) nodep->unlinkFrBack(); // Avoid circular node loop on errors
|
||||
else nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else {
|
||||
//
|
||||
|
|
@ -2042,7 +2042,7 @@ private:
|
|||
UINFO(9," cell -> iface varref "<<foundp->nodep()<<endl);
|
||||
AstNode* newp = new AstVarRef(ifaceRefVarp->fileline(),
|
||||
ifaceRefVarp, false);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(cellp->modp(), NotFoundModule)) {
|
||||
cellp->modNameFileline()->v3error("Cannot find file containing interface: "
|
||||
<<cellp->modp()->prettyNameQ());
|
||||
|
|
@ -2060,7 +2060,7 @@ private:
|
|||
m_ds.m_dotPos = DP_SCOPE;
|
||||
ok = true;
|
||||
AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (allowVar) {
|
||||
AstNode* newp;
|
||||
|
|
@ -2070,11 +2070,21 @@ private:
|
|||
refp->varp(varp);
|
||||
m_ds.m_dotText = "";
|
||||
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
|
||||
newp = new AstUnlinkedRef(nodep->fileline(), VN_CAST(refp, VarXRef),
|
||||
refp->name(),
|
||||
m_ds.m_unlinkedScope->unlinkFrBack());
|
||||
m_ds.m_unlinkedScope = NULL;
|
||||
m_ds.m_unresolved = false;
|
||||
string dotted = refp->dotted();
|
||||
size_t pos = dotted.find("__BRA__??__KET__");
|
||||
// Arrays of interfaces all have the same parameters
|
||||
if (pos != string::npos && varp->isParam()
|
||||
&& VN_IS(m_ds.m_unlinkedScope, CellArrayRef)) {
|
||||
refp->dotted(dotted.substr(0, pos));
|
||||
newp = refp;
|
||||
} else {
|
||||
newp = new AstUnlinkedRef(nodep->fileline(),
|
||||
VN_CAST(refp, VarXRef),
|
||||
refp->name(),
|
||||
m_ds.m_unlinkedScope->unlinkFrBack());
|
||||
m_ds.m_unlinkedScope = NULL;
|
||||
m_ds.m_unresolved = false;
|
||||
}
|
||||
} else {
|
||||
newp = refp;
|
||||
}
|
||||
|
|
@ -2084,7 +2094,7 @@ private:
|
|||
newp = refp;
|
||||
}
|
||||
UINFO(9," new "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
m_ds.m_dotPos = DP_MEMBER;
|
||||
ok = true;
|
||||
}
|
||||
|
|
@ -2117,14 +2127,14 @@ private:
|
|||
AstVar* varp = makeIfaceModportVar(nodep->fileline(),
|
||||
cellp, ifacep, modportp);
|
||||
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
|
||||
nodep->replaceWith(refp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(refp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) {
|
||||
if (allowVar) {
|
||||
AstNode* newp = new AstEnumItemRef(nodep->fileline(),
|
||||
valuep, foundp->packagep());
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
ok = true;
|
||||
m_ds.m_dotText = "";
|
||||
}
|
||||
|
|
@ -2166,7 +2176,7 @@ private:
|
|||
// Create if implicit, and also if error (so only complain once)
|
||||
AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err);
|
||||
}
|
||||
}
|
||||
|
|
@ -2175,7 +2185,7 @@ private:
|
|||
m_ds = lastStates;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
// VarRef: Resolve its reference
|
||||
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
|
||||
// errors here now that we have a VarRef.
|
||||
|
|
@ -2194,7 +2204,7 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
// VarRef: Resolve its reference
|
||||
// We always link even if varp() is set, because the module we choose may change
|
||||
// due to creating new modules, flattening, etc.
|
||||
|
|
@ -2237,11 +2247,10 @@ private:
|
|||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(),
|
||||
nodep->varp(), nodep->lvalue());
|
||||
nodep->replaceWith(newrefp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
string baddot;
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
AstVarScope* vscp = foundp ? VN_CAST(foundp->nodep(), VarScope) : NULL;
|
||||
if (!vscp) {
|
||||
|
|
@ -2262,17 +2271,17 @@ private:
|
|||
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
|
||||
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
|
||||
nodep->replaceWith(newvscp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
UINFO(9," new "<<newvscp<<endl); // Also prints taskp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) {
|
||||
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
|
||||
// EnumItemRef may be under a dot. Should already be resolved.
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstMethodCall* nodep) {
|
||||
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
|
||||
// Created here so should already be resolved.
|
||||
DotStates lastStates = m_ds;
|
||||
{
|
||||
|
|
@ -2281,7 +2290,7 @@ private:
|
|||
}
|
||||
m_ds = lastStates;
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
checkNoDot(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) {
|
||||
|
|
@ -2289,7 +2298,7 @@ private:
|
|||
<<nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->user3SetOnce()) return;
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
|
||||
|
|
@ -2323,7 +2332,7 @@ private:
|
|||
AstNode* newp = new AstMethodCall(nodep->fileline(), varEtcp,
|
||||
VFlagChildDType(), nodep->name(), argsp);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
} else {
|
||||
checkNoDot(nodep);
|
||||
|
|
@ -2403,7 +2412,7 @@ private:
|
|||
}
|
||||
m_ds = lastStates;
|
||||
}
|
||||
virtual void visit(AstSelBit* nodep) {
|
||||
virtual void visit(AstSelBit* nodep) VL_OVERRIDE {
|
||||
if (nodep->user3SetOnce()) return;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
|
|
@ -2425,10 +2434,10 @@ private:
|
|||
AstNode* exprp = nodep->bitp()->unlinkFrBack();
|
||||
AstCellArrayRef* newp
|
||||
= new AstCellArrayRef(nodep->fileline(), nodep->fromp()->name(), exprp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep) {
|
||||
virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE {
|
||||
// Excludes simple AstSelBit, see above
|
||||
if (nodep->user3SetOnce()) return;
|
||||
if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
|
|
@ -2446,11 +2455,11 @@ private:
|
|||
}
|
||||
m_ds = lastStates;
|
||||
}
|
||||
virtual void visit(AstMemberSel* nodep) {
|
||||
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
|
||||
// checkNoDot not appropriate, can be under a dot
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
checkNoDot(nodep);
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
|
|
@ -2462,7 +2471,7 @@ private:
|
|||
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
||||
UINFO(5," cur=se"<<cvtToHex(m_curSymp)<<endl);
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
checkNoDot(nodep);
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
|
|
@ -2474,7 +2483,7 @@ private:
|
|||
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
||||
m_ftaskp = NULL;
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep) {
|
||||
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
|
||||
// Resolve its reference
|
||||
if (nodep->user3SetOnce()) return;
|
||||
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
|
||||
|
|
@ -2488,7 +2497,8 @@ private:
|
|||
} else {
|
||||
checkNoDot(nodep);
|
||||
}
|
||||
if (!nodep->defp()) {
|
||||
if (nodep->typeofp()) { // Really is a typeof not a reference
|
||||
} else if (!nodep->defp()) {
|
||||
VSymEnt* foundp;
|
||||
if (nodep->packagep()) {
|
||||
foundp = m_statep->getNodeSym(nodep->packagep())->findIdFlat(nodep->name());
|
||||
|
|
@ -2510,7 +2520,7 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstDpiExport* nodep) {
|
||||
virtual void visit(AstDpiExport* nodep) VL_OVERRIDE {
|
||||
// AstDpiExport: Make sure the function referenced exists, then dump it
|
||||
iterateChildren(nodep);
|
||||
checkNoDot(nodep);
|
||||
|
|
@ -2525,37 +2535,37 @@ private:
|
|||
taskp->dpiExport(true);
|
||||
if (nodep->cname()!="") taskp->cname(nodep->cname());
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstPackageImport* nodep) {
|
||||
virtual void visit(AstPackageImport* nodep) VL_OVERRIDE {
|
||||
// No longer needed
|
||||
checkNoDot(nodep);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstPackageExport* nodep) {
|
||||
virtual void visit(AstPackageExport* nodep) VL_OVERRIDE {
|
||||
// No longer needed
|
||||
checkNoDot(nodep);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstPackageExportStarStar* nodep) {
|
||||
virtual void visit(AstPackageExportStarStar* nodep) VL_OVERRIDE {
|
||||
// No longer needed
|
||||
checkNoDot(nodep);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCellRef* nodep) {
|
||||
virtual void visit(AstCellRef* nodep) VL_OVERRIDE {
|
||||
UINFO(5," AstCellRef: "<<nodep<<" "<<m_ds.ascii()<<endl);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCellArrayRef* nodep) {
|
||||
virtual void visit(AstCellArrayRef* nodep) VL_OVERRIDE {
|
||||
UINFO(5," AstCellArrayRef: "<<nodep<<" "<<m_ds.ascii()<<endl);
|
||||
// Expression already iterated
|
||||
}
|
||||
virtual void visit(AstUnlinkedRef* nodep) {
|
||||
virtual void visit(AstUnlinkedRef* nodep) VL_OVERRIDE {
|
||||
UINFO(5," AstCellArrayRef: "<<nodep<<" "<<m_ds.ascii()<<endl);
|
||||
// No need to iterate, if we have a UnlinkedVarXRef, we're already done
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
checkNoDot(nodep);
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ private:
|
|||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
AstWhile* m_loopp; // Current loop
|
||||
bool m_loopInc; // In loop increment
|
||||
int m_repeatNum; // Repeat counter
|
||||
int m_modRepeatNum; // Repeat counter
|
||||
BeginStack m_beginStack; // All begin blocks above current node
|
||||
|
||||
// METHODS
|
||||
|
|
@ -107,30 +107,35 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
if (nodep->dead()) return;
|
||||
m_modp = nodep;
|
||||
m_repeatNum = 0;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
int origRepeatNum = m_modRepeatNum;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modRepeatNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_modRepeatNum = origRepeatNum;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_ftaskp = NULL;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
m_beginStack.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
m_beginStack.pop_back();
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep) {
|
||||
virtual void visit(AstRepeat* nodep) VL_OVERRIDE {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||
string name = string("__Vrepeat")+cvtToStr(m_modRepeatNum++);
|
||||
// Spec says value is integral, if negative is ignored
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
nodep->findSigned32DType());
|
||||
|
|
@ -156,9 +161,9 @@ private:
|
|||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
// Don't need to track AstRepeat/AstFor as they have already been converted
|
||||
AstWhile* lastLoopp = m_loopp;
|
||||
bool lastInc = m_loopInc;
|
||||
|
|
@ -172,7 +177,7 @@ private:
|
|||
m_loopInc = lastInc;
|
||||
m_loopp = lastLoopp;
|
||||
}
|
||||
virtual void visit(AstReturn* nodep) {
|
||||
virtual void visit(AstReturn* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
AstFunc* funcp = VN_CAST(m_ftaskp, Func);
|
||||
if (!m_ftaskp) {
|
||||
|
|
@ -193,9 +198,9 @@ private:
|
|||
AstJumpLabel* labelp = findAddLabel(m_ftaskp, false);
|
||||
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstBreak* nodep) {
|
||||
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); }
|
||||
else {
|
||||
|
|
@ -203,9 +208,9 @@ private:
|
|||
AstJumpLabel* labelp = findAddLabel(m_loopp, false);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstContinue* nodep) {
|
||||
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); }
|
||||
else {
|
||||
|
|
@ -214,9 +219,9 @@ private:
|
|||
AstJumpLabel* labelp = findAddLabel(m_loopp, true);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstDisable* nodep) {
|
||||
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
|
||||
UINFO(8," DISABLE "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
AstBegin* beginp = NULL;
|
||||
|
|
@ -236,15 +241,15 @@ private:
|
|||
AstJumpLabel* labelp = findAddLabel(beginp, false);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labelo: "); }
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true);
|
||||
}
|
||||
|
||||
virtual void visit(AstConst* nodep) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -254,7 +259,7 @@ public:
|
|||
m_ftaskp = NULL;
|
||||
m_loopp = NULL;
|
||||
m_loopInc = false;
|
||||
m_repeatNum = 0;
|
||||
m_modRepeatNum = 0;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~LinkJumpVisitor() {}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ private:
|
|||
|
||||
// VISITs
|
||||
// Result handing
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
// VarRef: LValue its reference
|
||||
if (m_setRefLvalue) {
|
||||
nodep->lvalue(true);
|
||||
|
|
@ -66,7 +66,7 @@ private:
|
|||
}
|
||||
|
||||
// Nodes that start propagating down lvalues
|
||||
virtual void visit(AstPin* nodep) {
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
if (nodep->modVarp() && nodep->modVarp()->isWritable()) {
|
||||
// When the varref's were created, we didn't know the I/O state
|
||||
// Now that we do, and it's from a output, we know it's a lvalue
|
||||
|
|
@ -77,7 +77,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -87,7 +87,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFOpen* nodep) {
|
||||
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -98,7 +98,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFClose* nodep) {
|
||||
virtual void visit(AstFClose* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -106,7 +106,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFFlush* nodep) {
|
||||
virtual void visit(AstFFlush* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -114,7 +114,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFGetC* nodep) {
|
||||
virtual void visit(AstFGetC* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -122,7 +122,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFGetS* nodep) {
|
||||
virtual void visit(AstFGetS* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -131,7 +131,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) {
|
||||
virtual void visit(AstFRead* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -140,7 +140,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) {
|
||||
virtual void visit(AstFScanF* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -149,7 +149,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFUngetC* nodep) {
|
||||
virtual void visit(AstFUngetC* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -157,7 +157,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstSScanF* nodep) {
|
||||
virtual void visit(AstSScanF* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -165,13 +165,13 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstSysIgnore* nodep) {
|
||||
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
|
||||
// Can't know if lvalue or not; presume so as stricter
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
iterateChildren(nodep);
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep) {
|
||||
virtual void visit(AstReadMem* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -183,7 +183,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
virtual void visit(AstValuePlusArgs* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = false;
|
||||
|
|
@ -193,7 +193,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep) {
|
||||
virtual void visit(AstSFormat* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
|
|
@ -205,7 +205,7 @@ private:
|
|||
}
|
||||
|
||||
// Nodes that change LValue state
|
||||
virtual void visit(AstSel* nodep) {
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
|
|
@ -216,7 +216,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstNodeSel* nodep) {
|
||||
virtual void visit(AstNodeSel* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{ // Only set lvalues on the from
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
|
|
@ -225,7 +225,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstCellArrayRef* nodep) {
|
||||
virtual void visit(AstCellArrayRef* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{ // selp is not an lvalue
|
||||
m_setRefLvalue = false;
|
||||
|
|
@ -233,7 +233,7 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep) {
|
||||
virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{ // Only set lvalues on the from
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
|
|
@ -243,12 +243,12 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_ftaskp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
AstNode* pinp = nodep->pinsp();
|
||||
AstNodeFTask* taskp = nodep->taskp();
|
||||
// We'll deal with mismatching pins later
|
||||
|
|
@ -270,7 +270,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "V3Global.h"
|
||||
#include "V3LinkParse.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Config.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
|
|
@ -105,7 +106,9 @@ private:
|
|||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
V3Config::applyFTask(m_modp, nodep);
|
||||
|
||||
if (!nodep->user1SetOnce()) { // Process only once.
|
||||
cleanFileline(nodep);
|
||||
m_ftaskp = nodep;
|
||||
|
|
@ -113,7 +116,7 @@ private:
|
|||
m_ftaskp = NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1SetOnce()) { // Process only once.
|
||||
cleanFileline(nodep);
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
|
|
@ -123,22 +126,22 @@ private:
|
|||
m_valueModp = upperValueModp;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) {
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstEnumDType* nodep) {
|
||||
virtual void visit(AstEnumDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->name() == "") {
|
||||
nodep->name(nameFromTypedef(nodep)); // Might still remain ""
|
||||
}
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) {
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->name() == "") {
|
||||
nodep->name(nameFromTypedef(nodep)); // Might still remain ""
|
||||
}
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstEnumItem* nodep) {
|
||||
virtual void visit(AstEnumItem* nodep) VL_OVERRIDE {
|
||||
// Expand ranges
|
||||
cleanFileline(nodep);
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -166,11 +169,11 @@ private:
|
|||
else addp = newp;
|
||||
}
|
||||
nodep->replaceWith(addp);
|
||||
nodep->deleteTree();
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
cleanFileline(nodep);
|
||||
if (VN_IS(nodep->subDTypep(), ParseTypeDType)) {
|
||||
// It's a parameter type. Use a different node type for this.
|
||||
|
|
@ -184,11 +187,14 @@ private:
|
|||
AstNode* newp = new AstParamTypeDType(nodep->fileline(),
|
||||
nodep->varType(), nodep->name(),
|
||||
VFlagChildDType(), dtypep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Maybe this variable has a signal attribute
|
||||
V3Config::applyVarAttr(m_modp, m_ftaskp, nodep);
|
||||
|
||||
if (v3Global.opt.publicFlatRW()) {
|
||||
switch (nodep->varType()) {
|
||||
case AstVarType::VAR:
|
||||
|
|
@ -249,74 +255,74 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAttrOf* nodep) {
|
||||
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
|
||||
cleanFileline(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (nodep->attrType() == AstAttrType::DT_PUBLIC) {
|
||||
AstTypedef* typep = VN_CAST(nodep->backp(), Typedef);
|
||||
UASSERT_OBJ(typep, nodep, "Attribute not attached to typedef");
|
||||
typep->attrPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
nodep->v3warn(DEPRECATED, "sc_clock is deprecated and will be removed");
|
||||
m_varp->attrScClocked(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrClockEn(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRdPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrIsolateAssign(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrSFormat(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrScBv(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrClocker(VVarAttrClocker::CLOCKER_YES);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrClocker(VVarAttrClocker::CLOCKER_NO);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
// AlwaysPublic was attached under a var, but it's a statement that should be
|
||||
// at the same level as the var
|
||||
cleanFileline(nodep);
|
||||
|
|
@ -331,7 +337,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDefImplicitDType* nodep) {
|
||||
virtual void visit(AstDefImplicitDType* nodep) VL_OVERRIDE {
|
||||
cleanFileline(nodep);
|
||||
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
||||
// Must remember what names we've already created, and combine duplicates
|
||||
|
|
@ -357,7 +363,7 @@ private:
|
|||
if (VN_IS(backp, Typedef)) { // A typedef doesn't need us to make yet another level of typedefing
|
||||
// For typedefs just remove the AstRefDType level of abstraction
|
||||
nodep->replaceWith(dtypep);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
} else {
|
||||
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL,
|
||||
|
|
@ -367,17 +373,17 @@ private:
|
|||
}
|
||||
}
|
||||
nodep->replaceWith(new AstRefDType(nodep->fileline(), defp->name()));
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstTypedefFwd* nodep) {
|
||||
virtual void visit(AstTypedefFwd* nodep) VL_OVERRIDE {
|
||||
// We only needed the forward declaration in order to parse correctly.
|
||||
// We won't even check it was ever really defined, as it might have been in a header
|
||||
// file referring to a module we never needed
|
||||
nodep->unlinkFrBack()->deleteTree();
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstForeach* nodep) {
|
||||
virtual void visit(AstForeach* nodep) VL_OVERRIDE {
|
||||
// FOREACH(array,loopvars,body)
|
||||
// -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body))
|
||||
//nodep->dumpTree(cout, "-foreach-old:");
|
||||
|
|
@ -433,19 +439,24 @@ private:
|
|||
dimension--;
|
||||
}
|
||||
//newp->dumpTree(cout, "-foreach-new:");
|
||||
firstVarsp->deleteTree(); VL_DANGLING(firstVarsp);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(firstVarsp->deleteTree(), firstVarsp);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
// Module: Create sim table for entire module and iterate
|
||||
cleanFileline(nodep);
|
||||
//
|
||||
m_modp = nodep;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
V3Config::applyModule(nodep);
|
||||
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
// Module: Create sim table for entire module and iterate
|
||||
cleanFileline(nodep);
|
||||
//
|
||||
m_modp = nodep;
|
||||
m_valueModp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_valueModp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
m_valueModp = NULL;
|
||||
}
|
||||
void visitIterateNoValueMod(AstNode* nodep) {
|
||||
// Iterate a node which shouldn't have any local variables moved to an Initial
|
||||
|
|
@ -456,25 +467,36 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_valueModp = upperValueModp;
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) {
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
m_inAlways = true;
|
||||
visitIterateNoValueMod(nodep);
|
||||
m_inAlways = false;
|
||||
}
|
||||
virtual void visit(AstCover* nodep) {
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstRestrict* nodep) {
|
||||
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
V3Config::applyCoverageBlock(m_modp, nodep);
|
||||
cleanFileline(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
V3Config::applyCase(nodep);
|
||||
cleanFileline(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
cleanFileline(nodep);
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -49,12 +49,12 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstCaseItem::user2() // bool Moved default caseitems
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
// Below state needs to be preserved between each module call.
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Function or task we're inside
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Function or task we're inside
|
||||
AstNodeCoverOrAssert* m_assertp; // Current assertion
|
||||
int m_senitemCvtNum; // Temporary signal counter
|
||||
|
||||
|
|
@ -65,31 +65,36 @@ private:
|
|||
// TODO: Most of these visitors are here for historical reasons.
|
||||
// TODO: ExpectDecriptor can move to data type resolution, and the rest
|
||||
// TODO: could move to V3LinkParse to get them out of the way of elaboration
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Module: Create sim table for entire module and iterate
|
||||
UINFO(8,"MODULE "<<nodep<<endl);
|
||||
if (nodep->dead()) return;
|
||||
m_modp = nodep;
|
||||
m_senitemCvtNum = 0;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
int origSenitemCvtNum = m_senitemCvtNum;
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_senitemCvtNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_senitemCvtNum = origSenitemCvtNum;
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Initial assignments under function/tasks can just be simple
|
||||
// assignments without the initial
|
||||
if (m_ftaskp) {
|
||||
nodep->replaceWith(nodep->bodysp()->unlinkFrBackWithNext()); VL_DANGLING(nodep);
|
||||
VL_DO_DANGLING(nodep->replaceWith(nodep->bodysp()->unlinkFrBackWithNext()), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) {
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) VL_OVERRIDE {
|
||||
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
||||
m_assertp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_assertp = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (m_ftaskp) nodep->funcLocal(true);
|
||||
if (nodep->isSigModPublic()) {
|
||||
|
|
@ -98,7 +103,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
// VarRef: Resolve its reference
|
||||
if (nodep->varp()) {
|
||||
nodep->varp()->usedParam(true);
|
||||
|
|
@ -106,7 +111,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
// NodeTask: Remember its name for later resolution
|
||||
// Remember the existing symbol table scope
|
||||
m_ftaskp = nodep;
|
||||
|
|
@ -116,14 +121,14 @@ private:
|
|||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->taskp() && (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
// Remove bit selects, and bark if it's not a simple variable
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isClocked()) {
|
||||
|
|
@ -167,18 +172,18 @@ private:
|
|||
did = 0;
|
||||
if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) {
|
||||
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); selp->deleteTree(); VL_DANGLING(selp);
|
||||
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
did = 1;
|
||||
}
|
||||
// NodeSel doesn't include AstSel....
|
||||
if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) {
|
||||
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); selp->deleteTree(); VL_DANGLING(selp);
|
||||
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
did = 1;
|
||||
}
|
||||
if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) {
|
||||
AstNode* fromp = selp->lhsp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); selp->deleteTree(); VL_DANGLING(selp);
|
||||
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
did = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -190,11 +195,11 @@ private:
|
|||
nodep->v3error("Unsupported: Complex statement in sensitivity list");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
|
||||
}
|
||||
|
||||
virtual void visit(AstNodePreSel* nodep) {
|
||||
virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE {
|
||||
if (!nodep->attrp()) {
|
||||
iterateChildren(nodep);
|
||||
// Constification may change the fromp() to a constant, which will lose the
|
||||
|
|
@ -226,7 +231,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstCaseItem* nodep) {
|
||||
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
|
||||
// Move default caseItems to the bottom of the list
|
||||
// That saves us from having to search each case list twice, for non-defaults and defaults
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -238,21 +243,21 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPragma* nodep) {
|
||||
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
|
||||
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) {
|
||||
UASSERT_OBJ(m_modp, nodep, "PUBLIC_MODULE not under a module");
|
||||
m_modp->modPublic(true);
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
|
||||
UASSERT_OBJ(m_ftaskp, nodep, "PUBLIC_TASK not under a task");
|
||||
m_ftaskp->taskPublic(true);
|
||||
m_modp->modPublic(true); // Need to get to the task...
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
|
||||
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize better without
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -270,7 +275,7 @@ private:
|
|||
if (!inPct && ch=='%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
} else if (inPct && (isdigit(ch) || ch=='.')) {
|
||||
} else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
|
|
@ -343,7 +348,7 @@ private:
|
|||
}
|
||||
newFormat.append(str);
|
||||
AstNode *nextp = argp->nextp();
|
||||
argp->unlinkFrBack(); pushDeletep(argp); VL_DANGLING(argp);
|
||||
argp->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(argp), argp);
|
||||
argp = nextp;
|
||||
} else {
|
||||
newFormat.append("%?"); // V3Width to figure it out
|
||||
|
|
@ -359,31 +364,31 @@ private:
|
|||
if (filep && filep->varp()) filep->varp()->attrFileDescr(true);
|
||||
}
|
||||
|
||||
virtual void visit(AstFOpen* nodep) {
|
||||
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
virtual void visit(AstFClose* nodep) {
|
||||
virtual void visit(AstFClose* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
virtual void visit(AstFEof* nodep) {
|
||||
virtual void visit(AstFEof* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) {
|
||||
virtual void visit(AstFRead* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) {
|
||||
virtual void visit(AstFScanF* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
||||
}
|
||||
virtual void visit(AstSScanF* nodep) {
|
||||
virtual void visit(AstSScanF* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Cleanup old-school displays without format arguments
|
||||
if (!nodep->hasFormat()) {
|
||||
|
|
@ -392,7 +397,7 @@ private:
|
|||
&& VN_CAST(nodep->exprsp(), Const)->num().isFromString()) {
|
||||
AstConst* fmtp = VN_CAST(nodep->exprsp()->unlinkFrBack(), Const);
|
||||
nodep->text(fmtp->num().toString());
|
||||
pushDeletep(fmtp); VL_DANGLING(fmtp);
|
||||
VL_DO_DANGLING(pushDeletep(fmtp), fmtp);
|
||||
}
|
||||
nodep->hasFormat(true);
|
||||
}
|
||||
|
|
@ -405,7 +410,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstUdpTable* nodep) {
|
||||
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
|
||||
UINFO(5,"UDPTABLE "<<nodep<<endl);
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
// We don't warn until V3Inst, so that UDPs that are in libraries and
|
||||
|
|
@ -432,27 +437,27 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstScCtor* nodep) {
|
||||
virtual void visit(AstScCtor* nodep) VL_OVERRIDE {
|
||||
// Constructor info means the module must remain public
|
||||
m_modp->modPublic(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScDtor* nodep) {
|
||||
virtual void visit(AstScDtor* nodep) VL_OVERRIDE {
|
||||
// Destructor info means the module must remain public
|
||||
m_modp->modPublic(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScInt* nodep) {
|
||||
virtual void visit(AstScInt* nodep) VL_OVERRIDE {
|
||||
// Special class info means the module must remain public
|
||||
m_modp->modPublic(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -484,24 +489,27 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
// Iterate modules backwards, in bottom-up order.
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
// Parent module inherits child's publicity
|
||||
if (nodep->modp()->modPublic()) m_modp->modPublic(true);
|
||||
//** No iteration for speed
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
// Speedup
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// Default: Just iterate
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,14 +77,14 @@ private:
|
|||
// See above
|
||||
|
||||
// METHODS
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
VarFlags flags (nodep->varp());
|
||||
if (flags.m_done) {
|
||||
nodep->hiername(""); // Remove this->
|
||||
nodep->hierThis(true);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
@ -151,11 +151,11 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
moveVars();
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
UINFO(4," CFUNC "<<nodep<<endl);
|
||||
m_cfuncp = nodep;
|
||||
searchFuncStmts(nodep->argsp());
|
||||
|
|
@ -186,7 +186,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (!nodep->isSigPublic()
|
||||
&& !nodep->isPrimaryIO()
|
||||
&& !m_cfuncp) { // Not already inside a function
|
||||
|
|
@ -195,7 +195,7 @@ private:
|
|||
}
|
||||
// No iterate; Don't want varrefs under it
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (!VarFlags(nodep->varp()).m_notOpt) {
|
||||
if (!m_cfuncp) { // Not in function, can't optimize
|
||||
clearOptimizable(nodep->varp(), "BVnofunc");
|
||||
|
|
@ -224,7 +224,7 @@ private:
|
|||
}
|
||||
// No iterate; Don't want varrefs under it
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ private:
|
|||
if (addPvt) {
|
||||
string newname = string("__PVT__")+nodep->name();
|
||||
nodep->name(newname);
|
||||
nodep->editCountInc();
|
||||
} else {
|
||||
string rsvd = m_words.isKeyword(nodep->name());
|
||||
if (rsvd != "") {
|
||||
|
|
@ -66,6 +67,7 @@ private:
|
|||
+": "<<nodep->prettyNameQ());
|
||||
string newname = string("__SYM__")+nodep->name();
|
||||
nodep->name(newname);
|
||||
nodep->editCountInc();
|
||||
}
|
||||
}
|
||||
nodep->user1(1);
|
||||
|
|
@ -73,50 +75,53 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_modp = NULL;
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
// Add __PVT__ to names of local signals
|
||||
virtual void visit(AstVar* nodep) {
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
// Don't iterate... Don't need temps for RANGES under the Var.
|
||||
rename(nodep, (!m_modp->isTop()
|
||||
&& !nodep->isSigPublic()
|
||||
&& !nodep->isFuncLocal() // Isn't exposed, and would mess up dpi import wrappers
|
||||
&& !nodep->isTemp())); // Don't bother to rename internal signals
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1()) {
|
||||
iterateChildren(nodep);
|
||||
rename(nodep, false);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp()) {
|
||||
iterate(nodep->varp());
|
||||
nodep->name(nodep->varp()->name());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1()) {
|
||||
rename(nodep, !nodep->modp()->modPublic());
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstMemberDType* nodep) {
|
||||
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1()) {
|
||||
rename(nodep, false);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstMemberSel* nodep) {
|
||||
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1()) {
|
||||
rename(nodep, false);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1SetOnce()) {
|
||||
if (nodep->aboveScopep()) iterate(nodep->aboveScopep());
|
||||
if (nodep->aboveCellp()) iterate(nodep->aboveCellp());
|
||||
|
|
@ -129,7 +134,7 @@ private:
|
|||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) {
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include <iomanip>
|
||||
|
||||
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
|
||||
#define MAX_WIDTH 5*1024 // Maximum width before error
|
||||
|
||||
// Number operations build output in-place so can't call e.g. foo.opX(foo)
|
||||
#define NUM_ASSERT_OP_ARGS1(arg1) \
|
||||
|
|
@ -125,10 +124,11 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl)
|
|||
value_startp = cp;
|
||||
|
||||
if (atoi(widthn.c_str())) {
|
||||
if (atoi(widthn.c_str()) < 0 || atoi(widthn.c_str()) > MAX_WIDTH) {
|
||||
if (atoi(widthn.c_str()) < 0 || atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) {
|
||||
// atoi might convert large number to negative, so can't tell which
|
||||
v3error("Unsupported: Width of number exceeds implementation limit: "<<sourcep);
|
||||
width(MAX_WIDTH, true);
|
||||
v3error("Unsupported: Width of number exceeds implementation limit: "
|
||||
<< sourcep << " (IEEE 1800-2017 6.9.1)");
|
||||
width(v3Global.opt.maxNumWidth(), true);
|
||||
} else {
|
||||
width(atoi(widthn.c_str()), true);
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl)
|
|||
<<std::endl
|
||||
<<((!m_sized && !warned++)
|
||||
? (V3Error::warnMore()+"... As that number was unsized"
|
||||
+" ('d...) it is limited to 32 bits (IEEE 2017 5.7.1)\n"
|
||||
+" ('d...) it is limited to 32 bits (IEEE 1800-2017 5.7.1)\n"
|
||||
+ V3Error::warnMore()+"... Suggest adding a size to it.")
|
||||
: ""));
|
||||
while (*(cp+1)) cp++; // Skip ahead so don't get multiple warnings
|
||||
|
|
@ -497,10 +497,10 @@ bool V3Number::displayedFmtLegal(char format) {
|
|||
}
|
||||
}
|
||||
|
||||
string V3Number::displayPad(size_t fmtsize, char pad, const string& in) {
|
||||
string prefix;
|
||||
if (in.length() < fmtsize) prefix = string(fmtsize - in.length(), pad);
|
||||
return prefix + in;
|
||||
string V3Number::displayPad(size_t fmtsize, char pad, bool left, const string& in) {
|
||||
string padding;
|
||||
if (in.length() < fmtsize) padding = string(fmtsize - in.length(), pad);
|
||||
return left ? (in + padding) : (padding + in);
|
||||
}
|
||||
|
||||
string V3Number::displayed(AstNode* nodep, const string& vformat) const {
|
||||
|
|
@ -512,6 +512,11 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
|||
UASSERT(pos != vformat.end() && pos[0]=='%',
|
||||
"$display-like function with non format argument "<<*this);
|
||||
++pos;
|
||||
bool left = false;
|
||||
if (pos[0] == '-') {
|
||||
left = true;
|
||||
++pos;
|
||||
}
|
||||
string fmtsize;
|
||||
for (; pos != vformat.end() && (isdigit(pos[0]) || pos[0]=='.'); ++pos) {
|
||||
fmtsize += pos[0];
|
||||
|
|
@ -574,7 +579,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
|||
}
|
||||
}
|
||||
size_t fmtsizen = static_cast<size_t>(atoi(fmtsize.c_str()));
|
||||
str = displayPad(fmtsizen, ' ', str);
|
||||
str = displayPad(fmtsizen, ' ', left, str);
|
||||
return str;
|
||||
}
|
||||
case '~': // Signed decimal
|
||||
|
|
@ -604,7 +609,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
|||
bool zeropad = fmtsize.length()>0 && fmtsize[0]=='0';
|
||||
// fmtsize might have changed since we parsed the %fmtsize
|
||||
size_t fmtsizen = static_cast<size_t>(atoi(fmtsize.c_str()));
|
||||
str = displayPad(fmtsizen, (zeropad ? '0' : ' '), str);
|
||||
str = displayPad(fmtsizen, (zeropad ? '0' : ' '), left, str);
|
||||
return str;
|
||||
}
|
||||
case 'e':
|
||||
|
|
@ -651,7 +656,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
|||
}
|
||||
case '@': { // Packed string
|
||||
size_t fmtsizen = static_cast<size_t>(atoi(fmtsize.c_str()));
|
||||
str = displayPad(fmtsizen, ' ', toString());
|
||||
str = displayPad(fmtsizen, ' ', left, toString());
|
||||
return str;
|
||||
}
|
||||
default:
|
||||
|
|
@ -1535,8 +1540,8 @@ V3Number& V3Number::opShiftRS(const V3Number& lhs, const V3Number& rhs, uint32_t
|
|||
if (rhs.isFourState()) return setAllBitsX();
|
||||
setZero();
|
||||
for (int bit=32; bit<rhs.width(); bit++) {
|
||||
for (int bit=0; bit<this->width(); bit++) {
|
||||
setBit(bit, lhs.bitIs(lbits-1)); // 0/1/X/Z
|
||||
for (int sbit = 0; sbit < this->width(); sbit++) {
|
||||
setBit(sbit, lhs.bitIs(lbits - 1)); // 0/1/X/Z
|
||||
}
|
||||
if (rhs.bitIs1(lbits-1)) setAllBits1(); // -1 else 0
|
||||
return *this; // shift of over 2^32 must be -1/0
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ public:
|
|||
V3Number(VerilogStringLiteral, AstNode* nodep, const string& str);
|
||||
class String {};
|
||||
V3Number(String, AstNode* nodep, const string& value) { init(nodep, 0); setString(value); }
|
||||
V3Number(const V3Number* nump, int width = 1) {
|
||||
explicit V3Number(const V3Number* nump, int width = 1) {
|
||||
init(NULL, width);
|
||||
m_fileline = nump->fileline();
|
||||
}
|
||||
|
|
@ -175,7 +175,7 @@ private:
|
|||
for (int i=0; i<words(); i++) m_value[i] = m_valueX[i] = 0;
|
||||
}
|
||||
void setNames(AstNode* nodep);
|
||||
static string displayPad(size_t fmtsize, char pad, const string& in);
|
||||
static string displayPad(size_t fmtsize, char pad, bool left, const string& in);
|
||||
string displayed(FileLine* fl, const string& vformat) const;
|
||||
string displayed(const string& vformat) const {
|
||||
return displayed(m_fileline, vformat);
|
||||
|
|
|
|||
|
|
@ -182,9 +182,7 @@ void V3Options::checkParameters() {
|
|||
}
|
||||
|
||||
void V3Options::addCppFile(const string& filename) {
|
||||
if (m_cppFiles.find(filename) == m_cppFiles.end()) {
|
||||
m_cppFiles.insert(filename);
|
||||
}
|
||||
m_cppFiles.insert(filename);
|
||||
}
|
||||
void V3Options::addCFlags(const string& filename) {
|
||||
m_cFlags.push_back(filename);
|
||||
|
|
@ -193,9 +191,7 @@ void V3Options::addLdLibs(const string& filename) {
|
|||
m_ldLibs.push_back(filename);
|
||||
}
|
||||
void V3Options::addFuture(const string& flag) {
|
||||
if (m_futures.find(flag) == m_futures.end()) {
|
||||
m_futures.insert(flag);
|
||||
}
|
||||
m_futures.insert(flag);
|
||||
}
|
||||
bool V3Options::isFuture(const string& flag) const {
|
||||
return m_futures.find(flag) != m_futures.end();
|
||||
|
|
@ -204,25 +200,19 @@ bool V3Options::isLibraryFile(const string& filename) const {
|
|||
return m_libraryFiles.find(filename) != m_libraryFiles.end();
|
||||
}
|
||||
void V3Options::addLibraryFile(const string& filename) {
|
||||
if (m_libraryFiles.find(filename) == m_libraryFiles.end()) {
|
||||
m_libraryFiles.insert(filename);
|
||||
}
|
||||
m_libraryFiles.insert(filename);
|
||||
}
|
||||
bool V3Options::isClocker(const string& signame) const {
|
||||
return m_clockers.find(signame) != m_clockers.end();
|
||||
}
|
||||
void V3Options::addClocker(const string& signame) {
|
||||
if (m_clockers.find(signame) == m_clockers.end()) {
|
||||
m_clockers.insert(signame);
|
||||
}
|
||||
m_clockers.insert(signame);
|
||||
}
|
||||
bool V3Options::isNoClocker(const string& signame) const {
|
||||
return m_noClockers.find(signame) != m_noClockers.end();
|
||||
}
|
||||
void V3Options::addNoClocker(const string& signame) {
|
||||
if (m_noClockers.find(signame) == m_noClockers.end()) {
|
||||
m_noClockers.insert(signame);
|
||||
}
|
||||
m_noClockers.insert(signame);
|
||||
}
|
||||
void V3Options::addVFile(const string& filename) {
|
||||
// We use a list for v files, because it's legal to have includes
|
||||
|
|
@ -374,7 +364,12 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la
|
|||
|
||||
void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
|
||||
static bool shown_notfound_msg = false;
|
||||
if (!shown_notfound_msg) {
|
||||
if (modname.find("__Vhsh") != string::npos) {
|
||||
std::cerr << V3Error::warnMore() << "... Unsupported: Name is longer than 127 characters;"
|
||||
<< " automatic file lookup not supported.\n";
|
||||
std::cerr << V3Error::warnMore() << "... Suggest putting filename with this module/package"
|
||||
<< " onto command line instead.\n";
|
||||
} else if (!shown_notfound_msg) {
|
||||
shown_notfound_msg = true;
|
||||
if (m_impp->m_incDirUsers.empty()) {
|
||||
fl->v3error("This may be because there's no search path specified with -I<dir>."<<endl);
|
||||
|
|
@ -943,6 +938,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||
fl->v3fatal("Unknown --make system specified: '"<<argv[i]<<"'");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(sw, "-max-num-width")) {
|
||||
shift;
|
||||
m_maxNumWidth = atoi(argv[i]);
|
||||
}
|
||||
else if (!strcmp(sw, "-no-l2name")) { // Historical and undocumented
|
||||
m_l2Name = "";
|
||||
}
|
||||
|
|
@ -1513,6 +1512,7 @@ V3Options::V3Options() {
|
|||
m_gateStmts = 100;
|
||||
m_ifDepth = 0;
|
||||
m_inlineMult = 2000;
|
||||
m_maxNumWidth = 65536;
|
||||
m_moduleRecursion = 100;
|
||||
m_outputSplit = 0;
|
||||
m_outputSplitCFuncs = 0;
|
||||
|
|
@ -1548,7 +1548,7 @@ V3Options::V3Options() {
|
|||
}
|
||||
|
||||
V3Options::~V3Options() {
|
||||
delete m_impp; m_impp = NULL;
|
||||
VL_DO_CLEAR(delete m_impp, m_impp = NULL);
|
||||
}
|
||||
|
||||
void V3Options::setDebugMode(int level) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue