Merge from master for release.
This commit is contained in:
commit
c37ec19751
|
|
@ -15,7 +15,7 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||
project(Verilator
|
||||
VERSION 5.008
|
||||
VERSION 5.010
|
||||
HOMEPAGE_URL https://verilator.org
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
|
@ -23,7 +23,8 @@ project(Verilator
|
|||
option(DEBUG_AND_RELEASE_AND_COVERAGE
|
||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.")
|
||||
|
||||
set(PYTHON3 python)
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
set(PYTHON3 Python3::Interpreter)
|
||||
set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX})
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
|
@ -44,15 +45,7 @@ if (MSVC)
|
|||
if (NOT WIN_FLEX_BISON)
|
||||
message(FATAL_ERROR "Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build.")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++20")
|
||||
else()
|
||||
if (NOT DEFINED ENV{FLEX_INCLUDE})
|
||||
message(FATAL_ERROR "Please set environment variable FLEX_INCLUDE to the directory containing FlexLexer.h")
|
||||
endif()
|
||||
set(WIN_FLEX_BISON "$ENV{FLEX_INCLUDE}")
|
||||
if (WIN32 AND NOT MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
endif()
|
||||
|
||||
find_package(BISON)
|
||||
|
|
@ -99,6 +92,7 @@ configure_package_config_file(verilator-config-version.cmake.in verilator-config
|
|||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
foreach (program
|
||||
verilator
|
||||
verilator_gantt
|
||||
verilator_ccache_report
|
||||
verilator_difftree
|
||||
|
|
|
|||
79
Changes
79
Changes
|
|
@ -8,6 +8,72 @@ The changes in each Verilator version are described below. The
|
|||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 5.010 2023-04-30
|
||||
==========================
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Add --public-depth to force public to a certain instance depth (#3952). [Andrew Nolte]
|
||||
* Add --public-params flag (#3990). [Andrew Nolte]
|
||||
* Add CONSTRAINTIGN warning when constraint ignored.
|
||||
* Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add error if class types don't match (#4064). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support class extends of package::class.
|
||||
* Support class srandom and class random stability.
|
||||
* Support class method calls without parenthesis (#3902) (#4082). [Srinivasan Venkataramanan]
|
||||
* Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support parameterized return types of methods (#4122). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support parameterized class references in extends statement (#4146). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support complicated IEEE 'for' assignments.
|
||||
* Support $fopen as an expression.
|
||||
* Support ++/-- on dotted member variables.
|
||||
* Optimize static trigger evaluation (#4142). [Geza Lore, X-EPIC]
|
||||
* Optimize more xor trees (#4071). [Yutetsu TAKATSUKASA]
|
||||
* Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras]
|
||||
* Change ZERODLY to a warning.
|
||||
* Fix random internal crashes (#666). [Dag Lem]
|
||||
* Fix install, standardization in cmake CMakeLists.txt (#3974). [Yu-Sheng Lin]
|
||||
* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker]
|
||||
* Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński]
|
||||
* Fix event controls reusing same variable (#4014). Kamil Rakoczy <krakoczy@antmicro.com>
|
||||
* Fix push to dynamic queue in struct (#4015). [ezchi]
|
||||
* Fix names for blocks in do..while loop (#4019). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix randomize on null field (#4023). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix rand fields in base classes (#4025). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt]
|
||||
* Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan]
|
||||
* Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube]
|
||||
* Fix characters from DEFENV literals for Conda (#4035) (#4044). [Tim Snyder]
|
||||
* Fix info message prints under --assert (#4036) (#4053). [Srinivasan Venkataramanan]
|
||||
* Fix C++ compile errors when passing class refs as task argument (#4063). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix NBAs inside fork-joins (#4050). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Fix task calls as fork statements (#4055). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix _Vilp used before declaration (#4057) (#4062). [Josep Sans]
|
||||
* Fix incorrect optimization of bit op tree (#4059) (#4070). [Yutetsu TAKATSUKASA]
|
||||
* Fix parameters in a class body to be localparam (#4061). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix interface generate begin (#4065). [Srinivasan Venkataramanan]
|
||||
* Fix tracing with awaits at end of block (#4075) (#4076). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix sense expression variable naming (#4081). [Kamil Rakoczy]
|
||||
* Fix importing symbols from base class (#4084). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix false error on new const assignment (#4098). [Tudor Timi]
|
||||
* Fix unpacked structs under classes (#4102). [Tudor Timi]
|
||||
* Fix variables in class methods to be automatic (#4111) (#4137). [Peter Monsson]
|
||||
* Fix to use parallel build for projects with a lot of files (#4116). [Krzysztof Boroński]
|
||||
* Fix including __Syms header in generated C++ files (#4123). [Krzysztof Boroński]
|
||||
* Fix systemc namespace issues (#4126) (#4127). [Eyck Jentzsch]
|
||||
* Fix class param extends A=B (#4128). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix missing begin block hierarchy in --xml-only cells section (#4129) (#4133). [Risto Pejašinović]
|
||||
* Fix resolution of class lvalues after parameterization (#4131). [Krzysztof Boroński]
|
||||
* Fix DFG error on $countbits (#4101) (#4143). [Paul Donahue]
|
||||
* Fix duplicating parameter class types (#4115). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix class extend param references (#4136). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix -CFLAGS to allow overriding optimization levels (#4140). [Peter Monsson]
|
||||
* Fix DPI function type alias (#4148) (#4149). [Toru Niina]
|
||||
* Fix deleting unused parameterized classes (#4150). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix false ENUMVALUE on expressions and arrays.
|
||||
* Fix unnecessary verilated_std.sv waivers in --waiver-output.
|
||||
|
||||
|
||||
Verilator 5.008 2023-03-04
|
||||
==========================
|
||||
|
||||
|
|
@ -31,7 +97,6 @@ Verilator 5.008 2023-03-04
|
|||
* Support function calls without parenthesis (#3903) (#3902). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support class extending its parameter (#3904). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support static function variables (#3830). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support vpiDefName (#3906) (#3931). [Andrew Nolte]
|
||||
* Support recursive methods (#3987). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix real parameters of infinity and NaN.
|
||||
* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal]
|
||||
|
|
@ -41,8 +106,8 @@ Verilator 5.008 2023-03-04
|
|||
* Fix namespace fallback resolution (#3863) (#3942). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Fix std:: to be parsed first (#3864) (#3928). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Fix cmake warning if multiple SOURCES w/o PREFIX (#3916) (#3927). [Yoda Lee]
|
||||
* Fix paramaterized class function linkage (#3917). [Ryszard Rozak]
|
||||
* Fix static members of type aliases of a parametrized class (#3922). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix parameterized class function linkage (#3917). [Ryszard Rozak]
|
||||
* Fix static members of type aliases of a parameterized class (#3922). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix class extend parameter dot case (#3926). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix MsWin missing directory exception, and ::std (#3928) (#3933) (#3935). [Kritik Bhimani]
|
||||
* Fix very long VPI signal names (#3929). [Marlon James]
|
||||
|
|
@ -54,13 +119,13 @@ Verilator 5.008 2023-03-04
|
|||
* Fix CMake bad C identifiers (#3948) (#3951). [Zixi Li]
|
||||
* Fix build on HP PA architecture (#3954). [John David Anglin]
|
||||
* Fix date on the front page of verilator.pdf (#3956) (#3957). [Larry Doolittle]
|
||||
* Fix dicts declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix associative arrays declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix missing error on negative replicate (#3963). [Benjamin Menküc]
|
||||
* Fix self references to parameterized classes (#3962). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix LITENDIAN warning is backwards (#3966) (#3967). [Cameron Kirk]
|
||||
* Fix subsequent parameter declarations (#3969). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix timing delays to not truncate below 64 bits (#3973) (#3982). [Felix Neumärker]
|
||||
* Fix cmake on macOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker]
|
||||
* Fix cmake on MacOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker]
|
||||
* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker]
|
||||
* Fix coverage of class methods (#3998). [Tim Paine]
|
||||
* Fix packed array structure replication.
|
||||
|
|
@ -80,7 +145,7 @@ Verilator 5.006 2023-01-22
|
|||
* Support import/export lists in modport (#3886). [Gökçe Aydos]
|
||||
* Support class queue equality (#3895). [Ilya Barkov]
|
||||
* Support type case and type equality comparisons.
|
||||
* Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add IMPLICITSTATIC warning when a task/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add VL_VALUE_STRING_MAX_WORDS override (#3869). [Andrew Nolte]
|
||||
* Optimize expansion of extend operators.
|
||||
* Internal multithreading tests. [Mariusz Glebocki, et al, Antmicro Ltd]
|
||||
|
|
@ -94,7 +159,7 @@ Verilator 5.006 2023-01-22
|
|||
* Fix self references when param class instantiated (#3833). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix memory leak in V3Sched, etc. (#3834). [Geza Lore]
|
||||
* Fix compatibility with musl libc / Alpine Linux (#3845). [Sören Tempel]
|
||||
* Fix empty case items crash (#3851). [rporter]
|
||||
* Fix empty case items crash (#3851). [Rich Porter]
|
||||
* Fix VL_CPU_RELAX on MIPS/Armel/s390/sparc (#3843) (#3891). [Kamil Rakoczy]
|
||||
* Fix module parameter name collision (#3854) (#3855). [James Shi]
|
||||
* Fix unpacked array expansion (#3861). [Joey Liu]
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ detailed descriptions of these arguments.
|
|||
--protect-key <key> Key for symbol protection
|
||||
--protect-lib <name> Create a DPI protected library
|
||||
--public Debugging; see docs
|
||||
--public-params Mark all parameters as public_flat
|
||||
--public-flat-rw Mark all variables, etc as public_flat_rw
|
||||
-pvalue+<name>=<value> Overwrite toplevel parameter
|
||||
--quiet-exit Don't print the command on failure
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.008 2023-03-04],
|
||||
AC_INIT([Verilator],[5.010 2023-04-30],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ AC_MSG_CHECKING(whether to use -m32)
|
|||
AC_ARG_ENABLE([m32],
|
||||
[AS_HELP_STRING([--enable-m32],
|
||||
[Use -m32 for all compilation and link,
|
||||
including Verialtor and generated models.])],
|
||||
including Verilator and generated models.])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_ENABLE_M32=yes ;;
|
||||
no) CFG_ENABLE_M32=no ;;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@ contributions flow more efficiently.
|
|||
Did you find a bug?
|
||||
-------------------
|
||||
|
||||
- Please **Ensure the bug was not already reported** by searching
|
||||
- Please **ensure the bug was not already reported** by searching
|
||||
`Verilator Issues <https://verilator.org/issues>`__.
|
||||
|
||||
- Please **download the latest development GitHub version**, build, and see
|
||||
if the issue has been fixed.
|
||||
|
||||
- If you're unable to find an open issue addressing the problem, `open a
|
||||
new Verilator issue <https://verilator.org/issues/new>`__.
|
||||
|
||||
|
|
@ -20,21 +23,28 @@ Did you find a bug?
|
|||
demonstrating the bug and expected behavior that is not occurring.
|
||||
|
||||
- The ideal example works against other simulators, and is in the
|
||||
test_regress/t test format, as described in `docs/internals
|
||||
<internals.rst>`__.
|
||||
test_regress/t test format, as described in
|
||||
`Verilator Internals Documentation
|
||||
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
|
||||
|
||||
|
||||
Did you write a patch that fixes a bug?
|
||||
---------------------------------------
|
||||
|
||||
- Please `Open a new issue <https://verilator.org/issues/new>`__.
|
||||
- Please `Open a new Verilator issue <https://verilator.org/issues/new>`__
|
||||
if there is not one already describing the bug.
|
||||
|
||||
- You may attach a patch to the issue, or (preferred) may request a
|
||||
GitHub pull request.
|
||||
- Please `Open a Verilator pull request
|
||||
<https://github.com/verilator/verilator/pulls>`__.
|
||||
|
||||
- Verilator uses GitHub Actions to provide continuous integration. You
|
||||
may want to enable Actions on your GitHub branch to ensure your changes
|
||||
keep the tests passing. See `docs/internals <internals.rst>`__.
|
||||
- See the coding conventions, and other developer information in
|
||||
``docs/internals.rst`` in the distribution, or as rendered at
|
||||
`Verilator Internals Documentation
|
||||
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
|
||||
|
||||
- Verilator uses GitHub Actions to provide continuous integration. You
|
||||
may want to enable Actions on your GitHub branch to ensure your changes
|
||||
keep the tests passing.
|
||||
|
||||
- Your source-code contributions must be certified as open source,
|
||||
under the `Developer Certificate of
|
||||
|
|
@ -56,13 +66,10 @@ Did you write a patch that fixes a bug?
|
|||
contribution.
|
||||
|
||||
- Your test contributions are generally considered released into the
|
||||
Creative Commons Public Domain (CC0), unless you request otherwise or
|
||||
Creative Commons Public Domain (CC0), unless you request otherwise, or
|
||||
put a GNU/Artistic license on your file.
|
||||
|
||||
- Most important is we get your patch. If you'd like to clean up
|
||||
indentation and related issues ahead of our feedback, that is
|
||||
appreciated; please see the coding conventions in `docs/internals
|
||||
<internals.rst>`__.
|
||||
- Most important is we get your patch.
|
||||
|
||||
|
||||
Do you have questions?
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ Drew Taussig
|
|||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Rippey
|
||||
Eyck Jentzsch
|
||||
Fan Shupei
|
||||
Felix Neumärker
|
||||
Felix Yan
|
||||
|
|
@ -61,6 +62,7 @@ Jamie Iles
|
|||
Jan Van Winkel
|
||||
Jean Berniolles
|
||||
Jeremy Bennett
|
||||
Jesse Taube
|
||||
Jevin Sweval
|
||||
Jiacheng Qian
|
||||
Jiuyang Liu
|
||||
|
|
@ -69,6 +71,7 @@ John Coiner
|
|||
John Demme
|
||||
Jonathan Drolet
|
||||
Joseph Nwabueze
|
||||
Josep Sans
|
||||
Josh Redford
|
||||
Julie Schwartz
|
||||
Julien Margetts
|
||||
|
|
@ -119,12 +122,15 @@ Qingyao Sun
|
|||
Rafal Kapuscik
|
||||
Raynard Qiao
|
||||
Richard Myers
|
||||
Risto Pejašinović
|
||||
Robert Balas
|
||||
Rupert Swarbrick
|
||||
Ryszard Rozak
|
||||
Samuel Riedel
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
Srinivasan Venkataramanan
|
||||
Stefan Wallentowitz
|
||||
Stephen Henry
|
||||
Steven Hugg
|
||||
|
|
@ -136,6 +142,7 @@ Tobias Wölfel
|
|||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Topa Topino
|
||||
Toru Niina
|
||||
Tymoteusz Blazejczyk
|
||||
Udi Finkelstein
|
||||
Unai Martinez-Corral
|
||||
|
|
|
|||
|
|
@ -120,6 +120,15 @@ code. This is a feature, as using the SystemC pin interconnect scheme
|
|||
everywhere would reduce performance by an order of magnitude.
|
||||
|
||||
|
||||
Verilated API
|
||||
=============
|
||||
|
||||
The API to a Verilated model is the C++ headers in the include/ directory
|
||||
in the distribution. These headers use Doxygen comments, `///` and `//<`,
|
||||
to indicate and document those functions that are part of the Verilated
|
||||
public API.
|
||||
|
||||
|
||||
Direct Programming Interface (DPI)
|
||||
==================================
|
||||
|
||||
|
|
|
|||
|
|
@ -1101,6 +1101,18 @@ Summary:
|
|||
marking only those signals that need public_flat_rw is typically
|
||||
significantly better performing.
|
||||
|
||||
.. option:: --public-depth <level>
|
||||
|
||||
Enables public as with :vlopt:`--public-flat-rw`, but only to the specified depth of modules.
|
||||
It operates at the module maximum level, so if a module's cells are A.B.X and A.X, the
|
||||
a --public-depth 3 must be used to make module X public, and both A.B.X and A.X will be public.
|
||||
|
||||
.. option:: --public-params
|
||||
|
||||
Declares all parameters public as if they had
|
||||
:code:`/*verilator public_flat_rd*/`
|
||||
metacomments.
|
||||
|
||||
.. option:: -pvalue+<name>=<value>
|
||||
|
||||
Overwrites the given parameter(s) of the top-level module. See
|
||||
|
|
@ -1502,10 +1514,10 @@ Summary:
|
|||
.. option:: -Wno-lint
|
||||
|
||||
Disable all lint-related warning messages, and all style warnings. This is
|
||||
equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE
|
||||
equivalent to ``-Wno-ALWCOMBORDER -Wno-ASCRANGE -Wno-BSSPACE -Wno-CASEINCOMPLETE
|
||||
-Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS
|
||||
-Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-LITENDIAN -Wno-PINCONNECTEMPTY
|
||||
-Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
|
||||
-Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-PINCONNECTEMPTY
|
||||
-Wno-PINMISSING -Wno-STATICVAR -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
|
||||
-Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL
|
||||
-Wno-WIDTH`` plus the list shown for Wno-style.
|
||||
|
||||
|
|
@ -1542,7 +1554,7 @@ Summary:
|
|||
enabled), but do not affect style messages. This is equivalent to
|
||||
``-Wwarn-ALWCOMBORDER -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE
|
||||
-Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CASEWITHX -Wwarn-CMPCONST
|
||||
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-LITENDIAN
|
||||
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-ASCRANGE
|
||||
-Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``.
|
||||
|
||||
.. option:: -Wwarn-style
|
||||
|
|
|
|||
|
|
@ -498,3 +498,20 @@ Clang. The process in GCC 10 was as follows:
|
|||
Clang and GCC also support -fauto-profile, which uses sample-based
|
||||
feedback-directed optimization. See the appropriate compiler
|
||||
documentation.
|
||||
|
||||
|
||||
.. _Runtime Debugging
|
||||
|
||||
Runtime Debugging
|
||||
=================
|
||||
|
||||
To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a
|
||||
similar tool. Typically you will want to have debugger symbols inserted by
|
||||
the compiler, assertions enabled in the C library, and assertions enabled
|
||||
in the Verilated library. (These options slow down the executable, so do
|
||||
this only when debugging.) To enable this, Verilate with:
|
||||
|
||||
-CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG
|
||||
|
||||
The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options pass arguments
|
||||
directly to the compiler or linker.
|
||||
|
|
|
|||
|
|
@ -97,6 +97,24 @@ List Of Warnings
|
|||
simulate correctly.
|
||||
|
||||
|
||||
.. option:: ASCRANGE
|
||||
|
||||
.. TODO better example
|
||||
|
||||
Warns that a packed vector is declared with ascending bit range
|
||||
(i.e. [0:7]). Descending bit range is now the overwhelming standard,
|
||||
and ascending ranges are now thus often due to simple oversight
|
||||
instead of intent (a notable exception is the OpenPOWER code base).
|
||||
|
||||
It also warns that an instance is declared with ascending range
|
||||
(i.e. [0:7] or [7]) and is connected to an N-wide signal.
|
||||
The bits will likely be in the reversed order from what people may expect
|
||||
(i.e., instance [0] will connect to signal bit [N-1] not bit [0]).
|
||||
|
||||
Ignoring this warning will only suppress the lint check; it will
|
||||
simulate correctly.
|
||||
|
||||
|
||||
.. option:: ASSIGNDLY
|
||||
|
||||
.. TODO better example
|
||||
|
|
@ -378,6 +396,16 @@ List Of Warnings
|
|||
simulators.
|
||||
|
||||
|
||||
.. option:: CONSTRAINTIGN
|
||||
|
||||
Warns that Verilator does not support :code:`constraint`,
|
||||
:code:`constraint_mode`, or :code:`rand_mode`, and the construct was are
|
||||
ignored.
|
||||
|
||||
Ignoring this warning may make Verilator randomize() simulations differ
|
||||
from other simulators.
|
||||
|
||||
|
||||
.. option:: CONTASSREG
|
||||
|
||||
.. TODO better example
|
||||
|
|
@ -738,7 +766,7 @@ List Of Warnings
|
|||
|
||||
This is a warning because the static default differs from C++, differs
|
||||
from class member function/tasks. Static is a more dangerous default
|
||||
then automatic as static prevents the function from being reinterant,
|
||||
then automatic as static prevents the function from being reentrant,
|
||||
which may be a source of bugs, and/or performance issues.
|
||||
|
||||
If the function does not require static behavior, change it to "function
|
||||
|
|
@ -850,18 +878,10 @@ List Of Warnings
|
|||
|
||||
.. TODO better example
|
||||
|
||||
Warns that a packed vector is declared with big endian bit numbering
|
||||
(i.e. [0:7]). Little endian bit numbering is now the overwhelming
|
||||
standard, and big numbering is now thus often due to simple oversight
|
||||
instead of intent.
|
||||
|
||||
It also warns that an instance is declared with big endian range
|
||||
(i.e. [0:7] or [7]) and is connected to an N-wide signal.
|
||||
The bits will likely be backward from what people may expect
|
||||
(i.e., instance [0] will connect to signal bit [N-1] not bit [0]).
|
||||
|
||||
Ignoring this warning will only suppress the lint check; it will
|
||||
simulate correctly.
|
||||
The naming of this warning is in contradiction with the common
|
||||
interpretation of little endian. It was therefore renamed to
|
||||
:option:`ASCRANGE`. While :option:`LITENDIAN` remains for
|
||||
backwards compatibility, new projects should use :option:`ASCRANGE`.
|
||||
|
||||
|
||||
.. option:: MINTYPMAX
|
||||
|
|
@ -1302,6 +1322,17 @@ List Of Warnings
|
|||
* The variable is tristate or bidirectional. (e.g., :code:`inout`).
|
||||
|
||||
|
||||
.. option:: STATICVAR
|
||||
|
||||
Warns that a static variable declared in a loop with declaration assignment
|
||||
was converted to automatic. Often such variables were intended to
|
||||
instead be declared "automatic".
|
||||
|
||||
Ignoring this warning may make Verilator differ from other simulators,
|
||||
which will treat the variable as static. Verilator may in future versions also
|
||||
treat the variable as static.
|
||||
|
||||
|
||||
.. option:: STMTDLY
|
||||
|
||||
Warns that the code has a statement with a delayed time in front of it.
|
||||
|
|
@ -1813,7 +1844,7 @@ List Of Warnings
|
|||
|
||||
.. option:: WIDTHXZEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is xz expanded
|
||||
A more granular WIDTH warning, for when a value is X/Z expanded
|
||||
|
||||
.. option:: WIDTHCONCAT
|
||||
|
||||
|
|
|
|||
|
|
@ -628,16 +628,12 @@ coroutines ``co_await`` its ``join`` function, and forked ones call ``done``
|
|||
when they're finished. Once the required number of coroutines (set using
|
||||
``setCounter``) finish execution, the forking coroutine is resumed.
|
||||
|
||||
Awaitable Utilities
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
``VlForever``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
There are also two small utility awaitable types:
|
||||
|
||||
* ``VlNow`` is an awaitable that suspends and immediately resumes coroutines.
|
||||
It is used for forcing a coroutine to be moved onto the heap. See the `Forks`
|
||||
section for more detail.
|
||||
* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass`
|
||||
section for more detail.
|
||||
A small utility awaitable type. It allows for blocking a coroutine forever. It
|
||||
is currently only used for ``wait`` statements that await a constant false
|
||||
condition. See the `Timing Pass` section for more details.
|
||||
|
||||
Timing Pass
|
||||
~~~~~~~~~~~
|
||||
|
|
@ -749,9 +745,7 @@ doesn't suspend the forking process.
|
|||
|
||||
In forked processes, references to local variables are only allowed in
|
||||
``fork..join``, as this is the only case that ensures the lifetime of these
|
||||
locals are at least as long as the execution of the forked processes. This is
|
||||
where ``VlNow`` is used, to ensure the locals are moved to the heap before they
|
||||
are passed by reference to the forked processes.
|
||||
locals are at least as long as the execution of the forked processes.
|
||||
|
||||
|
||||
Multithreaded Mode
|
||||
|
|
@ -1807,8 +1801,6 @@ IEEE 1800-2017 6.12 "shortreal"
|
|||
Little/no tool support, and easily promoted to real.
|
||||
IEEE 1800-2017 11.11 Min, typ, max
|
||||
No SDF support, so will always use typical.
|
||||
IEEE 1800-2017 11.12 "let"
|
||||
Little/no tool support, makes it difficult to implement parsers.
|
||||
IEEE 1800-2017 20.16 Stochastic analysis
|
||||
Little industry use.
|
||||
IEEE 1800-2017 20.17 PLA modeling
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Alexandre
|
|||
Ami
|
||||
Amir
|
||||
Anastasiadis
|
||||
Anglin
|
||||
Anikin
|
||||
Antmicro
|
||||
Antonin
|
||||
|
|
@ -42,6 +43,8 @@ Chandan
|
|||
Chitlesh
|
||||
Christophe
|
||||
Cochrane
|
||||
Conda
|
||||
Corteggiani
|
||||
Cuan
|
||||
Cygwin
|
||||
DErrico
|
||||
|
|
@ -96,6 +99,7 @@ Fredieu
|
|||
GTKWave
|
||||
Galbi
|
||||
Gantt
|
||||
Garnal
|
||||
Gartner
|
||||
Gelinek
|
||||
Geoff
|
||||
|
|
@ -188,6 +192,7 @@ Laurens
|
|||
Lavino
|
||||
Leber
|
||||
Leendert
|
||||
Lem
|
||||
Lesik
|
||||
Liland
|
||||
Liu
|
||||
|
|
@ -207,6 +212,7 @@ Matveyenko
|
|||
Maupin
|
||||
Mdir
|
||||
Mednick
|
||||
Menküc
|
||||
Michiels
|
||||
Microsystems
|
||||
Milanovic
|
||||
|
|
@ -223,8 +229,10 @@ Muhlestein
|
|||
Multithreaded
|
||||
Multithreading
|
||||
NOUNOPTFLAT
|
||||
NaN
|
||||
Nalbantis
|
||||
Narayan
|
||||
Nassim
|
||||
Nauticus
|
||||
Newgard
|
||||
Nigam
|
||||
|
|
@ -295,6 +303,7 @@ Solomatnikov
|
|||
Solt
|
||||
Southwell
|
||||
Srini
|
||||
Srinivasan
|
||||
Stamness
|
||||
Stephane
|
||||
Stoddard
|
||||
|
|
@ -319,6 +328,7 @@ Thiede
|
|||
Thierry
|
||||
Thyer
|
||||
Tichelaar
|
||||
Timi
|
||||
Tomov
|
||||
Tood
|
||||
Topa
|
||||
|
|
@ -343,6 +353,7 @@ Vdeeptemp
|
|||
Vdly
|
||||
Vemumtab
|
||||
Vemuri
|
||||
Venkataramanan
|
||||
Veriable
|
||||
Verialted
|
||||
Verilate
|
||||
|
|
@ -353,6 +364,7 @@ Verilator
|
|||
Verilog
|
||||
Vighnesh
|
||||
Viktor
|
||||
Vilp
|
||||
Vm
|
||||
Vukobratovic
|
||||
Wai
|
||||
|
|
@ -376,6 +388,7 @@ Xuan
|
|||
Xuanqi
|
||||
Yazdanbakhsh
|
||||
Yi
|
||||
Yike
|
||||
Yinan
|
||||
Yosys
|
||||
Yu
|
||||
|
|
@ -452,6 +465,7 @@ commandArgsPlusMatch
|
|||
compilable
|
||||
concat
|
||||
concats
|
||||
conf
|
||||
config
|
||||
const
|
||||
constexpr
|
||||
|
|
@ -512,6 +526,7 @@ dumpportson
|
|||
dumpvars
|
||||
dut
|
||||
dx
|
||||
dynarray
|
||||
elab
|
||||
elike
|
||||
elsif
|
||||
|
|
@ -520,6 +535,7 @@ endcelldefine
|
|||
endfunction
|
||||
endgenerate
|
||||
endian
|
||||
endianness
|
||||
endif
|
||||
endmodule
|
||||
endprotect
|
||||
|
|
@ -541,6 +557,7 @@ exe
|
|||
executables
|
||||
expr
|
||||
extern
|
||||
ezchi
|
||||
fanin
|
||||
fasttrace
|
||||
fauto
|
||||
|
|
@ -635,6 +652,7 @@ lcov
|
|||
ld
|
||||
leavinel
|
||||
len
|
||||
libc
|
||||
libext
|
||||
libgoogle
|
||||
libsystemc
|
||||
|
|
@ -653,7 +671,9 @@ logicals
|
|||
longint
|
||||
lossy
|
||||
lsb
|
||||
lubc
|
||||
lvalue
|
||||
lvalues
|
||||
lxt
|
||||
macromodule
|
||||
makefile
|
||||
|
|
@ -678,12 +698,15 @@ mtasks
|
|||
mulithreaded
|
||||
mult
|
||||
multidim
|
||||
multidriven
|
||||
multiinterfaces
|
||||
multiline
|
||||
multipling
|
||||
multipoint
|
||||
multithread
|
||||
multithreaded
|
||||
multithreading
|
||||
musl
|
||||
mutexes
|
||||
mux
|
||||
myftptoyman
|
||||
|
|
@ -714,6 +737,7 @@ ortegon
|
|||
oversubscription
|
||||
parallelized
|
||||
param
|
||||
parameterization
|
||||
parameterized
|
||||
params
|
||||
parens
|
||||
|
|
@ -762,6 +786,7 @@ pulldowns
|
|||
pullup
|
||||
pvalue
|
||||
pwd
|
||||
py
|
||||
qrq
|
||||
radix
|
||||
randc
|
||||
|
|
@ -807,6 +832,7 @@ specparam
|
|||
splitme
|
||||
spp
|
||||
sqrt
|
||||
srandom
|
||||
src
|
||||
srcdir
|
||||
srcfile
|
||||
|
|
@ -838,6 +864,7 @@ svdpi
|
|||
swrite
|
||||
sys
|
||||
systemc
|
||||
tenghtt
|
||||
testbench
|
||||
threadsafe
|
||||
threashold
|
||||
|
|
@ -909,6 +936,7 @@ vlt
|
|||
vltstd
|
||||
vluint
|
||||
vpi
|
||||
vpiDefName
|
||||
vpiLeftRange
|
||||
vpiModule
|
||||
vpiSize
|
||||
|
|
@ -938,4 +966,3 @@ ypq
|
|||
yurivict
|
||||
zdave
|
||||
Øyvind
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
//======================================================================
|
||||
|
||||
// SystemC global header
|
||||
#include <systemc.h>
|
||||
#include <systemc>
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
|
|
@ -15,6 +15,8 @@
|
|||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
using namespace sc_core;
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// See a similar example walkthrough in the verilator manpage.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <memory>
|
||||
|
||||
// SystemC global header
|
||||
#include <systemc.h>
|
||||
#include <systemc>
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
|
|
@ -23,6 +23,8 @@
|
|||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
using namespace sc_core;
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -131,7 +132,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
|||
#define FST_GZIO_LEN (32768)
|
||||
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) || defined(__aarch64__)
|
||||
#define FST_DO_MISALIGNED_OPS
|
||||
#endif
|
||||
|
||||
|
|
@ -334,26 +335,22 @@ return(NULL);
|
|||
/*
|
||||
* mmap compatibility
|
||||
*/
|
||||
#if defined __CYGWIN__ || defined __MINGW32__
|
||||
#if defined __MINGW32__
|
||||
#include <limits.h>
|
||||
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
||||
#define fstMunmap(__addr,__len) free(__addr)
|
||||
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
|
||||
|
||||
static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
|
||||
{
|
||||
(void)__off;
|
||||
HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL,
|
||||
PAGE_READWRITE, (DWORD)(__len >> 32),
|
||||
(DWORD)__len, NULL);
|
||||
if (!handle) { return NULL; }
|
||||
|
||||
unsigned char *pnt = (unsigned char *)malloc(__len);
|
||||
fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
|
||||
size_t i;
|
||||
|
||||
lseek(__fd, 0, SEEK_SET);
|
||||
for(i=0;i<__len;i+=SSIZE_MAX)
|
||||
{
|
||||
read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
|
||||
}
|
||||
lseek(__fd, cur_offs, SEEK_SET);
|
||||
return(pnt);
|
||||
void *ptr = MapViewOfFileEx(handle, FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
0, (DWORD)__off, (SIZE_T)__len, (LPVOID)NULL);
|
||||
CloseHandle(handle);
|
||||
return ptr;
|
||||
}
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
|
|
@ -984,14 +981,26 @@ fflush(xc->handle);
|
|||
*/
|
||||
static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage)
|
||||
{
|
||||
#if !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||
if(pnt == MAP_FAILED)
|
||||
if(pnt == NULL
|
||||
#ifdef MAP_FAILED
|
||||
|| pnt == MAP_FAILED
|
||||
#endif
|
||||
)
|
||||
{
|
||||
fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
|
||||
#if !defined(__MINGW32__)
|
||||
perror("Why");
|
||||
#else
|
||||
LPSTR mbuf = NULL;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&mbuf, 0, NULL);
|
||||
fprintf(stderr, "%s", mbuf);
|
||||
LocalFree(mbuf);
|
||||
#endif
|
||||
pnt = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1037,34 +1046,11 @@ if(!xc->curval_mem)
|
|||
|
||||
static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
|
||||
{
|
||||
#if !defined __CYGWIN__ && !defined __MINGW32__
|
||||
(void)is_closing;
|
||||
#endif
|
||||
|
||||
fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
|
||||
xc->valpos_mem = NULL;
|
||||
|
||||
#if defined __CYGWIN__ || defined __MINGW32__
|
||||
if(xc->curval_mem)
|
||||
{
|
||||
if(!is_closing) /* need to flush out for next emulated mmap() read */
|
||||
{
|
||||
unsigned char *pnt = xc->curval_mem;
|
||||
int __fd = fileno(xc->curval_handle);
|
||||
fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
|
||||
size_t i;
|
||||
size_t __len = xc->maxvalpos;
|
||||
|
||||
lseek(__fd, 0, SEEK_SET);
|
||||
for(i=0;i<__len;i+=SSIZE_MAX)
|
||||
{
|
||||
write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
|
||||
}
|
||||
lseek(__fd, cur_offs, SEEK_SET);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fstMunmap(xc->curval_mem, xc->maxvalpos);
|
||||
xc->curval_mem = NULL;
|
||||
}
|
||||
|
|
@ -3412,6 +3398,7 @@ int flat_hier_alloc_len;
|
|||
unsigned do_rewind : 1;
|
||||
char str_scope_nam[FST_ID_NAM_SIZ+1];
|
||||
char str_scope_comp[FST_ID_NAM_SIZ+1];
|
||||
char *str_scope_attr;
|
||||
|
||||
unsigned fseek_failed : 1;
|
||||
|
||||
|
|
@ -4140,7 +4127,7 @@ if(!(isfeof=feof(xc->fh)))
|
|||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
|
|
@ -4152,7 +4139,7 @@ if(!(isfeof=feof(xc->fh)))
|
|||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
|
|
@ -4169,15 +4156,19 @@ if(!(isfeof=feof(xc->fh)))
|
|||
xc->hier.htyp = FST_HT_ATTRBEGIN;
|
||||
xc->hier.u.attr.typ = fgetc(xc->fh);
|
||||
xc->hier.u.attr.subtype = fgetc(xc->fh);
|
||||
xc->hier.u.attr.name = pnt = xc->str_scope_nam;
|
||||
if(!xc->str_scope_attr)
|
||||
{
|
||||
xc->str_scope_attr = (char *)calloc(1, FST_ID_NAM_ATTR_SIZ+1);
|
||||
}
|
||||
xc->hier.u.attr.name = pnt = xc->str_scope_attr;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* scopename */
|
||||
}; /* attrname */
|
||||
pnt[cl] = 0;
|
||||
xc->hier.u.attr.name_length = cl;
|
||||
|
||||
|
|
@ -4237,7 +4228,7 @@ if(!(isfeof=feof(xc->fh)))
|
|||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
|
|
@ -4376,7 +4367,7 @@ while(!feof(xc->fh))
|
|||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
|
|
@ -4398,7 +4389,7 @@ while(!feof(xc->fh))
|
|||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
|
|
@ -4487,7 +4478,7 @@ while(!feof(xc->fh))
|
|||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
|
|
@ -4974,6 +4965,7 @@ if(xc)
|
|||
free(xc->signal_typs); xc->signal_typs = NULL;
|
||||
free(xc->signal_lens); xc->signal_lens = NULL;
|
||||
free(xc->filename); xc->filename = NULL;
|
||||
free(xc->str_scope_attr); xc->str_scope_attr = NULL;
|
||||
|
||||
if(xc->fh)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -232,9 +232,9 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
|
|||
char* const bufp = new char[len + 1];
|
||||
VL_VSNPRINTF(bufp, len + 1, formatp, ap);
|
||||
|
||||
std::string out{bufp, len}; // Not const to allow move optimization
|
||||
std::string result{bufp, len}; // Not const to allow move optimization
|
||||
delete[] bufp;
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t _vl_dbg_sequence_number() VL_MT_SAFE {
|
||||
|
|
@ -255,30 +255,76 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
|
|||
// includes that otherwise would be required in every Verilated module
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
const std::string out = _vl_string_vprintf(formatp, ap);
|
||||
const std::string result = _vl_string_vprintf(formatp, ap);
|
||||
va_end(ap);
|
||||
// printf("-imm-V{t%d,%" PRId64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(),
|
||||
// out.c_str());
|
||||
// result.c_str());
|
||||
|
||||
// Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF
|
||||
// from within the guts of the thread execution machinery (and it goes
|
||||
// to the screen and not into the queues we're debugging)
|
||||
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
|
||||
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), result.c_str());
|
||||
}
|
||||
|
||||
void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
const std::string out = _vl_string_vprintf(formatp, ap);
|
||||
const std::string result = _vl_string_vprintf(formatp, ap);
|
||||
va_end(ap);
|
||||
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
||||
VL_PRINTF("%s", out.c_str());
|
||||
VL_PRINTF("%s", result.c_str());
|
||||
}});
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Random -- Mostly called at init time, so not inline.
|
||||
|
||||
VlRNG::VlRNG() VL_MT_SAFE {
|
||||
// Starting point for this new class comes from the global RNG
|
||||
VlRNG& fromr = vl_thread_rng();
|
||||
m_state = fromr.m_state;
|
||||
// Advance the *source* so it can later generate a new number
|
||||
// Xoroshiro128+ algorithm
|
||||
fromr.m_state[1] ^= fromr.m_state[0];
|
||||
fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1]
|
||||
^ (fromr.m_state[1] << 14));
|
||||
fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28);
|
||||
}
|
||||
uint64_t VlRNG::rand64() VL_MT_UNSAFE {
|
||||
// Xoroshiro128+ algorithm
|
||||
const uint64_t result = m_state[0] + m_state[1];
|
||||
m_state[1] ^= m_state[0];
|
||||
m_state[0] = (((m_state[0] << 55) | (m_state[0] >> 9)) ^ m_state[1] ^ (m_state[1] << 14));
|
||||
m_state[1] = (m_state[1] << 36) | (m_state[1] >> 28);
|
||||
return result;
|
||||
}
|
||||
uint64_t VlRNG::vl_thread_rng_rand64() VL_MT_SAFE {
|
||||
VlRNG& fromr = vl_thread_rng();
|
||||
const uint64_t result = fromr.m_state[0] + fromr.m_state[1];
|
||||
fromr.m_state[1] ^= fromr.m_state[0];
|
||||
fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1]
|
||||
^ (fromr.m_state[1] << 14));
|
||||
fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28);
|
||||
return result;
|
||||
}
|
||||
void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE {
|
||||
m_state[0] = n;
|
||||
m_state[1] = m_state[0];
|
||||
// Fix state as algorithm is slow to randomize if many zeros
|
||||
// This causes a loss of ~ 1 bit of seed entropy, no big deal
|
||||
if (VL_COUNTONES_I(m_state[0]) < 10) m_state[0] = ~m_state[0];
|
||||
if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1];
|
||||
}
|
||||
// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
|
||||
// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) {
|
||||
// Unused: memcpy(m_state, state.data(), sizeof(m_state));
|
||||
// Unused: }
|
||||
// Unused: }
|
||||
// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
|
||||
// Unused: std::string result{reinterpret_cast<const char *>(&m_state), sizeof(m_state)};
|
||||
// Unused: return result;
|
||||
// Unused: }
|
||||
|
||||
static uint32_t vl_sys_rand32() VL_MT_SAFE {
|
||||
// Return random 32-bits using system library.
|
||||
// Used only to construct seed for Verilator's PRNG.
|
||||
|
|
@ -292,27 +338,23 @@ static uint32_t vl_sys_rand32() VL_MT_SAFE {
|
|||
#endif
|
||||
}
|
||||
|
||||
uint64_t vl_rand64() VL_MT_SAFE {
|
||||
static thread_local uint64_t t_state[2];
|
||||
VlRNG& VlRNG::vl_thread_rng() VL_MT_SAFE {
|
||||
static thread_local VlRNG t_rng{0};
|
||||
static thread_local uint32_t t_seedEpoch = 0;
|
||||
// For speed, we use a thread-local epoch number to know when to reseed
|
||||
// A thread always belongs to a single context, so this works out ok
|
||||
if (VL_UNLIKELY(t_seedEpoch != VerilatedContextImp::randSeedEpoch())) {
|
||||
// Set epoch before state, to avoid race case with new seeding
|
||||
t_seedEpoch = VerilatedContextImp::randSeedEpoch();
|
||||
t_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64();
|
||||
t_state[1] = t_state[0];
|
||||
// Same as srandom() but here as needs to be VL_MT_SAFE
|
||||
t_rng.m_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64();
|
||||
t_rng.m_state[1] = t_rng.m_state[0];
|
||||
// Fix state as algorithm is slow to randomize if many zeros
|
||||
// This causes a loss of ~ 1 bit of seed entropy, no big deal
|
||||
if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0];
|
||||
if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1];
|
||||
if (VL_COUNTONES_I(t_rng.m_state[0]) < 10) t_rng.m_state[0] = ~t_rng.m_state[0];
|
||||
if (VL_COUNTONES_I(t_rng.m_state[1]) < 10) t_rng.m_state[1] = ~t_rng.m_state[1];
|
||||
}
|
||||
// Xoroshiro128+ algorithm
|
||||
const uint64_t result = t_state[0] + t_state[1];
|
||||
t_state[1] ^= t_state[0];
|
||||
t_state[0] = (((t_state[0] << 55) | (t_state[0] >> 9)) ^ t_state[1] ^ (t_state[1] << 14));
|
||||
t_state[1] = (t_state[1] << 36) | (t_state[1] >> 28);
|
||||
return result;
|
||||
return t_rng;
|
||||
}
|
||||
|
||||
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
|
|
@ -321,6 +363,12 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
|||
return outwp;
|
||||
}
|
||||
|
||||
WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = rngr.rand64();
|
||||
// Last word is unclean
|
||||
return outwp;
|
||||
}
|
||||
|
||||
IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE {
|
||||
// $random - seed is a new seed to apply, then we return new seed
|
||||
Verilated::threadContextp()->randSeed(static_cast<int>(seedr));
|
||||
|
|
@ -518,12 +566,12 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE
|
|||
// Skip check for rhs == 0, as short-circuit doesn't save time
|
||||
if (VL_UNLIKELY(lhs == 0)) return 0;
|
||||
QData power = lhs;
|
||||
QData out = 1ULL;
|
||||
QData result = 1ULL;
|
||||
for (int bit = 0; bit < rbits; ++bit) {
|
||||
if (bit > 0) power = power * power;
|
||||
if (VL_BITISSET_W(rwp, bit)) out *= power;
|
||||
if (VL_BITISSET_W(rwp, bit)) result *= power;
|
||||
}
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
|
||||
|
|
@ -645,7 +693,7 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) {
|
||||
std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) VL_MT_SAFE {
|
||||
const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp();
|
||||
const std::string suffix = ctxImpp->timeFormatSuffix();
|
||||
const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15
|
||||
|
|
@ -1651,15 +1699,15 @@ std::string VL_STACKTRACE_N() VL_MT_SAFE {
|
|||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (!strings) return "Unable to backtrace\n";
|
||||
|
||||
std::string out = "Backtrace:\n";
|
||||
for (int j = 0; j < nptrs; j++) out += std::string{strings[j]} + std::string{"\n"};
|
||||
std::string result = "Backtrace:\n";
|
||||
for (int j = 0; j < nptrs; j++) result += std::string{strings[j]} + std::string{"\n"};
|
||||
free(strings);
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
void VL_STACKTRACE() VL_MT_SAFE {
|
||||
const std::string out = VL_STACKTRACE_N();
|
||||
VL_PRINTF("%s", out.c_str());
|
||||
const std::string result = VL_STACKTRACE_N();
|
||||
VL_PRINTF("%s", result.c_str());
|
||||
}
|
||||
|
||||
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
||||
|
|
@ -1805,14 +1853,14 @@ std::string VL_TO_STRING_W(int words, const WDataInP obj) {
|
|||
}
|
||||
|
||||
std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE {
|
||||
std::string out = ld;
|
||||
for (auto& cr : out) cr = std::tolower(cr);
|
||||
return out;
|
||||
std::string result = ld;
|
||||
for (auto& cr : result) cr = std::tolower(cr);
|
||||
return result;
|
||||
}
|
||||
std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE {
|
||||
std::string out = ld;
|
||||
for (auto& cr : out) cr = std::toupper(cr);
|
||||
return out;
|
||||
std::string result = ld;
|
||||
for (auto& cr : result) cr = std::toupper(cr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
|
||||
|
|
@ -1871,7 +1919,6 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
|
|||
IData VL_NTOI_I(int obits, const std::string& str) VL_PURE { return VL_NTOI_Q(obits, str); }
|
||||
QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE {
|
||||
QData out = 0;
|
||||
const size_t procLen = std::min(str.length(), static_cast<size_t>(8));
|
||||
const char* const datap = str.data();
|
||||
int pos = static_cast<int>(str.length()) - 1;
|
||||
int bit = 0;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@
|
|||
#ifndef VERILATOR_VERILATED_H_
|
||||
#define VERILATOR_VERILATED_H_
|
||||
#define VERILATOR_VERILATED_H_INTERNAL_
|
||||
#ifdef VERILATOR_INTERNAL_
|
||||
// This file contains definition of VerilationMutex that should
|
||||
// only be used by verilated code. Verilator itself should use
|
||||
// mutex from V3Mutex.h. Make sure this file isn't included in
|
||||
// verilator code.
|
||||
#error "verilated.h should only be included in verilated code"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
#include "verilatedos.h"
|
||||
|
|
@ -142,6 +149,15 @@ enum VerilatedVarFlags {
|
|||
VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Utility functions
|
||||
|
||||
template <size_t N>
|
||||
inline constexpr size_t roundUpToMultipleOf(size_t value) {
|
||||
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
|
||||
return (value + N - 1) & ~(N - 1);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Mutex and threading support
|
||||
|
||||
|
|
@ -607,6 +623,7 @@ public: // But for internal use only
|
|||
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
|
||||
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
|
||||
~VerilatedSyms();
|
||||
VL_UNCOPYABLE(VerilatedSyms);
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
|
@ -945,18 +962,18 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
|
|||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_s.m_timeprecision = value;
|
||||
#if VM_SC
|
||||
const sc_time sc_res = sc_get_time_resolution();
|
||||
if (sc_res == sc_time(1, SC_SEC)) {
|
||||
const sc_core::sc_time sc_res = sc_core::sc_get_time_resolution();
|
||||
if (sc_res == sc_core::sc_time(1, sc_core::SC_SEC)) {
|
||||
sc_prec = 0;
|
||||
} else if (sc_res == sc_time(1, SC_MS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_MS)) {
|
||||
sc_prec = 3;
|
||||
} else if (sc_res == sc_time(1, SC_US)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_US)) {
|
||||
sc_prec = 6;
|
||||
} else if (sc_res == sc_time(1, SC_NS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_NS)) {
|
||||
sc_prec = 9;
|
||||
} else if (sc_res == sc_time(1, SC_PS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_PS)) {
|
||||
sc_prec = 12;
|
||||
} else if (sc_res == sc_time(1, SC_FS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) {
|
||||
sc_prec = 15;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -235,14 +235,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
|
|||
ifneq ($(VM_DEFAULT_RULES),0)
|
||||
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
|
||||
# and user files passed on the Verilator command line use this rule.
|
||||
# We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
|
||||
# allow USER_CPPFLAGS to override them
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
$(VK_SLOW_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
$(VK_GLOBAL_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
|
||||
$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
#Default rule embedded in make:
|
||||
|
|
|
|||
|
|
@ -208,11 +208,11 @@ private:
|
|||
// Forward to . so we have a whole word
|
||||
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
|
||||
|
||||
std::string out = prefix + "*" + suffix;
|
||||
std::string result = prefix + "*" + suffix;
|
||||
|
||||
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
|
||||
// <<"\ncho="<<out<<endl;
|
||||
return out;
|
||||
// <<"\ncho="<<result<<endl;
|
||||
return result;
|
||||
}
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
|
||||
VL_REQUIRES(m_mutex) {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef VERILATOR_VERILATED_VCD_SC_H_
|
||||
#define VERILATOR_VERILATED_VCD_SC_H_
|
||||
#ifndef VERILATOR_VERILATED_FST_SC_H_
|
||||
#define VERILATOR_VERILATED_FST_SC_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
|
|
@ -36,23 +36,23 @@
|
|||
/// with the SystemC simulation kernel, just like a SystemC-documented
|
||||
/// trace format.
|
||||
|
||||
class VerilatedFstSc final : sc_trace_file, public VerilatedFstC {
|
||||
class VerilatedFstSc final : sc_core::sc_trace_file, public VerilatedFstC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFstSc);
|
||||
|
||||
public:
|
||||
/// Construct a SC trace object, and register with the SystemC kernel
|
||||
VerilatedFstSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an
|
||||
// annoying "to turn off" message.
|
||||
const sc_time t1sec{1, SC_SEC};
|
||||
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
|
||||
if (t1sec.to_default_time_units() != 0) {
|
||||
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
|
||||
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
|
||||
}
|
||||
/// Destruct, flush, and close the dump
|
||||
~VerilatedFstSc() override { close(); }
|
||||
|
|
@ -60,7 +60,7 @@ public:
|
|||
// METHODS - for SC kernel
|
||||
// Called by SystemC simulate()
|
||||
void cycle(bool delta_cycle) override {
|
||||
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
|
||||
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
|
||||
}
|
||||
|
||||
// Override VerilatedFstC. Must be called after starting simulation.
|
||||
|
|
@ -79,7 +79,7 @@ private:
|
|||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
void set_time_unit(int exponent10_seconds) override {} // deprecated
|
||||
#endif
|
||||
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
|
|
@ -96,8 +96,8 @@ private:
|
|||
// Formatting matches that of sc_trace.h
|
||||
// LCOV_EXCL_START
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_time )
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ extern void _vl_debug_print_w(int lbits, WDataInP const iwp) VL_MT_SAFE;
|
|||
#if defined(SYSTEMC_VERSION)
|
||||
/// Return current simulation time
|
||||
// Already defined: extern sc_time sc_time_stamp();
|
||||
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_time_stamp().value(); }
|
||||
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_core::sc_time_stamp().value(); }
|
||||
#else // Non-SystemC
|
||||
# if !defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)
|
||||
# ifdef VL_TIME_STAMP64
|
||||
|
|
@ -2201,10 +2201,10 @@ inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs
|
|||
return lhs + rhs;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNQ(const std::string& lhs, IData rep) VL_PURE {
|
||||
std::string out;
|
||||
out.reserve(lhs.length() * rep);
|
||||
for (unsigned times = 0; times < rep; ++times) out += lhs;
|
||||
return out;
|
||||
std::string result;
|
||||
result.reserve(lhs.length() * rep);
|
||||
for (unsigned times = 0; times < rep; ++times) result += lhs;
|
||||
return result;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(lhs, rep);
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ public:
|
|||
private:
|
||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||
// METHODS
|
||||
static VerilatedThreadMsgQueue& threadton() {
|
||||
static VerilatedThreadMsgQueue& threadton() VL_MT_SAFE {
|
||||
static thread_local VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "systemc.h"
|
||||
#include <systemc>
|
||||
|
||||
//=============================================================================
|
||||
// For \internal use, get a pointer to m_data in the sc_bv_base class,
|
||||
|
|
@ -37,9 +37,9 @@
|
|||
// use cast magic to get at it. Saves patching get_datap in SystemC.
|
||||
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
|
||||
// This class is thread safe (though most of SystemC is not).
|
||||
class VlScBvExposer final : public sc_bv_base {
|
||||
class VlScBvExposer final : public sc_dt::sc_bv_base {
|
||||
public:
|
||||
static const uint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE {
|
||||
static const uint32_t* sp_datap(const sc_dt::sc_bv_base& base) VL_MT_SAFE {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp();
|
||||
}
|
||||
const uint32_t* sp_datatp() const { return reinterpret_cast<uint32_t*>(m_data); }
|
||||
|
|
|
|||
|
|
@ -26,93 +26,134 @@
|
|||
// verilator lint_off TIMESCALEMOD
|
||||
// verilator lint_off UNUSEDSIGNAL
|
||||
package std;
|
||||
// The process class is not implemented, but it's predeclared here,
|
||||
// so the linter accepts references to it.
|
||||
typedef class process;
|
||||
// The process class is not implemented, but it's predeclared here,
|
||||
// so the linter accepts references to it.
|
||||
typedef class process;
|
||||
|
||||
class mailbox #(type T);
|
||||
protected int m_bound;
|
||||
protected T m_queue[$];
|
||||
class mailbox #(type T);
|
||||
protected int m_bound;
|
||||
protected T m_queue[$];
|
||||
|
||||
function new(int bound = 0);
|
||||
m_bound = bound;
|
||||
endfunction
|
||||
function new(int bound = 0);
|
||||
m_bound = bound;
|
||||
endfunction
|
||||
|
||||
function int num();
|
||||
return m_queue.size();
|
||||
endfunction
|
||||
function int num();
|
||||
return m_queue.size();
|
||||
endfunction
|
||||
|
||||
task put(T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
if (m_bound != 0)
|
||||
wait (m_queue.size() < m_bound);
|
||||
task put(T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
if (m_bound != 0)
|
||||
wait (m_queue.size() < m_bound);
|
||||
m_queue.push_back(message);
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_put(T message);
|
||||
if (num() < m_bound) begin
|
||||
m_queue.push_back(message);
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
|
||||
function int try_put(T message);
|
||||
if (num() < m_bound) begin
|
||||
m_queue.push_back(message);
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
task get(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
message = m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
|
||||
task get(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
function int try_get(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
|
||||
function int try_get(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue.pop_front();
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
task peek(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
message = m_queue[0];
|
||||
`endif
|
||||
endtask
|
||||
|
||||
task peek(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
function int try_peek(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue[0];
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
function int try_peek(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue[0];
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
class semaphore;
|
||||
protected int m_keyCount;
|
||||
|
||||
class semaphore;
|
||||
protected int m_keyCount;
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_keyCount >= keyCount);
|
||||
m_keyCount -= keyCount;
|
||||
`endif
|
||||
endtask
|
||||
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_keyCount >= keyCount);
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount >= keyCount) begin
|
||||
m_keyCount -= keyCount;
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class process;
|
||||
typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state;
|
||||
static process _s_global_process;
|
||||
static function process self();
|
||||
// Unsupported, emulating with single process' state
|
||||
if (!_s_global_process) _s_global_process = new;
|
||||
return _s_global_process;
|
||||
endfunction
|
||||
function state status();
|
||||
// Unsupported, emulating with single process' state
|
||||
return RUNNING;
|
||||
endfunction
|
||||
function void kill();
|
||||
$error("std::process::kill() not supported");
|
||||
endfunction
|
||||
task await();
|
||||
$error("std::process::await() not supported");
|
||||
endtask
|
||||
function void suspend();
|
||||
$error("std::process::suspend() not supported");
|
||||
endfunction
|
||||
function void resume();
|
||||
$error("std::process::resume() not supported");
|
||||
endfunction
|
||||
// When really implemented, srandom must operates on the process, but for
|
||||
// now rely on the srandom() that is automatically generated for all
|
||||
// classes.
|
||||
// function void srandom(int seed);
|
||||
// endfunction
|
||||
function string get_randstate();
|
||||
// Could operate on all proceses for now
|
||||
// No error, as harmless until set_randstate is called
|
||||
return "NOT_SUPPORTED";
|
||||
endfunction
|
||||
function void set_randstate(string randstate);
|
||||
$error("std::process::set_randstate() not supported");
|
||||
// Could operate on all proceses for now
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount >= keyCount) begin
|
||||
m_keyCount -= keyCount;
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
endpackage
|
||||
|
|
|
|||
|
|
@ -312,16 +312,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine.
|
||||
// Allows forcing the move of coroutine locals to the heap.
|
||||
|
||||
struct VlNow {
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
bool await_suspend(std::coroutine_handle<>) const { return false; } // Resume immediately
|
||||
void await_resume() const {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant
|
||||
// wait statements.
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
|||
template <std::size_t T_size> //
|
||||
class VlTriggerVec final {
|
||||
// TODO: static assert T_size > 0, and don't generate when empty
|
||||
private:
|
||||
|
||||
// MEMBERS
|
||||
std::array<bool, T_size> m_flags; // State of the assoc array
|
||||
alignas(16) std::array<uint64_t, roundUpToMultipleOf<64>(T_size) / 64> m_flags; // The flags
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
|
|
@ -91,10 +91,18 @@ public:
|
|||
// METHODS
|
||||
|
||||
// Set all elements to false
|
||||
void clear() { m_flags.fill(false); }
|
||||
void clear() { m_flags.fill(0); }
|
||||
|
||||
// Reference to element at 'index'
|
||||
bool& at(size_t index) { return m_flags.at(index); }
|
||||
// Word at given 'wordIndex'
|
||||
uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; }
|
||||
|
||||
// Set specified flag to given value
|
||||
void set(size_t index, bool value) {
|
||||
uint64_t& w = m_flags[index / 64];
|
||||
const size_t bitIndex = index % 64;
|
||||
w &= ~(1ULL << bitIndex);
|
||||
w |= (static_cast<uint64_t>(value) << bitIndex);
|
||||
}
|
||||
|
||||
// Return true iff at least one element is set
|
||||
bool any() const {
|
||||
|
|
@ -104,13 +112,13 @@ public:
|
|||
}
|
||||
|
||||
// Set all elements true in 'this' that are set in 'other'
|
||||
void set(const VlTriggerVec<T_size>& other) {
|
||||
void thisOr(const VlTriggerVec<T_size>& other) {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i];
|
||||
}
|
||||
|
||||
// Set elements of 'this' to 'a & !b' element-wise
|
||||
void andNot(const VlTriggerVec<T_size>& a, const VlTriggerVec<T_size>& b) {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] && !b.m_flags[i];
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] & ~b.m_flags[i];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -136,14 +144,34 @@ public:
|
|||
};
|
||||
|
||||
inline std::string VL_TO_STRING(const VlEvent& e) {
|
||||
return std::string("triggered=") + (e.isTriggered() ? "true" : "false");
|
||||
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Shuffle RNG
|
||||
// Random
|
||||
|
||||
extern uint64_t vl_rand64() VL_MT_SAFE;
|
||||
// Random Number Generator with internal state
|
||||
class VlRNG final {
|
||||
std::array<uint64_t, 2> m_state;
|
||||
|
||||
public:
|
||||
// The default constructor simply sets state, to avoid vl_rand64()
|
||||
// having to check for construction at each call
|
||||
// Alternative: seed with zero and check on rand64() call
|
||||
VlRNG() VL_MT_SAFE;
|
||||
explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {}
|
||||
void srandom(uint64_t n) VL_MT_UNSAFE;
|
||||
// Unused: std::string get_randstate() const VL_MT_UNSAFE;
|
||||
// Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE;
|
||||
uint64_t rand64() VL_MT_UNSAFE;
|
||||
// Threadsafe, but requires use on vl_thread_rng
|
||||
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
|
||||
static VlRNG& vl_thread_rng() VL_MT_SAFE;
|
||||
};
|
||||
|
||||
inline uint64_t vl_rand64() VL_MT_SAFE { return VlRNG::vl_thread_rng_rand64(); }
|
||||
|
||||
// RNG for shuffle()
|
||||
class VlURNG final {
|
||||
public:
|
||||
using result_type = size_t;
|
||||
|
|
@ -152,6 +180,11 @@ public:
|
|||
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
|
||||
};
|
||||
|
||||
// These require the class object to have the thread safety lock
|
||||
inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
extern WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE;
|
||||
|
||||
//===================================================================
|
||||
// Readmem/Writemem operation classes
|
||||
|
||||
|
|
@ -370,18 +403,17 @@ public:
|
|||
// Can't just overload operator[] or provide a "at" reference to set,
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(int32_t index) {
|
||||
static thread_local T_Value s_throwAway;
|
||||
static thread_local T_Value t_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
s_throwAway = atDefault();
|
||||
return s_throwAway;
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(int32_t index) const {
|
||||
static thread_local T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
return atDefault();
|
||||
|
|
@ -389,6 +421,10 @@ public:
|
|||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// Access with an index counted from end (e.g. q[$])
|
||||
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
|
||||
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
|
||||
|
||||
// function void q.insert(index, value);
|
||||
void insert(int32_t index, const T_Value& value) {
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
|
||||
|
|
@ -404,6 +440,12 @@ public:
|
|||
for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
|
||||
return out;
|
||||
}
|
||||
VlQueue sliceFrontBack(int32_t lsb, int32_t msb) const {
|
||||
return slice(lsb, m_deque.size() - 1 - msb);
|
||||
}
|
||||
VlQueue sliceBackBack(int32_t lsb, int32_t msb) const {
|
||||
return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb);
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
|
|
@ -1166,7 +1208,8 @@ public:
|
|||
// CONSTRUCTORS
|
||||
VlClassRef() = default;
|
||||
// Init with nullptr
|
||||
explicit VlClassRef(VlNull){};
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlClassRef(VlNull){};
|
||||
template <typename... T_Args>
|
||||
VlClassRef(VlDeleter& deleter, T_Args&&... args)
|
||||
// () required here to avoid narrowing conversion warnings,
|
||||
|
|
@ -1188,6 +1231,16 @@ public:
|
|||
// cppcheck-suppress noExplicitConstructor
|
||||
VlClassRef(VlClassRef&& moved)
|
||||
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef(const VlClassRef<T_OtherClass>& copied)
|
||||
: m_objp{copied.m_objp} {
|
||||
refCountInc();
|
||||
}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef(VlClassRef<T_OtherClass>&& moved)
|
||||
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
|
||||
~VlClassRef() { refCountDec(); }
|
||||
|
||||
// METHODS
|
||||
|
|
|
|||
|
|
@ -61,16 +61,6 @@ constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; // Maximum length of a VCD s
|
|||
// cache-lines.
|
||||
constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; // Size of a suffix entry
|
||||
|
||||
//=============================================================================
|
||||
// Utility functions: TODO: put these in a common place and share them.
|
||||
|
||||
template <size_t N>
|
||||
static size_t roundUpToMultipleOf(size_t value) {
|
||||
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
|
||||
size_t mask = N - 1;
|
||||
return (value + mask) & ~mask;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Specialization of the generics for this trace format
|
||||
|
||||
|
|
|
|||
|
|
@ -36,23 +36,23 @@
|
|||
/// with the SystemC simulation kernel, just like a SystemC-documented
|
||||
/// trace format.
|
||||
|
||||
class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC {
|
||||
class VerilatedVcdSc final : sc_core::sc_trace_file, public VerilatedVcdC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdSc);
|
||||
|
||||
public:
|
||||
/// Construct a SC trace object, and register with the SystemC kernel
|
||||
VerilatedVcdSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an
|
||||
// annoying "to turn off" message.
|
||||
const sc_time t1sec{1, SC_SEC};
|
||||
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
|
||||
if (t1sec.to_default_time_units() != 0) {
|
||||
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
|
||||
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
|
||||
}
|
||||
/// Destruct, flush, and close the dump
|
||||
~VerilatedVcdSc() override { close(); }
|
||||
|
|
@ -60,7 +60,7 @@ public:
|
|||
// METHODS - for SC kernel
|
||||
// Called by SystemC simulate()
|
||||
void cycle(bool delta_cycle) override {
|
||||
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
|
||||
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
|
||||
}
|
||||
|
||||
// Override VerilatedVcdC. Must be called after starting simulation.
|
||||
|
|
@ -78,7 +78,7 @@ private:
|
|||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
void set_time_unit(int exponent10_seconds) override {} // deprecated
|
||||
#endif
|
||||
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
|
|
@ -95,8 +95,8 @@ private:
|
|||
// Formatting matches that of sc_trace.h
|
||||
// LCOV_EXCL_START
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_time )
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
|
|
|
|||
|
|
@ -791,7 +791,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE {
|
|||
}
|
||||
for (auto& ifuture : s().m_nextCbs) {
|
||||
const QData time = ifuture.first.first;
|
||||
const uint64_t id = ifuture.first.second;
|
||||
VerilatedVpiCbHolder& ho = ifuture.second;
|
||||
if (VL_UNLIKELY(!ho.invalid())) {
|
||||
VL_DBG_MSGF("- vpi: time=%" PRId64 "(NEXT) reason=%d=%s id=%" PRId64 "\n", time,
|
||||
|
|
@ -802,7 +801,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE {
|
|||
}
|
||||
for (auto& ifuture : s().m_futureCbs) {
|
||||
const QData time = ifuture.first.first;
|
||||
const uint64_t id = ifuture.first.second;
|
||||
VerilatedVpiCbHolder& ho = ifuture.second;
|
||||
if (VL_UNLIKELY(!ho.invalid())) {
|
||||
VL_DBG_MSGF("- vpi: time=%" PRId64 " reason=%d=%s id=%" PRId64 "\n", time,
|
||||
|
|
|
|||
|
|
@ -160,6 +160,13 @@
|
|||
#else
|
||||
# define VL_MT_SAFE
|
||||
#endif
|
||||
// Comment tag that function is threadsafe, only if
|
||||
// other threads doesn't change tree topology
|
||||
#if defined(__clang__)
|
||||
# define VL_MT_STABLE __attribute__((annotate("MT_STABLE")))
|
||||
#else
|
||||
# define VL_MT_STABLE
|
||||
#endif
|
||||
// Comment tag that function is threadsafe, only
|
||||
// during normal operation (post-init)
|
||||
#if defined(__clang__)
|
||||
|
|
@ -596,8 +603,12 @@ reverse_wrapper<T> reverse_view(const T& v) {
|
|||
}
|
||||
|
||||
// C++17's std::as_const
|
||||
// `VL_MT_SAFE` annotation only applies to this function.
|
||||
// Object that is returned by this function is not considered
|
||||
// as MT_SAFE and any function call on this object still
|
||||
// needs to be `VL_MT_SAFE`.
|
||||
template <class T>
|
||||
T const& as_const(T& v) {
|
||||
T const& as_const(T& v) VL_MT_SAFE {
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ def fully_qualified_name(node):
|
|||
class VlAnnotations:
|
||||
mt_start: bool = False
|
||||
mt_safe: bool = False
|
||||
stable_tree: bool = False
|
||||
mt_safe_postinit: bool = False
|
||||
mt_unsafe: bool = False
|
||||
mt_unsafe_one: bool = False
|
||||
|
|
@ -48,12 +49,17 @@ class VlAnnotations:
|
|||
release: bool = False
|
||||
|
||||
def is_mt_safe_context(self):
|
||||
return (not (self.mt_unsafe or self.mt_unsafe_one)
|
||||
and (self.mt_safe or self.mt_start))
|
||||
return self.mt_safe and not (self.mt_unsafe or self.mt_unsafe_one)
|
||||
|
||||
def is_pure_context(self):
|
||||
return self.pure
|
||||
|
||||
def is_stabe_tree_context(self):
|
||||
# stable tree context requires calls to be marked
|
||||
# as MT_SAFE or MT_STABLE
|
||||
# Functions in MT_START needs to be MT_SAFE or MT_STABLE
|
||||
return self.stable_tree or self.mt_start
|
||||
|
||||
def is_mt_unsafe_call(self):
|
||||
return self.mt_unsafe or self.mt_unsafe_one
|
||||
|
||||
|
|
@ -66,6 +72,9 @@ class VlAnnotations:
|
|||
def is_pure_call(self):
|
||||
return self.pure
|
||||
|
||||
def is_stabe_tree_call(self):
|
||||
return self.stable_tree
|
||||
|
||||
def __or__(self, other: "VlAnnotations"):
|
||||
result = VlAnnotations()
|
||||
for key, value in dataclasses.asdict(self).items():
|
||||
|
|
@ -94,6 +103,8 @@ class VlAnnotations:
|
|||
result.mt_start = True
|
||||
elif node.displayname == "MT_SAFE":
|
||||
result.mt_safe = True
|
||||
elif node.displayname == "MT_STABLE":
|
||||
result.stable_tree = True
|
||||
elif node.displayname == "MT_SAFE_POSTINIT":
|
||||
result.mt_safe_postinit = True
|
||||
elif node.displayname == "MT_UNSAFE":
|
||||
|
|
@ -196,6 +207,7 @@ class DiagnosticKind(Enum):
|
|||
ANNOTATIONS_DEF_DECL_MISMATCH = enum.auto()
|
||||
NON_PURE_CALL_IN_PURE_CTX = enum.auto()
|
||||
NON_MT_SAFE_CALL_IN_MT_SAFE_CTX = enum.auto()
|
||||
NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX = enum.auto()
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.value < other.value
|
||||
|
|
@ -377,6 +389,17 @@ class CallAnnotationsValidator:
|
|||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_stabe_tree_call()
|
||||
or annotations.is_pure_call()
|
||||
or self.check_mt_safe_call(node, refd, annotations)):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
self.emit_diagnostic(
|
||||
|
|
@ -394,6 +417,17 @@ class CallAnnotationsValidator:
|
|||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_pure_call()
|
||||
or annotations.is_mt_safe_call()
|
||||
or annotations.is_stabe_tree_call()):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
|
|
@ -414,6 +448,13 @@ class CallAnnotationsValidator:
|
|||
self.dispatch_node_inside_definition)
|
||||
self._constructor_context -= 1
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
self._constructor_context += 1
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self._constructor_context -= 1
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call(
|
||||
|
|
@ -428,11 +469,19 @@ class CallAnnotationsValidator:
|
|||
if not supported:
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
return True
|
||||
|
||||
assert refd is not None
|
||||
if self._is_ignored_call(refd):
|
||||
return
|
||||
return True
|
||||
|
||||
if "std::function" in refd.displayname:
|
||||
# Workaroud for missing support for lambda annotations
|
||||
# in c++11.
|
||||
# If function takes std::function as argument,
|
||||
# assume, that this std::function will be called inside it.
|
||||
self.process_function_definition(node)
|
||||
return False
|
||||
|
||||
assert self._call_location is not None
|
||||
node_file = os.path.abspath(node.location.file.name)
|
||||
|
|
@ -444,47 +493,40 @@ class CallAnnotationsValidator:
|
|||
or refd.kind == CursorKind.CXX_METHOD
|
||||
and refd.is_static_method()):
|
||||
self.process_function_call(refd, annotations)
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
# Function pointer
|
||||
if refd.kind in [
|
||||
elif refd.kind in [
|
||||
CursorKind.VAR_DECL, CursorKind.FIELD_DECL,
|
||||
CursorKind.PARM_DECL
|
||||
]:
|
||||
self.process_function_call(refd, annotations)
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
# Non-static class methods
|
||||
if refd.kind == CursorKind.CXX_METHOD:
|
||||
elif refd.kind == CursorKind.CXX_METHOD:
|
||||
self.process_method_call(node, refd, annotations)
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
# Conversion method (e.g. `operator int()`)
|
||||
if refd.kind == CursorKind.CONVERSION_FUNCTION:
|
||||
elif refd.kind == CursorKind.CONVERSION_FUNCTION:
|
||||
self.process_method_call(node, refd, annotations)
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
# Constructors
|
||||
if refd.kind == CursorKind.CONSTRUCTOR:
|
||||
elif refd.kind == CursorKind.CONSTRUCTOR:
|
||||
self.process_constructor_call(refd, annotations)
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
|
||||
# Ignore other callables
|
||||
print(f"{refd.location.file.name}:{refd.location.line}: "
|
||||
f"{refd.displayname} {refd.kind}\n"
|
||||
f" from: {node.location.file.name}:{node.location.line}")
|
||||
else:
|
||||
# Ignore other callables, but report them
|
||||
print("Unknown callable: "
|
||||
f"{refd.location.file.name}:{refd.location.line}: "
|
||||
f"{refd.displayname} {refd.kind}\n"
|
||||
f" from: {node.location.file.name}:{node.location.line}")
|
||||
return True
|
||||
|
||||
# Definition handling
|
||||
|
||||
def dispatch_node_inside_definition(self, node: clang.cindex.Cursor):
|
||||
if node.kind == CursorKind.CALL_EXPR:
|
||||
self.dispatch_call_node(node)
|
||||
if self.dispatch_call_node(node) is False:
|
||||
return None
|
||||
elif node.is_definition() and node.kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
||||
]:
|
||||
self.process_function_definition(node)
|
||||
return None
|
||||
|
||||
return self.iterate_children(node.get_children(),
|
||||
|
|
@ -519,12 +561,14 @@ class CallAnnotationsValidator:
|
|||
# for callees validation.
|
||||
self._caller = FunctionInfo.from_node(node, refd,
|
||||
def_annotations | annotations)
|
||||
prev_call_location = self._call_location
|
||||
self._call_location = self._caller
|
||||
|
||||
self.iterate_children(node_children,
|
||||
self.dispatch_node_inside_definition)
|
||||
|
||||
self._call_location = None
|
||||
self._call_location = prev_call_location
|
||||
self._caller = prev_call_location
|
||||
|
||||
return None
|
||||
|
||||
|
|
@ -788,6 +832,8 @@ class TopDownSummaryPrinter():
|
|||
name += "is mtsafe but calls non-mtsafe function(s)"
|
||||
elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
|
||||
name += "is pure but calls non-pure function(s)"
|
||||
elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX:
|
||||
name += "is stable_tree but calls non-stable_tree or non-mtsafe"
|
||||
else:
|
||||
name += "for unknown reason (please add description)"
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ endif
|
|||
# -lfl not needed as Flex invoked with %nowrap option
|
||||
LIBS = $(CFG_LIBS) -lm
|
||||
|
||||
CPPFLAGS += -DVERILATOR_INTERNAL_
|
||||
CPPFLAGS += -MMD
|
||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ private:
|
|||
const string m_name; // Only used for .dot file generation
|
||||
const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
|
||||
|
||||
string typestr() const { // "
|
||||
string typestr() const VL_MT_SAFE { // "
|
||||
switch (m_type) {
|
||||
case VT_BLOCK: return "(||)"; // basic block node
|
||||
case VT_BRANCH: return "(&&)"; // if/else branch mode
|
||||
|
|
@ -68,7 +68,7 @@ public:
|
|||
: V3GraphVertex{graphp}
|
||||
, m_name{name}
|
||||
, m_type{type} {}
|
||||
string name() const override { return m_name + " " + typestr(); }
|
||||
string name() const override VL_MT_STABLE { return m_name + " " + typestr(); }
|
||||
string dotColor() const override { return user() ? "green" : "black"; }
|
||||
virtual int type() const { return m_type; }
|
||||
};
|
||||
|
|
@ -309,7 +309,7 @@ AstActive*& ActiveNamer::getSpecialActive<AstSenItem::Combo>() {
|
|||
//######################################################################
|
||||
// Latch checking visitor
|
||||
|
||||
class ActiveLatchCheckVisitor final : public VNVisitor {
|
||||
class ActiveLatchCheckVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Input:
|
||||
|
|
@ -329,20 +329,20 @@ private:
|
|||
LatchDetectGraphVertex* const parentp = m_graph.currentp();
|
||||
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
|
||||
m_graph.addPathVertex(branchp, "IF");
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
m_graph.addPathVertex(branchp, "ELSE");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
m_graph.currentp(parentp);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ActiveLatchCheckVisitor(AstNode* nodep, bool expectLatch) {
|
||||
m_graph.begin();
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
m_graph.latchCheck(nodep, expectLatch);
|
||||
}
|
||||
~ActiveLatchCheckVisitor() override = default;
|
||||
|
|
|
|||
|
|
@ -51,14 +51,22 @@ private:
|
|||
bool m_inSampled = false; // True inside a sampled expression
|
||||
|
||||
// METHODS
|
||||
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
|
||||
return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message,
|
||||
VDisplayType severity) {
|
||||
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
|
||||
return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
} else {
|
||||
return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
}
|
||||
}
|
||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||
nodep->fmtp()->text(
|
||||
assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType()));
|
||||
nodep->displayType(VDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
// cppcheck-suppress nullPointer
|
||||
AstNodeExpr* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
|
||||
if (AstNodeExpr* const timesp = nodep->fmtp()->exprsp()) {
|
||||
|
|
@ -182,7 +190,7 @@ private:
|
|||
const bool force = VN_IS(nodep, AssertIntrinsic);
|
||||
if (passsp) passsp = newIfAssertOn(passsp, force);
|
||||
if (failsp) failsp = newIfAssertOn(failsp, force);
|
||||
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||
if (!passsp && !failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||
ifp = new AstIf{nodep->fileline(), propp, passsp, failsp};
|
||||
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||
// It's more LIKELY that we'll take the nullptr if clause
|
||||
|
|
@ -419,9 +427,10 @@ private:
|
|||
replaceDisplay(nodep, "-Info");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_WARNING) {
|
||||
replaceDisplay(nodep, "%%Warning");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_ERROR
|
||||
|| nodep->displayType() == VDisplayType::DT_FATAL) {
|
||||
} else if (nodep->displayType() == VDisplayType::DT_ERROR) {
|
||||
replaceDisplay(nodep, "%%Error");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_FATAL) {
|
||||
replaceDisplay(nodep, "%%Fatal");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_MONITOR) {
|
||||
nodep->displayType(VDisplayType::DT_DISPLAY);
|
||||
const auto fl = nodep->fileline();
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ private:
|
|||
// always queue.push(<sampled var>);
|
||||
AstCMethodHard* const pushp = new AstCMethodHard{
|
||||
flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push",
|
||||
new AstTime(nodep->fileline(), m_modp->timeunit())};
|
||||
new AstTime{nodep->fileline(), m_modp->timeunit()}};
|
||||
pushp->addPinsp(exprp->cloneTree(false));
|
||||
pushp->dtypeSetVoid();
|
||||
m_clockingp->addNextHere(
|
||||
|
|
@ -238,7 +238,7 @@ private:
|
|||
// always @<clocking event> queue.pop(<skew>, /*out*/<skewed var>});
|
||||
AstCMethodHard* const popp = new AstCMethodHard{
|
||||
flp, new AstVarRef{flp, queueVarp, VAccess::READWRITE}, "pop",
|
||||
new AstTime(nodep->fileline(), m_modp->timeunit())};
|
||||
new AstTime{nodep->fileline(), m_modp->timeunit()}};
|
||||
popp->addPinsp(skewp->unlinkFrBack());
|
||||
popp->addPinsp(refp);
|
||||
popp->dtypeSetVoid();
|
||||
|
|
|
|||
|
|
@ -125,7 +125,9 @@ string AstNode::encodeNumber(int64_t num) {
|
|||
}
|
||||
}
|
||||
|
||||
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
|
||||
string AstNode::nameProtect() const VL_MT_STABLE {
|
||||
return VIdProtect::protectIf(name(), protect());
|
||||
}
|
||||
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
|
||||
|
||||
string AstNode::shortName() const {
|
||||
|
|
@ -155,7 +157,7 @@ string AstNode::vcdName(const string& namein) {
|
|||
return prettyName(pretty);
|
||||
}
|
||||
|
||||
string AstNode::prettyName(const string& namein) {
|
||||
string AstNode::prettyName(const string& namein) VL_PURE {
|
||||
// This function is somewhat hot, so we short-circuit some compares
|
||||
string pretty;
|
||||
pretty.reserve(namein.length());
|
||||
|
|
@ -283,7 +285,7 @@ string AstNode::vpiName(const string& namein) {
|
|||
return pretty;
|
||||
}
|
||||
|
||||
string AstNode::prettyTypeName() const {
|
||||
string AstNode::prettyTypeName() const VL_MT_STABLE {
|
||||
if (name() == "") return typeName();
|
||||
return std::string{typeName()} + " '" + prettyName() + "'";
|
||||
}
|
||||
|
|
@ -296,17 +298,19 @@ void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int line
|
|||
// Called on all major tree changers.
|
||||
// Only for use for those really nasty bugs relating to internals
|
||||
// Note this may be null.
|
||||
// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
||||
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
// if (debug() && nodep) cout << "-treeChange: V3Ast.cpp:" << lineno
|
||||
// << " Tree Change for " << prefix << ": "
|
||||
// << cvtToHex(nodep) << " <e" << AstNode::s_editCntGbl << ">"
|
||||
// << "m_iterpp=" << (void*)nodep->m_iterpp << endl;
|
||||
// if (debug()) {
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// // Commenting out the section below may crash, as the tree state
|
||||
// // between edits is not always consistent for printing
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// v3Global.rootp()->dumpTree("- treeChange: ");
|
||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||
// else this->dumpTree(prefix);
|
||||
// this->checkTree();
|
||||
// if (next||1) nodep->dumpTreeAndNext(cout, prefix);
|
||||
// else nodep->dumpTree(prefix);
|
||||
// nodep->checkTree();
|
||||
// v3Global.rootp()->checkTree();
|
||||
//}
|
||||
#endif
|
||||
|
|
@ -345,7 +349,8 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp) {
|
|||
newtailp->m_headtailp = headp;
|
||||
headp->m_headtailp = newtailp;
|
||||
newp->editCountInc();
|
||||
if (oldtailp->m_iterpp) *(oldtailp->m_iterpp) = newp; // Iterate on new item
|
||||
// No change of m_iterpp, as only changing m_nextp of current node;
|
||||
// the current node is still the one at the iteration point
|
||||
}
|
||||
debugTreeChange(nodep, "-addNextOut:", __LINE__, true);
|
||||
return nodep;
|
||||
|
|
@ -395,7 +400,8 @@ void AstNode::addNextHere(AstNode* newp) {
|
|||
} // else is head, and we're inserting into the middle, so no other change
|
||||
}
|
||||
|
||||
if (this->m_iterpp) *(this->m_iterpp) = newp; // Iterate on new item
|
||||
// No change of m_iterpp, as adding after current node;
|
||||
// the current node is still the one at the iteration point
|
||||
debugTreeChange(this, "-addHereOut: ", __LINE__, true);
|
||||
}
|
||||
|
||||
|
|
@ -563,8 +569,10 @@ AstNode* AstNode::unlinkFrBackWithNext(VNRelinker* linkerp) {
|
|||
// Relink
|
||||
oldp->m_backp = nullptr;
|
||||
// Iterator fixup
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
if (oldp->m_iterpp) {
|
||||
*(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
}
|
||||
debugTreeChange(oldp, "-unlinkWNextOut: ", __LINE__, true);
|
||||
return oldp;
|
||||
}
|
||||
|
|
@ -578,7 +586,11 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
|
|||
if (linkerp) {
|
||||
linkerp->m_oldp = oldp;
|
||||
linkerp->m_backp = backp;
|
||||
linkerp->m_iterpp = oldp->m_iterpp;
|
||||
if (oldp->m_iterpp) { // Assumes we will always relink() if want to keep iterating
|
||||
linkerp->m_iterpp = oldp->m_iterpp;
|
||||
*(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
}
|
||||
if (backp->m_nextp == oldp) {
|
||||
linkerp->m_chg = VNRelinker::RELINK_NEXT;
|
||||
} else if (backp->m_op1p == oldp) {
|
||||
|
|
@ -623,12 +635,15 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
|
|||
}
|
||||
}
|
||||
// Iterator fixup
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = oldp->m_nextp;
|
||||
if (oldp->m_iterpp) { // Only if no linker, point to next in list
|
||||
if (oldp->m_nextp) oldp->m_nextp->m_iterpp = oldp->m_iterpp;
|
||||
*(oldp->m_iterpp) = oldp->m_nextp;
|
||||
oldp->m_iterpp = nullptr;
|
||||
}
|
||||
// Relink
|
||||
oldp->m_nextp = nullptr;
|
||||
oldp->m_backp = nullptr;
|
||||
oldp->m_headtailp = this;
|
||||
oldp->m_iterpp = nullptr;
|
||||
oldp->m_headtailp = oldp;
|
||||
debugTreeChange(oldp, "-unlinkFrBkOut: ", __LINE__, true);
|
||||
return oldp;
|
||||
}
|
||||
|
|
@ -666,12 +681,12 @@ void AstNode::relink(VNRelinker* linkerp) {
|
|||
// Iterator fixup
|
||||
if (linkerp->m_iterpp) {
|
||||
// If we're iterating over a next() link, we need to follow links off the
|
||||
// NEW node. Thus we pass iteration information via a pointer in the node.
|
||||
// NEW node, which is always assumed to be what we are relinking to.
|
||||
// This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing
|
||||
// across every function.
|
||||
// If anyone has a cleaner way, I'd be grateful.
|
||||
*(linkerp->m_iterpp) = newp;
|
||||
newp->m_iterpp = linkerp->m_iterpp;
|
||||
*(newp->m_iterpp) = newp;
|
||||
}
|
||||
// Empty the linker so not used twice accidentally
|
||||
linkerp->m_backp = nullptr;
|
||||
|
|
@ -833,6 +848,7 @@ void AstNode::deleteNode() {
|
|||
this->m_op2p = reinterpret_cast<AstNode*>(0x1);
|
||||
this->m_op3p = reinterpret_cast<AstNode*>(0x1);
|
||||
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
|
||||
this->m_iterpp = reinterpret_cast<AstNode**>(0x1);
|
||||
if (
|
||||
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
|
||||
true
|
||||
|
|
@ -907,7 +923,7 @@ void AstNode::iterateChildren(VNVisitor& v) {
|
|||
if (m_op4p) m_op4p->iterateAndNext(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateChildrenConst(VNVisitor& v) {
|
||||
void AstNode::iterateChildrenConst(VNVisitorConst& v) {
|
||||
// This is a very hot function
|
||||
ASTNODE_PREFETCH(m_op1p);
|
||||
ASTNODE_PREFETCH(m_op2p);
|
||||
|
|
@ -948,13 +964,13 @@ void AstNode::iterateAndNext(VNVisitor& v) {
|
|||
niterp->m_iterpp = nullptr;
|
||||
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
|
||||
nodep = niterp;
|
||||
} else { // Unchanged node, just continue loop
|
||||
} else { // Unchanged node (though maybe updated m_next), just continue loop
|
||||
nodep = niterp->m_nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::iterateListBackwards(VNVisitor& v) {
|
||||
void AstNode::iterateListBackwardsConst(VNVisitorConst& v) {
|
||||
AstNode* nodep = this;
|
||||
while (nodep->m_nextp) nodep = nodep->m_nextp;
|
||||
while (nodep) {
|
||||
|
|
@ -968,14 +984,14 @@ void AstNode::iterateListBackwards(VNVisitor& v) {
|
|||
}
|
||||
}
|
||||
|
||||
void AstNode::iterateChildrenBackwards(VNVisitor& v) {
|
||||
if (m_op1p) m_op1p->iterateListBackwards(v);
|
||||
if (m_op2p) m_op2p->iterateListBackwards(v);
|
||||
if (m_op3p) m_op3p->iterateListBackwards(v);
|
||||
if (m_op4p) m_op4p->iterateListBackwards(v);
|
||||
void AstNode::iterateChildrenBackwardsConst(VNVisitorConst& v) {
|
||||
if (m_op1p) m_op1p->iterateListBackwardsConst(v);
|
||||
if (m_op2p) m_op2p->iterateListBackwardsConst(v);
|
||||
if (m_op3p) m_op3p->iterateListBackwardsConst(v);
|
||||
if (m_op4p) m_op4p->iterateListBackwardsConst(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateAndNextConst(VNVisitor& v) {
|
||||
void AstNode::iterateAndNextConst(VNVisitorConst& v) {
|
||||
// Keep following the current list even if edits change it
|
||||
AstNode* nodep = this;
|
||||
do {
|
||||
|
|
@ -1079,7 +1095,7 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
|
|||
//======================================================================
|
||||
// Debugging
|
||||
|
||||
void AstNode::checkTreeIter(const AstNode* prevBackp) const {
|
||||
void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
|
||||
// private: Check a tree and children
|
||||
UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent");
|
||||
switch (this->type()) {
|
||||
|
|
@ -1129,7 +1145,7 @@ void AstNode::checkIter() const {
|
|||
if (m_iterpp) {
|
||||
dumpPtrs(cout);
|
||||
// Perhaps something forgot to clear m_iterpp?
|
||||
this->v3fatalSrc("Iteration link should be nullptr");
|
||||
this->v3fatalSrc("Iteration link m_iterpp should be nullptr");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1342,7 +1358,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) {
|
|||
dtypeSetLogicUnsized(width, widthMin, numeric);
|
||||
} else {
|
||||
if (width == dtypep()->width() && widthMin == dtypep()->widthMin()
|
||||
&& numeric == dtypep()->numeric())
|
||||
&& numeric == dtypep()->numeric()
|
||||
// Enums need to become direct sizes to avoid later ENUMVALUE errors
|
||||
&& !VN_IS(dtypep()->skipRefToEnump(), EnumDType))
|
||||
return; // Correct already
|
||||
// FUTURE: We may be pointing at a two state data type, and this may
|
||||
// convert it to logic. Since the AstVar remains correct, we
|
||||
|
|
|
|||
180
src/V3Ast.h
180
src/V3Ast.h
|
|
@ -102,11 +102,11 @@ public:
|
|||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const VL_MT_SAFE { return m_e; }
|
||||
};
|
||||
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_MT_SAFE {
|
||||
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_PURE {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; }
|
||||
constexpr bool operator==(const VNType& lhs, VNType::en rhs) VL_PURE { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VNType::en lhs, const VNType& rhs) VL_PURE { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VNType& rhs) { return os << rhs.ascii(); }
|
||||
|
||||
// ######################################################################
|
||||
|
|
@ -470,7 +470,7 @@ public:
|
|||
_ENUM_MAX
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
const char* ascii() const VL_MT_SAFE {
|
||||
static const char* const names[] = {"%E-unk",
|
||||
"bit",
|
||||
"byte",
|
||||
|
|
@ -1097,21 +1097,21 @@ public:
|
|||
}
|
||||
//
|
||||
VNumRange() = default;
|
||||
VNumRange(int hi, int lo, bool littleEndian) { init(hi, lo, littleEndian); }
|
||||
VNumRange(int hi, int lo, bool ascending) { init(hi, lo, ascending); }
|
||||
VNumRange(int left, int right)
|
||||
: m_left{left}
|
||||
, m_right{right}
|
||||
, m_ranged{true} {}
|
||||
~VNumRange() = default;
|
||||
// MEMBERS
|
||||
void init(int hi, int lo, bool littleEndian) {
|
||||
void init(int hi, int lo, bool ascending) {
|
||||
if (lo > hi) {
|
||||
const int t = hi;
|
||||
hi = lo;
|
||||
lo = t;
|
||||
}
|
||||
m_left = littleEndian ? lo : hi;
|
||||
m_right = littleEndian ? hi : lo;
|
||||
m_left = ascending ? lo : hi;
|
||||
m_right = ascending ? hi : lo;
|
||||
m_ranged = true;
|
||||
}
|
||||
int left() const { return m_left; }
|
||||
|
|
@ -1122,10 +1122,10 @@ public:
|
|||
int lo() const VL_MT_SAFE {
|
||||
return m_left > m_right ? m_right : m_left;
|
||||
} // How to show a declaration
|
||||
int leftToRightInc() const { return littleEndian() ? 1 : -1; }
|
||||
int leftToRightInc() const { return ascending() ? 1 : -1; }
|
||||
int elements() const VL_MT_SAFE { return hi() - lo() + 1; }
|
||||
bool ranged() const { return m_ranged; }
|
||||
bool littleEndian() const { return m_left < m_right; }
|
||||
bool ascending() const { return m_left < m_right; }
|
||||
int hiMaxSelect() const {
|
||||
return (lo() < 0 ? hi() - lo() : hi());
|
||||
} // Maximum value a [] select may index
|
||||
|
|
@ -1373,13 +1373,38 @@ public:
|
|||
virtual ~VNDeleter() { doDeletes(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// VNVisitorConst -- Allows new functions to be called on each node
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
// This only has the constant fuctions for non-modifying visitors.
|
||||
// For more typical usage see VNVisitor
|
||||
|
||||
class VNVisitorConst VL_NOT_FINAL : public VNDeleter {
|
||||
friend class AstNode;
|
||||
|
||||
public:
|
||||
/// Call visit()s on nodep
|
||||
inline void iterateConst(AstNode* nodep);
|
||||
/// Call visit()s on nodep
|
||||
inline void iterateConstNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep's children
|
||||
inline void iterateChildrenConst(AstNode* nodep);
|
||||
/// Call visit()s on nodep's children in backp() order
|
||||
inline void iterateChildrenBackwardsConst(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
|
||||
inline void iterateAndNextConstNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
|
||||
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
|
||||
|
||||
virtual void visit(AstNode* nodep) = 0;
|
||||
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// VNVisitor -- Allows new functions to be called on each node
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
|
||||
class VNVisitor VL_NOT_FINAL : public VNDeleter {
|
||||
friend class AstNode;
|
||||
|
||||
class VNVisitor VL_NOT_FINAL : public VNVisitorConst {
|
||||
public:
|
||||
/// Call visit()s on nodep
|
||||
inline void iterate(AstNode* nodep);
|
||||
|
|
@ -1387,21 +1412,10 @@ public:
|
|||
inline void iterateNull(AstNode* nodep);
|
||||
/// Call visit()s on nodep's children
|
||||
inline void iterateChildren(AstNode* nodep);
|
||||
/// Call visit()s on nodep's children in backp() order
|
||||
inline void iterateChildrenBackwards(AstNode* nodep);
|
||||
/// Call visit()s on const nodep's children
|
||||
inline void iterateChildrenConst(AstNode* nodep);
|
||||
/// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list
|
||||
inline void iterateAndNextNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
|
||||
inline void iterateAndNextConstNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
|
||||
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
|
||||
/// Return edited nodep; see comments in V3Ast.cpp
|
||||
inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
|
||||
|
||||
virtual void visit(AstNode* nodep) = 0;
|
||||
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -1426,6 +1440,13 @@ protected:
|
|||
|
||||
public:
|
||||
VNRelinker() = default;
|
||||
~VNRelinker() {
|
||||
// Relink is needed so m_iterpp's get restored, e.g. can't have:
|
||||
// ->unlinkFrBack(relinker);
|
||||
// if (only_sometimes) relinker.relink(newp);
|
||||
UDEBUGONLY(
|
||||
UASSERT_STATIC(!m_backp, "Active linker must be relink()ed before destruction"););
|
||||
}
|
||||
inline void relink(AstNode* newp);
|
||||
AstNode* oldp() const { return m_oldp; }
|
||||
void dump(std::ostream& str = std::cout) const;
|
||||
|
|
@ -1545,7 +1566,7 @@ class AstNode VL_NOT_FINAL {
|
|||
private:
|
||||
AstNode* cloneTreeIter();
|
||||
AstNode* cloneTreeIterList();
|
||||
void checkTreeIter(const AstNode* prevBackp) const VL_MT_SAFE;
|
||||
void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE;
|
||||
bool gateTreeIter() const;
|
||||
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
|
||||
bool gateOnly);
|
||||
|
|
@ -1601,14 +1622,14 @@ public:
|
|||
// ACCESSORS
|
||||
VNType type() const VL_MT_SAFE { return m_type; }
|
||||
const char* typeName() const VL_MT_SAFE { return type().ascii(); } // See also prettyTypeName
|
||||
AstNode* nextp() const VL_MT_SAFE { return m_nextp; }
|
||||
AstNode* backp() const VL_MT_SAFE { return m_backp; }
|
||||
AstNode* nextp() const VL_MT_STABLE { return m_nextp; }
|
||||
AstNode* backp() const VL_MT_STABLE { return m_backp; }
|
||||
AstNode* abovep() const; // Parent node above, only when no nextp() as otherwise slow
|
||||
AstNode* op1p() const VL_MT_SAFE { return m_op1p; }
|
||||
AstNode* op2p() const VL_MT_SAFE { return m_op2p; }
|
||||
AstNode* op3p() const VL_MT_SAFE { return m_op3p; }
|
||||
AstNode* op4p() const VL_MT_SAFE { return m_op4p; }
|
||||
AstNodeDType* dtypep() const VL_MT_SAFE { return m_dtypep; }
|
||||
AstNode* op1p() const VL_MT_STABLE { return m_op1p; }
|
||||
AstNode* op2p() const VL_MT_STABLE { return m_op2p; }
|
||||
AstNode* op3p() const VL_MT_STABLE { return m_op3p; }
|
||||
AstNode* op4p() const VL_MT_STABLE { return m_op4p; }
|
||||
AstNodeDType* dtypep() const VL_MT_STABLE { return m_dtypep; }
|
||||
AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : nullptr); }
|
||||
AstNode* firstAbovep() const { // Returns nullptr when second or later in list
|
||||
return ((backp() && backp()->nextp() != this) ? backp() : nullptr);
|
||||
|
|
@ -1655,7 +1676,7 @@ public:
|
|||
static constexpr int INSTR_COUNT_PLI = 20; // PLI routines
|
||||
|
||||
// ACCESSORS
|
||||
virtual string name() const VL_MT_SAFE { return ""; }
|
||||
virtual string name() const VL_MT_STABLE { return ""; }
|
||||
virtual string origName() const { return ""; }
|
||||
virtual void name(const string& name) {
|
||||
this->v3fatalSrc("name() called on object without name() method");
|
||||
|
|
@ -1663,22 +1684,23 @@ public:
|
|||
virtual void tag(const string& text) {}
|
||||
virtual string tag() const { return ""; }
|
||||
virtual string verilogKwd() const { return ""; }
|
||||
string nameProtect() const VL_MT_SAFE; // Name with --protect-id applied
|
||||
string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied
|
||||
string origNameProtect() const; // origName with --protect-id applied
|
||||
string shortName() const; // Name with __PVT__ removed for concatenating scopes
|
||||
static string dedotName(const string& namein); // Name with dots removed
|
||||
static string prettyName(const string& namein); // Name for printing out to the user
|
||||
static string prettyName(const string& namein) VL_PURE; // Name for printing out to the user
|
||||
static string vpiName(const string& namein); // Name for vpi access
|
||||
static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors)
|
||||
return std::string{"'"} + prettyName(namein) + "'";
|
||||
}
|
||||
static string
|
||||
encodeName(const string& namein); // Encode user name into internal C representation
|
||||
// Encode user name into internal C representation
|
||||
static string encodeName(const string& namein);
|
||||
static string encodeNumber(int64_t num); // Encode number into internal C representation
|
||||
static string vcdName(const string& namein); // Name for printing out to vcd files
|
||||
string prettyName() const VL_MT_SAFE { return prettyName(name()); }
|
||||
string prettyName() const VL_MT_STABLE { return prettyName(name()); }
|
||||
string prettyNameQ() const { return prettyNameQ(name()); }
|
||||
string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name)
|
||||
// "VARREF" for error messages (NOT dtype's pretty name)
|
||||
string prettyTypeName() const VL_MT_STABLE;
|
||||
virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
|
||||
FileLine* fileline() const VL_MT_SAFE { return m_fileline; }
|
||||
void fileline(FileLine* fl) { m_fileline = fl; }
|
||||
|
|
@ -1697,25 +1719,25 @@ public:
|
|||
void protect(bool flag) { m_flags.protect = flag; }
|
||||
|
||||
// TODO stomp these width functions out, and call via dtypep() instead
|
||||
inline int width() const VL_MT_SAFE;
|
||||
inline int width() const VL_MT_STABLE;
|
||||
inline int widthMin() const;
|
||||
int widthMinV() const {
|
||||
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
|
||||
}
|
||||
int widthWords() const { return VL_WORDS_I(width()); }
|
||||
bool isQuad() const VL_MT_SAFE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
|
||||
bool isWide() const VL_MT_SAFE { return (width() > VL_QUADSIZE); }
|
||||
inline bool isDouble() const;
|
||||
inline bool isSigned() const;
|
||||
inline bool isString() const;
|
||||
bool isQuad() const VL_MT_STABLE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
|
||||
bool isWide() const VL_MT_STABLE { return (width() > VL_QUADSIZE); }
|
||||
inline bool isDouble() const VL_MT_STABLE;
|
||||
inline bool isSigned() const VL_MT_STABLE;
|
||||
inline bool isString() const VL_MT_STABLE;
|
||||
|
||||
// clang-format off
|
||||
VNUser user1u() const VL_MT_SAFE {
|
||||
VNUser user1u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0});
|
||||
}
|
||||
AstNode* user1p() const VL_MT_SAFE { return user1u().toNodep(); }
|
||||
AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); }
|
||||
void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; }
|
||||
void user1p(void* userp) { user1u(VNUser{userp}); }
|
||||
int user1() const { return user1u().toInt(); }
|
||||
|
|
@ -1724,12 +1746,12 @@ public:
|
|||
int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc()
|
||||
static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user2u() const VL_MT_SAFE {
|
||||
VNUser user2u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0});
|
||||
}
|
||||
AstNode* user2p() const VL_MT_SAFE { return user2u().toNodep(); }
|
||||
AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); }
|
||||
void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; }
|
||||
void user2p(void* userp) { user2u(VNUser{userp}); }
|
||||
int user2() const { return user2u().toInt(); }
|
||||
|
|
@ -1738,12 +1760,12 @@ public:
|
|||
int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc()
|
||||
static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user3u() const VL_MT_SAFE {
|
||||
VNUser user3u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0});
|
||||
}
|
||||
AstNode* user3p() const VL_MT_SAFE { return user3u().toNodep(); }
|
||||
AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); }
|
||||
void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; }
|
||||
void user3p(void* userp) { user3u(VNUser{userp}); }
|
||||
int user3() const { return user3u().toInt(); }
|
||||
|
|
@ -1752,12 +1774,12 @@ public:
|
|||
int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc()
|
||||
static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user4u() const VL_MT_SAFE {
|
||||
VNUser user4u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0});
|
||||
}
|
||||
AstNode* user4p() const VL_MT_SAFE { return user4u().toNodep(); }
|
||||
AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); }
|
||||
void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; }
|
||||
void user4p(void* userp) { user4u(VNUser{userp}); }
|
||||
int user4() const { return user4u().toInt(); }
|
||||
|
|
@ -1766,12 +1788,12 @@ public:
|
|||
int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc()
|
||||
static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user5u() const VL_MT_SAFE {
|
||||
VNUser user5u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0});
|
||||
}
|
||||
AstNode* user5p() const VL_MT_SAFE { return user5u().toNodep(); }
|
||||
AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); }
|
||||
void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; }
|
||||
void user5p(void* userp) { user5u(VNUser{userp}); }
|
||||
int user5() const { return user5u().toInt(); }
|
||||
|
|
@ -1907,7 +1929,7 @@ public:
|
|||
// Does tree of this == node2p?, not allowing non-isGateOptimizable
|
||||
inline bool sameGateTree(const AstNode* node2p) const;
|
||||
void deleteTree(); // Always deletes the next link
|
||||
void checkTree() const VL_MT_SAFE {
|
||||
void checkTree() const VL_MT_STABLE {
|
||||
if (v3Global.opt.debugCheck()) checkTreeIter(backp());
|
||||
}
|
||||
void checkIter() const;
|
||||
|
|
@ -1964,26 +1986,27 @@ public:
|
|||
virtual const char* broken() const { return nullptr; }
|
||||
|
||||
// INVOKERS
|
||||
virtual void accept(VNVisitor& v) = 0;
|
||||
virtual void accept(VNVisitorConst& v) = 0;
|
||||
|
||||
protected:
|
||||
// All VNVisitor related functions are called as methods off the visitor
|
||||
friend class VNVisitor;
|
||||
friend class VNVisitorConst;
|
||||
// Use instead VNVisitor::iterateChildren
|
||||
void iterateChildren(VNVisitor& v);
|
||||
// Use instead VNVisitor::iterateChildrenBackwards
|
||||
void iterateChildrenBackwards(VNVisitor& v);
|
||||
// Use instead VNVisitor::iterateChildrenBackwardsConst
|
||||
void iterateChildrenBackwardsConst(VNVisitorConst& v);
|
||||
// Use instead VNVisitor::iterateChildrenConst
|
||||
void iterateChildrenConst(VNVisitor& v);
|
||||
void iterateChildrenConst(VNVisitorConst& v);
|
||||
// Use instead VNVisitor::iterateAndNextNull
|
||||
void iterateAndNext(VNVisitor& v);
|
||||
// Use instead VNVisitor::iterateAndNextConstNull
|
||||
void iterateAndNextConst(VNVisitor& v);
|
||||
void iterateAndNextConst(VNVisitorConst& v);
|
||||
// Use instead VNVisitor::iterateSubtreeReturnEdits
|
||||
AstNode* iterateSubtreeReturnEdits(VNVisitor& v);
|
||||
|
||||
private:
|
||||
void iterateListBackwards(VNVisitor& v);
|
||||
void iterateListBackwardsConst(VNVisitorConst& v);
|
||||
|
||||
// For internal use only.
|
||||
// Note: specializations for particular node types are provided by 'astgen'
|
||||
|
|
@ -1992,7 +2015,7 @@ private:
|
|||
|
||||
// For internal use only.
|
||||
template <typename TargetType, typename DeclType>
|
||||
constexpr static bool uselessCast() {
|
||||
constexpr static bool uselessCast() VL_PURE {
|
||||
using NonRef = typename std::remove_reference<DeclType>::type;
|
||||
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
||||
using NonCV = typename std::remove_cv<NonPtr>::type;
|
||||
|
|
@ -2001,7 +2024,7 @@ private:
|
|||
|
||||
// For internal use only.
|
||||
template <typename TargetType, typename DeclType>
|
||||
constexpr static bool impossibleCast() {
|
||||
constexpr static bool impossibleCast() VL_PURE {
|
||||
using NonRef = typename std::remove_reference<DeclType>::type;
|
||||
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
||||
using NonCV = typename std::remove_cv<NonPtr>::type;
|
||||
|
|
@ -2035,7 +2058,7 @@ public:
|
|||
|
||||
// For use via the VN_AS macro only
|
||||
template <typename T, typename E>
|
||||
static T* privateAs(AstNode* nodep) VL_MT_SAFE {
|
||||
static T* privateAs(AstNode* nodep) VL_PURE {
|
||||
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
|
||||
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
|
||||
|
|
@ -2044,7 +2067,7 @@ public:
|
|||
return reinterpret_cast<T*>(nodep);
|
||||
}
|
||||
template <typename T, typename E>
|
||||
static const T* privateAs(const AstNode* nodep) VL_MT_SAFE {
|
||||
static const T* privateAs(const AstNode* nodep) VL_PURE {
|
||||
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
|
||||
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
|
||||
|
|
@ -2483,24 +2506,29 @@ struct std::equal_to<VNRef<T_Node>> final {
|
|||
//######################################################################
|
||||
// Inline VNVisitor METHODS
|
||||
|
||||
void VNVisitorConst::iterateConst(AstNode* nodep) { nodep->accept(*this); }
|
||||
void VNVisitorConst::iterateConstNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->accept(*this);
|
||||
}
|
||||
void VNVisitorConst::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
|
||||
void VNVisitorConst::iterateChildrenBackwardsConst(AstNode* nodep) {
|
||||
nodep->iterateChildrenBackwardsConst(*this);
|
||||
}
|
||||
void VNVisitorConst::iterateAndNextConstNullBackwards(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateListBackwardsConst(*this);
|
||||
}
|
||||
void VNVisitorConst::iterateAndNextConstNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
|
||||
}
|
||||
|
||||
void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); }
|
||||
void VNVisitor::iterateNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->accept(*this);
|
||||
}
|
||||
void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); }
|
||||
void VNVisitor::iterateChildrenBackwards(AstNode* nodep) {
|
||||
nodep->iterateChildrenBackwards(*this);
|
||||
}
|
||||
void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
|
||||
void VNVisitor::iterateAndNextNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this);
|
||||
}
|
||||
void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateListBackwards(*this);
|
||||
}
|
||||
void VNVisitor::iterateAndNextConstNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
|
||||
}
|
||||
AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
|
||||
return nodep->iterateSubtreeReturnEdits(*this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
//######################################################################
|
||||
// Inline METHODS
|
||||
|
||||
int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; }
|
||||
int AstNode::width() const VL_MT_STABLE { return dtypep() ? dtypep()->width() : 0; }
|
||||
int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; }
|
||||
bool AstNode::width1() const { // V3Const uses to know it can optimize
|
||||
return dtypep() && dtypep()->width() == 1;
|
||||
|
|
@ -33,13 +33,13 @@ bool AstNode::width1() const { // V3Const uses to know it can optimize
|
|||
int AstNode::widthInstrs() const {
|
||||
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
|
||||
}
|
||||
bool AstNode::isDouble() const VL_MT_SAFE {
|
||||
bool AstNode::isDouble() const VL_MT_STABLE {
|
||||
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
|
||||
}
|
||||
bool AstNode::isString() const VL_MT_SAFE {
|
||||
bool AstNode::isString() const VL_MT_STABLE {
|
||||
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
|
||||
}
|
||||
bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
|
||||
bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); }
|
||||
|
||||
bool AstNode::isZero() const {
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
|
||||
|
|
@ -61,12 +61,12 @@ bool AstNode::sameGateTree(const AstNode* node2p) const {
|
|||
return sameTreeIter(this, node2p, true, true);
|
||||
}
|
||||
|
||||
int AstNodeArrayDType::left() const VL_MT_SAFE { return rangep()->leftConst(); }
|
||||
int AstNodeArrayDType::right() const VL_MT_SAFE { return rangep()->rightConst(); }
|
||||
int AstNodeArrayDType::hi() const VL_MT_SAFE { return rangep()->hiConst(); }
|
||||
int AstNodeArrayDType::lo() const VL_MT_SAFE { return rangep()->loConst(); }
|
||||
int AstNodeArrayDType::elementsConst() const VL_MT_SAFE { return rangep()->elementsConst(); }
|
||||
VNumRange AstNodeArrayDType::declRange() const VL_MT_SAFE { return VNumRange{left(), right()}; }
|
||||
int AstNodeArrayDType::left() const VL_MT_STABLE { return rangep()->leftConst(); }
|
||||
int AstNodeArrayDType::right() const VL_MT_STABLE { return rangep()->rightConst(); }
|
||||
int AstNodeArrayDType::hi() const VL_MT_STABLE { return rangep()->hiConst(); }
|
||||
int AstNodeArrayDType::lo() const VL_MT_STABLE { return rangep()->loConst(); }
|
||||
int AstNodeArrayDType::elementsConst() const VL_MT_STABLE { return rangep()->elementsConst(); }
|
||||
VNumRange AstNodeArrayDType::declRange() const VL_MT_STABLE { return VNumRange{left(), right()}; }
|
||||
|
||||
AstRange::AstRange(FileLine* fl, int left, int right)
|
||||
: ASTGEN_SUPER_Range(fl) {
|
||||
|
|
@ -78,16 +78,16 @@ AstRange::AstRange(FileLine* fl, const VNumRange& range)
|
|||
leftp(new AstConst{fl, static_cast<uint32_t>(range.left())});
|
||||
rightp(new AstConst{fl, static_cast<uint32_t>(range.right())});
|
||||
}
|
||||
int AstRange::leftConst() const {
|
||||
int AstRange::leftConst() const VL_MT_STABLE {
|
||||
AstConst* const constp = VN_CAST(leftp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
int AstRange::rightConst() const {
|
||||
int AstRange::rightConst() const VL_MT_STABLE {
|
||||
AstConst* const constp = VN_CAST(rightp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
|
||||
int AstQueueDType::boundConst() const VL_MT_SAFE {
|
||||
int AstQueueDType::boundConst() const VL_MT_STABLE {
|
||||
AstConst* const constp = VN_CAST(boundp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
|
|
@ -123,8 +123,8 @@ int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nra
|
|||
int AstBasicDType::elements() const {
|
||||
return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements());
|
||||
}
|
||||
bool AstBasicDType::littleEndian() const {
|
||||
return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian());
|
||||
bool AstBasicDType::ascending() const {
|
||||
return (rangep() ? rangep()->ascending() : m.m_nrange.ascending());
|
||||
}
|
||||
|
||||
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ public:
|
|||
// Integral or packed, allowed inside an unpacked union/struct
|
||||
virtual bool isIntegralOrPacked() const { return !isCompound(); }
|
||||
// (Slow) recurse down to find basic data type
|
||||
virtual AstBasicDType* basicp() const = 0;
|
||||
virtual AstBasicDType* basicp() const VL_MT_STABLE = 0;
|
||||
// recurses over typedefs/const/enum to next non-typeref type
|
||||
virtual AstNodeDType* skipRefp() const = 0;
|
||||
virtual AstNodeDType* skipRefp() const VL_MT_STABLE = 0;
|
||||
// recurses over typedefs to next non-typeref-or-const type
|
||||
virtual AstNodeDType* skipRefToConstp() const = 0;
|
||||
// recurses over typedefs/const to next non-typeref-or-enum/struct type
|
||||
|
|
@ -86,7 +86,7 @@ public:
|
|||
// Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
virtual bool similarDType(const AstNodeDType* samep) const = 0;
|
||||
// Iff has a non-null subDTypep(), as generic node function
|
||||
virtual AstNodeDType* subDTypep() const { return nullptr; }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_SAFE { return nullptr; }
|
||||
virtual bool isFourstate() const;
|
||||
// Ideally an IEEE $typename
|
||||
virtual string prettyDTypeName() const { return prettyTypeName(); }
|
||||
|
|
@ -126,12 +126,13 @@ public:
|
|||
const char* charIQWN() const {
|
||||
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
|
||||
}
|
||||
string cType(const string& name, bool forFunc, bool isRef) const VL_MT_SAFE;
|
||||
bool isLiteralType() const VL_MT_SAFE; // Represents a C++ LiteralType? (can be constexpr)
|
||||
string cType(const string& name, bool forFunc, bool isRef) const VL_MT_STABLE;
|
||||
// Represents a C++ LiteralType? (can be constexpr)
|
||||
bool isLiteralType() const VL_MT_STABLE;
|
||||
|
||||
private:
|
||||
class CTypeRecursed;
|
||||
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_SAFE;
|
||||
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_STABLE;
|
||||
};
|
||||
class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
|
||||
// Array data type, ie "some_dtype var_name [2:0]"
|
||||
|
|
@ -170,29 +171,29 @@ public:
|
|||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE {
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE {
|
||||
return subDTypep()->basicp();
|
||||
} // (Slow) recurse down to find basic data type
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override {
|
||||
return elementsConst() * subDTypep()->widthTotalBytes();
|
||||
}
|
||||
inline int left() const;
|
||||
inline int right() const;
|
||||
inline int hi() const;
|
||||
inline int lo() const;
|
||||
inline int elementsConst() const;
|
||||
inline VNumRange declRange() const;
|
||||
inline int left() const VL_MT_STABLE;
|
||||
inline int right() const VL_MT_STABLE;
|
||||
inline int hi() const VL_MT_STABLE;
|
||||
inline int lo() const VL_MT_STABLE;
|
||||
inline int elementsConst() const VL_MT_STABLE;
|
||||
inline VNumRange declRange() const VL_MT_STABLE;
|
||||
};
|
||||
class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
|
||||
// A struct or union; common handling
|
||||
|
|
@ -231,7 +232,7 @@ public:
|
|||
: VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
BasicDType));
|
||||
}
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
|
|
@ -241,14 +242,14 @@ public:
|
|||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
return this == samep; // We don't compare members, require exact equivalence
|
||||
}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool packed() const VL_MT_SAFE { return m_packed; }
|
||||
void packed(bool flag) { m_packed = flag; }
|
||||
// packed() but as don't support unpacked, presently all structs
|
||||
static bool packedUnsup() { return true; }
|
||||
void isFourstate(bool flag) { m_isFourstate = flag; }
|
||||
bool isFourstate() const override { return m_isFourstate; }
|
||||
bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; }
|
||||
void clearCache() { m_members.clear(); }
|
||||
void repairMemberCache();
|
||||
AstMemberDType* findMember(const string& name) const {
|
||||
|
|
@ -280,7 +281,7 @@ public:
|
|||
this->valuep(valuep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstEnumItem;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
|
|
@ -336,7 +337,7 @@ public:
|
|||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
|
|
@ -345,13 +346,13 @@ public:
|
|||
AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; }
|
||||
void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); }
|
||||
//
|
||||
AstNodeDType* keyDTypep() const VL_MT_SAFE {
|
||||
AstNodeDType* keyDTypep() const VL_MT_STABLE {
|
||||
return m_keyDTypep ? m_keyDTypep : keyChildDTypep();
|
||||
}
|
||||
void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
|
|
@ -401,14 +402,11 @@ public:
|
|||
ASTGEN_MEMBERS_AstBasicDType;
|
||||
void dump(std::ostream& str) const override;
|
||||
// width/widthMin/numeric compared elsewhere
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
|
||||
return m == sp->m;
|
||||
}
|
||||
bool same(const AstNode* samep) const override;
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
return type() == samep->type() && same(samep);
|
||||
}
|
||||
string name() const override { return m.m_keyword.ascii(); }
|
||||
string name() const override VL_MT_STABLE { return m.m_keyword.ascii(); }
|
||||
string prettyDTypeName() const override;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(dtypep() != this);
|
||||
|
|
@ -423,8 +421,8 @@ public:
|
|||
}
|
||||
}
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return (AstBasicDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return (AstBasicDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
|
|
@ -467,9 +465,9 @@ public:
|
|||
inline int hi() const;
|
||||
inline int lo() const;
|
||||
inline int elements() const;
|
||||
int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration
|
||||
int right() const { return littleEndian() ? hi() : lo(); }
|
||||
inline bool littleEndian() const;
|
||||
int left() const { return ascending() ? lo() : hi(); } // How to show a declaration
|
||||
int right() const { return ascending() ? hi() : lo(); }
|
||||
inline bool ascending() const;
|
||||
bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; }
|
||||
bool untyped() const { return keyword() == VBasicDTypeKwd::UNTYPED; }
|
||||
VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; }
|
||||
|
|
@ -491,13 +489,13 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstBracketArrayDType;
|
||||
bool similarDType(const AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); }
|
||||
AstNodeDType* subDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return childDTypep(); }
|
||||
// METHODS
|
||||
// Will be removed in V3Width, which relies on this
|
||||
// being a child not a dtype pointed node
|
||||
bool maybePointedTo() const override { return false; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); }
|
||||
|
|
@ -530,19 +528,19 @@ public:
|
|||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override;
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
string name() const override VL_MT_STABLE;
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return 0; }
|
||||
int widthTotalBytes() const override { return 0; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
AstNodeDType* subDTypep() const override { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
AstClass* classp() const { return m_classp; }
|
||||
AstClass* classp() const VL_MT_STABLE { return m_classp; }
|
||||
void classp(AstClass* nodep) { m_classp = nodep; }
|
||||
bool isCompound() const override { return true; }
|
||||
};
|
||||
|
|
@ -578,13 +576,15 @@ public:
|
|||
return skipRefp()->similarDType(samep->skipRefp());
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
|
|
@ -625,18 +625,20 @@ public:
|
|||
return type() == samep->type() && same(samep);
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
void* containerp() const { return m_containerp; }
|
||||
// METHODS
|
||||
// op1 = Range of variable
|
||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool isCompound() const override { return false; }
|
||||
};
|
||||
|
|
@ -679,15 +681,15 @@ public:
|
|||
string prettyDTypeName() const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
|
|
@ -706,13 +708,13 @@ public:
|
|||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
|
|
@ -756,17 +758,19 @@ public:
|
|||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
|
|
@ -818,8 +822,8 @@ public:
|
|||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
void cloneRelink() override;
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
|
|
@ -872,7 +876,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstMemberDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
const char* broken() const override {
|
||||
|
|
@ -883,7 +887,9 @@ public:
|
|||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
|
|
@ -891,10 +897,10 @@ public:
|
|||
//
|
||||
// (Slow) recurse down to find basic data type (Note don't need virtual -
|
||||
// AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
// op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
|
|
@ -931,9 +937,11 @@ public:
|
|||
ASTGEN_MEMBERS_AstParamTypeDType;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
|
|
@ -944,7 +952,7 @@ public:
|
|||
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
// METHODS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
|
|
@ -967,8 +975,8 @@ public:
|
|||
AstNodeDType* dtypep() const { return nullptr; }
|
||||
// METHODS
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
|
|
@ -1022,17 +1030,17 @@ public:
|
|||
void dumpSmall(std::ostream& str) const override;
|
||||
string prettyDTypeName() const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
inline int boundConst() const;
|
||||
inline int boundConst() const VL_MT_STABLE;
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
|
|
@ -1082,15 +1090,15 @@ public:
|
|||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
string prettyDTypeName() const override {
|
||||
return subDTypep() ? prettyName(subDTypep()->name()) : prettyName();
|
||||
}
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE {
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE {
|
||||
return subDTypep() ? subDTypep()->basicp() : nullptr;
|
||||
}
|
||||
AstNodeDType* subDTypep() const override;
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE;
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE {
|
||||
// Skip past both the Ref and the Typedef
|
||||
if (subDTypep()) {
|
||||
return subDTypep()->skipRefp();
|
||||
|
|
@ -1119,9 +1127,9 @@ public:
|
|||
int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||
AstTypedef* typedefp() const { return m_typedefp; }
|
||||
AstTypedef* typedefp() const VL_MT_SAFE { return m_typedefp; }
|
||||
void typedefp(AstTypedef* nodep) { m_typedefp = nodep; }
|
||||
AstNodeDType* refDTypep() const { return m_refDTypep; }
|
||||
AstNodeDType* refDTypep() const VL_MT_SAFE { return m_refDTypep; }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return refDTypep(); }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
|
|
@ -1163,13 +1171,15 @@ public:
|
|||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
// op1 = Range of variable
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return sizeof(std::map<std::string, std::string>); }
|
||||
|
|
@ -1201,13 +1211,15 @@ public:
|
|||
bool similarDType(const AstNodeDType* samep) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
|
|
@ -1226,13 +1238,13 @@ public:
|
|||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
|
|
@ -1266,15 +1278,15 @@ public:
|
|||
bool similarDType(const AstNodeDType* samep) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return sizeof(std::map<std::string, std::string>); }
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ public:
|
|||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool isGateOptimizable() const override;
|
||||
string dotted() const { return m_dotted; } // * = Scope name or ""
|
||||
string inlinedDots() const { return m_inlinedDots; }
|
||||
|
|
@ -322,7 +322,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstNodeTermop;
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(VNVisitor& v) {}
|
||||
void iterateChildren(VNVisitorConst& v) {}
|
||||
void dump(std::ostream& str) const override;
|
||||
};
|
||||
class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
|
||||
|
|
@ -474,7 +474,7 @@ public:
|
|||
const char* broken() const override;
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
void cloneRelink() override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
VAccess access() const { return m_access; }
|
||||
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
|
||||
|
|
@ -492,7 +492,7 @@ public:
|
|||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(VNVisitor& v) {}
|
||||
void iterateChildren(VNVisitorConst& v) {}
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
|
|
@ -532,7 +532,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstArg;
|
||||
bool hasDType() const override { return false; }
|
||||
string name() const override { return m_name; } // * = Pin name, ""=go by number
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
|
||||
|
||||
|
|
@ -610,7 +610,7 @@ public:
|
|||
this->addPinsp(pinsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCMethodHard;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCMethodHard* asamep = static_cast<const AstCMethodHard*>(samep);
|
||||
|
|
@ -644,7 +644,7 @@ public:
|
|||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
||||
};
|
||||
class AstCastParse final : public AstNodeExpr {
|
||||
// Cast to appropriate type, where we haven't determined yet what the data type is
|
||||
|
|
@ -689,7 +689,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstCellArrayRef;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Array name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
|
|
@ -710,7 +710,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstCellRef;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Array name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
|
|
@ -746,7 +746,7 @@ public:
|
|||
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
|
||||
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
|
||||
AstNodeModule* classOrPackagep() const;
|
||||
|
|
@ -990,7 +990,7 @@ public:
|
|||
initWithNumber();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConst;
|
||||
string name() const override { return num().ascii(); } // * = Value
|
||||
string name() const override VL_MT_STABLE { return num().ascii(); } // * = Value
|
||||
const V3Number& num() const VL_MT_SAFE { return m_num; } // * = Value
|
||||
V3Number& num() { return m_num; } // * = Value
|
||||
uint32_t toUInt() const { return num().toUInt(); }
|
||||
|
|
@ -1058,7 +1058,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstEnumItemRef;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return itemp()->name(); }
|
||||
string name() const override VL_MT_STABLE { return itemp()->name(); }
|
||||
int instrCount() const override { return 0; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override {
|
||||
|
|
@ -1068,7 +1068,7 @@ public:
|
|||
const AstEnumItemRef* const sp = static_cast<const AstEnumItemRef*>(samep);
|
||||
return itemp() == sp->itemp();
|
||||
}
|
||||
AstEnumItem* itemp() const { return m_itemp; }
|
||||
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -1109,9 +1109,50 @@ public:
|
|||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpen final : public AstNodeExpr {
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
// @astgen op3 := modep : AstNodeExpr
|
||||
public:
|
||||
AstFOpen(FileLine* fl, AstNodeExpr* filenamep, AstNodeExpr* modep)
|
||||
: ASTGEN_SUPER_FOpen(fl) {
|
||||
this->filenamep(filenamep);
|
||||
this->modep(modep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpen;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpenMcd final : public AstNodeExpr {
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
public:
|
||||
AstFOpenMcd(FileLine* fl, AstNodeExpr* filenamep)
|
||||
: ASTGEN_SUPER_FOpenMcd(fl) {
|
||||
this->filenamep(filenamep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpenMcd;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFRead final : public AstNodeExpr {
|
||||
// @astgen op1 := memp : AstNode // VarRef for result
|
||||
// @astgen op2 := filep : AstNode // file (must be a VarRef)
|
||||
|
|
@ -1168,7 +1209,7 @@ public:
|
|||
this->filep(filep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFScanF;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string verilogKwd() const override { return "$fscanf"; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
|
|
@ -1365,7 +1406,7 @@ public:
|
|||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool index() const { return m_index; }
|
||||
};
|
||||
|
|
@ -1391,7 +1432,7 @@ public:
|
|||
void cloneRelink() override;
|
||||
const char* broken() const override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
|
|
@ -1456,7 +1497,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstParseRef;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstParseRef* const asamep = static_cast<const AstParseRef*>(samep);
|
||||
return (expect() == asamep->expect() && m_name == asamep->m_name);
|
||||
|
|
@ -1533,7 +1574,7 @@ public:
|
|||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
||||
};
|
||||
class AstRand final : public AstNodeExpr {
|
||||
// $random/$random(seed) or $urandom/$urandom(seed)
|
||||
|
|
@ -1579,6 +1620,26 @@ public:
|
|||
bool reset() const { return m_reset; }
|
||||
bool urandom() const { return m_urandom; }
|
||||
};
|
||||
class AstRandRNG final : public AstNodeExpr {
|
||||
// Random used in a class using VlRNG
|
||||
// Return a random number, based upon width()
|
||||
public:
|
||||
AstRandRNG(FileLine* fl, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_RandRNG(fl) {
|
||||
dtypep(dtp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstRandRNG;
|
||||
string emitVerilog() override { return "%f$rngrandom()"; }
|
||||
string emitC() override {
|
||||
return isWide() ? "VL_RANDOM_RNG_%nq(__Vm_rng, %nw, %P)" //
|
||||
: "VL_RANDOM_RNG_%nq(__Vm_rng)";
|
||||
}
|
||||
bool cleanOut() const override { return false; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstRose final : public AstNodeExpr {
|
||||
// Verilog $rose
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
|
|
@ -1630,7 +1691,7 @@ public:
|
|||
addExprsp(exprsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSFormatF;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return text() == static_cast<const AstSFormatF*>(samep)->text();
|
||||
|
|
@ -1665,7 +1726,7 @@ public:
|
|||
this->fromp(fromp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSScanF;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string verilogKwd() const override { return "$sscanf"; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
|
|
@ -1850,7 +1911,7 @@ public:
|
|||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_AstStructSel;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
|
|
@ -1931,7 +1992,7 @@ public:
|
|||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool cleanOut() const override { return true; }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
||||
};
|
||||
class AstTimePrecision final : public AstNodeExpr {
|
||||
// Verilog $timeprecision
|
||||
|
|
@ -2159,7 +2220,7 @@ public:
|
|||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opCompareNN(lhs, rhs, m_ignoreCase);
|
||||
}
|
||||
string name() const override { return m_ignoreCase ? "icompare" : "compare"; }
|
||||
string name() const override VL_MT_STABLE { return m_ignoreCase ? "icompare" : "compare"; }
|
||||
string emitVerilog() override {
|
||||
return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))";
|
||||
}
|
||||
|
|
@ -2364,6 +2425,7 @@ public:
|
|||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
AstNode* charp() const { return rhsp(); }
|
||||
|
|
@ -2382,7 +2444,7 @@ public:
|
|||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opGetcN(lhs, rhs);
|
||||
}
|
||||
string name() const override { return "getc"; }
|
||||
string name() const override VL_MT_STABLE { return "getc"; }
|
||||
string emitVerilog() override { return "%k(%l.getc(%r))"; }
|
||||
string emitC() override { return "VL_GETC_N(%li,%ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
|
|
@ -4012,7 +4074,6 @@ public:
|
|||
BROKEN_RTN(!fromp());
|
||||
return nullptr;
|
||||
}
|
||||
void dump(std::ostream& str) const override;
|
||||
};
|
||||
class AstNew final : public AstNodeFTaskRef {
|
||||
// New as constructor
|
||||
|
|
@ -4263,7 +4324,7 @@ public:
|
|||
const V3Number& ths) override {
|
||||
out.opPutcN(lhs, rhs, ths);
|
||||
}
|
||||
string name() const override { return "putc"; }
|
||||
string name() const override VL_MT_STABLE { return "putc"; }
|
||||
string emitVerilog() override { return "%k(%l.putc(%r,%t))"; }
|
||||
string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
|
|
@ -4370,7 +4431,7 @@ public:
|
|||
const V3Number& ths) override {
|
||||
out.opSubstrN(lhs, rhs, ths);
|
||||
}
|
||||
string name() const override { return "substr"; }
|
||||
string name() const override VL_MT_STABLE { return "substr"; }
|
||||
string emitVerilog() override { return "%k(%l.substr(%r,%t))"; }
|
||||
string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
|
|
@ -4447,7 +4508,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstAtoN;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); }
|
||||
string name() const override {
|
||||
string name() const override VL_MT_STABLE {
|
||||
switch (m_fmt) {
|
||||
case ATOI: return "atoi";
|
||||
case ATOHEX: return "atohex";
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ protected:
|
|||
public:
|
||||
ASTGEN_MEMBERS_AstNodeBlock;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; } // * = Block name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool unnamed() const { return m_unnamed; }
|
||||
bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); }
|
||||
|
|
@ -118,7 +118,7 @@ protected:
|
|||
public:
|
||||
ASTGEN_MEMBERS_AstNodeFTask;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); }
|
||||
// {AstFunc only} op1 = Range output variable
|
||||
|
|
@ -186,7 +186,7 @@ public:
|
|||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstNodeFile;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstNodeModule VL_NOT_FINAL : public AstNode {
|
||||
|
|
@ -234,7 +234,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstNodeModule;
|
||||
void dump(std::ostream& str) const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
virtual bool timescaleMatters() const = 0;
|
||||
// ACCESSORS
|
||||
void name(const string& name) override { m_name = name; }
|
||||
|
|
@ -373,7 +373,7 @@ public:
|
|||
this->addPasssp(passsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstNodeCoverOrAssert;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool same(const AstNode* samep) const override { return samep->name() == name(); }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
|
|
@ -512,7 +512,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstActive;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
// Statements are broken into pieces, as some must come before others.
|
||||
|
|
@ -537,7 +537,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstBind;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Bind Target name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Bind Target name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
};
|
||||
class AstCFunc final : public AstNode {
|
||||
|
|
@ -607,7 +607,7 @@ public:
|
|||
m_dpiTraceInit = false;
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
|
|
@ -702,7 +702,7 @@ public:
|
|||
, m_useType{useType} {}
|
||||
ASTGEN_MEMBERS_AstCUse;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
VUseType useType() const { return m_useType; }
|
||||
};
|
||||
class AstCaseItem final : public AstNode {
|
||||
|
|
@ -755,7 +755,7 @@ public:
|
|||
const char* broken() const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Cell name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string origName() const override { return m_origName; } // * = Original name
|
||||
void origName(const string& name) { m_origName = name; }
|
||||
|
|
@ -794,7 +794,7 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
const char* broken() const override;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Cell name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
||||
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void scopep(AstScope* scp) { m_scopep = scp; }
|
||||
|
|
@ -845,7 +845,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstClocking;
|
||||
void dump(std::ostream& str) const override;
|
||||
std::string name() const override { return m_name; }
|
||||
std::string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool isDefault() const { return m_isDefault; }
|
||||
bool isGlobal() const { return m_isGlobal; }
|
||||
};
|
||||
|
|
@ -863,8 +863,8 @@ public:
|
|||
: ASTGEN_SUPER_ClockingItem(fl) {
|
||||
m_direction = direction;
|
||||
this->skewp(skewp);
|
||||
if (AstAssign* const assignp = VN_CAST(clockingDeclp, Assign)) {
|
||||
this->assignp(assignp);
|
||||
if (AstAssign* const clkAssignp = VN_CAST(clockingDeclp, Assign)) {
|
||||
this->assignp(clkAssignp);
|
||||
} else {
|
||||
exprp(VN_AS(clockingDeclp, NodeExpr));
|
||||
}
|
||||
|
|
@ -916,7 +916,7 @@ public:
|
|||
, m_path{path} {
|
||||
this->rhsp(rhsp);
|
||||
}
|
||||
string name() const override { return m_name; } // * = Scope name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
||||
ASTGEN_MEMBERS_AstDefParam;
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
string path() const { return m_path; }
|
||||
|
|
@ -934,7 +934,7 @@ public:
|
|||
, m_name{vname}
|
||||
, m_cname{cname} {}
|
||||
ASTGEN_MEMBERS_AstDpiExport;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string cname() const { return m_cname; }
|
||||
void cname(const string& cname) { m_cname = cname; }
|
||||
|
|
@ -952,7 +952,7 @@ public:
|
|||
BROKEN_RTN(!fmtp());
|
||||
return nullptr;
|
||||
}
|
||||
string verilogKwd() const override { return (string("$") + string(displayType().ascii())); }
|
||||
string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
|
|
@ -995,7 +995,7 @@ public:
|
|||
BROKEN_RTN(!m_depGraphp);
|
||||
return nullptr;
|
||||
}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
V3Graph* depGraphp() { return m_depGraphp; }
|
||||
const V3Graph* depGraphp() const { return m_depGraphp; }
|
||||
};
|
||||
|
|
@ -1033,7 +1033,7 @@ public:
|
|||
AstIntfRef(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_IntfRef(fl)
|
||||
, m_name{name} {}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
ASTGEN_MEMBERS_AstIntfRef;
|
||||
};
|
||||
class AstMTaskBody final : public AstNode {
|
||||
|
|
@ -1070,7 +1070,7 @@ public:
|
|||
, m_name{name} {
|
||||
this->addVarsp(varsp);
|
||||
}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
ASTGEN_MEMBERS_AstModport;
|
||||
};
|
||||
|
|
@ -1092,7 +1092,7 @@ public:
|
|||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool isImport() const { return !m_export; }
|
||||
bool isExport() const { return m_export; }
|
||||
AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable
|
||||
|
|
@ -1115,7 +1115,7 @@ public:
|
|||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void direction(const VDirection& flag) { m_direction = flag; }
|
||||
VDirection direction() const { return m_direction; }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
|
|
@ -1149,9 +1149,9 @@ public:
|
|||
ASTGEN_MEMBERS_AstNetlist;
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override { V3ERROR_NA; }
|
||||
string name() const override { return "$root"; }
|
||||
string name() const override VL_MT_STABLE { return "$root"; }
|
||||
void dump(std::ostream& str) const override;
|
||||
AstNodeModule* topModulep() const { // Top module in hierarchy
|
||||
AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy
|
||||
return modulesp(); // First one in the list, for now
|
||||
}
|
||||
AstTypeTable* typeTablep() { return m_typeTablep; }
|
||||
|
|
@ -1198,7 +1198,7 @@ public:
|
|||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
};
|
||||
|
|
@ -1224,7 +1224,7 @@ public:
|
|||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
};
|
||||
|
|
@ -1250,7 +1250,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstPin;
|
||||
void dump(std::ostream& str) const override;
|
||||
const char* broken() const override;
|
||||
string name() const override { return m_name; } // * = Pin name, ""=go by number
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string prettyOperatorName() const override;
|
||||
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
|
||||
|
|
@ -1278,7 +1278,7 @@ public:
|
|||
, m_pinNum{pinnum}
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstPort;
|
||||
string name() const override { return m_name; } // * = Port name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Port name
|
||||
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
|
||||
};
|
||||
class AstPragma final : public AstNode {
|
||||
|
|
@ -1356,11 +1356,11 @@ public:
|
|||
void cloneRelink() override;
|
||||
const char* broken() const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override { return m_name; } // * = Scope name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void dump(std::ostream& str) const override;
|
||||
string nameDotless() const;
|
||||
string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); }
|
||||
string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); }
|
||||
AstNodeModule* modp() const { return m_modp; }
|
||||
//
|
||||
AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; }
|
||||
|
|
@ -1544,9 +1544,11 @@ public:
|
|||
ASTGEN_MEMBERS_AstTypedef;
|
||||
void dump(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
// METHODS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
|
|
@ -1566,7 +1568,7 @@ public:
|
|||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstTypedefFwd;
|
||||
// METHODS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
};
|
||||
class AstUdpTable final : public AstNode {
|
||||
|
|
@ -1586,7 +1588,7 @@ public:
|
|||
: ASTGEN_SUPER_UdpTableLine(fl)
|
||||
, m_text{text} {}
|
||||
ASTGEN_MEMBERS_AstUdpTableLine;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string text() const { return m_text; }
|
||||
};
|
||||
class AstVar final : public AstNode {
|
||||
|
|
@ -1756,7 +1758,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstVar;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override VL_MT_SAFE { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string origName() const override { return m_origName; } // * = Original name
|
||||
|
|
@ -1787,17 +1789,17 @@ public:
|
|||
string dpiTmpVarType(const string& varName) const;
|
||||
// Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "",
|
||||
bool asRef = false) const VL_MT_SAFE;
|
||||
bool asRef = false) const VL_MT_STABLE;
|
||||
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
|
||||
string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration
|
||||
void combineType(VVarType type);
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* dtypeSkipRefp() const VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* dtypeSkipRefp() const VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
// (Slow) recurse down to find basic data type (Note don't need virtual -
|
||||
// AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_SAFE {
|
||||
AstBasicDType* basicp() const VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
void ansi(bool flag) { m_ansi = flag; }
|
||||
|
|
@ -1996,11 +1998,11 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override { return scopep()->name() + "->" + varp()->name(); }
|
||||
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
|
||||
void dump(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under
|
||||
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
|
||||
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
|
||||
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
void trace(bool flag) { m_trace = flag; }
|
||||
|
|
@ -2114,7 +2116,9 @@ class AstClass final : public AstNodeModule {
|
|||
AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under
|
||||
bool m_extended = false; // Is extension or extended by other classes
|
||||
bool m_interfaceClass = false; // Interface class
|
||||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||
bool m_virtual = false; // Virtual class
|
||||
bool m_parameterized = false; // Parameterized class
|
||||
void insertCache(AstNode* nodep);
|
||||
|
||||
public:
|
||||
|
|
@ -2146,9 +2150,15 @@ public:
|
|||
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
|
||||
bool isVirtual() const { return m_virtual; }
|
||||
void isVirtual(bool flag) { m_virtual = flag; }
|
||||
bool needRNG() const { return m_needRNG; }
|
||||
void needRNG(bool flag) { m_needRNG = flag; }
|
||||
bool isParameterized() const { return m_parameterized; }
|
||||
void isParameterized(bool flag) { m_parameterized = flag; }
|
||||
// Return true if this class is an extension of base class (SLOW)
|
||||
// Accepts nullptrs
|
||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||
// Return the lowest class extended from, or this class
|
||||
AstClass* baseMostClassp();
|
||||
};
|
||||
class AstClassPackage final : public AstNodeModule {
|
||||
// The static information portion of a class (treated similarly to a package)
|
||||
|
|
@ -2334,20 +2344,20 @@ public:
|
|||
inline AstRange(FileLine* fl, int left, int right);
|
||||
inline AstRange(FileLine* fl, const VNumRange& range);
|
||||
ASTGEN_MEMBERS_AstRange;
|
||||
inline int leftConst() const VL_MT_SAFE;
|
||||
inline int rightConst() const VL_MT_SAFE;
|
||||
int hiConst() const VL_MT_SAFE {
|
||||
inline int leftConst() const VL_MT_STABLE;
|
||||
inline int rightConst() const VL_MT_STABLE;
|
||||
int hiConst() const VL_MT_STABLE {
|
||||
const int l = leftConst();
|
||||
const int r = rightConst();
|
||||
return l > r ? l : r;
|
||||
}
|
||||
int loConst() const VL_MT_SAFE {
|
||||
int loConst() const VL_MT_STABLE {
|
||||
const int l = leftConst();
|
||||
const int r = rightConst();
|
||||
return l > r ? r : l;
|
||||
}
|
||||
int elementsConst() const VL_MT_SAFE { return hiConst() - loConst() + 1; }
|
||||
bool littleEndian() const { return leftConst() < rightConst(); }
|
||||
int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; }
|
||||
bool ascending() const { return leftConst() < rightConst(); }
|
||||
void dump(std::ostream& str) const override;
|
||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
|
|
@ -2450,7 +2460,7 @@ public:
|
|||
, m_name{name}
|
||||
, m_showAt{showAt} {}
|
||||
ASTGEN_MEMBERS_AstComment;
|
||||
string name() const override { return m_name; } // * = Text
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Text
|
||||
bool same(const AstNode* samep) const override { return true; } // Ignore name in comments
|
||||
virtual bool showAt() const { return m_showAt; }
|
||||
};
|
||||
|
|
@ -2591,7 +2601,7 @@ public:
|
|||
: ASTGEN_SUPER_Disable(fl)
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstDisable;
|
||||
string name() const override { return m_name; } // * = Block name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool isBrancher() const override {
|
||||
return true; // SPECIAL: We don't process code after breaks
|
||||
|
|
@ -2633,8 +2643,8 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
string verilogKwd() const override {
|
||||
return (filep() ? string("$f") + string(displayType().ascii())
|
||||
: string("$") + string(displayType().ascii()));
|
||||
return (filep() ? string{"$f"} + string{displayType().ascii()}
|
||||
: string{"$"} + string{displayType().ascii()});
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
|
|
@ -2651,17 +2661,13 @@ public:
|
|||
bool addNewline() const { return displayType().addNewline(); }
|
||||
};
|
||||
class AstDoWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNodeExpr
|
||||
// @astgen op3 := stmtsp : List[AstNode]
|
||||
// @astgen op4 := incsp : List[AstNode]
|
||||
// @astgen op1 := condp : AstNodeExpr
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
public:
|
||||
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr,
|
||||
AstNode* incsp = nullptr)
|
||||
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr)
|
||||
: ASTGEN_SUPER_DoWhile(fl) {
|
||||
condp(conditionp);
|
||||
addStmtsp(stmtsp);
|
||||
addIncsp(incsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstDoWhile;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
|
|
@ -2739,46 +2745,6 @@ public:
|
|||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpen final : public AstNodeStmt {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
// @astgen op1 := filep : AstNodeExpr
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
// @astgen op3 := modep : AstNodeExpr
|
||||
public:
|
||||
AstFOpen(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep, AstNodeExpr* modep)
|
||||
: ASTGEN_SUPER_FOpen(fl) {
|
||||
this->filep(filep);
|
||||
this->filenamep(filenamep);
|
||||
this->modep(modep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpen;
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpenMcd final : public AstNodeStmt {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
// @astgen op1 := filep : AstNodeExpr
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
public:
|
||||
AstFOpenMcd(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep)
|
||||
: ASTGEN_SUPER_FOpenMcd(fl) {
|
||||
this->filep(filep);
|
||||
this->filenamep(filenamep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpenMcd;
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFinish final : public AstNodeStmt {
|
||||
public:
|
||||
explicit AstFinish(FileLine* fl)
|
||||
|
|
@ -2821,7 +2787,7 @@ public:
|
|||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
};
|
||||
class AstJumpBlock final : public AstNodeStmt {
|
||||
// Block of code including a JumpGo and JumpLabel
|
||||
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
|
||||
// Parents: {statement list}
|
||||
// Children: {statement list, with JumpGo and JumpLabel below}
|
||||
// @astgen op1 := stmtsp : List[AstNode]
|
||||
|
|
@ -2926,7 +2892,7 @@ public:
|
|||
: ASTGEN_SUPER_PrintTimeScale(fl) {}
|
||||
ASTGEN_MEMBERS_AstPrintTimeScale;
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void dump(std::ostream& str) const override;
|
||||
string verilogKwd() const override { return "$printtimescale"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
|
|
@ -3145,7 +3111,7 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
int instrCount() const override { return 100; } // Large...
|
||||
ASTGEN_MEMBERS_AstTraceDecl;
|
||||
string name() const override { return m_showname; }
|
||||
string name() const override VL_MT_STABLE { return m_showname; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool same(const AstNode* samep) const override { return false; }
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
|
|||
}
|
||||
|
||||
const char* AstNodeUOrStructDType::broken() const {
|
||||
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||
std::unordered_set<AstMemberDType*> exists;
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
exists.insert(itemp);
|
||||
|
|
@ -232,6 +233,15 @@ int AstBasicDType::widthTotalBytes() const {
|
|||
}
|
||||
}
|
||||
|
||||
bool AstBasicDType::same(const AstNode* samep) const {
|
||||
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
|
||||
if (!rangep() && !sp->rangep() && m == sp->m) {
|
||||
return true;
|
||||
} else {
|
||||
return m == sp->m && rangep() && rangep()->sameTree(sp->rangep());
|
||||
}
|
||||
}
|
||||
|
||||
int AstNodeUOrStructDType::widthTotalBytes() const {
|
||||
if (width() <= 8) {
|
||||
return 1;
|
||||
|
|
@ -387,7 +397,7 @@ string AstVar::verilogKwd() const {
|
|||
}
|
||||
|
||||
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
|
||||
bool asRef) const VL_MT_SAFE {
|
||||
bool asRef) const VL_MT_STABLE {
|
||||
UASSERT_OBJ(!forReturn, this,
|
||||
"Internal data is never passed as return, but as first argument");
|
||||
string ostatic;
|
||||
|
|
@ -573,7 +583,7 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|||
} else {
|
||||
class converter final : public dpiTypesToStringConverter {
|
||||
string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
||||
return string(varp->isReadOnly() ? "const " : "")
|
||||
return string{varp->isReadOnly() ? "const " : ""}
|
||||
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
||||
}
|
||||
string primitive(const AstVar* varp) const override {
|
||||
|
|
@ -636,13 +646,13 @@ string AstVar::dpiTmpVarType(const string& varName) const {
|
|||
|
||||
string AstVar::scType() const {
|
||||
if (isScBigUint()) {
|
||||
return (string("sc_biguint<") + cvtToStr(widthMin())
|
||||
return (string{"sc_biguint<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (isScUint()) {
|
||||
return (string("sc_uint<") + cvtToStr(widthMin())
|
||||
return (string{"sc_uint<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (isScBv()) {
|
||||
return (string("sc_bv<") + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
||||
return (string{"sc_bv<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
||||
} else if (widthMin() == 1) {
|
||||
return "bool";
|
||||
} else if (widthMin() <= VL_IDATASIZE) {
|
||||
|
|
@ -704,12 +714,12 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_SAFE {
|
||||
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_STABLE {
|
||||
const CTypeRecursed info = cTypeRecurse(false);
|
||||
return info.render(name, isRef);
|
||||
}
|
||||
|
||||
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_MT_STABLE {
|
||||
// Legacy compound argument currently just passed through and unused
|
||||
CTypeRecursed info;
|
||||
|
||||
|
|
@ -734,9 +744,9 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
|||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlSampleQueue<" + sub.m_type + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
||||
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||
info.m_type = "VlClassRef<" + EmitCBase::prefixNameProtect(adtypep) + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) {
|
||||
info.m_type = EmitCBaseVisitor::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
||||
info.m_type = EmitCBase::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (adtypep->isCompound()) compound = true;
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
||||
|
|
@ -745,7 +755,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
|||
info.m_type += ">";
|
||||
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
|
||||
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
||||
info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep);
|
||||
info.m_type = EmitCBase::prefixNameProtect(sdtypep);
|
||||
} else if (const AstBasicDType* const bdtypep = dtypep->basicp()) {
|
||||
// We don't print msb()/lsb() as multidim packed would require recursion,
|
||||
// and may confuse users as C++ data is stored always with bit 0 used
|
||||
|
|
@ -846,7 +856,7 @@ int AstNodeDType::widthPow2() const {
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool AstNodeDType::isLiteralType() const VL_MT_SAFE {
|
||||
bool AstNodeDType::isLiteralType() const VL_MT_STABLE {
|
||||
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
|
||||
return dtypep->keyword().isLiteralType();
|
||||
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
|
||||
|
|
@ -916,10 +926,10 @@ void AstScope::cloneRelink() {
|
|||
}
|
||||
}
|
||||
string AstScope::nameDotless() const {
|
||||
string out = shortName();
|
||||
string result = shortName();
|
||||
string::size_type pos;
|
||||
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
|
||||
return out;
|
||||
while ((pos = result.find('.')) != string::npos) result.replace(pos, 1, "__");
|
||||
return result;
|
||||
}
|
||||
|
||||
AstVarScope* AstScope::createTemp(const string& name, unsigned width) {
|
||||
|
|
@ -1454,6 +1464,13 @@ void AstClass::repairCache() {
|
|||
}
|
||||
}
|
||||
}
|
||||
AstClass* AstClass::baseMostClassp() {
|
||||
AstClass* basep = this;
|
||||
while (basep->extendsp() && basep->extendsp()->classp()) {
|
||||
basep = basep->extendsp()->classp();
|
||||
}
|
||||
return basep;
|
||||
}
|
||||
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
|
||||
// TAIL RECURSIVE
|
||||
if (!refClassp || !baseClassp) return false;
|
||||
|
|
@ -1672,15 +1689,6 @@ const char* AstMemberSel::broken() const {
|
|||
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
||||
return nullptr;
|
||||
}
|
||||
void AstMethodCall::dump(std::ostream& str) const {
|
||||
this->AstNodeFTaskRef::dump(str);
|
||||
str << " -> ";
|
||||
if (taskp()) {
|
||||
taskp()->dump(str);
|
||||
} else {
|
||||
str << " -> UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstModportFTaskRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isExport()) str << " EXPORT";
|
||||
|
|
@ -1767,7 +1775,7 @@ void AstTypedef::dump(std::ostream& str) const {
|
|||
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstRange::dump(std::ostream& str) const {
|
||||
this->AstNodeRange::dump(str);
|
||||
if (littleEndian()) str << " [LITTLE]";
|
||||
if (ascending()) str << " [ASCENDING]";
|
||||
}
|
||||
void AstParamTypeDType::dump(std::ostream& str) const {
|
||||
this->AstNodeDType::dump(str);
|
||||
|
|
@ -1813,7 +1821,7 @@ void AstRefDType::cloneRelink() {
|
|||
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||
}
|
||||
}
|
||||
AstNodeDType* AstRefDType::subDTypep() const {
|
||||
AstNodeDType* AstRefDType::subDTypep() const VL_MT_STABLE {
|
||||
if (typedefp()) return typedefp()->subDTypep();
|
||||
return refDTypep(); // Maybe nullptr
|
||||
}
|
||||
|
|
@ -2313,7 +2321,7 @@ int AstCMethodHard::instrCount() const {
|
|||
if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) {
|
||||
// TODO: add a more structured description of library methods, rather than using string
|
||||
// matching. See #3715.
|
||||
if (basicp->isTriggerVec() && m_name == "at") {
|
||||
if (basicp->isTriggerVec() && m_name == "word") {
|
||||
// This is an important special case for scheduling so we compute it precisely,
|
||||
// it is simply a load.
|
||||
return INSTR_COUNT_LD;
|
||||
|
|
|
|||
|
|
@ -144,9 +144,20 @@ private:
|
|||
|
||||
// VISITORS
|
||||
void visit(AstFork* nodep) override {
|
||||
// Keep this begin to group its statements together
|
||||
// Keep begins in forks to group their statements together
|
||||
VL_RESTORER(m_keepBegins);
|
||||
m_keepBegins = true;
|
||||
// If a statement is not a begin, wrap it in a begin. This fixes an issue when the
|
||||
// statement is a task call that gets inlined later (or any other statement that gets
|
||||
// replaced with multiple statements)
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (!VN_IS(stmtp, Begin)) {
|
||||
AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr};
|
||||
stmtp->replaceWith(beginp);
|
||||
beginp->addStmtsp(stmtp);
|
||||
stmtp = beginp;
|
||||
}
|
||||
}
|
||||
dotNames(nodep, "__FORK__");
|
||||
nodep->name("");
|
||||
}
|
||||
|
|
@ -288,7 +299,7 @@ private:
|
|||
// To keep correct visual order, must add before other Text's
|
||||
AstText* const afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->addScopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
|
||||
nodep->addScopeAttrp(new AstText{nodep->fileline(), string{"__DOT__"} + scname});
|
||||
if (afterp) nodep->addScopeAttrp(afterp);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
// Branch state, as a visitor of each AstNode
|
||||
|
||||
class BranchVisitor final : public VNVisitor {
|
||||
class BranchVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
|
|
@ -71,12 +71,12 @@ private:
|
|||
{
|
||||
// Do if
|
||||
reset();
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
const int ifLikely = m_likely;
|
||||
const int ifUnlikely = m_unlikely;
|
||||
// Do else
|
||||
reset();
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
const int elseLikely = m_likely;
|
||||
const int elseUnlikely = m_unlikely;
|
||||
// Compute
|
||||
|
|
@ -91,16 +91,16 @@ private:
|
|||
void visit(AstNodeCCall* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
nodep->funcp()->user1Inc();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCFunc* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
m_cfuncsp.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNode* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
|
|
@ -114,7 +114,7 @@ public:
|
|||
// CONSTRUCTORS
|
||||
explicit BranchVisitor(AstNetlist* nodep) {
|
||||
reset();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
calc_tasks();
|
||||
}
|
||||
~BranchVisitor() override = default;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ public:
|
|||
}
|
||||
} s_brokenCntGlobal;
|
||||
|
||||
static bool s_brokenAllowMidvisitorCheck = false;
|
||||
|
||||
//######################################################################
|
||||
// Table of allocated AstNode pointers
|
||||
|
||||
|
|
@ -144,7 +146,7 @@ bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinka
|
|||
//######################################################################
|
||||
// Check every node in tree
|
||||
|
||||
class BrokenCheckVisitor final : public VNVisitor {
|
||||
class BrokenCheckVisitor final : public VNVisitorConst {
|
||||
bool m_inScope = false; // Under AstScope
|
||||
|
||||
// Constants for marking we are under/not under a node
|
||||
|
|
@ -172,6 +174,7 @@ private:
|
|||
const char* const whyp = nodep->broken();
|
||||
UASSERT_OBJ(!whyp, nodep,
|
||||
"Broken link in node (or something without maybePointedTo): " << whyp);
|
||||
if (!s_brokenAllowMidvisitorCheck) nodep->checkIter();
|
||||
if (nodep->dtypep()) {
|
||||
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
|
||||
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
|
||||
|
|
@ -312,7 +315,7 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterateConstNull(nodep); }
|
||||
~BrokenCheckVisitor() override = default;
|
||||
};
|
||||
|
||||
|
|
@ -351,6 +354,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
|
|||
}
|
||||
}
|
||||
|
||||
void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck = flag; }
|
||||
|
||||
//######################################################################
|
||||
// Self test
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ public:
|
|||
static bool isLinkable(const AstNode* nodep);
|
||||
static void addNewed(const AstNode* nodep);
|
||||
static void deleted(const AstNode* nodep);
|
||||
// Called on error to say may be inside visitor,
|
||||
// Disables checks that may misfire if not called at stable point between visitors
|
||||
static void allowMidvisitorCheck(bool flag);
|
||||
static void selfTest();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ private:
|
|||
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
|
||||
string preventUnusedStmt;
|
||||
if (m_type.isClass()) {
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->argTypes(EmitCBase::symClassVar());
|
||||
preventUnusedStmt = "if (false && vlSymsp) {} // Prevent unused\n";
|
||||
} else if (m_type.isCoverage()) {
|
||||
funcp->argTypes("bool first");
|
||||
|
|
@ -148,6 +148,7 @@ private:
|
|||
m_modp = nodep;
|
||||
V3CCtorsBuilder var_reset{nodep, "_ctor_var_reset",
|
||||
VN_IS(nodep, Class) ? VCtorType::CLASS : VCtorType::MODULE};
|
||||
// cppcheck-suppress danglingLifetime
|
||||
m_varResetp = &var_reset;
|
||||
iterateChildren(nodep);
|
||||
|
||||
|
|
@ -201,7 +202,7 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
explicit CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
~CCtorsVisitor() override = default;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
|
||||
//######################################################################
|
||||
|
||||
class CaseLintVisitor final : public VNVisitor {
|
||||
class CaseLintVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
const AstNodeCase* m_caseExprp
|
||||
= nullptr; // Under a CASE value node, if so the relevant case statement
|
||||
|
|
@ -79,10 +79,10 @@ private:
|
|||
// Check for X/Z in non-casex statements
|
||||
{
|
||||
m_caseExprp = nodep;
|
||||
iterate(nodep->exprp());
|
||||
iterateConst(nodep->exprp());
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
iterateAndNextNull(itemp->condsp());
|
||||
iterateAndNextConstNull(itemp->condsp());
|
||||
}
|
||||
m_caseExprp = nullptr;
|
||||
}
|
||||
|
|
@ -108,11 +108,11 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); }
|
||||
~CaseLintVisitor() override = default;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ private:
|
|||
|
||||
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
|
||||
// Give it a pointer to its package and a final name
|
||||
dtypep->classOrPackagep(m_modp);
|
||||
dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp);
|
||||
dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct")
|
||||
+ cvtToStr(dtypep->uniqueNum()));
|
||||
|
||||
|
|
@ -193,6 +193,7 @@ private:
|
|||
void visit(AstTypedef* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
|
||||
|
||||
AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType);
|
||||
if (dtypep && !dtypep->packed()) {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ private:
|
|||
if (vscp->user1p()) return VN_AS(vscp->user1p(), VarScope);
|
||||
const AstVar* const varp = vscp->varp();
|
||||
const string newvarname
|
||||
= string("__Vsampled__") + vscp->scopep()->nameDotless() + "__" + varp->name();
|
||||
= string{"__Vsampled__"} + vscp->scopep()->nameDotless() + "__" + varp->name();
|
||||
FileLine* const flp = vscp->fileline();
|
||||
AstVar* const newvarp = new AstVar{flp, VVarType::MODULETEMP, newvarname, varp->dtypep()};
|
||||
newvarp->noReset(true); // Reset by below assign
|
||||
|
|
@ -146,17 +146,19 @@ private:
|
|||
UASSERT_OBJ(nodep->hasClocked(), nodep, "Should have been converted by V3Sched");
|
||||
UASSERT_OBJ(nodep->stmtsp(), nodep, "Should not have been created if empty");
|
||||
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
|
||||
// Create 'if' statement, if needed
|
||||
if (!m_lastSenp || !nodep->sensesp()->sameTree(m_lastSenp)) {
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
clearLastSen();
|
||||
m_lastSenp = nodep->sensesp();
|
||||
// Make a new if statement
|
||||
m_lastIfp = makeActiveIf(m_lastSenp);
|
||||
relinker.relink(m_lastIfp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
|
||||
// Move statements to if
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
static void makeVlToString(AstClass* nodep) {
|
||||
AstCFunc* const funcp
|
||||
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
|
||||
funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) + ">& obj");
|
||||
funcp->argTypes("const VlClassRef<" + EmitCBase::prefixNameProtect(nodep) + ">& obj");
|
||||
funcp->isMethod(false);
|
||||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
|
|
@ -51,7 +51,7 @@ static void makeVlToString(AstClass* nodep) {
|
|||
static void makeVlToString(AstIface* nodep) {
|
||||
AstCFunc* const funcp
|
||||
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
|
||||
funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "* obj");
|
||||
funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "* obj");
|
||||
funcp->isMethod(false);
|
||||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
|
|
@ -65,7 +65,7 @@ static void makeVlToString(AstNodeUOrStructDType* nodep) {
|
|||
AstNodeModule* const modp = nodep->classOrPackagep();
|
||||
AstCFunc* const funcp
|
||||
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
|
||||
funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "& obj");
|
||||
funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "& obj");
|
||||
funcp->isMethod(false);
|
||||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
|
|
@ -137,7 +137,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
|||
string stmt = "out += ";
|
||||
if (!comma.empty()) stmt += "\", \"+ ";
|
||||
// comma = ", "; // Nothing further so not needed
|
||||
stmt += EmitCBaseVisitor::prefixNameProtect(nodep->extendsp()->dtypep());
|
||||
stmt += EmitCBase::prefixNameProtect(nodep->extendsp()->dtypep());
|
||||
stmt += "::to_string_middle();\n";
|
||||
nodep->user1(true); // So what we extend dumps this
|
||||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
|
||||
|
|
|
|||
|
|
@ -40,25 +40,31 @@ template <typename T>
|
|||
class V3ConfigWildcardResolver final {
|
||||
using Map = std::map<const std::string, T>;
|
||||
|
||||
Map m_mapWildcard; // Wildcard strings to entities
|
||||
Map m_mapResolved; // Resolved strings to converged entities
|
||||
mutable V3Mutex m_mutex; // protects members
|
||||
Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities
|
||||
Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities
|
||||
public:
|
||||
V3ConfigWildcardResolver() = default;
|
||||
~V3ConfigWildcardResolver() = default;
|
||||
|
||||
/// Update into maps from other
|
||||
void update(const V3ConfigWildcardResolver& other) {
|
||||
void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex)
|
||||
VL_EXCLUDES(other.m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
V3LockGuard otherLock{other.m_mutex};
|
||||
for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second);
|
||||
for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second);
|
||||
}
|
||||
|
||||
// Access and create a (wildcard) entity
|
||||
T& at(const string& name) {
|
||||
T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
// 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) {
|
||||
T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
// Lookup if it was resolved before, typically not
|
||||
auto it = m_mapResolved.find(name);
|
||||
if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second;
|
||||
|
|
@ -78,7 +84,10 @@ public:
|
|||
return newp;
|
||||
}
|
||||
// Flush on update
|
||||
void flush() { m_mapResolved.clear(); }
|
||||
void flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
m_mapResolved.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// Only public_flat_rw has the sensitity tree
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "V3Ast.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3Mutex.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
|
|||
213
src/V3Const.cpp
213
src/V3Const.cpp
|
|
@ -70,7 +70,7 @@ static int countTrailingZeroes(uint64_t val) {
|
|||
// This visitor can be used in the post-expanded Ast from V3Expand, where the Ast satisfies:
|
||||
// - Constants are 64 bit at most (because words are accessed via AstWordSel)
|
||||
// - Variables are scoped.
|
||||
class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
class ConstBitOpTreeVisitor final : public VNVisitorConst {
|
||||
// NODE STATE
|
||||
// AstVarRef::user4u -> Base index of m_varInfos that points VarInfo
|
||||
// AstVarScope::user4u -> Same as AstVarRef::user4
|
||||
|
|
@ -416,7 +416,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
{
|
||||
VL_RESTORER(m_leafp);
|
||||
m_leafp = &info;
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
|
||||
bool ok = !m_failed;
|
||||
|
|
@ -431,7 +431,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
// VISITORS
|
||||
void visit(AstNode* nodep) override { CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); }
|
||||
void visit(AstCCast* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_leafp) m_leafp->updateBitRange(nodep);
|
||||
}
|
||||
void visit(AstShiftR* nodep) override {
|
||||
|
|
@ -440,7 +440,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
|
||||
m_lsb += constp->toUInt();
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->lhsp());
|
||||
iterateConst(nodep->lhsp());
|
||||
m_leafp->updateBitRange(nodep);
|
||||
m_lsb -= constp->toUInt();
|
||||
}
|
||||
|
|
@ -449,12 +449,10 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
AstNode* lhsp = nodep->lhsp();
|
||||
AstCCast* const castp = VN_CAST(lhsp, CCast);
|
||||
if (castp) lhsp = castp->lhsp();
|
||||
CONST_BITOP_RETURN_IF(!VN_IS(lhsp, VarRef) && !VN_IS(lhsp, Xor) && !VN_IS(lhsp, RedXor)
|
||||
&& !VN_IS(lhsp, ShiftR),
|
||||
lhsp);
|
||||
CONST_BITOP_RETURN_IF(!isXorTree() && !VN_IS(lhsp, VarRef) && !VN_IS(lhsp, ShiftR), lhsp);
|
||||
incrOps(nodep, __LINE__);
|
||||
m_polarity = !m_polarity;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
// Don't restore m_polarity for Xor as it counts parity of the entire tree
|
||||
if (!isXorTree()) m_polarity = !m_polarity;
|
||||
if (m_leafp && castp) m_leafp->updateBitRange(castp);
|
||||
|
|
@ -465,7 +463,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
|
||||
UASSERT_OBJ(m_leafp->wordIdx() == -1, nodep, "Unexpected nested WordSel");
|
||||
m_leafp->wordIdx(constp->toSInt());
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
}
|
||||
void visit(AstVarRef* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
|
|
@ -529,7 +527,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
// Always reach past a plain making AND
|
||||
Restorer restorer{*this};
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->rhsp());
|
||||
iterateConst(nodep->rhsp());
|
||||
CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp());
|
||||
restorer.disableRestore(); // Now all checks passed
|
||||
} else if (nodep->type() == m_rootp->type()) { // And, Or, Xor
|
||||
|
|
@ -542,13 +540,14 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
m_leafp = &leafInfo;
|
||||
AstNodeExpr* opp = right ? nodep->rhsp() : nodep->lhsp();
|
||||
const bool origFailed = m_failed;
|
||||
iterate(opp);
|
||||
iterateConst(opp);
|
||||
if (leafInfo.constp() || m_failed) {
|
||||
// Revert changes in leaf
|
||||
restorer.restoreNow();
|
||||
// Reach past a cast then add to frozen nodes to be added to final reduction
|
||||
if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp();
|
||||
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{m_polarity, m_lsb});
|
||||
const bool pol = isXorTree() || m_polarity; // Only AND/OR tree needs polarity
|
||||
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{pol, m_lsb});
|
||||
m_failed = origFailed;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -647,11 +646,11 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
m_varInfos.push_back(nullptr);
|
||||
CONST_BITOP_RETURN_IF(!isAndTree() && !isOrTree() && !isXorTree(), nodep);
|
||||
if (AstNodeBiop* const biopp = VN_CAST(nodep, NodeBiop)) {
|
||||
iterate(biopp);
|
||||
iterateConst(biopp);
|
||||
} else {
|
||||
UASSERT_OBJ(VN_IS(nodep, RedXor), nodep, "Must be RedXor");
|
||||
incrOps(nodep, __LINE__);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
for (auto&& entry : m_bitPolarities) {
|
||||
getVarInfo(entry.m_info).setPolarity(entry.m_polarity, entry.m_bit);
|
||||
|
|
@ -2265,7 +2264,7 @@ private:
|
|||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Iterate modules backwards, in bottom-up order. That's faster
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
|
|
@ -2747,52 +2746,74 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
struct SenItemCmp {
|
||||
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
|
||||
if (lhsp->type() < rhsp->type()) return true;
|
||||
if (lhsp->type() > rhsp->type()) return false;
|
||||
// Looks visually better if we keep sorted by name
|
||||
if (!lhsp->sensp() && rhsp->sensp()) return true;
|
||||
if (lhsp->sensp() && !rhsp->sensp()) return false;
|
||||
if (lhsp->varrefp() && !rhsp->varrefp()) return true;
|
||||
if (!lhsp->varrefp() && rhsp->varrefp()) return false;
|
||||
if (lhsp->varrefp() && rhsp->varrefp()) {
|
||||
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
|
||||
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
|
||||
class SenItemCmp final {
|
||||
static int cmp(const AstNodeExpr* ap, const AstNodeExpr* bp) {
|
||||
const VNType aType = ap->type();
|
||||
const VNType bType = bp->type();
|
||||
if (aType != bType) return static_cast<int>(bType) - static_cast<int>(aType);
|
||||
|
||||
if (const AstVarRef* const aRefp = VN_CAST(ap, VarRef)) {
|
||||
const AstVarRef* const bRefp = VN_AS(bp, VarRef);
|
||||
// Looks visually better if we keep sorted by name
|
||||
if (aRefp->name() < bRefp->name()) return -1;
|
||||
if (aRefp->name() > bRefp->name()) return 1;
|
||||
// But might be same name with different scopes
|
||||
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) return true;
|
||||
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) return false;
|
||||
if (aRefp->varScopep() < bRefp->varScopep()) return -1;
|
||||
if (aRefp->varScopep() > bRefp->varScopep()) return 1;
|
||||
// Or rarely, different data types
|
||||
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
|
||||
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
|
||||
} else if (AstCMethodHard* const lp = VN_CAST(lhsp->sensp(), CMethodHard)) {
|
||||
if (AstCMethodHard* const rp = VN_CAST(rhsp->sensp(), CMethodHard)) {
|
||||
if (AstVarRef* const lRefp = VN_CAST(lp->fromp(), VarRef)) {
|
||||
if (AstVarRef* const rRefp = VN_CAST(rp->fromp(), VarRef)) {
|
||||
if (lRefp->name() < rRefp->name()) return true;
|
||||
if (lRefp->name() > rRefp->name()) return false;
|
||||
// But might be same name with different scopes
|
||||
if (lRefp->varScopep() < rRefp->varScopep()) return true;
|
||||
if (lRefp->varScopep() > rRefp->varScopep()) return false;
|
||||
// Or rarely, different data types
|
||||
if (lRefp->dtypep() < rRefp->dtypep()) return true;
|
||||
if (lRefp->dtypep() > rRefp->dtypep()) return false;
|
||||
}
|
||||
}
|
||||
if (AstConst* lConstp = VN_CAST(lp->pinsp(), Const)) {
|
||||
if (AstConst* rConstp = VN_CAST(rp->pinsp(), Const)) {
|
||||
if (lConstp->toUInt() < rConstp->toUInt()) return true;
|
||||
if (lConstp->toUInt() > rConstp->toUInt()) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aRefp->dtypep() < bRefp->dtypep()) return -1;
|
||||
if (aRefp->dtypep() > bRefp->dtypep()) return 1;
|
||||
return 0;
|
||||
}
|
||||
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
|
||||
// note the SenTree optimizer requires this order (more
|
||||
// general first, less general last)
|
||||
if (lhsp->edgeType() < rhsp->edgeType()) return true;
|
||||
if (lhsp->edgeType() > rhsp->edgeType()) return false;
|
||||
return false;
|
||||
|
||||
if (const AstConst* const aConstp = VN_CAST(ap, Const)) {
|
||||
const AstConst* const bConstp = VN_AS(bp, Const);
|
||||
if (aConstp->toUQuad() < bConstp->toUQuad()) return -1;
|
||||
if (aConstp->toUQuad() > bConstp->toUQuad()) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (const AstNodeBiop* const aBiOpp = VN_CAST(ap, NodeBiop)) {
|
||||
const AstNodeBiop* const bBiOpp = VN_AS(bp, NodeBiop);
|
||||
// Compare RHSs first as LHS might be const, but the variable term should become
|
||||
// adjacent for optimization if identical.
|
||||
if (const int c = cmp(aBiOpp->rhsp(), bBiOpp->rhsp())) return c;
|
||||
return cmp(aBiOpp->lhsp(), bBiOpp->lhsp());
|
||||
}
|
||||
|
||||
if (const AstCMethodHard* const aCallp = VN_CAST(ap, CMethodHard)) {
|
||||
const AstCMethodHard* const bCallp = VN_AS(bp, CMethodHard);
|
||||
if (aCallp->name() < bCallp->name()) return -1;
|
||||
if (aCallp->name() > bCallp->name()) return 1;
|
||||
if (const int c = cmp(aCallp->fromp(), bCallp->fromp())) return c;
|
||||
AstNodeExpr* aPinsp = aCallp->pinsp();
|
||||
AstNodeExpr* bPinsp = bCallp->pinsp();
|
||||
while (aPinsp && bPinsp) {
|
||||
if (const int c = cmp(aPinsp, bPinsp)) return c;
|
||||
aPinsp = VN_AS(aPinsp->nextp(), NodeExpr);
|
||||
bPinsp = VN_AS(bPinsp->nextp(), NodeExpr);
|
||||
}
|
||||
return aPinsp ? -1 : bPinsp ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
|
||||
AstNodeExpr* const lSensp = lhsp->sensp();
|
||||
AstNodeExpr* const rSensp = rhsp->sensp();
|
||||
if (lSensp && rSensp) {
|
||||
// If both terms have sensitivity expressions, recursively compare them
|
||||
if (const int c = cmp(lSensp, rSensp)) return c < 0;
|
||||
} else if (lSensp || rSensp) {
|
||||
// Terms with sensitivity expressions come after those without
|
||||
return rSensp;
|
||||
}
|
||||
// Finally sort by edge, AFTER variable, as we want multiple edges for same var
|
||||
// adjacent. note the SenTree optimizer requires this order (more general first,
|
||||
// less general last)
|
||||
return lhsp->edgeType() < rhsp->edgeType();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2817,9 +2838,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
|
||||
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
|
||||
// Make things a little faster; check first if we need a sort
|
||||
// Pass 1: Sort the sensitivity items so "posedge a or b" and "posedge b or a" and
|
||||
// similar, optimizable expressions end up next to each other.
|
||||
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
|
||||
nextp = VN_AS(senp->nextp(), SenItem);
|
||||
// cppcheck-suppress unassignedVariable // cppcheck bug
|
||||
|
|
@ -2839,35 +2859,53 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// Pass2, remove dup edges
|
||||
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
|
||||
// Pass 2, remove duplicates and simplify adjacent terms if possible
|
||||
for (AstSenItem *senp = nodep->sensesp(), *nextp; senp; senp = nextp) {
|
||||
nextp = VN_AS(senp->nextp(), SenItem);
|
||||
AstSenItem* const litemp = senp;
|
||||
AstSenItem* const ritemp = nextp;
|
||||
if (ritemp) {
|
||||
if ((litemp->sensp() && ritemp->sensp()
|
||||
&& litemp->sensp()->sameGateTree(ritemp->sensp()))
|
||||
|| (!litemp->sensp() && !ritemp->sensp())) {
|
||||
// We've sorted in the order ANY, BOTH, POS, NEG,
|
||||
// so we don't need to try opposite orders
|
||||
if ((litemp->edgeType() == VEdgeType::ET_POSEDGE // POS or NEG -> BOTH
|
||||
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|
||||
|| (litemp->edgeType() == ritemp->edgeType()) // Identical edges
|
||||
) {
|
||||
// Fix edge of old node
|
||||
if (litemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|
||||
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
// Remove redundant node
|
||||
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
|
||||
VL_DANGLING(ritemp);
|
||||
// Try to collapse again
|
||||
nextp = litemp;
|
||||
if (!nextp) break;
|
||||
AstSenItem* const lItemp = senp;
|
||||
AstSenItem* const rItemp = nextp;
|
||||
AstNodeExpr* const lSenp = lItemp->sensp();
|
||||
AstNodeExpr* const rSenp = rItemp->sensp();
|
||||
if (!lSenp || !rSenp) continue;
|
||||
|
||||
if (lSenp->sameGateTree(rSenp)) {
|
||||
// POSEDGE or NEGEDGE -> BOTHEDGE. (We've sorted POSEDGE, before NEGEDGE, so we
|
||||
// do not need to test for the opposite orders.)
|
||||
if (lItemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
&& rItemp->edgeType() == VEdgeType::ET_NEGEDGE) {
|
||||
// Make both terms BOTHEDGE, the second will be removed below
|
||||
lItemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
rItemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
}
|
||||
|
||||
// Remove identical expressions
|
||||
if (lItemp->edgeType() == rItemp->edgeType()) {
|
||||
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
|
||||
nextp = lItemp;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not identical terms, check if they can be combined
|
||||
if (lSenp->width() != rSenp->width()) continue;
|
||||
if (AstAnd* const lAndp = VN_CAST(lSenp, And)) {
|
||||
if (AstAnd* const rAndp = VN_CAST(rSenp, And)) {
|
||||
if (AstConst* const lConstp = VN_CAST(lAndp->lhsp(), Const)) {
|
||||
if (AstConst* const rConstp = VN_CAST(rAndp->lhsp(), Const)) {
|
||||
if (lAndp->rhsp()->sameTree(rAndp->rhsp())) {
|
||||
const V3Number lNum{lConstp->num()};
|
||||
lConstp->num().opOr(lNum, rConstp->num());
|
||||
// Remove redundant term
|
||||
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
|
||||
nextp = lItemp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// nodep->dumpTree("- ssou: ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2975,6 +3013,7 @@ private:
|
|||
AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext();
|
||||
AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext();
|
||||
AstIf* const ifp = new AstIf{nodep->fileline(), condp, elsesp, thensp};
|
||||
ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info
|
||||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -3188,7 +3227,7 @@ private:
|
|||
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->exprp()) {
|
||||
if (!nodep->exprp() || VN_IS(nodep->exprp(), Const)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
|
|
@ -3207,7 +3246,7 @@ private:
|
|||
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Jump to label where label immediately follows label is not useful
|
||||
// Jump to label where label immediately follows this go is not useful
|
||||
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
// Keep the label, might be other jumps pointing to it, gets cleaned later
|
||||
|
|
|
|||
|
|
@ -262,8 +262,8 @@ private:
|
|||
if (VN_IS(dimp, Const)) { // bit = const, can just use it
|
||||
dimreadps.push_front(dimp);
|
||||
} else {
|
||||
const string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
|
||||
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
const string bitvarname = string{"__Vdlyvdim"} + cvtToStr(dimension) + "__"
|
||||
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
AstVarScope* const bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
|
||||
AstAssign* const bitassignp = new AstAssign{
|
||||
|
|
@ -282,8 +282,8 @@ private:
|
|||
// vlsb = constant, can just push constant into where we use it
|
||||
bitreadp = lsbvaluep;
|
||||
} else {
|
||||
const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
|
||||
+ cvtToStr(modVecNum));
|
||||
const string bitvarname
|
||||
= string{"__Vdlyvlsb__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
AstVarScope* const bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
|
||||
AstAssign* const bitassignp = new AstAssign{
|
||||
|
|
@ -301,7 +301,7 @@ private:
|
|||
valreadp = nodep->rhsp()->unlinkFrBack();
|
||||
} else {
|
||||
const string valvarname
|
||||
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
= string{"__Vdlyvval__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
AstVarScope* const valvscp
|
||||
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
newlhsp = new AstVarRef{nodep->fileline(), valvscp, VAccess::WRITE};
|
||||
|
|
@ -321,7 +321,7 @@ private:
|
|||
++m_statSharedSet;
|
||||
} else { // Create new one
|
||||
const string setvarname
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
= string{"__Vdlyvset__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
|
||||
if (!m_inSuspendableOrFork) {
|
||||
// Suspendables reset __Vdlyvset__ in the AstAlwaysPost
|
||||
|
|
@ -474,14 +474,16 @@ private:
|
|||
m_inSuspendableOrFork = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCAwait* nodep) override { m_timingDomains.insert(nodep->sensesp()); }
|
||||
void visit(AstCAwait* nodep) override {
|
||||
if (nodep->sensesp()) m_timingDomains.insert(nodep->sensesp());
|
||||
}
|
||||
void visit(AstFireEvent* nodep) override {
|
||||
UASSERT_OBJ(v3Global.hasEvents(), nodep, "Inconsistent");
|
||||
FileLine* const flp = nodep->fileline();
|
||||
if (nodep->isDelayed()) {
|
||||
AstVarRef* const vrefp = VN_AS(nodep->operandp(), VarRef);
|
||||
vrefp->unlinkFrBack();
|
||||
const string newvarname = (string("__Vdly__") + vrefp->varp()->shortName());
|
||||
const string newvarname = string{"__Vdly__"} + vrefp->varp()->shortName();
|
||||
AstVarScope* const dlyvscp = createVarSc(vrefp->varScopep(), newvarname, 1, nullptr);
|
||||
|
||||
const auto dlyRef = [=](VAccess access) {
|
||||
|
|
@ -570,7 +572,7 @@ private:
|
|||
checkActivePost(nodep, oldactivep);
|
||||
}
|
||||
if (!dlyvscp) { // First use of this delayed variable
|
||||
const string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
|
||||
const string newvarname = string{"__Vdly__"} + nodep->varp()->shortName();
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
|
||||
AstNodeAssign* const prep = new AstAssignPre{
|
||||
nodep->fileline(),
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ private:
|
|||
AstCCall* const callp = new AstCCall{nodep->fileline(), funcp};
|
||||
callp->dtypeSetVoid();
|
||||
if (VN_IS(m_modp, Class)) {
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->argTypes(EmitCBase::symClassVar());
|
||||
callp->argTypes("vlSymsp");
|
||||
}
|
||||
UINFO(6, " New " << callp << endl);
|
||||
|
|
@ -93,6 +93,7 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstStmtExpr* nodep) override {} // Stop recursion after introducing new function
|
||||
void visit(AstJumpBlock*) override {} // Stop recursion as can't break up across a jump
|
||||
void visit(AstNodeStmt* nodep) override {
|
||||
m_depth++;
|
||||
if (m_depth > v3Global.opt.compLimitBlocks()) { // Already done
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ private:
|
|||
new AstEq{
|
||||
funcp->fileline(), new AstCExpr{funcp->fileline(), "this", 64},
|
||||
new AstCExpr{funcp->fileline(),
|
||||
string("&(") + funcp->scopep()->nameVlSym() + ")",
|
||||
string{"&("} + funcp->scopep()->nameVlSym() + ")",
|
||||
64}},
|
||||
returnp};
|
||||
newfuncp->addStmtsp(ifp);
|
||||
|
|
@ -178,7 +178,7 @@ private:
|
|||
// to come up with some return value
|
||||
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
|
||||
// VDisplayType::DT_WARNING,
|
||||
// string("%%Error: ")+name+"() called with bad
|
||||
// string{"%%Error: "}+name+"() called with bad
|
||||
// scope", nullptr));
|
||||
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
||||
if (debug() >= 9) newfuncp->dumpTree("- newfunc: ");
|
||||
|
|
|
|||
|
|
@ -59,8 +59,7 @@ AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( //
|
|||
const DfgCountOnes* vtxp, AstNodeExpr* op1) {
|
||||
AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1};
|
||||
// Set dtype same as V3Width
|
||||
const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
|
||||
nodep->dtypeSetLogicSized(selwidth, VSigning::UNSIGNED);
|
||||
nodep->dtypeSetLogicSized(32, VSigning::UNSIGNED);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ EmitCParentModule::EmitCParentModule() {
|
|||
//######################################################################
|
||||
// EmitCBaseVisitor implementation
|
||||
|
||||
string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
||||
string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
||||
modp = modp ? modp : EmitCParentModule::get(nodep);
|
||||
string name;
|
||||
if (nodep->isConstructor()) {
|
||||
|
|
@ -57,15 +57,21 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
|
|||
return name;
|
||||
}
|
||||
|
||||
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) {
|
||||
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
|
||||
cfilep->slow(slow);
|
||||
cfilep->source(source);
|
||||
if (add) v3Global.rootp()->addFilesp(cfilep);
|
||||
AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source) {
|
||||
AstCFile* const cfilep = createCFile(filename, slow, source);
|
||||
v3Global.rootp()->addFilesp(cfilep);
|
||||
return cfilep;
|
||||
}
|
||||
|
||||
string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
|
||||
AstCFile* EmitCBaseVisitorConst::createCFile(const string& filename, bool slow,
|
||||
bool source) VL_MT_SAFE {
|
||||
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
|
||||
cfilep->slow(slow);
|
||||
cfilep->source(source);
|
||||
return cfilep;
|
||||
}
|
||||
|
||||
string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) {
|
||||
// Return argument list for given C function
|
||||
string args;
|
||||
if (nodep->isLoose() && !nodep->isStatic()) {
|
||||
|
|
@ -95,8 +101,8 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
|
|||
return args;
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool withScope) {
|
||||
void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool withScope) {
|
||||
if (funcp->slow()) puts("VL_ATTR_COLD ");
|
||||
if (!funcp->isConstructor() && !funcp->isDestructor()) {
|
||||
puts(funcp->rtnTypeVoid());
|
||||
|
|
@ -114,8 +120,8 @@ void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModul
|
|||
if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const");
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool cLinkage) {
|
||||
void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool cLinkage) {
|
||||
ensureNewLine();
|
||||
if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n");
|
||||
if (cLinkage) puts("extern \"C\" ");
|
||||
|
|
@ -129,7 +135,7 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule*
|
|||
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
||||
void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
|
||||
const AstBasicDType* const basicp = nodep->basicp();
|
||||
bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
||||
|
||||
|
|
@ -217,7 +223,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
||||
void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
||||
string nl;
|
||||
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
||||
|
|
@ -235,7 +241,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType)
|
|||
puts(nl);
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, VNType type) {
|
||||
void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) {
|
||||
// Short circuit if nothing to do. This can save a lot of time on large designs as this
|
||||
// function needs to traverse the entire module linearly.
|
||||
if (!v3Global.hasSCTextSections()) return;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public:
|
|||
EmitCParentModule();
|
||||
VL_UNCOPYABLE(EmitCParentModule);
|
||||
|
||||
static const AstNodeModule* get(const AstNode* nodep) {
|
||||
static const AstNodeModule* get(const AstNode* nodep) VL_MT_STABLE {
|
||||
return VN_AS(nodep->user4p(), NodeModule);
|
||||
}
|
||||
};
|
||||
|
|
@ -48,51 +48,23 @@ public:
|
|||
//######################################################################
|
||||
// Base Visitor class -- holds output file pointer
|
||||
|
||||
class EmitCBaseVisitor VL_NOT_FINAL : public VNVisitor {
|
||||
class EmitCBase VL_NOT_FINAL {
|
||||
public:
|
||||
// STATE
|
||||
V3OutCFile* m_ofp = nullptr;
|
||||
bool m_trackText = false; // Always track AstText nodes
|
||||
// METHODS
|
||||
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
|
||||
void puts(const string& str) { ofp()->puts(str); }
|
||||
void putbs(const string& str) { ofp()->putbs(str); }
|
||||
void putsDecoration(const string& str) {
|
||||
if (v3Global.opt.decoration()) puts(str);
|
||||
}
|
||||
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
|
||||
void ensureNewLine() { ofp()->ensureNewLine(); }
|
||||
bool optSystemC() { return v3Global.opt.systemC(); }
|
||||
static string protect(const string& name) { return VIdProtect::protectIf(name, true); }
|
||||
static string protectIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectIf(name, doIt);
|
||||
}
|
||||
static string protectWordsIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectWordsIf(name, doIt);
|
||||
}
|
||||
static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; }
|
||||
static string voidSelfAssign(const AstNodeModule* modp) {
|
||||
const string className = prefixNameProtect(modp);
|
||||
return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className
|
||||
+ "*>(voidSelf);\n";
|
||||
}
|
||||
static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); }
|
||||
static string symClassName() VL_MT_STABLE {
|
||||
return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms");
|
||||
}
|
||||
static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; }
|
||||
static string symClassAssign() {
|
||||
return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n";
|
||||
}
|
||||
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
|
||||
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
|
||||
return v3Global.opt.modPrefix() + "_" + protect(nodep->name());
|
||||
static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix
|
||||
return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name());
|
||||
}
|
||||
static string topClassName() { // Return name of top wrapper module
|
||||
return v3Global.opt.prefix();
|
||||
}
|
||||
|
||||
static bool isConstPoolMod(const AstNode* modp) {
|
||||
return modp == v3Global.rootp()->constPoolp()->modp();
|
||||
}
|
||||
|
||||
static bool isAnonOk(const AstVar* varp) {
|
||||
return v3Global.opt.compLimitMembers() != 0 // Enabled
|
||||
&& !varp->isStatic() // Not a static variable
|
||||
|
|
@ -100,8 +72,43 @@ public:
|
|||
&& !VN_IS(varp->dtypep()->skipRefp(), SampleQueueDType) // Aggregates can't be anon
|
||||
&& (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon
|
||||
}
|
||||
static bool isConstPoolMod(const AstNode* modp) {
|
||||
return modp == v3Global.rootp()->constPoolp()->modp();
|
||||
}
|
||||
};
|
||||
|
||||
static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true);
|
||||
class EmitCBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst, public EmitCBase {
|
||||
public:
|
||||
// STATE
|
||||
V3OutCFile* m_ofp = nullptr;
|
||||
bool m_trackText = false; // Always track AstText nodes
|
||||
// METHODS
|
||||
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
|
||||
void puts(const string& str) { ofp()->puts(str); }
|
||||
void putsHeader() { ofp()->putsHeader(); }
|
||||
void putbs(const string& str) { ofp()->putbs(str); }
|
||||
void putsDecoration(const string& str) {
|
||||
if (v3Global.opt.decoration()) puts(str);
|
||||
}
|
||||
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
|
||||
void ensureNewLine() { ofp()->ensureNewLine(); }
|
||||
bool optSystemC() { return v3Global.opt.systemC(); }
|
||||
static string protect(const string& name) VL_MT_SAFE { return VIdProtect::protect(name); }
|
||||
static string protectIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectIf(name, doIt);
|
||||
}
|
||||
static string protectWordsIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectWordsIf(name, doIt);
|
||||
}
|
||||
static string ifNoProtect(const string& in) VL_MT_SAFE {
|
||||
return v3Global.opt.protectIds() ? "" : in;
|
||||
}
|
||||
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
|
||||
static string topClassName() VL_MT_SAFE { // Return name of top wrapper module
|
||||
return v3Global.opt.prefix();
|
||||
}
|
||||
static AstCFile* newCFile(const string& filename, bool slow, bool source);
|
||||
static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE;
|
||||
string cFuncArgs(const AstCFunc* nodep);
|
||||
void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope);
|
||||
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
|
||||
|
|
@ -110,8 +117,8 @@ public:
|
|||
void emitTextSection(const AstNodeModule* modp, VNType type);
|
||||
|
||||
// CONSTRUCTORS
|
||||
EmitCBaseVisitor() = default;
|
||||
~EmitCBaseVisitor() override = default;
|
||||
EmitCBaseVisitorConst() = default;
|
||||
~EmitCBaseVisitorConst() override = default;
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
//######################################################################
|
||||
// Emitter that can emit constant initializer expressions
|
||||
|
||||
class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor {
|
||||
class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||
// MEMBERS
|
||||
uint32_t m_unpackedWord = 0;
|
||||
bool m_inUnpacked = false;
|
||||
|
|
@ -64,7 +64,7 @@ protected:
|
|||
ofp()->printf("%" PRIx64 "ULL", itr.first);
|
||||
ofp()->putsNoTracking(":");
|
||||
ofp()->putsNoTracking("{");
|
||||
iterate(nodep->getIndexValuep(itr.first));
|
||||
iterateConst(nodep->getIndexValuep(itr.first));
|
||||
ofp()->putsNoTracking("}");
|
||||
}
|
||||
puts("\n");
|
||||
|
|
@ -83,7 +83,7 @@ protected:
|
|||
for (uint64_t n = 0; n < size; ++n) {
|
||||
m_unpackedWord = n;
|
||||
if (n) puts((n % tabMod) ? ", " : ",\n");
|
||||
iterate(nodep->getIndexDefaultedValuep(n));
|
||||
iterateConst(nodep->getIndexDefaultedValuep(n));
|
||||
}
|
||||
puts("\n");
|
||||
puts("}");
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class EmitCConstPool final : public EmitCConstInit {
|
|||
puts("extern const ");
|
||||
puts(varp->dtypep()->cType(nameProtect, false, false));
|
||||
puts(" = ");
|
||||
iterate(varp->valuep());
|
||||
iterateConst(varp->valuep());
|
||||
puts(";\n");
|
||||
// Keep track of stats
|
||||
if (VN_IS(varp->dtypep(), UnpackArrayDType)) {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
|||
case 'i':
|
||||
COMMA;
|
||||
UASSERT_OBJ(detailp, nodep, "emitOperator() references undef node");
|
||||
iterateAndNextNull(detailp);
|
||||
iterateAndNextConstNull(detailp);
|
||||
needComma = true;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -174,7 +174,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
|
||||
isStmt = false;
|
||||
puts("VL_FSCANF_IX(");
|
||||
iterate(dispp->filep());
|
||||
iterateConst(dispp->filep());
|
||||
puts(",");
|
||||
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
|
||||
isStmt = false;
|
||||
|
|
@ -184,13 +184,13 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
puts("X(");
|
||||
puts(cvtToStr(dispp->fromp()->widthMin()));
|
||||
puts(",");
|
||||
iterate(dispp->fromp());
|
||||
iterateConst(dispp->fromp());
|
||||
puts(",");
|
||||
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
|
||||
isStmt = true;
|
||||
if (dispp->filep()) {
|
||||
puts("VL_FWRITEF(");
|
||||
iterate(dispp->filep());
|
||||
iterateConst(dispp->filep());
|
||||
puts(",");
|
||||
} else {
|
||||
puts("VL_WRITEF(");
|
||||
|
|
@ -200,7 +200,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
puts("VL_SFORMAT_X(");
|
||||
puts(cvtToStr(dispp->lhsp()->widthMin()));
|
||||
putbs(",");
|
||||
iterate(dispp->lhsp());
|
||||
iterateConst(dispp->lhsp());
|
||||
putbs(",");
|
||||
} else if (VN_IS(nodep, SFormatF)) {
|
||||
isStmt = false;
|
||||
|
|
@ -223,7 +223,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
} else if (argp) {
|
||||
const bool addrof = isScan || (fmt == '@');
|
||||
if (addrof) puts("&(");
|
||||
iterate(argp);
|
||||
iterateConst(argp);
|
||||
if (!addrof) emitDatap(argp);
|
||||
if (addrof) puts(")");
|
||||
}
|
||||
|
|
@ -275,9 +275,9 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
|
|||
double dchars = mantissabits / 3.321928094887362 + 1.0;
|
||||
if (fmtLetter == 'd') dchars++; // space for sign
|
||||
const int nchars = int(dchars);
|
||||
pfmt = string("%") + cvtToStr(nchars) + fmtLetter;
|
||||
pfmt = string{"%"} + cvtToStr(nchars) + fmtLetter;
|
||||
} else {
|
||||
pfmt = string("%") + vfmt + fmtLetter;
|
||||
pfmt = string{"%"} + vfmt + fmtLetter;
|
||||
}
|
||||
m_emitDispState.pushFormat(pfmt);
|
||||
if (!ignore) {
|
||||
|
|
@ -452,16 +452,16 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
|
|||
puts(cvtToStr(nodep->widthWords()));
|
||||
puts(", ");
|
||||
}
|
||||
iterateAndNextNull(nodep);
|
||||
iterateAndNextConstNull(nodep);
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
|
||||
putbs("VL_CVT_W_A(");
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
puts(", ");
|
||||
iterate(fromp);
|
||||
iterateConst(fromp);
|
||||
putbs(".atDefault()"); // Not accessed; only to get the proper type of values
|
||||
puts(")");
|
||||
}
|
||||
|
|
@ -672,7 +672,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
|
|||
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp,
|
||||
"Should have swapped msb & lsb earlier.");
|
||||
const string ivar = string("__Vi") + cvtToStr(depth);
|
||||
const string ivar = string{"__Vi"} + cvtToStr(depth);
|
||||
const string pre = ("for (int " + ivar + " = " + cvtToStr(0) + "; " + ivar + " < "
|
||||
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
|
||||
const string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(),
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ constexpr int EMITC_NUM_CONSTW = 8;
|
|||
//######################################################################
|
||||
// Emit lazy forward declarations
|
||||
|
||||
class EmitCLazyDecls final : public VNVisitor {
|
||||
class EmitCLazyDecls final : public VNVisitorConst {
|
||||
// NODE STATE/TYPES
|
||||
// None allowed to support threaded emitting
|
||||
|
||||
// MEMBERS
|
||||
std::unordered_set<string> m_emittedManually; // Set of names already declared manually.
|
||||
EmitCBaseVisitor& m_emitter; // For access to file output
|
||||
EmitCBaseVisitorConst& m_emitter; // For access to file output
|
||||
bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic)
|
||||
std::set<AstNode*> m_emitted; // -> in set. Already emitted decl for symbols.
|
||||
|
||||
|
|
@ -72,18 +72,18 @@ class EmitCLazyDecls final : public VNVisitor {
|
|||
// VISITORS
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
lazyDeclare(nodep->funcp());
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
void visit(AstAddrOfCFunc* nodep) override {
|
||||
lazyDeclare(nodep->funcp());
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
void visit(AstVarRef* nodep) override {
|
||||
AstVar* const varp = nodep->varp();
|
||||
// Only constant pool symbols are lazy declared for now ...
|
||||
if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) {
|
||||
if (EmitCBase::isConstPoolMod(EmitCParentModule::get(varp))) {
|
||||
lazyDeclareConstPoolVar(varp);
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ class EmitCLazyDecls final : public VNVisitor {
|
|||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
explicit EmitCLazyDecls(EmitCBaseVisitor& emitter)
|
||||
explicit EmitCLazyDecls(EmitCBaseVisitorConst& emitter)
|
||||
: m_emitter(emitter) {}
|
||||
void emit(AstNode* nodep) {
|
||||
m_needsBlankLine = false;
|
||||
|
|
@ -203,12 +203,12 @@ public:
|
|||
// variables. That way we could just invoke the appropriate emitter as needed.
|
||||
VL_RESTORER(m_emitConstInit);
|
||||
m_emitConstInit = true;
|
||||
iterate(initp);
|
||||
iterateConst(initp);
|
||||
}
|
||||
void putCommaIterateNext(AstNode* nodep, bool comma = false) {
|
||||
for (AstNode* subnodep = nodep; subnodep; subnodep = subnodep->nextp()) {
|
||||
if (comma) puts(", ");
|
||||
iterate(subnodep);
|
||||
iterateConst(subnodep);
|
||||
comma = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -273,17 +273,17 @@ public:
|
|||
|
||||
if (nodep->initsp()) {
|
||||
putsDecoration("// Init\n");
|
||||
iterateAndNextNull(nodep->initsp());
|
||||
iterateAndNextConstNull(nodep->initsp());
|
||||
}
|
||||
|
||||
if (nodep->stmtsp()) {
|
||||
putsDecoration("// Body\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
}
|
||||
|
||||
if (nodep->finalsp()) {
|
||||
putsDecoration("// Final\n");
|
||||
iterateAndNextNull(nodep->finalsp());
|
||||
iterateAndNextConstNull(nodep->finalsp());
|
||||
}
|
||||
|
||||
puts("}\n");
|
||||
|
|
@ -309,9 +309,9 @@ public:
|
|||
} else {
|
||||
puts("I(");
|
||||
}
|
||||
iterateAndNextNull(selp->lsbp());
|
||||
iterateAndNextConstNull(selp->lsbp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->fromp());
|
||||
iterateAndNextConstNull(selp->fromp());
|
||||
if (rhs) puts(", ");
|
||||
} else {
|
||||
putbs("VL_ASSIGNSEL_");
|
||||
|
|
@ -320,18 +320,18 @@ public:
|
|||
puts("(");
|
||||
puts(cvtToStr(selp->fromp()->widthMin()) + ",");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(selp->lsbp());
|
||||
iterateAndNextConstNull(selp->lsbp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->fromp());
|
||||
iterateAndNextConstNull(selp->fromp());
|
||||
puts(", ");
|
||||
}
|
||||
} else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
|
||||
iterateAndNextNull(selp->lhsp());
|
||||
iterateAndNextConstNull(selp->lhsp());
|
||||
puts(" = ");
|
||||
putbs("VL_PUTC_N(");
|
||||
iterateAndNextNull(selp->lhsp());
|
||||
iterateAndNextConstNull(selp->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->rhsp());
|
||||
iterateAndNextConstNull(selp->rhsp());
|
||||
puts(", ");
|
||||
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) {
|
||||
putbs("VL_ASSIGN_"); // Set a systemC variable
|
||||
|
|
@ -339,7 +339,7 @@ public:
|
|||
emitIQW(nodep);
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) {
|
||||
putbs("VL_ASSIGN_"); // Get a systemC variable
|
||||
|
|
@ -347,7 +347,7 @@ public:
|
|||
emitScIQW(varp);
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) //
|
||||
&& !VN_IS(nodep->rhsp(), CExpr) //
|
||||
|
|
@ -361,41 +361,41 @@ public:
|
|||
} else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
putbs("VL_ASSIGN_W(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else {
|
||||
paren = false;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(" ");
|
||||
ofp()->blockInc();
|
||||
decind = true;
|
||||
if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak();
|
||||
puts("= ");
|
||||
}
|
||||
if (rhs) iterateAndNextNull(nodep->rhsp());
|
||||
if (rhs) iterateAndNextConstNull(nodep->rhsp());
|
||||
if (paren) puts(")");
|
||||
if (decind) ofp()->blockDec();
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstAlwaysPublic*) override {}
|
||||
void visit(AstAssocSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs(".at(");
|
||||
AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType);
|
||||
UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type");
|
||||
if (adtypep->keyDTypep()->isWide()) {
|
||||
emitCvtWideArray(nodep->bitp(), nodep->fromp());
|
||||
} else {
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
iterateAndNextConstNull(nodep->bitp());
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstWildcardSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs(".at(");
|
||||
AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType);
|
||||
UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type");
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
iterateAndNextConstNull(nodep->bitp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCCall* nodep) override {
|
||||
|
|
@ -427,14 +427,14 @@ public:
|
|||
void visit(AstCMethodCall* nodep) override {
|
||||
const AstCFunc* const funcp = nodep->funcp();
|
||||
UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall");
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
putbs("->");
|
||||
puts(funcp->nameProtect());
|
||||
emitCCallArgs(nodep, "");
|
||||
}
|
||||
void visit(AstCAwait* nodep) override {
|
||||
puts("co_await ");
|
||||
iterate(nodep->exprp());
|
||||
iterateConst(nodep->exprp());
|
||||
}
|
||||
void visit(AstCNew* nodep) override {
|
||||
if (VN_IS(nodep->dtypep(), VoidDType)) {
|
||||
|
|
@ -447,7 +447,7 @@ public:
|
|||
puts(")");
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
puts(".");
|
||||
puts(nodep->name());
|
||||
puts("(");
|
||||
|
|
@ -458,7 +458,7 @@ public:
|
|||
if (VN_IS(nodep->fromp()->dtypep(), QueueDType) && subnodep->dtypep()->isWide()) {
|
||||
emitCvtWideArray(subnodep, nodep->fromp());
|
||||
} else {
|
||||
iterate(subnodep);
|
||||
iterateConst(subnodep);
|
||||
}
|
||||
comma = true;
|
||||
}
|
||||
|
|
@ -477,7 +477,7 @@ public:
|
|||
}
|
||||
// Probably fragile, V3Task may need to convert to a AstCReturn
|
||||
puts(") { return ");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts("; }\n");
|
||||
}
|
||||
void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE
|
||||
|
|
@ -492,9 +492,9 @@ public:
|
|||
if (!v3Global.opt.protectIds()) return;
|
||||
}
|
||||
if (!(nodep->protect() && v3Global.opt.protectIds())) {
|
||||
putsDecoration(string("// ") + nodep->name() + at + "\n");
|
||||
putsDecoration(string{"// "} + nodep->name() + at + "\n");
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
|
||||
|
|
@ -537,7 +537,7 @@ public:
|
|||
}
|
||||
void visit(AstCReturn* nodep) override {
|
||||
puts("return (");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstDisplay* nodep) override {
|
||||
|
|
@ -615,7 +615,7 @@ public:
|
|||
emitCvtPackStr(nodep->searchp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->outp());
|
||||
iterateAndNextConstNull(nodep->outp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstTestPlusArgs* nodep) override {
|
||||
|
|
@ -626,13 +626,13 @@ public:
|
|||
void visit(AstFError* nodep) override {
|
||||
puts("VL_FERROR_I");
|
||||
puts(nodep->strp()->isString() ? "N(" : "W(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
putbs(", ");
|
||||
if (nodep->strp()->isWide()) {
|
||||
puts(cvtToStr(nodep->strp()->widthWords()));
|
||||
putbs(", ");
|
||||
}
|
||||
iterateAndNextNull(nodep->strp());
|
||||
iterateAndNextConstNull(nodep->strp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFGetS* nodep) override {
|
||||
|
|
@ -649,8 +649,7 @@ public:
|
|||
}
|
||||
}
|
||||
void visit(AstFOpen* nodep) override {
|
||||
iterateAndNextNull(nodep->filep());
|
||||
puts(" = VL_FOPEN_NN(");
|
||||
puts("VL_FOPEN_NN(");
|
||||
emitCvtPackStr(nodep->filenamep());
|
||||
putbs(", ");
|
||||
if (nodep->modep()->width() > 4 * 8)
|
||||
|
|
@ -659,8 +658,7 @@ public:
|
|||
puts(");\n");
|
||||
}
|
||||
void visit(AstFOpenMcd* nodep) override {
|
||||
iterateAndNextNull(nodep->filep());
|
||||
puts(" = VL_FOPEN_MCD_N(");
|
||||
puts("VL_FOPEN_MCD_N(");
|
||||
emitCvtPackStr(nodep->filenamep());
|
||||
puts(");\n");
|
||||
}
|
||||
|
|
@ -696,18 +694,18 @@ public:
|
|||
{
|
||||
const bool need_ptr = !VN_IS(nodep->memp()->dtypep(), AssocArrayDType);
|
||||
if (need_ptr) puts(" &(");
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextConstNull(nodep->memp());
|
||||
if (need_ptr) puts(")");
|
||||
}
|
||||
putbs(", ");
|
||||
if (nodep->lsbp()) {
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
iterateAndNextConstNull(nodep->lsbp());
|
||||
} else {
|
||||
puts(cvtToStr(array_lo));
|
||||
}
|
||||
putbs(", ");
|
||||
if (nodep->msbp()) {
|
||||
iterateAndNextNull(nodep->msbp());
|
||||
iterateAndNextConstNull(nodep->msbp());
|
||||
} else {
|
||||
puts("~0ULL");
|
||||
}
|
||||
|
|
@ -715,39 +713,37 @@ public:
|
|||
}
|
||||
void visit(AstFClose* nodep) override {
|
||||
puts("VL_FCLOSE_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts("); ");
|
||||
iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it.
|
||||
puts(" = 0;\n");
|
||||
}
|
||||
void visit(AstFFlush* nodep) override {
|
||||
if (!nodep->filep()) {
|
||||
puts("Verilated::runFlushCallbacks();\n");
|
||||
} else {
|
||||
puts("if (");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(") { VL_FFLUSH_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts("); }\n");
|
||||
}
|
||||
}
|
||||
void visit(AstFSeek* nodep) override {
|
||||
puts("(VL_FSEEK_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->offset());
|
||||
iterateAndNextConstNull(nodep->offset());
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->operation());
|
||||
iterateAndNextConstNull(nodep->operation());
|
||||
puts(") == -1 ? -1 : 0)");
|
||||
}
|
||||
void visit(AstFTell* nodep) override {
|
||||
puts("VL_FTELL_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFRewind* nodep) override {
|
||||
puts("(VL_FSEEK_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(", 0, 0) == -1 ? -1 : 0)");
|
||||
}
|
||||
void visit(AstFRead* nodep) override {
|
||||
|
|
@ -775,19 +771,19 @@ public:
|
|||
puts(cvtToStr(array_size));
|
||||
putbs(", ");
|
||||
puts("&(");
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextConstNull(nodep->memp());
|
||||
puts(")");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
putbs(", ");
|
||||
if (nodep->startp()) {
|
||||
iterateAndNextNull(nodep->startp());
|
||||
iterateAndNextConstNull(nodep->startp());
|
||||
} else {
|
||||
puts(cvtToStr(array_lo));
|
||||
}
|
||||
putbs(", ");
|
||||
if (nodep->countp()) {
|
||||
iterateAndNextNull(nodep->countp());
|
||||
iterateAndNextConstNull(nodep->countp());
|
||||
} else {
|
||||
puts(cvtToStr(array_size));
|
||||
}
|
||||
|
|
@ -795,7 +791,7 @@ public:
|
|||
}
|
||||
void visit(AstSysFuncAsTask* nodep) override {
|
||||
if (!nodep->lhsp()->isWide()) puts("(void)");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
if (!nodep->lhsp()->isWide()) puts(";");
|
||||
}
|
||||
void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); }
|
||||
|
|
@ -809,7 +805,7 @@ public:
|
|||
putbs(", ");
|
||||
}
|
||||
checkMaxWords(nodep->lhsp());
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstSystemF* nodep) override {
|
||||
|
|
@ -821,18 +817,18 @@ public:
|
|||
putbs(", ");
|
||||
}
|
||||
checkMaxWords(nodep->lhsp());
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstStmtExpr* node) override {
|
||||
iterate(node->exprp());
|
||||
iterateConst(node->exprp());
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstJumpBlock* nodep) override {
|
||||
nodep->labelNum(++m_labelNum);
|
||||
puts("{\n"); // Make it visually obvious label jumps outside these
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(nodep->endStmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->endStmtsp());
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
|
|
@ -842,13 +838,13 @@ public:
|
|||
puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
|
||||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
puts("while (");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
puts(") {\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->incsp());
|
||||
iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstNodeIf* nodep) override {
|
||||
|
|
@ -857,20 +853,20 @@ public:
|
|||
puts(nodep->branchPred().ascii());
|
||||
puts("(");
|
||||
}
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
if (!nodep->branchPred().unknown()) puts(")");
|
||||
puts(") {\n");
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
puts("}");
|
||||
if (!nodep->elsesp()) {
|
||||
puts("\n");
|
||||
} else {
|
||||
if (VN_IS(nodep->elsesp(), NodeIf) && !nodep->elsesp()->nextp()) {
|
||||
puts(" else ");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
} else {
|
||||
puts(" else {\n");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
puts("}\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -879,9 +875,9 @@ public:
|
|||
// GCC allows compound statements in expressions, but this is not standard.
|
||||
// So we use an immediate-evaluation lambda and comma operator
|
||||
putbs("([&]() {\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
puts("}(), ");
|
||||
iterateAndNextNull(nodep->resultp());
|
||||
iterateAndNextConstNull(nodep->resultp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstStop* nodep) override {
|
||||
|
|
@ -909,6 +905,9 @@ public:
|
|||
void visit(AstRand* nodep) override {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr);
|
||||
}
|
||||
void visit(AstRandRNG* nodep) override {
|
||||
emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr);
|
||||
}
|
||||
void visit(AstTime* nodep) override {
|
||||
puts("VL_TIME_UNITED_Q(");
|
||||
if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units");
|
||||
|
|
@ -925,13 +924,13 @@ public:
|
|||
}
|
||||
void visit(AstTimeFormat* nodep) override {
|
||||
puts("VL_TIMEFORMAT_IINI(");
|
||||
iterateAndNextNull(nodep->unitsp());
|
||||
iterateAndNextConstNull(nodep->unitsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->precisionp());
|
||||
iterateAndNextConstNull(nodep->precisionp());
|
||||
puts(", ");
|
||||
emitCvtPackStr(nodep->suffixp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->widthp());
|
||||
iterateAndNextConstNull(nodep->widthp());
|
||||
puts(", vlSymsp->_vm_contextp__);\n");
|
||||
}
|
||||
void visit(AstTimePrecision* nodep) override {
|
||||
|
|
@ -950,23 +949,23 @@ public:
|
|||
void visit(AstTextBlock* nodep) override {
|
||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterate(childp);
|
||||
iterateConst(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
}
|
||||
void visit(AstCStmt* nodep) override {
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
}
|
||||
void visit(AstCExpr* nodep) override {
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
VL_RESTORER(m_inUC);
|
||||
m_inUC = true;
|
||||
putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n"));
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
puts("\n");
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
|
|
@ -974,7 +973,7 @@ public:
|
|||
m_inUC = true;
|
||||
puts("\n");
|
||||
putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n"));
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
|
|
@ -996,7 +995,7 @@ public:
|
|||
putbs("(");
|
||||
puts(nodep->emitSimpleOperator());
|
||||
puts(" ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
} else {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr);
|
||||
|
|
@ -1012,11 +1011,11 @@ public:
|
|||
}
|
||||
if (emitSimpleOk(nodep)) {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(" ");
|
||||
putbs(nodep->emitSimpleOperator());
|
||||
puts(" ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
} else {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
|
||||
|
|
@ -1038,7 +1037,7 @@ public:
|
|||
putbs("VL_REDXOR_");
|
||||
puts(cvtToStr(widthPow2));
|
||||
puts("(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
|
@ -1049,7 +1048,7 @@ public:
|
|||
} else {
|
||||
puts("(QData)(");
|
||||
}
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstNodeCond* nodep) override {
|
||||
|
|
@ -1058,27 +1057,27 @@ public:
|
|||
emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep());
|
||||
} else {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
putbs(" ? ");
|
||||
iterateAndNextNull(nodep->thenp());
|
||||
iterateAndNextConstNull(nodep->thenp());
|
||||
putbs(" : ");
|
||||
iterateAndNextNull(nodep->elsep());
|
||||
iterateAndNextConstNull(nodep->elsep());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs("->");
|
||||
puts(nodep->varp()->nameProtect());
|
||||
}
|
||||
void visit(AstStructSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs(".");
|
||||
puts(nodep->nameProtect());
|
||||
}
|
||||
void visit(AstNullCheck* nodep) override {
|
||||
puts("VL_NULL_CHECK(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
putsQuoted(protect(nodep->fileline()->filename()));
|
||||
puts(", ");
|
||||
|
|
@ -1088,7 +1087,7 @@ public:
|
|||
void visit(AstNewCopy* nodep) override {
|
||||
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", ");
|
||||
puts("*"); // i.e. make into a reference
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstSel* nodep) override {
|
||||
|
|
@ -1106,9 +1105,9 @@ public:
|
|||
puts("OI(");
|
||||
if (nodep->lhsp()) puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
} else {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
|
||||
|
|
@ -1126,7 +1125,7 @@ public:
|
|||
puts("I(");
|
||||
puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
const uint32_t rd_log2 = V3Number::log2b(VN_AS(nodep->rhsp(), Const)->toUInt());
|
||||
puts(cvtToStr(rd_log2) + ")");
|
||||
|
|
@ -1138,9 +1137,9 @@ public:
|
|||
}
|
||||
void visit(AstCastDynamic* nodep) override {
|
||||
putbs("VL_CAST_DYNAMIC(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCountBits* nodep) override {
|
||||
|
|
@ -1154,16 +1153,16 @@ public:
|
|||
// (which is always 32)
|
||||
puts(", ");
|
||||
}
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->thsp());
|
||||
iterateAndNextConstNull(nodep->thsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->fhsp());
|
||||
iterateAndNextConstNull(nodep->fhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstInitItem* nodep) override { iterateChildrenConst(nodep); }
|
||||
// Terminals
|
||||
void visit(AstVarRef* nodep) override {
|
||||
const AstVar* const varp = nodep->varp();
|
||||
|
|
@ -1221,17 +1220,17 @@ public:
|
|||
puts("()");
|
||||
if (nodep->defaultp()) {
|
||||
putbs(".setDefault(");
|
||||
iterateAndNextNull(nodep->defaultp());
|
||||
iterateAndNextConstNull(nodep->defaultp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstSetAssoc* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
putbs(".set(");
|
||||
iterateAndNextNull(nodep->keyp());
|
||||
iterateAndNextConstNull(nodep->keyp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->valuep());
|
||||
iterateAndNextConstNull(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstConsWildcard* nodep) override {
|
||||
|
|
@ -1239,17 +1238,17 @@ public:
|
|||
puts("()");
|
||||
if (nodep->defaultp()) {
|
||||
putbs(".setDefault(");
|
||||
iterateAndNextNull(nodep->defaultp());
|
||||
iterateAndNextConstNull(nodep->defaultp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstSetWildcard* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
putbs(".set(");
|
||||
iterateAndNextNull(nodep->keyp());
|
||||
iterateAndNextConstNull(nodep->keyp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->valuep());
|
||||
iterateAndNextConstNull(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstConsDynArray* nodep) override {
|
||||
|
|
@ -1258,12 +1257,12 @@ public:
|
|||
puts("()");
|
||||
} else {
|
||||
puts("::cons(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
if (nodep->rhsp()) {
|
||||
puts(", ");
|
||||
putbs("");
|
||||
}
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
|
@ -1271,7 +1270,7 @@ public:
|
|||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
puts("{");
|
||||
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
iterate(memberp);
|
||||
iterateConst(memberp);
|
||||
if (memberp->nextp()) { puts(", "); }
|
||||
}
|
||||
puts("}");
|
||||
|
|
@ -1281,7 +1280,7 @@ public:
|
|||
putbs(".");
|
||||
puts(vdtypep->name());
|
||||
puts(" = ");
|
||||
iterate(nodep->rhsp());
|
||||
iterateConst(nodep->rhsp());
|
||||
}
|
||||
void visit(AstConsQueue* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
|
|
@ -1289,12 +1288,12 @@ public:
|
|||
puts("()");
|
||||
} else {
|
||||
puts("::cons(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
if (nodep->rhsp()) {
|
||||
puts(", ");
|
||||
putbs("");
|
||||
}
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
|
@ -1311,8 +1310,8 @@ public:
|
|||
|
||||
// Default
|
||||
void visit(AstNode* nodep) override {
|
||||
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
|
||||
iterateChildren(nodep);
|
||||
puts(string{"\n???? // "} + nodep->prettyTypeName() + "\n");
|
||||
iterateChildrenConst(nodep);
|
||||
// LCOV_EXCL_START
|
||||
if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress
|
||||
nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
|
|
@ -1326,7 +1325,7 @@ public:
|
|||
: EmitCFunc{} {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~EmitCFunc() override = default;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -117,7 +117,12 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
emitCurrentList();
|
||||
}
|
||||
void emitInternalVarDecls(const AstNodeModule* modp) {
|
||||
if (!VN_IS(modp, Class)) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (classp->needRNG()) {
|
||||
putsDecoration("\n// INTERNAL VARIABLES\n");
|
||||
puts("VlRNG __Vm_rng;\n");
|
||||
}
|
||||
} else { // not class
|
||||
putsDecoration("\n// INTERNAL VARIABLES\n");
|
||||
puts(symClassName() + "* const vlSymsp;\n");
|
||||
}
|
||||
|
|
@ -136,7 +141,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
puts(varp->dtypep()->cType(varp->nameProtect(), false, false));
|
||||
if (canBeConstexpr) {
|
||||
puts(" = ");
|
||||
iterate(varp->valuep());
|
||||
iterateConst(varp->valuep());
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
|
|
@ -200,7 +205,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
}
|
||||
puts(itemp->nameProtect());
|
||||
puts(" = ");
|
||||
iterate(itemp->valuep());
|
||||
iterateConst(itemp->valuep());
|
||||
if (VN_IS(itemp->nextp(), EnumItem)) puts(",");
|
||||
puts("\n");
|
||||
}
|
||||
|
|
@ -224,7 +229,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
}
|
||||
}
|
||||
puts(sdtypep->verilogKwd()); // "struct"/"union"
|
||||
puts(" " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n");
|
||||
puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n");
|
||||
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false));
|
||||
|
|
|
|||
|
|
@ -33,28 +33,27 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
// Visitor that gathers the headers required by an AstCFunc
|
||||
|
||||
class EmitCGatherDependencies final : VNVisitor {
|
||||
class EmitCGatherDependencies final : VNVisitorConst {
|
||||
// Ordered set, as it is used as a key in another map.
|
||||
std::set<string> m_dependencies; // Header names to be included in output C++ file
|
||||
|
||||
// METHODS
|
||||
void addSymsDependency() { m_dependencies.insert(EmitCBaseVisitor::symClassName()); }
|
||||
void addSymsDependency() { m_dependencies.insert(EmitCBase::symClassName()); }
|
||||
void addModDependency(const AstNodeModule* modp) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(classp->classOrPackagep()));
|
||||
m_dependencies.insert(EmitCBase::prefixNameProtect(classp->classOrPackagep()));
|
||||
} else {
|
||||
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(modp));
|
||||
m_dependencies.insert(EmitCBase::prefixNameProtect(modp));
|
||||
}
|
||||
}
|
||||
void addDTypeDependency(const AstNodeDType* nodep) {
|
||||
if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) {
|
||||
m_dependencies.insert(
|
||||
EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep()));
|
||||
EmitCBase::prefixNameProtect(dtypep->classp()->classOrPackagep()));
|
||||
} else if (const AstNodeUOrStructDType* const dtypep
|
||||
= VN_CAST(nodep, NodeUOrStructDType)) {
|
||||
if (!dtypep->packed()) {
|
||||
m_dependencies.insert(
|
||||
EmitCBaseVisitor::prefixNameProtect(dtypep->classOrPackagep()));
|
||||
m_dependencies.insert(EmitCBase::prefixNameProtect(dtypep->classOrPackagep()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +141,7 @@ class EmitCGatherDependencies final : VNVisitor {
|
|||
// declaration of the receiver class, but their body very likely includes at least one
|
||||
// relative reference, so we are probably not loosing much.
|
||||
addModDependency(EmitCParentModule::get(cfuncp));
|
||||
iterate(cfuncp);
|
||||
iterateConst(cfuncp);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -175,8 +174,7 @@ class EmitCImp final : EmitCFunc {
|
|||
// Unfortunately we have some lint checks here, so we can't just skip processing.
|
||||
// We should move them to a different stage.
|
||||
const string filename = VL_DEV_NULL;
|
||||
m_cfilesr.push_back(
|
||||
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
|
||||
m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true));
|
||||
m_ofp = new V3OutCFile{filename};
|
||||
} else {
|
||||
string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp);
|
||||
|
|
@ -186,12 +184,11 @@ class EmitCImp final : EmitCFunc {
|
|||
}
|
||||
if (m_slow) filename += "__Slow";
|
||||
filename += ".cpp";
|
||||
m_cfilesr.push_back(
|
||||
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
|
||||
m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true));
|
||||
m_ofp = v3Global.opt.systemC() ? new V3OutScFile{filename} : new V3OutCFile{filename};
|
||||
}
|
||||
|
||||
ofp()->putsHeader();
|
||||
putsHeader();
|
||||
puts("// DESCRIPTION: Verilator output: Design implementation internals\n");
|
||||
puts("// See " + topClassName() + ".h for the primary calling header\n");
|
||||
|
||||
|
|
@ -199,6 +196,7 @@ class EmitCImp final : EmitCFunc {
|
|||
puts("\n#include \"verilated.h\"\n");
|
||||
if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n");
|
||||
puts("\n");
|
||||
puts("#include \"" + symClassName() + ".h\"\n");
|
||||
for (const string& name : headers) puts("#include \"" + name + ".h\"\n");
|
||||
|
||||
emitTextSection(m_modp, VNType::atScImpHdr);
|
||||
|
|
@ -263,7 +261,7 @@ class EmitCImp final : EmitCFunc {
|
|||
puts(", ");
|
||||
puts(varp->nameProtect());
|
||||
puts("(");
|
||||
iterate(varp->valuep());
|
||||
iterateConst(varp->valuep());
|
||||
puts(")\n");
|
||||
} else if (varp->isIO() && varp->isSc()) {
|
||||
puts(", ");
|
||||
|
|
@ -402,7 +400,7 @@ class EmitCImp final : EmitCFunc {
|
|||
const int vecnum = vects++;
|
||||
UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp,
|
||||
"Should have swapped msb & lsb earlier.");
|
||||
const string ivar = string("__Vi") + cvtToStr(vecnum);
|
||||
const string ivar = string{"__Vi"} + cvtToStr(vecnum);
|
||||
puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0));
|
||||
puts("; " + ivar + " < " + cvtToStr(arrayp->elementsConst()));
|
||||
puts("; ++" + ivar + ") {\n");
|
||||
|
|
@ -416,7 +414,7 @@ class EmitCImp final : EmitCFunc {
|
|||
if (elementp->isWide()
|
||||
&& !(basicp && basicp->keyword() == VBasicDTypeKwd::STRING)) {
|
||||
const int vecnum = vects++;
|
||||
const string ivar = string("__Vi") + cvtToStr(vecnum);
|
||||
const string ivar = string{"__Vi"} + cvtToStr(vecnum);
|
||||
puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0));
|
||||
puts("; " + ivar + " < " + cvtToStr(elementp->widthWords()));
|
||||
puts("; ++" + ivar + ") {\n");
|
||||
|
|
@ -515,7 +513,7 @@ class EmitCImp final : EmitCFunc {
|
|||
// Compute the hash of the dependencies, so we can add it to the filenames to
|
||||
// disambiguate them
|
||||
V3Hash hash;
|
||||
for (const string& name : *m_requiredHeadersp) { hash += name; }
|
||||
for (const string& name : *m_requiredHeadersp) hash += name;
|
||||
m_subFileName = "DepSet_" + hash.toString();
|
||||
// Open output file
|
||||
openNextOutputFile(*m_requiredHeadersp, m_subFileName);
|
||||
|
|
@ -523,7 +521,7 @@ class EmitCImp final : EmitCFunc {
|
|||
for (AstCFunc* const funcp : pair.second) {
|
||||
VL_RESTORER(m_modp);
|
||||
m_modp = EmitCParentModule::get(funcp);
|
||||
iterate(funcp);
|
||||
iterateConst(funcp);
|
||||
}
|
||||
// Close output file
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
|
|
@ -598,7 +596,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
if (m_slow) filename += "__Slow";
|
||||
filename += ".cpp";
|
||||
|
||||
AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/);
|
||||
AstCFile* const cfilep = createCFile(filename, m_slow, true /*source*/);
|
||||
cfilep->support(true);
|
||||
m_cfilesr.push_back(cfilep);
|
||||
|
||||
|
|
@ -607,9 +605,9 @@ class EmitCTrace final : EmitCFunc {
|
|||
} else {
|
||||
m_ofp = new V3OutCFile{filename};
|
||||
}
|
||||
m_ofp->putsHeader();
|
||||
m_ofp->puts("// DESCR"
|
||||
"IPTION: Verilator output: Tracing implementation internals\n");
|
||||
putsHeader();
|
||||
puts("// DESCR"
|
||||
"IPTION: Verilator output: Tracing implementation internals\n");
|
||||
|
||||
// Includes
|
||||
puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n");
|
||||
|
|
@ -775,7 +773,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
}
|
||||
|
||||
void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) {
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
const string func = nodep->full() ? "full" : "chg";
|
||||
bool emitWidth = true;
|
||||
if (nodep->dtypep()->basicp()->isDouble()) {
|
||||
|
|
@ -818,7 +816,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
} else if (emitTraceIsScBv(nodep)) {
|
||||
puts("VL_SC_BV_DATAP(");
|
||||
}
|
||||
iterate(varrefp); // Put var name out
|
||||
iterateConst(varrefp); // Put var name out
|
||||
// Tracing only supports 1D arrays
|
||||
if (nodep->declp()->arrayRange().ranged()) {
|
||||
if (arrayindex == -2) {
|
||||
|
|
@ -840,7 +838,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
puts(")");
|
||||
} else {
|
||||
puts("(");
|
||||
iterate(nodep->valuep());
|
||||
iterateConst(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
|
@ -902,7 +900,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
openNextOutputFile();
|
||||
// Emit functions
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterate(funcp); }
|
||||
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterateConst(funcp); }
|
||||
}
|
||||
// Close output file
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
|
||||
//######################################################################
|
||||
|
||||
class EmitCInlines final : EmitCBaseVisitor {
|
||||
class EmitCInlines final : EmitCBaseVisitorConst {
|
||||
// STATE
|
||||
|
||||
// METHODS
|
||||
|
|
@ -37,26 +37,26 @@ class EmitCInlines final : EmitCBaseVisitor {
|
|||
void visit(AstCNew* nodep) override {
|
||||
if (v3Global.opt.savable())
|
||||
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstDumpCtl* nodep) override {
|
||||
if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeDistBiop* nodep) override {
|
||||
v3Global.setUsesProbDist();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeDistTriop* nodep) override {
|
||||
v3Global.setUsesProbDist();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); }
|
||||
explicit EmitCInlines(AstNetlist* nodep) { iterateConst(nodep); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -64,5 +64,5 @@ public:
|
|||
|
||||
void V3EmitC::emitcInlines() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
EmitCInlines(v3Global.rootp());
|
||||
{ EmitCInlines{v3Global.rootp()}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
|
||||
//######################################################################
|
||||
|
||||
class EmitCMain final : EmitCBaseVisitor {
|
||||
class EmitCMain final : EmitCBaseVisitorConst {
|
||||
// METHODS
|
||||
|
||||
// VISITORS
|
||||
// This visitor doesn't really iterate, but exist to appease base class
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // LCOV_EXCL_LINE
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
|
|
|
|||
|
|
@ -658,7 +658,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts("\n");
|
||||
}
|
||||
|
||||
iterate(funcp);
|
||||
iterateConst(funcp);
|
||||
}
|
||||
|
||||
if (m_ofp) { VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); }
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
// Symbol table emitting
|
||||
|
||||
class EmitCSyms final : EmitCBaseVisitor {
|
||||
class EmitCSyms final : EmitCBaseVisitorConst {
|
||||
// NODE STATE
|
||||
// Cleared on Netlist
|
||||
// AstNodeModule::user1() -> bool. Set true __Vconfigure called
|
||||
|
|
@ -278,7 +278,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Collect list of scopes
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
varsExpand();
|
||||
|
||||
if (v3Global.opt.vpi()) buildVpiHierarchy();
|
||||
|
|
@ -304,7 +304,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstCellInline* nodep) override {
|
||||
|
|
@ -356,7 +356,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
nameCheck(nodep);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (nodep->isSigUserRdPublic() && !m_cfuncp)
|
||||
m_modVars.emplace_back(std::make_pair(m_modp, nodep));
|
||||
}
|
||||
|
|
@ -372,18 +372,18 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
VL_RESTORER(m_cfuncp);
|
||||
{
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
void visit(AstConst*) override {}
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly)
|
||||
: m_dpiHdrOnly{dpiHdrOnly} {
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -432,7 +432,8 @@ void EmitCSyms::emitSymHdr() {
|
|||
if (funcp->dpiExportImpl()) {
|
||||
const string cbtype
|
||||
= protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t");
|
||||
types["using " + cbtype + " = void (*) (" + cFuncArgs(funcp) + ");\n"] = 1;
|
||||
const string functype = funcp->rtnTypeVoid() + " (*) (" + cFuncArgs(funcp) + ")";
|
||||
types["using " + cbtype + " = " + functype + ";\n"] = 1;
|
||||
}
|
||||
}
|
||||
for (const auto& i : types) puts(i.first);
|
||||
|
|
@ -516,7 +517,7 @@ void EmitCSyms::emitSymHdr() {
|
|||
puts("\n// CONSTRUCTORS\n");
|
||||
puts(symClassName() + "(VerilatedContext* contextp, const char* namep, " + topClassName()
|
||||
+ "* modelp);\n");
|
||||
puts(string("~") + symClassName() + "();\n");
|
||||
puts(string{"~"} + symClassName() + "();\n");
|
||||
|
||||
for (const auto& i : m_usesVfinal) {
|
||||
puts("void " + symClassName() + "_" + cvtToStr(i.first) + "(");
|
||||
|
|
|
|||
|
|
@ -156,9 +156,9 @@ public:
|
|||
of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n");
|
||||
of.puts("VERILATOR_ROOT = " + V3Options::getenvVERILATOR_ROOT() + "\n");
|
||||
of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n");
|
||||
of.puts(string("SYSTEMC_INCLUDE ?= ") + V3Options::getenvSYSTEMC_INCLUDE() + "\n");
|
||||
of.puts(string{"SYSTEMC_INCLUDE ?= "} + V3Options::getenvSYSTEMC_INCLUDE() + "\n");
|
||||
of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n");
|
||||
of.puts(string("SYSTEMC_LIBDIR ?= ") + V3Options::getenvSYSTEMC_LIBDIR() + "\n");
|
||||
of.puts(string{"SYSTEMC_LIBDIR ?= "} + V3Options::getenvSYSTEMC_LIBDIR() + "\n");
|
||||
|
||||
// Only check it if we really need the value
|
||||
if (v3Global.opt.systemC() && !V3Options::systemCFound()) {
|
||||
|
|
@ -169,22 +169,22 @@ public:
|
|||
|
||||
of.puts("\n### Switches...\n");
|
||||
of.puts("# C++ code coverage 0/1 (from --prof-c)\n");
|
||||
of.puts(string("VM_PROFC = ") + ((v3Global.opt.profC()) ? "1" : "0") + "\n");
|
||||
of.puts(string{"VM_PROFC = "} + ((v3Global.opt.profC()) ? "1" : "0") + "\n");
|
||||
of.puts("# SystemC output mode? 0/1 (from --sc)\n");
|
||||
of.puts(string("VM_SC = ") + ((v3Global.opt.systemC()) ? "1" : "0") + "\n");
|
||||
of.puts(string{"VM_SC = "} + ((v3Global.opt.systemC()) ? "1" : "0") + "\n");
|
||||
of.puts("# Legacy or SystemC output mode? 0/1 (from --sc)\n");
|
||||
of.puts(string("VM_SP_OR_SC = $(VM_SC)\n"));
|
||||
of.puts(string{"VM_SP_OR_SC = $(VM_SC)\n"});
|
||||
of.puts("# Deprecated\n");
|
||||
of.puts(string("VM_PCLI = ") + (v3Global.opt.systemC() ? "0" : "1") + "\n");
|
||||
of.puts(string{"VM_PCLI = "} + (v3Global.opt.systemC() ? "0" : "1") + "\n");
|
||||
of.puts(
|
||||
"# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n");
|
||||
of.puts(string("VM_SC_TARGET_ARCH = ") + V3Options::getenvSYSTEMC_ARCH() + "\n");
|
||||
of.puts(string{"VM_SC_TARGET_ARCH = "} + V3Options::getenvSYSTEMC_ARCH() + "\n");
|
||||
|
||||
of.puts("\n### Vars...\n");
|
||||
of.puts("# Design prefix (from --prefix)\n");
|
||||
of.puts(string("VM_PREFIX = ") + v3Global.opt.prefix() + "\n");
|
||||
of.puts(string{"VM_PREFIX = "} + v3Global.opt.prefix() + "\n");
|
||||
of.puts("# Module prefix (from --prefix)\n");
|
||||
of.puts(string("VM_MODPREFIX = ") + v3Global.opt.modPrefix() + "\n");
|
||||
of.puts(string{"VM_MODPREFIX = "} + v3Global.opt.modPrefix() + "\n");
|
||||
|
||||
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
|
||||
of.puts("VM_USER_CFLAGS = \\\n");
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ class V3HierBlockPlan;
|
|||
|
||||
class V3EmitMk final {
|
||||
public:
|
||||
// Number of source files after which to use parallel compiles
|
||||
static const size_t PARALLEL_FILE_CNT_THRESHOLD = 128;
|
||||
|
||||
static void emitmk();
|
||||
static void emitHierVerilation(const V3HierBlockPlan* planp);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
// ######################################################################
|
||||
// Emit statements and expressions
|
||||
|
||||
class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
||||
class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||
// MEMBERS
|
||||
bool m_suppressSemi = false;
|
||||
const bool m_suppressUnknown = false;
|
||||
|
|
@ -166,7 +166,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
// AstSenItem is called for dumping in isolation by V3Order
|
||||
putfs(nodep, "@(");
|
||||
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
|
||||
iterate(expp);
|
||||
iterateConst(expp);
|
||||
if (expp->nextp()) putqs(expp->nextp(), " or ");
|
||||
}
|
||||
puts(")");
|
||||
|
|
@ -382,7 +382,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); }
|
||||
void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); }
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
iterate(nodep->exprp());
|
||||
iterateConst(nodep->exprp());
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstNodeSimpleText* nodep) override {
|
||||
|
|
@ -398,7 +398,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
VL_RESTORER(m_suppressSemi);
|
||||
m_suppressVarSemi = nodep->commas();
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterate(childp);
|
||||
iterateConst(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
}
|
||||
|
|
@ -426,11 +426,11 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
}
|
||||
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
puts("." + nodep->name() + "(");
|
||||
for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) {
|
||||
if (pinp != nodep->pinsp()) puts(", ");
|
||||
iterate(pinp);
|
||||
iterateConst(pinp);
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
|
|
@ -506,7 +506,12 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
nodep->thsp());
|
||||
}
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
puts(".");
|
||||
puts(nodep->prettyName());
|
||||
}
|
||||
void visit(AstStructSel* nodep) override {
|
||||
iterateConst(nodep->fromp());
|
||||
puts(".");
|
||||
puts(nodep->prettyName());
|
||||
}
|
||||
|
|
@ -528,7 +533,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
puts(cvtToStr(itr.first));
|
||||
puts(":");
|
||||
AstNode* const valuep = itr.second->valuep();
|
||||
iterate(valuep);
|
||||
iterateConst(valuep);
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
|
|
@ -608,13 +613,13 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
}
|
||||
void visit(AstConstDType* nodep) override {
|
||||
putfs(nodep, "const ");
|
||||
iterate(nodep->subDTypep());
|
||||
iterateConst(nodep->subDTypep());
|
||||
}
|
||||
void visit(AstNodeArrayDType* nodep) override {
|
||||
iterate(nodep->subDTypep());
|
||||
iterateConst(nodep->subDTypep());
|
||||
iterateAndNextConstNull(nodep->rangep());
|
||||
}
|
||||
void visit(AstRefDType* nodep) override { iterate(nodep->skipRefp()); }
|
||||
void visit(AstRefDType* nodep) override { iterateConst(nodep->skipRefp()); }
|
||||
void visit(AstNodeUOrStructDType* nodep) override {
|
||||
puts(nodep->verilogKwd() + " ");
|
||||
if (nodep->packed()) puts("packed ");
|
||||
|
|
@ -622,13 +627,13 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
puts("{");
|
||||
for (AstMemberDType* itemp = nodep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
iterate(itemp);
|
||||
iterateConst(itemp);
|
||||
puts(";");
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
void visit(AstMemberDType* nodep) override {
|
||||
iterate(nodep->subDTypep());
|
||||
iterateConst(nodep->subDTypep());
|
||||
puts(" ");
|
||||
puts(nodep->name());
|
||||
}
|
||||
|
|
@ -693,7 +698,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
unpackps.push_back(unpackp);
|
||||
dtypep = unpackp->subDTypep();
|
||||
} else {
|
||||
iterate(dtypep);
|
||||
iterateConst(dtypep);
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
dtypep = nullptr;
|
||||
|
|
@ -735,16 +740,16 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
|
||||
public:
|
||||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
|
||||
explicit EmitVBaseVisitorConst(bool suppressUnknown, AstSenTree* domainp)
|
||||
: m_suppressUnknown{suppressUnknown}
|
||||
, m_sensesp{domainp} {}
|
||||
~EmitVBaseVisitor() override = default;
|
||||
~EmitVBaseVisitorConst() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Emit to an output file
|
||||
|
||||
class EmitVFileVisitor final : public EmitVBaseVisitor {
|
||||
class EmitVFileVisitor final : public EmitVBaseVisitorConst {
|
||||
// METHODS
|
||||
void puts(const string& str) override { ofp()->puts(str); }
|
||||
void putbs(const string& str) override { ofp()->putbs(str); }
|
||||
|
|
@ -754,10 +759,10 @@ class EmitVFileVisitor final : public EmitVBaseVisitor {
|
|||
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutVFile* ofp, bool trackText, bool suppressUnknown)
|
||||
: EmitVBaseVisitor{suppressUnknown, nullptr} {
|
||||
: EmitVBaseVisitorConst{suppressUnknown, nullptr} {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~EmitVFileVisitor() override = default;
|
||||
};
|
||||
|
|
@ -765,7 +770,7 @@ public:
|
|||
//######################################################################
|
||||
// Emit to a stream (perhaps stringstream)
|
||||
|
||||
class EmitVStreamVisitor final : public EmitVBaseVisitor {
|
||||
class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
// METHODS
|
||||
|
|
@ -777,9 +782,9 @@ class EmitVStreamVisitor final : public EmitVBaseVisitor {
|
|||
|
||||
public:
|
||||
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os)
|
||||
: EmitVBaseVisitor{false, nullptr}
|
||||
: EmitVBaseVisitorConst{false, nullptr}
|
||||
, m_os(os) { // Need () or GCC 4.8 false warning
|
||||
iterate(const_cast<AstNode*>(nodep));
|
||||
iterateConst(const_cast<AstNode*>(nodep));
|
||||
}
|
||||
~EmitVStreamVisitor() override = default;
|
||||
};
|
||||
|
|
@ -832,7 +837,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class EmitVPrefixedVisitor final : public EmitVBaseVisitor {
|
||||
class EmitVPrefixedVisitor final : public EmitVBaseVisitorConst {
|
||||
// MEMBERS
|
||||
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the
|
||||
// inheritance is another unused V3OutFormatter)
|
||||
|
|
@ -856,10 +861,10 @@ class EmitVPrefixedVisitor final : public EmitVBaseVisitor {
|
|||
public:
|
||||
EmitVPrefixedVisitor(const AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
|
||||
AstSenTree* domainp, bool user3mark)
|
||||
: EmitVBaseVisitor{false, domainp}
|
||||
: EmitVBaseVisitorConst{false, domainp}
|
||||
, m_formatter{os, prefix, flWidth} {
|
||||
if (user3mark) VNUser3InUse::check();
|
||||
iterate(const_cast<AstNode*>(nodep));
|
||||
iterateConst(const_cast<AstNode*>(nodep));
|
||||
}
|
||||
~EmitVPrefixedVisitor() override = default;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
// ######################################################################
|
||||
// Emit statements and expressions
|
||||
|
||||
class EmitXmlFileVisitor final : public VNVisitor {
|
||||
class EmitXmlFileVisitor final : public VNVisitorConst {
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNode::user1 -> uint64_t, number to connect crossrefs
|
||||
|
|
@ -94,7 +94,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
|
|||
if (tag == "") tag = VString::downcase(nodep->typeName());
|
||||
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
|
||||
puts(">\n");
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
puts("</" + tag + ">\n");
|
||||
} else {
|
||||
puts("/>\n");
|
||||
|
|
@ -117,13 +117,13 @@ class EmitXmlFileVisitor final : public VNVisitor {
|
|||
void visit(AstNodeIf* nodep) override {
|
||||
outputTag(nodep, "if");
|
||||
puts(">\n");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
puts("<begin>\n");
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
puts("</begin>\n");
|
||||
if (nodep->elsesp()) {
|
||||
puts("<begin>\n");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
puts("</begin>\n");
|
||||
}
|
||||
puts("</if>\n");
|
||||
|
|
@ -132,34 +132,34 @@ class EmitXmlFileVisitor final : public VNVisitor {
|
|||
outputTag(nodep, "while");
|
||||
puts(">\n");
|
||||
puts("<begin>\n");
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
puts("</begin>\n");
|
||||
if (nodep->condp()) {
|
||||
puts("<begin>\n");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
puts("</begin>\n");
|
||||
}
|
||||
if (nodep->stmtsp()) {
|
||||
puts("<begin>\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
puts("</begin>\n");
|
||||
}
|
||||
if (nodep->incsp()) {
|
||||
puts("<begin>\n");
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
iterateAndNextConstNull(nodep->incsp());
|
||||
puts("</begin>\n");
|
||||
}
|
||||
puts("</while>\n");
|
||||
}
|
||||
void visit(AstNetlist* nodep) override {
|
||||
puts("<netlist>\n");
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
puts("</netlist>\n");
|
||||
}
|
||||
void visit(AstConstPool* nodep) override {
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
puts("<constpool>\n");
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
puts("</constpool>\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
|
|||
puts("<inititem index=\"");
|
||||
puts(cvtToStr(itr.first));
|
||||
puts("\">\n");
|
||||
iterateChildren(itr.second);
|
||||
iterateChildrenConst(itr.second);
|
||||
puts("</inititem>\n");
|
||||
}
|
||||
puts("</initarray>\n");
|
||||
|
|
@ -314,7 +314,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
|
|||
public:
|
||||
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp)
|
||||
: m_ofp{ofp} {
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~EmitXmlFileVisitor() override = default;
|
||||
};
|
||||
|
|
@ -322,7 +322,7 @@ public:
|
|||
//######################################################################
|
||||
// List of module files xml visitor
|
||||
|
||||
class ModuleFilesXmlVisitor final : public VNVisitor {
|
||||
class ModuleFilesXmlVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
|
|
@ -334,7 +334,7 @@ private:
|
|||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Children are iterated backwards to ensure correct compilation order
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
// Only list modules and interfaces
|
||||
|
|
@ -354,7 +354,7 @@ public:
|
|||
ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
||||
: m_os(os) { // Need () or GCC 4.8 false warning
|
||||
// Operate on whole netlist
|
||||
nodep->accept(*this);
|
||||
iterateConst(nodep);
|
||||
// Xml output
|
||||
m_os << "<module_files>\n";
|
||||
for (const FileLine* ifp : m_nodeModules) {
|
||||
|
|
@ -369,7 +369,7 @@ public:
|
|||
//######################################################################
|
||||
// Hierarchy of Cells visitor
|
||||
|
||||
class HierCellsXmlVisitor final : public VNVisitor {
|
||||
class HierCellsXmlVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
|
|
@ -391,7 +391,7 @@ private:
|
|||
<< " hier=\"" << nodep->prettyName() << "\"";
|
||||
m_hier = nodep->prettyName() + ".";
|
||||
m_hasChildren = false;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_hasChildren) {
|
||||
m_os << "</cell>\n";
|
||||
} else {
|
||||
|
|
@ -410,7 +410,7 @@ private:
|
|||
const std::string hier = m_hier;
|
||||
m_hier += nodep->name() + ".";
|
||||
m_hasChildren = false;
|
||||
iterateChildren(nodep->modp());
|
||||
iterateChildrenConst(nodep->modp());
|
||||
if (m_hasChildren) {
|
||||
m_os << "</cell>\n";
|
||||
} else {
|
||||
|
|
@ -419,15 +419,19 @@ private:
|
|||
m_hier = hier;
|
||||
m_hasChildren = true;
|
||||
}
|
||||
void visit(AstBegin* nodep) override {
|
||||
VL_RESTORER(m_hier);
|
||||
if (nodep->name() != "") m_hier += nodep->name() + ".";
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
//-----
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
||||
: m_os(os) { // Need () or GCC 4.8 false warning
|
||||
// Operate on whole netlist
|
||||
nodep->accept(*this);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~HierCellsXmlVisitor() override = default;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
|
|||
const V3ErrorCode code{codei};
|
||||
if (0 == VL_STRCASECMP(msgp, code.ascii())) {
|
||||
m_e = code;
|
||||
if (isRenamed()) m_e = renamedTo().m_e;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -220,6 +221,7 @@ void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra)
|
|||
}
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
if (dumpTree() || debug()) {
|
||||
V3Broken::allowMidvisitorCheck(true);
|
||||
V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) {
|
||||
if (dumpTree()) {
|
||||
v3Global.rootp()->dumpTreeFile(
|
||||
|
|
@ -255,7 +257,7 @@ void V3Error::init() {
|
|||
describedEachWarn(static_cast<V3ErrorCode>(i), false);
|
||||
pretendError(static_cast<V3ErrorCode>(i), V3ErrorCode{i}.pretendError());
|
||||
}
|
||||
if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) {
|
||||
if (VL_UNCOVERABLE(string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} != " MAX")) {
|
||||
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated_threads.h"
|
||||
#include "V3Mutex.h"
|
||||
|
||||
// Limited V3 headers here - this is a base class for Vlc etc
|
||||
#include "V3String.h"
|
||||
|
|
@ -70,6 +70,7 @@ public:
|
|||
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
||||
//
|
||||
ALWCOMBORDER, // Always_comb with unordered statements
|
||||
ASCRANGE, // Ascending bit range vector
|
||||
ASSIGNDLY, // Assignment delays
|
||||
ASSIGNIN, // Assigning to input
|
||||
BADSTDPRAGMA, // Any error related to pragmas
|
||||
|
|
@ -87,6 +88,7 @@ public:
|
|||
CMPCONST, // Comparison is constant due to limited range
|
||||
COLONPLUS, // :+ instead of +:
|
||||
COMBDLY, // Combinatorial delayed assignment
|
||||
CONSTRAINTIGN, // Constraint ignored
|
||||
CONTASSREG, // Continuous assignment on reg
|
||||
DECLFILENAME, // Declaration doesn't match filename
|
||||
DEFPARAM, // Style: Defparam
|
||||
|
|
@ -109,7 +111,7 @@ public:
|
|||
INITIALDLY, // Initial delayed statement
|
||||
INSECURE, // Insecure options
|
||||
LATCH, // Latch detected outside of always_latch block
|
||||
LITENDIAN, // Little bit endian vector
|
||||
LITENDIAN, // Little endian, renamed to ASCRANGE
|
||||
MINTYPMAXDLY, // Unsupported: min/typ/max delay expressions
|
||||
MODDUP, // Duplicate module
|
||||
MULTIDRIVEN, // Driven from multiple blocks
|
||||
|
|
@ -131,6 +133,7 @@ public:
|
|||
SELRANGE, // Selection index out of range
|
||||
SHORTREAL, // Shortreal not supported
|
||||
SPLITVAR, // Cannot split the variable
|
||||
STATICVAR, // Static variable declared in a loop with a declaration assignment
|
||||
STMTDLY, // Delayed statement
|
||||
SYMRSVDWORD, // Symbol is Reserved Word
|
||||
SYNCASYNCNET, // Mixed sync + async reset
|
||||
|
|
@ -182,10 +185,10 @@ public:
|
|||
"PORTSHORT", "UNSUPPORTED", "TASKNSVAR", "NEEDTIMINGOPT", "NOTIMING",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN",
|
||||
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
|
||||
"ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
|
||||
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
|
||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
|
||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG",
|
||||
"DECLFILENAME", "DEFPARAM", "DEPRECATED",
|
||||
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "HIERBLOCK",
|
||||
"IFDEPTH", "IGNOREDRETURN",
|
||||
|
|
@ -195,7 +198,7 @@ public:
|
|||
"MULTIDRIVEN", "MULTITOP", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY",
|
||||
"PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE",
|
||||
"PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY",
|
||||
"SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"SELRANGE", "SHORTREAL", "SPLITVAR", "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"TICKCOUNT", "TIMESCALEMOD",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
||||
"UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDPARAM", "UNUSEDSIGNAL",
|
||||
|
|
@ -219,18 +222,18 @@ public:
|
|||
|| m_e == CONTASSREG || m_e == ENCAPSULATED || m_e == ENDLABEL || m_e == ENUMVALUE
|
||||
|| m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL
|
||||
|| m_e == PROCASSWIRE // Says IEEE
|
||||
|| m_e == ZERODLY);
|
||||
);
|
||||
}
|
||||
// Warnings to mention manual
|
||||
bool mentionManual() const VL_MT_SAFE {
|
||||
return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || pretendError());
|
||||
return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || m_e == ZERODLY || pretendError());
|
||||
}
|
||||
// Warnings that are lint only
|
||||
bool lintError() const VL_MT_SAFE {
|
||||
return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE
|
||||
return (m_e == ALWCOMBORDER || m_e == ASCRANGE || m_e == BSSPACE || m_e == CASEINCOMPLETE
|
||||
|| m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST
|
||||
|| m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC
|
||||
|| m_e == LATCH || m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT
|
||||
|| m_e == LATCH || m_e == PINMISSING || m_e == REALCVT || m_e == STATICVAR
|
||||
|| m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC || m_e == WIDTHEXPAND
|
||||
|| m_e == WIDTHXZEXPAND);
|
||||
}
|
||||
|
|
@ -248,12 +251,17 @@ public:
|
|||
return (m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL);
|
||||
}
|
||||
|
||||
V3ErrorCode renamedTo() const {
|
||||
// Return a new error this error has been renamed to
|
||||
if (m_e == LITENDIAN) return V3ErrorCode{ASCRANGE};
|
||||
return V3ErrorCode{EC_MIN}; // Not renamed; see isRenamed()
|
||||
}
|
||||
bool isRenamed() const { return renamedTo() != V3ErrorCode{EC_MIN}; }
|
||||
bool isUnder(V3ErrorCode other) {
|
||||
// backwards compatibility inheritance-like warnings
|
||||
if (m_e == other) { return true; }
|
||||
if (other == V3ErrorCode::WIDTH) {
|
||||
return (m_e == WIDTH || m_e == WIDTHEXPAND || m_e == WIDTHTRUNC
|
||||
|| m_e == WIDTHXZEXPAND);
|
||||
return (m_e == WIDTHEXPAND || m_e == WIDTHTRUNC || m_e == WIDTHXZEXPAND);
|
||||
}
|
||||
if (other == V3ErrorCode::I_UNUSED) {
|
||||
return (m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL);
|
||||
|
|
@ -307,7 +315,7 @@ private:
|
|||
bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal
|
||||
std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed
|
||||
public:
|
||||
VerilatedMutex m_mutex; // Make sure only single thread is in class
|
||||
V3RecursiveMutex m_mutex; // Make sure only single thread is in class
|
||||
|
||||
string msgPrefix() VL_REQUIRES(m_mutex); // returns %Error/%Warn
|
||||
string warnMore() VL_REQUIRES(m_mutex);
|
||||
|
|
@ -400,57 +408,57 @@ public:
|
|||
static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); }
|
||||
static int debugDefault() VL_MT_SAFE { return s().debugDefault(); }
|
||||
static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().errorLimit(level);
|
||||
}
|
||||
static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().errorLimit();
|
||||
}
|
||||
static void warnFatal(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().warnFatal(flag);
|
||||
}
|
||||
static bool warnFatal() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().warnFatal();
|
||||
}
|
||||
// returns %Error/%Warn
|
||||
static string msgPrefix() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().msgPrefix();
|
||||
}
|
||||
static int errorCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().errorCount();
|
||||
}
|
||||
static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().pretendError(errorCode);
|
||||
}
|
||||
static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().warnCount();
|
||||
}
|
||||
static bool errorContexted() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().errorContexted();
|
||||
}
|
||||
static void errorContexted(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().errorContexted(flag);
|
||||
}
|
||||
static void describedEachWarn(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().describedEachWarn(code, flag);
|
||||
}
|
||||
// METHODS
|
||||
static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().incErrors();
|
||||
}
|
||||
static void incWarnings() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().incWarnings();
|
||||
}
|
||||
static void init();
|
||||
|
|
@ -460,20 +468,20 @@ public:
|
|||
static void abortIfWarnings();
|
||||
// Suppress next %Warn if user has it off
|
||||
static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().suppressThisWarning();
|
||||
}
|
||||
static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().pretendError(code, flag);
|
||||
}
|
||||
static string lineStr(const char* filename, int lineno) VL_PURE;
|
||||
static V3ErrorCode errorCode() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().errorCode();
|
||||
}
|
||||
static void errorExitCb(V3ErrorGuarded::ErrorExitCb cb) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().errorExitCb(cb);
|
||||
}
|
||||
|
||||
|
|
@ -484,7 +492,7 @@ public:
|
|||
// streamed directly to cerr.
|
||||
// Use with caution as this function isn't MT_SAFE.
|
||||
static string warnMoreStandalone() VL_EXCLUDES(s().m_mutex) VL_MT_UNSAFE {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().warnMore();
|
||||
}
|
||||
// This function marks place in error message from which point message
|
||||
|
|
@ -500,18 +508,18 @@ public:
|
|||
// Internals for v3error()/v3fatal() macros only
|
||||
// Error end takes the string stream to output, be careful to seek() as needed
|
||||
static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().v3errorPrep(code);
|
||||
}
|
||||
static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
return s().v3errorStr();
|
||||
}
|
||||
static void vlAbort();
|
||||
// static, but often overridden in classes.
|
||||
static void v3errorEnd(std::ostringstream& sstr, const string& extra = "")
|
||||
VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||
s().v3errorEnd(sstr, extra);
|
||||
}
|
||||
// We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal',
|
||||
|
|
@ -642,7 +650,7 @@ inline void v3errorEndFatal(std::ostringstream& sstr)
|
|||
// Helper macros for VL_DEFINE_DEBUG_FUNCTIONS
|
||||
// Takes an optional "name" (as __VA_ARGS__)
|
||||
#define VL_DEFINE_DEBUG(...) \
|
||||
VL_ATTR_UNUSED static int debug##__VA_ARGS__() { \
|
||||
VL_ATTR_UNUSED static int debug##__VA_ARGS__() VL_MT_SAFE { \
|
||||
static int level = -1; \
|
||||
if (VL_UNLIKELY(level < 0)) { \
|
||||
std::string tag{VL_STRINGIFY(__VA_ARGS__)}; \
|
||||
|
|
|
|||
|
|
@ -108,7 +108,8 @@ class V3FileDependImp final {
|
|||
};
|
||||
|
||||
// MEMBERS
|
||||
std::set<string> m_filenameSet; // Files generated (elim duplicates)
|
||||
V3Mutex m_mutex; // Protects members
|
||||
std::set<string> m_filenameSet VL_GUARDED_BY(m_mutex); // Files generated (elim duplicates)
|
||||
std::set<DependFile> m_filenameList; // Files sourced/generated
|
||||
|
||||
static string stripQuotes(const string& in) {
|
||||
|
|
@ -121,7 +122,8 @@ class V3FileDependImp final {
|
|||
|
||||
public:
|
||||
// ACCESSOR METHODS
|
||||
void addSrcDepend(const string& filename) {
|
||||
void addSrcDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
const V3LockGuard lock{m_mutex};
|
||||
const auto itFoundPair = m_filenameSet.insert(filename);
|
||||
if (itFoundPair.second) {
|
||||
DependFile df{filename, false};
|
||||
|
|
@ -129,7 +131,8 @@ public:
|
|||
m_filenameList.insert(df);
|
||||
}
|
||||
}
|
||||
void addTgtDepend(const string& filename) {
|
||||
void addTgtDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
const V3LockGuard lock{m_mutex};
|
||||
const auto itFoundPair = m_filenameSet.insert(filename);
|
||||
if (itFoundPair.second) m_filenameList.insert(DependFile{filename, true});
|
||||
}
|
||||
|
|
@ -297,8 +300,8 @@ bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn
|
|||
//######################################################################
|
||||
// V3File
|
||||
|
||||
void V3File::addSrcDepend(const string& filename) { dependImp.addSrcDepend(filename); }
|
||||
void V3File::addTgtDepend(const string& filename) { dependImp.addTgtDepend(filename); }
|
||||
void V3File::addSrcDepend(const string& filename) VL_MT_SAFE { dependImp.addSrcDepend(filename); }
|
||||
void V3File::addTgtDepend(const string& filename) VL_MT_SAFE { dependImp.addTgtDepend(filename); }
|
||||
void V3File::writeDepend(const string& filename) { dependImp.writeDepend(filename); }
|
||||
std::vector<string> V3File::getAllDeps() { return dependImp.getAllDeps(); }
|
||||
void V3File::writeTimes(const string& filename, const string& cmdlineIn) {
|
||||
|
|
@ -581,14 +584,14 @@ protected:
|
|||
return true;
|
||||
}
|
||||
static size_t listSize(const StrList& sl) {
|
||||
size_t out = 0;
|
||||
for (const string& i : sl) out += i.length();
|
||||
return out;
|
||||
size_t result = 0;
|
||||
for (const string& i : sl) result += i.length();
|
||||
return result;
|
||||
}
|
||||
static string listString(const StrList& sl) {
|
||||
string out;
|
||||
for (const string& i : sl) out += i;
|
||||
return out;
|
||||
string result;
|
||||
for (const string& i : sl) result += i;
|
||||
return result;
|
||||
}
|
||||
// CONSTRUCTORS
|
||||
explicit VInFilterImp(const string& command) { start(command); }
|
||||
|
|
@ -853,7 +856,8 @@ void V3OutFormatter::putcNoTracking(char chr) {
|
|||
putcOutput(chr);
|
||||
}
|
||||
|
||||
string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::Language lang) {
|
||||
string V3OutFormatter::quoteNameControls(const string& namein,
|
||||
V3OutFormatter::Language lang) VL_PURE {
|
||||
// Encode control chars into output-appropriate escapes
|
||||
// Reverse is V3Parse::deQuote
|
||||
string out;
|
||||
|
|
@ -933,7 +937,7 @@ V3OutFile::~V3OutFile() {
|
|||
|
||||
void V3OutFile::putsForceIncs() {
|
||||
const V3StringList& forceIncs = v3Global.opt.forceIncs();
|
||||
for (const string& i : forceIncs) { puts("#include \"" + i + "\"\n"); }
|
||||
for (const string& i : forceIncs) puts("#include \"" + i + "\"\n");
|
||||
}
|
||||
|
||||
void V3OutCFile::putsGuard() {
|
||||
|
|
@ -953,12 +957,13 @@ void V3OutCFile::putsGuard() {
|
|||
|
||||
class VIdProtectImp final {
|
||||
// MEMBERS
|
||||
V3Mutex m_mutex; // Protects members
|
||||
std::map<const std::string, std::string> m_nameMap; // Map of old name into new name
|
||||
std::unordered_set<std::string> m_newIdSet; // Which new names exist
|
||||
std::unordered_set<std::string> m_newIdSet VL_GUARDED_BY(m_mutex); // Which new names exist
|
||||
protected:
|
||||
// CONSTRUCTORS
|
||||
friend class VIdProtect;
|
||||
static VIdProtectImp& singleton() {
|
||||
static VIdProtectImp& singleton() VL_MT_SAFE {
|
||||
static VIdProtectImp s;
|
||||
return s;
|
||||
}
|
||||
|
|
@ -972,8 +977,9 @@ public:
|
|||
}
|
||||
~VIdProtectImp() = default;
|
||||
// METHODS
|
||||
string passthru(const string& old) {
|
||||
string passthru(const string& old) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
if (!v3Global.opt.protectIds()) return old;
|
||||
const V3LockGuard lock{m_mutex};
|
||||
const auto it = m_nameMap.find(old);
|
||||
if (it != m_nameMap.end()) {
|
||||
// No way to go back and correct the older crypt name
|
||||
|
|
@ -985,8 +991,9 @@ public:
|
|||
}
|
||||
return old;
|
||||
}
|
||||
string protectIf(const string& old, bool doIt) {
|
||||
string protectIf(const string& old, bool doIt) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old;
|
||||
const V3LockGuard lock{m_mutex};
|
||||
const auto it = m_nameMap.find(old);
|
||||
if (it != m_nameMap.end()) {
|
||||
return it->second;
|
||||
|
|
@ -1016,7 +1023,7 @@ public:
|
|||
return out;
|
||||
}
|
||||
}
|
||||
string protectWordsIf(const string& old, bool doIt) {
|
||||
string protectWordsIf(const string& old, bool doIt) VL_MT_SAFE {
|
||||
// Split at " " (for traces), "." (for scopes), "->", "(", "&", ")" (for self pointers)
|
||||
if (!(doIt && v3Global.opt.protectIds())) return old;
|
||||
string out;
|
||||
|
|
@ -1055,7 +1062,7 @@ public:
|
|||
|
||||
private:
|
||||
void trySep(const string& old, string::size_type start, const string& trySep,
|
||||
string::size_type& posr, string& separatorr) {
|
||||
string::size_type& posr, string& separatorr) VL_PURE {
|
||||
const string::size_type trypos = old.find(trySep, start);
|
||||
if (trypos != string::npos) {
|
||||
if (posr == string::npos || (posr > trypos)) {
|
||||
|
|
@ -1066,10 +1073,10 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
string VIdProtect::protectIf(const string& old, bool doIt) {
|
||||
string VIdProtect::protectIf(const string& old, bool doIt) VL_MT_SAFE {
|
||||
return VIdProtectImp::singleton().protectIf(old, doIt);
|
||||
}
|
||||
string VIdProtect::protectWordsIf(const string& old, bool doIt) {
|
||||
string VIdProtect::protectWordsIf(const string& old, bool doIt) VL_MT_SAFE {
|
||||
return VIdProtectImp::singleton().protectWordsIf(old, doIt);
|
||||
}
|
||||
void VIdProtect::writeMapFile(const string& filename) {
|
||||
|
|
|
|||
14
src/V3File.h
14
src/V3File.h
|
|
@ -39,7 +39,7 @@ public:
|
|||
addSrcDepend(filename);
|
||||
return new_ifstream_nodepend(filename);
|
||||
}
|
||||
static std::ifstream* new_ifstream_nodepend(const string& filename) {
|
||||
static std::ifstream* new_ifstream_nodepend(const string& filename) VL_MT_SAFE {
|
||||
return new std::ifstream{filename.c_str()};
|
||||
}
|
||||
static std::ofstream* new_ofstream(const string& filename, bool append = false) {
|
||||
|
|
@ -61,8 +61,8 @@ public:
|
|||
}
|
||||
|
||||
// Dependencies
|
||||
static void addSrcDepend(const string& filename);
|
||||
static void addTgtDepend(const string& filename);
|
||||
static void addSrcDepend(const string& filename) VL_MT_SAFE;
|
||||
static void addTgtDepend(const string& filename) VL_MT_SAFE;
|
||||
static void writeDepend(const string& filename);
|
||||
static std::vector<string> getAllDeps();
|
||||
static void writeTimes(const string& filename, const string& cmdlineIn);
|
||||
|
|
@ -171,7 +171,7 @@ public:
|
|||
// STATIC METHODS
|
||||
static string indentSpaces(int num);
|
||||
// Add escaped characters to strings
|
||||
static string quoteNameControls(const string& namein, Language lang = LA_C);
|
||||
static string quoteNameControls(const string& namein, Language lang = LA_C) VL_PURE;
|
||||
static bool tokenMatch(const char* cp, const char* cmp);
|
||||
static bool tokenNotStart(const char* cp); // Import/export meaning no endfunction
|
||||
static bool tokenStart(const char* cp);
|
||||
|
|
@ -318,10 +318,10 @@ class VIdProtect final {
|
|||
public:
|
||||
// METHODS
|
||||
// Rename to a new encoded string (unless earlier passthru'ed)
|
||||
static string protect(const string& old) { return protectIf(old, true); }
|
||||
static string protectIf(const string& old, bool doIt = true);
|
||||
static string protect(const string& old) VL_MT_SAFE { return protectIf(old, true); }
|
||||
static string protectIf(const string& old, bool doIt = true) VL_MT_SAFE;
|
||||
// Rename words to a new encoded string
|
||||
static string protectWordsIf(const string& old, bool doIt = true);
|
||||
static string protectWordsIf(const string& old, bool doIt = true) VL_MT_SAFE;
|
||||
// Write map of renames to output file
|
||||
static void writeMapFile(const string& filename);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
// FileLineSingleton class functions
|
||||
|
||||
string FileLineSingleton::filenameLetters(fileNameIdx_t fileno) {
|
||||
string FileLineSingleton::filenameLetters(fileNameIdx_t fileno) VL_PURE {
|
||||
constexpr int size
|
||||
= 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number
|
||||
char out[size];
|
||||
|
|
@ -87,7 +87,9 @@ void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) {
|
|||
os << "</files>\n";
|
||||
}
|
||||
|
||||
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet) {
|
||||
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet)
|
||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0);
|
||||
msgEnSetIdx_t& idx = pair.first->second;
|
||||
if (pair.second) {
|
||||
|
|
@ -100,7 +102,7 @@ FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBi
|
|||
return idx;
|
||||
}
|
||||
|
||||
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() {
|
||||
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() VL_MT_SAFE {
|
||||
MsgEnBitSet msgEnBitSet;
|
||||
for (int i = V3ErrorCode::EC_MIN; i < V3ErrorCode::_ENUM_MAX; ++i) {
|
||||
msgEnBitSet.set(i, !V3ErrorCode{i}.defaultsOff());
|
||||
|
|
@ -416,7 +418,7 @@ string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) {
|
|||
}
|
||||
};
|
||||
string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE {
|
||||
const VerilatedLockGuard guard{V3Error::s().m_mutex};
|
||||
const V3RecursiveLockGuard guard{V3Error::s().m_mutex};
|
||||
return warnOther();
|
||||
}
|
||||
|
||||
|
|
@ -465,13 +467,13 @@ string FileLine::warnContext() const {
|
|||
}
|
||||
|
||||
string FileLine::warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
string out;
|
||||
string result;
|
||||
for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) {
|
||||
if (parentFl->filenameIsGlobal()) break;
|
||||
out += parentFl->warnOther() + "... note: In file included from "
|
||||
+ parentFl->filebasename() + "\n";
|
||||
result += parentFl->warnOther() + "... note: In file included from "
|
||||
+ parentFl->filebasename() + "\n";
|
||||
}
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
std::unordered_set<FileLine*> fileLineLeakChecks;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "V3Error.h"
|
||||
#include "V3LangCode.h"
|
||||
#include "V3Mutex.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
|
|
@ -50,12 +51,13 @@ class FileLineSingleton final {
|
|||
using MsgEnBitSet = std::bitset<V3ErrorCode::_ENUM_MAX>;
|
||||
|
||||
// MEMBERS
|
||||
V3Mutex m_mutex; // protects members
|
||||
std::map<const std::string, fileNameIdx_t> m_namemap; // filenameno for each filename
|
||||
std::deque<string> m_names; // filename text for each filenameno
|
||||
std::deque<V3LangCode> m_languages; // language for each filenameno
|
||||
|
||||
// Map from flag set to the index in m_internedMsgEns for interning
|
||||
std::unordered_map<MsgEnBitSet, msgEnSetIdx_t> m_internedMsgEnIdxs;
|
||||
std::unordered_map<MsgEnBitSet, msgEnSetIdx_t> m_internedMsgEnIdxs VL_GUARDED_BY(m_mutex);
|
||||
// Interned message enablement flag sets
|
||||
std::vector<MsgEnBitSet> m_internedMsgEns;
|
||||
|
||||
|
|
@ -64,7 +66,7 @@ class FileLineSingleton final {
|
|||
~FileLineSingleton() = default;
|
||||
|
||||
fileNameIdx_t nameToNumber(const string& filename);
|
||||
string numberToName(fileNameIdx_t filenameno) const { return m_names[filenameno]; }
|
||||
string numberToName(fileNameIdx_t filenameno) const VL_MT_SAFE { return m_names[filenameno]; }
|
||||
V3LangCode numberToLang(fileNameIdx_t filenameno) const { return m_languages[filenameno]; }
|
||||
void numberToLang(fileNameIdx_t filenameno, const V3LangCode& l) {
|
||||
m_languages[filenameno] = l;
|
||||
|
|
@ -75,12 +77,12 @@ class FileLineSingleton final {
|
|||
m_languages.clear();
|
||||
}
|
||||
void fileNameNumMapDumpXml(std::ostream& os);
|
||||
static string filenameLetters(fileNameIdx_t fileno);
|
||||
static string filenameLetters(fileNameIdx_t fileno) VL_PURE;
|
||||
|
||||
// Add given bitset to the interned bitsets, return interned index
|
||||
msgEnSetIdx_t addMsgEnBitSet(const MsgEnBitSet& bitSet);
|
||||
msgEnSetIdx_t addMsgEnBitSet(const MsgEnBitSet& bitSet) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
// Add index of default bitset
|
||||
msgEnSetIdx_t defaultMsgEnIndex();
|
||||
msgEnSetIdx_t defaultMsgEnIndex() VL_MT_SAFE;
|
||||
// Set bitIdx to value in bitset at interned index setIdx, return interned index of result
|
||||
msgEnSetIdx_t msgEnSetBit(msgEnSetIdx_t setIdx, size_t bitIdx, bool value);
|
||||
// Return index to intersection set
|
||||
|
|
@ -159,11 +161,11 @@ protected:
|
|||
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
static FileLineSingleton& singleton() {
|
||||
static FileLineSingleton& singleton() VL_MT_SAFE {
|
||||
static FileLineSingleton s;
|
||||
return s;
|
||||
}
|
||||
static FileLine& defaultFileLine() {
|
||||
static FileLine& defaultFileLine() VL_MT_SAFE {
|
||||
static FileLine s;
|
||||
return s;
|
||||
}
|
||||
|
|
@ -242,7 +244,7 @@ public:
|
|||
string prettySource() const VL_MT_SAFE; // Source, w/stripped unprintables and newlines
|
||||
FileLine* parent() const VL_MT_SAFE { return m_parent; }
|
||||
V3LangCode language() const { return singleton().numberToLang(filenameno()); }
|
||||
string ascii() const;
|
||||
string ascii() const VL_MT_SAFE;
|
||||
string asciiLineCol() const;
|
||||
int filenameno() const VL_MT_SAFE { return m_filenameno; }
|
||||
string filename() const VL_MT_SAFE { return singleton().numberToName(filenameno()); }
|
||||
|
|
@ -270,7 +272,7 @@ public:
|
|||
}
|
||||
void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); }
|
||||
bool warnOff(const string& msg, bool flag); // Returns 1 if ok
|
||||
bool warnIsOff(V3ErrorCode code) const;
|
||||
bool warnIsOff(V3ErrorCode code) const VL_MT_SAFE;
|
||||
void warnLintOff(bool flag);
|
||||
void warnStyleOff(bool flag);
|
||||
void warnUnusedOff(bool flag);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public:
|
|||
~GateEitherVertex() override = default;
|
||||
// ACCESSORS
|
||||
string dotStyle() const override { return m_consumed ? "" : "dotted"; }
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
AstScope* scopep() const VL_MT_STABLE { return m_scopep; }
|
||||
bool reducible() const { return m_reducible; }
|
||||
bool dedupable() const { return m_dedupable; }
|
||||
void setConsumed(const char* /*consumedReason*/) {
|
||||
|
|
@ -133,8 +133,10 @@ public:
|
|||
, m_varScp{varScp} {}
|
||||
~GateVarVertex() override = default;
|
||||
// ACCESSORS
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
AstVarScope* varScp() const VL_MT_STABLE { return m_varScp; }
|
||||
string name() const override VL_MT_STABLE {
|
||||
return (cvtToHex(m_varScp) + " " + varScp()->name());
|
||||
}
|
||||
string dotColor() const override { return "blue"; }
|
||||
bool isTop() const { return m_isTop; }
|
||||
void setIsTop() { m_isTop = true; }
|
||||
|
|
@ -174,7 +176,9 @@ public:
|
|||
, m_slow{slow} {}
|
||||
~GateLogicVertex() override = default;
|
||||
// ACCESSORS
|
||||
string name() const override { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); }
|
||||
string name() const override VL_MT_STABLE {
|
||||
return (cvtToHex(m_nodep) + "@" + scopep()->prettyName());
|
||||
}
|
||||
string dotColor() const override { return "purple"; }
|
||||
FileLine* fileline() const override { return nodep()->fileline(); }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
|
|
@ -188,7 +192,7 @@ public:
|
|||
// ######################################################################
|
||||
// Is this a simple expression with a single input and single output?
|
||||
|
||||
class GateOkVisitor final : public VNVisitor {
|
||||
class GateOkVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// RETURN STATE
|
||||
bool m_isSimple = true; // Set false when we know it isn't simple
|
||||
|
|
@ -211,7 +215,7 @@ private:
|
|||
// VISITORS
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
++m_ops;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
// We only allow a LHS ref for the var being set, and a RHS ref for
|
||||
// something else being read.
|
||||
if (nodep->varScopep()->varp()->isSc()) {
|
||||
|
|
@ -242,7 +246,7 @@ private:
|
|||
} else if (nodep->isTimingControl()) {
|
||||
clearSimple("Timing control");
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
// We don't push logic other then assignments/NOTs into SenItems
|
||||
// This avoids a mess in computing what exactly a POSEDGE is
|
||||
|
|
@ -267,7 +271,7 @@ private:
|
|||
UINFO(5, "Non optimizable type: " << nodep << endl);
|
||||
clearSimple("Non optimizable type");
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +281,7 @@ public:
|
|||
m_buffersOnly = buffersOnly;
|
||||
m_dedupe = dedupe;
|
||||
// Iterate
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
// Check results
|
||||
if (!m_substTreep) clearSimple("No assignment found\n");
|
||||
for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin(); it != m_rhsVarRefs.end();
|
||||
|
|
@ -1288,7 +1292,7 @@ void GateVisitor::mergeAssigns() {
|
|||
//######################################################################
|
||||
// Find a var's offset in a concatenation
|
||||
|
||||
class GateConcatVisitor final : public VNVisitor {
|
||||
class GateConcatVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// STATE
|
||||
const AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
|
||||
|
|
@ -1311,11 +1315,11 @@ private:
|
|||
}
|
||||
void visit(AstConcat* nodep) override {
|
||||
UINFO(9, "CLK DECOMP Concat search (off = " << m_offset << ") - " << nodep << endl);
|
||||
iterate(nodep->rhsp());
|
||||
iterate(nodep->lhsp());
|
||||
iterateConst(nodep->rhsp());
|
||||
iterateConst(nodep->lhsp());
|
||||
}
|
||||
//--------------------
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
|
|
@ -1327,7 +1331,7 @@ public:
|
|||
m_offset = 0;
|
||||
m_found = false;
|
||||
// Iterate
|
||||
iterate(concatp);
|
||||
iterateConst(concatp);
|
||||
UINFO(9, "CLK DECOMP Concat Offset (found = " << m_found << ") (" << m_found_offset
|
||||
<< ") - " << concatp << " : " << vscp
|
||||
<< endl);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ void V3Global::readFiles() {
|
|||
VInFilter filter{v3Global.opt.pipeFilter()};
|
||||
V3ParseSym parseSyms{v3Global.rootp()}; // Symbol table must be common across all parsing
|
||||
|
||||
V3Parse parser(v3Global.rootp(), &filter, &parseSyms);
|
||||
V3Parse parser{v3Global.rootp(), &filter, &parseSyms};
|
||||
|
||||
// Parse the std package
|
||||
if (v3Global.opt.std()) {
|
||||
|
|
@ -77,14 +77,6 @@ void V3Global::readFiles() {
|
|||
"Cannot find file containing library module: ");
|
||||
}
|
||||
|
||||
// Delete the std package if unused
|
||||
if (!usesStdPackage()) {
|
||||
if (AstNodeModule* stdp = v3Global.rootp()->stdPackagep()) {
|
||||
v3Global.rootp()->stdPackagep(nullptr);
|
||||
VL_DO_DANGLING(stdp->unlinkFrBack()->deleteTree(), stdp);
|
||||
}
|
||||
}
|
||||
|
||||
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree"));
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
|
|
@ -94,6 +86,16 @@ void V3Global::readFiles() {
|
|||
}
|
||||
}
|
||||
|
||||
void V3Global::removeStd() {
|
||||
// Delete the std package if unused
|
||||
if (!usesStdPackage()) {
|
||||
if (AstNodeModule* stdp = v3Global.rootp()->stdPackagep()) {
|
||||
v3Global.rootp()->stdPackagep(nullptr);
|
||||
VL_DO_DANGLING(stdp->unlinkFrBack()->deleteTree(), stdp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string V3Global::debugFilename(const string& nameComment, int newNumber) {
|
||||
++m_debugFileNumber;
|
||||
if (newNumber) m_debugFileNumber = newNumber;
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class V3Global final {
|
|||
VWidthMinUsage m_widthMinUsage
|
||||
= VWidthMinUsage::LINT_WIDTH; // What AstNode::widthMin() is used for
|
||||
|
||||
int m_debugFileNumber = 0; // Number to append to debug files created
|
||||
std::atomic_int m_debugFileNumber{0}; // Number to append to debug files created
|
||||
bool m_assertDTypesResolved = false; // Tree should have dtypep()'s
|
||||
bool m_assertScoped = false; // Tree is scoped
|
||||
bool m_constRemoveXs = false; // Const needs to strip any Xs
|
||||
|
|
@ -135,6 +135,7 @@ public:
|
|||
|
||||
// METHODS
|
||||
void readFiles();
|
||||
void removeStd();
|
||||
void checkTree() const;
|
||||
static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0,
|
||||
bool doDump = true);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public:
|
|||
, m_name{name} {}
|
||||
~V3GraphTestVertex() override = default;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
};
|
||||
|
||||
class V3GraphTestVarVertex final : public V3GraphTestVertex {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
V3Hash::V3Hash(const std::string& val)
|
||||
: m_value{static_cast<uint32_t>(std::hash<std::string>{}(val))} {}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
|
||||
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) VL_MT_SAFE {
|
||||
return os << 'h' << std::hex << std::setw(8) << std::setfill('0') << rhs.value();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs);
|
||||
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) VL_MT_SAFE;
|
||||
|
||||
template <>
|
||||
struct std::hash<V3Hash> {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
// Visitor that computes node hashes
|
||||
|
||||
class HasherVisitor final : public VNVisitor {
|
||||
class HasherVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
|
|
@ -48,7 +48,8 @@ private:
|
|||
// Reset accumulator
|
||||
m_hash = V3Hash{nodep->type()}; // Node type
|
||||
f(); // Node specific hash
|
||||
if (hashDType && nodep != nodep->dtypep()) iterateNull(nodep->dtypep()); // Node dtype
|
||||
if (hashDType && nodep != nodep->dtypep())
|
||||
iterateConstNull(nodep->dtypep()); // Node dtype
|
||||
if (hashChildren) iterateChildrenConst(nodep); // Children
|
||||
if (m_cacheInUser4) nodep->user4(m_hash.value());
|
||||
return m_hash;
|
||||
|
|
@ -92,7 +93,7 @@ private:
|
|||
// AstNodeDType
|
||||
void visit(AstNodeArrayDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
m_hash += nodep->left();
|
||||
m_hash += nodep->right();
|
||||
});
|
||||
|
|
@ -120,23 +121,23 @@ private:
|
|||
}
|
||||
void visit(AstAssocArrayDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateNull(nodep->virtRefDType2p());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDType2p());
|
||||
});
|
||||
}
|
||||
void visit(AstDynArrayDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
void visit(AstUnsizedArrayDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
void visit(AstWildcardArrayDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
void visit(AstBasicDType* nodep) override {
|
||||
|
|
@ -148,29 +149,29 @@ private:
|
|||
}
|
||||
void visit(AstConstDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
void visit(AstClassRefDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->classp());
|
||||
iterateConstNull(nodep->classp());
|
||||
});
|
||||
}
|
||||
void visit(AstIfaceRefDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->cellp());
|
||||
iterateConstNull(nodep->cellp());
|
||||
});
|
||||
}
|
||||
void visit(AstQueueDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
void visit(AstRefDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
|
||||
m_hash += nodep->name();
|
||||
iterateNull(nodep->typedefp());
|
||||
iterateNull(nodep->refDTypep());
|
||||
iterateConstNull(nodep->typedefp());
|
||||
iterateConstNull(nodep->refDTypep());
|
||||
});
|
||||
}
|
||||
void visit(AstVoidDType* nodep) override {
|
||||
|
|
@ -203,16 +204,16 @@ private:
|
|||
void visit(AstVarRef* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
if (nodep->varScopep()) {
|
||||
iterateNull(nodep->varScopep());
|
||||
iterateConstNull(nodep->varScopep());
|
||||
} else {
|
||||
iterateNull(nodep->varp());
|
||||
iterateConstNull(nodep->varp());
|
||||
m_hash += nodep->selfPointer();
|
||||
}
|
||||
});
|
||||
}
|
||||
void visit(AstVarXRef* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
iterateNull(nodep->varp());
|
||||
iterateConstNull(nodep->varp());
|
||||
m_hash += nodep->dotted();
|
||||
});
|
||||
}
|
||||
|
|
@ -233,7 +234,7 @@ private:
|
|||
}
|
||||
void visit(AstAddrOfCFunc* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->funcp());
|
||||
iterateConstNull(nodep->funcp());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -249,13 +250,13 @@ private:
|
|||
}
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->funcp());
|
||||
iterateConstNull(nodep->funcp());
|
||||
});
|
||||
}
|
||||
void visit(AstNodeFTaskRef* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
|
||||
iterateNull(nodep->taskp());
|
||||
iterateNull(nodep->classOrPackagep());
|
||||
iterateConstNull(nodep->taskp());
|
||||
iterateConstNull(nodep->classOrPackagep());
|
||||
});
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
|
|
@ -265,12 +266,12 @@ private:
|
|||
}
|
||||
void visit(AstCAwait* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->sensesp());
|
||||
iterateConstNull(nodep->sensesp());
|
||||
});
|
||||
}
|
||||
void visit(AstCoverInc* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->declp());
|
||||
iterateConstNull(nodep->declp());
|
||||
});
|
||||
}
|
||||
void visit(AstDisplay* nodep) override {
|
||||
|
|
@ -285,12 +286,12 @@ private:
|
|||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->labelp());
|
||||
iterateConstNull(nodep->labelp());
|
||||
});
|
||||
}
|
||||
void visit(AstTraceInc* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->declp());
|
||||
iterateConstNull(nodep->declp());
|
||||
});
|
||||
}
|
||||
void visit(AstNodeCoverOrAssert* nodep) override {
|
||||
|
|
@ -332,7 +333,7 @@ private:
|
|||
}
|
||||
void visit(AstClassOrPackageRef* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->classOrPackageNodep());
|
||||
iterateConstNull(nodep->classOrPackageNodep());
|
||||
});
|
||||
}
|
||||
void visit(AstSenItem* nodep) override {
|
||||
|
|
@ -376,7 +377,7 @@ private:
|
|||
if (dtypep) {
|
||||
const uint32_t size = dtypep->elementsConst();
|
||||
for (uint32_t n = 0; n < size; ++n) { //
|
||||
iterateNull(nodep->getIndexDefaultedValuep(n));
|
||||
iterateConstNull(nodep->getIndexDefaultedValuep(n));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -417,13 +418,13 @@ private:
|
|||
void visit(AstScope* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() {
|
||||
m_hash += nodep->name();
|
||||
iterateNull(nodep->aboveScopep());
|
||||
iterateConstNull(nodep->aboveScopep());
|
||||
});
|
||||
}
|
||||
void visit(AstVarScope* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
iterateNull(nodep->varp());
|
||||
iterateNull(nodep->scopep());
|
||||
iterateConstNull(nodep->varp());
|
||||
iterateConstNull(nodep->scopep());
|
||||
});
|
||||
}
|
||||
void visit(AstEnumItem* nodep) override {
|
||||
|
|
@ -443,19 +444,19 @@ private:
|
|||
}
|
||||
void visit(AstActive* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->sensesp());
|
||||
iterateConstNull(nodep->sensesp());
|
||||
});
|
||||
}
|
||||
void visit(AstCell* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
m_hash += nodep->name();
|
||||
iterateNull(nodep->modp());
|
||||
iterateConstNull(nodep->modp());
|
||||
});
|
||||
}
|
||||
void visit(AstCellInline* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
m_hash += nodep->name();
|
||||
iterateNull(nodep->scopep());
|
||||
iterateConstNull(nodep->scopep());
|
||||
});
|
||||
}
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
|
|
@ -471,13 +472,13 @@ private:
|
|||
void visit(AstModportVarRef* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
m_hash += nodep->name();
|
||||
iterateNull(nodep->varp());
|
||||
iterateConstNull(nodep->varp());
|
||||
});
|
||||
}
|
||||
void visit(AstModportFTaskRef* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
|
||||
m_hash += nodep->name();
|
||||
iterateNull(nodep->ftaskp());
|
||||
iterateConstNull(nodep->ftaskp());
|
||||
});
|
||||
}
|
||||
void visit(AstMTaskBody* nodep) override {
|
||||
|
|
@ -502,12 +503,12 @@ public:
|
|||
// CONSTRUCTORS
|
||||
explicit HasherVisitor(AstNode* nodep)
|
||||
: m_cacheInUser4{true} {
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
class Uncached {};
|
||||
HasherVisitor(const AstNode* nodep, Uncached)
|
||||
: m_cacheInUser4{false} {
|
||||
iterate(const_cast<AstNode*>(nodep));
|
||||
iterateConst(const_cast<AstNode*>(nodep));
|
||||
}
|
||||
V3Hash finalHash() const { return m_hash; }
|
||||
~HasherVisitor() override = default;
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ public:
|
|||
|
||||
//######################################################################
|
||||
|
||||
class InstDeModVarVisitor final : public VNVisitor {
|
||||
class InstDeModVarVisitor final : public VNVisitorConst {
|
||||
// Expand all module variables, and save names for later reference
|
||||
private:
|
||||
// STATE
|
||||
|
|
@ -151,10 +151,10 @@ private:
|
|||
UINFO(8, " dm-1-VAR " << nodep << endl);
|
||||
insert(nodep);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeExpr*) override {} // Accelerate
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
|
|
@ -182,7 +182,7 @@ public:
|
|||
void main(AstNodeModule* nodep) {
|
||||
UINFO(8, " dmMODULE " << nodep << endl);
|
||||
m_modVarNameMap.clear();
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ private:
|
|||
// Make all of the required clones
|
||||
for (int i = 0; i < m_cellRangep->elementsConst(); i++) {
|
||||
m_instSelNum
|
||||
= m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
|
||||
= m_cellRangep->ascending() ? (m_cellRangep->elementsConst() - 1 - i) : i;
|
||||
const int instNum = m_cellRangep->loConst() + i;
|
||||
|
||||
AstCell* const newp = nodep->cloneTree(false);
|
||||
|
|
@ -331,7 +331,7 @@ private:
|
|||
// Connection to array, where array dimensions match the instant dimension
|
||||
const AstRange* const rangep
|
||||
= VN_AS(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep();
|
||||
const int arraySelNum = rangep->littleEndian()
|
||||
const int arraySelNum = rangep->ascending()
|
||||
? (rangep->elementsConst() - 1 - m_instSelNum)
|
||||
: m_instSelNum;
|
||||
AstNodeExpr* exprp = VN_AS(nodep->exprp(), NodeExpr)->unlinkFrBack();
|
||||
|
|
@ -342,11 +342,11 @@ private:
|
|||
} else if (expwidth == modwidth * m_cellRangep->elementsConst()) {
|
||||
// Arrayed instants: one bit for each of the instants (each
|
||||
// assign is 1 modwidth wide)
|
||||
if (m_cellRangep->littleEndian()) {
|
||||
nodep->exprp()->v3warn(LITENDIAN, "Big endian instance range connecting to "
|
||||
"vector: left < right of instance range: ["
|
||||
<< m_cellRangep->leftConst() << ":"
|
||||
<< m_cellRangep->rightConst() << "]");
|
||||
if (m_cellRangep->ascending()) {
|
||||
nodep->exprp()->v3warn(ASCRANGE, "Ascending instance range connecting to "
|
||||
"vector: left < right of instance range: ["
|
||||
<< m_cellRangep->leftConst() << ":"
|
||||
<< m_cellRangep->rightConst() << "]");
|
||||
}
|
||||
AstNodeExpr* exprp = VN_AS(nodep->exprp(), NodeExpr)->unlinkFrBack();
|
||||
const bool inputPin = nodep->modVarp()->isNonOutput();
|
||||
|
|
@ -555,7 +555,7 @@ public:
|
|||
V3Inst::checkOutputShort(pinp);
|
||||
AstNodeExpr* const pinexprp = VN_AS(pinp->exprp(), NodeExpr)->unlinkFrBack();
|
||||
const string newvarname
|
||||
= (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||
= (string{pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp"}
|
||||
// Prevent name conflict if both tri & non-tri add signals
|
||||
+ (forTristate ? "t" : "") + "__" + cellp->name() + "__" + pinp->name());
|
||||
AstVar* const newvarp
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
/// we'll count instructions from either the 'if' or the 'else' branch,
|
||||
/// whichever is larger. We know we won't run both.
|
||||
|
||||
class InstrCountVisitor final : public VNVisitor {
|
||||
class InstrCountVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> int. Path cost + 1, 0 means don't dump
|
||||
|
|
@ -76,7 +76,7 @@ public:
|
|||
: m_startNodep{nodep}
|
||||
, m_assertNoDups{assertNoDups}
|
||||
, m_osp{osp} {
|
||||
if (nodep) iterate(nodep);
|
||||
if (nodep) iterateConst(nodep);
|
||||
}
|
||||
~InstrCountVisitor() override = default;
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ private:
|
|||
// Hence, exclude the child of the AstWordSel from the computation,
|
||||
// whose cost scales with the size of the entire (maybe large) vector.
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
iterateAndNextConstNull(nodep->bitp());
|
||||
}
|
||||
void visit(AstSel* nodep) override {
|
||||
if (m_ignoreRemaining) return;
|
||||
|
|
@ -144,8 +144,8 @@ private:
|
|||
// its width) and the cost of the lsbp() and widthp() nodes, but not
|
||||
// the fromp() node which could be disproportionately large.
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
iterateAndNextNull(nodep->widthp());
|
||||
iterateAndNextConstNull(nodep->lsbp());
|
||||
iterateAndNextConstNull(nodep->widthp());
|
||||
}
|
||||
void visit(AstSliceSel* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("AstSliceSel unhandled");
|
||||
|
|
@ -177,18 +177,18 @@ private:
|
|||
void visit(AstNodeIf* nodep) override {
|
||||
if (m_ignoreRemaining) return;
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
const uint32_t savedCount = m_instrCount;
|
||||
|
||||
UINFO(8, "thensp:\n");
|
||||
reset();
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
uint32_t ifCount = m_instrCount;
|
||||
if (nodep->branchPred().unlikely()) ifCount = 0;
|
||||
|
||||
UINFO(8, "elsesp:\n");
|
||||
reset();
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
uint32_t elseCount = m_instrCount;
|
||||
if (nodep->branchPred().likely()) elseCount = 0;
|
||||
|
||||
|
|
@ -206,17 +206,17 @@ private:
|
|||
// Just like if/else above, the ternary operator only evaluates
|
||||
// one of the two expressions, so only count the max.
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
const uint32_t savedCount = m_instrCount;
|
||||
|
||||
UINFO(8, "?\n");
|
||||
reset();
|
||||
iterateAndNextNull(nodep->thenp());
|
||||
iterateAndNextConstNull(nodep->thenp());
|
||||
const uint32_t ifCount = m_instrCount;
|
||||
|
||||
UINFO(8, ":\n");
|
||||
reset();
|
||||
iterateAndNextNull(nodep->elsep());
|
||||
iterateAndNextConstNull(nodep->elsep());
|
||||
const uint32_t elseCount = m_instrCount;
|
||||
|
||||
reset();
|
||||
|
|
@ -230,7 +230,7 @@ private:
|
|||
}
|
||||
void visit(AstCAwait* nodep) override {
|
||||
if (m_ignoreRemaining) return;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
// Anything past a co_await is irrelevant
|
||||
m_ignoreRemaining = true;
|
||||
}
|
||||
|
|
@ -241,7 +241,7 @@ private:
|
|||
// Sum counts in each statement until the first await
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
reset();
|
||||
iterate(stmtp);
|
||||
iterateConst(stmtp);
|
||||
totalCount += m_instrCount;
|
||||
}
|
||||
m_instrCount = totalCount;
|
||||
|
|
@ -266,9 +266,9 @@ private:
|
|||
void visit(AstNodeCCall* nodep) override {
|
||||
if (m_ignoreRemaining) return;
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
m_tracingCall = true;
|
||||
iterate(nodep->funcp());
|
||||
iterateConst(nodep->funcp());
|
||||
UASSERT_OBJ(!m_tracingCall, nodep, "visit(AstCFunc) should have cleared m_tracingCall.");
|
||||
}
|
||||
void visit(AstCFunc* nodep) override {
|
||||
|
|
@ -282,21 +282,21 @@ private:
|
|||
{
|
||||
m_inCFunc = true;
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
m_ignoreRemaining = false;
|
||||
}
|
||||
void visit(AstNode* nodep) override {
|
||||
if (m_ignoreRemaining) return;
|
||||
const VisitBase vb{this, nodep};
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
VL_UNCOPYABLE(InstrCountVisitor);
|
||||
};
|
||||
|
||||
// Iterate the graph printing the critical path marked by previous visitation
|
||||
class InstrCountDumpVisitor final : public VNVisitor {
|
||||
class InstrCountDumpVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> int. Path cost, 0 means don't dump
|
||||
|
|
@ -311,7 +311,7 @@ public:
|
|||
: m_osp{osp} {
|
||||
// No check for nullptr output, so...
|
||||
UASSERT_OBJ(osp, nodep, "Don't call if not dumping");
|
||||
if (nodep) iterate(nodep);
|
||||
if (nodep) iterateConst(nodep);
|
||||
}
|
||||
~InstrCountDumpVisitor() override = default;
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ private:
|
|||
if (unsigned costPlus1 = nodep->user4()) {
|
||||
*m_osp << " " << indent() << "cost " << std::setw(6) << std::left << (costPlus1 - 1)
|
||||
<< " " << nodep << '\n';
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
--m_depth;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ public:
|
|||
: V3GraphVertex{graphp}
|
||||
, m_modp{modp} {}
|
||||
~LinkCellsVertex() override = default;
|
||||
AstNodeModule* modp() const { return m_modp; }
|
||||
string name() const override { return modp()->name(); }
|
||||
AstNodeModule* modp() const VL_MT_STABLE { return m_modp; }
|
||||
string name() const override VL_MT_STABLE { return modp()->name(); }
|
||||
FileLine* fileline() const override { return modp()->fileline(); }
|
||||
// Recursive modules get space for maximum recursion
|
||||
uint32_t rankAdder() const override {
|
||||
|
|
@ -73,7 +73,7 @@ public:
|
|||
explicit LibraryVertex(V3Graph* graphp)
|
||||
: V3GraphVertex{graphp} {}
|
||||
~LibraryVertex() override = default;
|
||||
string name() const override { return "*LIBRARY*"; }
|
||||
string name() const override VL_MT_STABLE { return "*LIBRARY*"; }
|
||||
};
|
||||
|
||||
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,6 @@ private:
|
|||
bool m_forPrimary; // First link
|
||||
bool m_forPrearray; // Compress cell__[array] refs
|
||||
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
|
||||
bool m_removeVoidParamedClasses; // Remove classes with void params
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
|
|
@ -208,7 +207,6 @@ public:
|
|||
m_forPrimary = (step == LDS_PRIMARY);
|
||||
m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY);
|
||||
m_forScopeCreation = (step == LDS_SCOPED);
|
||||
m_removeVoidParamedClasses = (step == LDS_PARAMED);
|
||||
s_errorThisp = this;
|
||||
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
|
||||
}
|
||||
|
|
@ -222,7 +220,6 @@ public:
|
|||
bool forPrimary() const { return m_forPrimary; }
|
||||
bool forPrearray() const { return m_forPrearray; }
|
||||
bool forScopeCreation() const { return m_forScopeCreation; }
|
||||
bool removeVoidParamedClasses() const { return m_removeVoidParamedClasses; }
|
||||
|
||||
// METHODS
|
||||
static string nodeTextType(AstNode* nodep) {
|
||||
|
|
@ -780,7 +777,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
|
||||
// First back iterate, to find all packages. Backward as must do base
|
||||
// packages before using packages
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
|
||||
// The first modules in the list are always the top modules
|
||||
// (sorted before this is called).
|
||||
|
|
@ -916,18 +913,6 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
void visit(AstClass* nodep) override {
|
||||
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
|
||||
UINFO(8, " " << nodep << endl);
|
||||
// Remove classes that have void params, as they were only used for the parameterization
|
||||
// step and will not be instantiated
|
||||
if (m_statep->removeVoidParamedClasses()) {
|
||||
for (auto* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (auto* dtypep = VN_CAST(stmtp, ParamTypeDType)) {
|
||||
if (VN_IS(dtypep->subDTypep(), VoidDType)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VL_RESTORER(m_scope);
|
||||
VL_RESTORER(m_classOrPackagep);
|
||||
VL_RESTORER(m_modSymp);
|
||||
|
|
@ -1709,6 +1694,13 @@ private:
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstPull* nodep) 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);
|
||||
}
|
||||
void visit(AstTypedefFwd* nodep) override {
|
||||
VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->name());
|
||||
if (!foundp && v3Global.opt.pedantic()
|
||||
|
|
@ -1749,7 +1741,7 @@ class LinkDotScopeVisitor final : public VNVisitor {
|
|||
// VISITs
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Recurse..., backward as must do packages before using packages
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
}
|
||||
void visit(AstConstPool*) override {}
|
||||
void visit(AstScope* nodep) override {
|
||||
|
|
@ -2004,9 +1996,6 @@ private:
|
|||
// *::user4() -> See LinkDotState
|
||||
// Cleared on Cell
|
||||
// AstVar::user5() // bool. True if pin used in this cell
|
||||
// AstClass::user5() // bool. True if class has a parameter
|
||||
// as a (possibly indirect) base class.
|
||||
// Used only in LDS_PRIMARY pass
|
||||
const VNUser3InUse m_inuser3;
|
||||
const VNUser5InUse m_inuser5;
|
||||
|
||||
|
|
@ -2030,6 +2019,9 @@ private:
|
|||
int m_modportNum = 0; // Uniqueify modport numbers
|
||||
bool m_inSens = false; // True if in senitem
|
||||
std::set<std::string> m_ifClassImpNames; // Names imported from interface class
|
||||
std::set<AstClass*> m_extendsParam; // Classes that has a parameter as its super class
|
||||
bool m_insideClassExtParam = false; // Inside a class that extends a parameter.
|
||||
// It may be set only in linkDotPrimary.
|
||||
|
||||
struct DotStates {
|
||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||
|
|
@ -2227,11 +2219,17 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
void importSymbolsFromExtended(AstClass* const nodep, AstClassExtends* const cextp) {
|
||||
AstClass* const classp = cextp->classp();
|
||||
VSymEnt* const srcp = m_statep->getNodeSym(classp);
|
||||
if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp);
|
||||
if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp);
|
||||
}
|
||||
|
||||
// VISITs
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Recurse..., backward as must do packages before using packages
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
}
|
||||
void visit(AstTypeTable*) override {}
|
||||
void visit(AstConstPool*) override {}
|
||||
|
|
@ -2393,12 +2391,17 @@ private:
|
|||
nodep->v3error("'super' used on non-extended class (IEEE 1800-2017 8.15)");
|
||||
m_ds.m_dotErr = true;
|
||||
} else {
|
||||
const auto cextp = classp->extendsp();
|
||||
UASSERT_OBJ(cextp, nodep, "Bad super extends link");
|
||||
const auto sclassp = cextp->classp();
|
||||
UASSERT_OBJ(sclassp, nodep, "Bad superclass");
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(sclassp);
|
||||
UINFO(8, " super. " << m_ds.ascii() << endl);
|
||||
if (m_statep->forPrimary()
|
||||
&& m_extendsParam.find(classp) != m_extendsParam.end()) {
|
||||
m_ds.m_unresolvedClass = true;
|
||||
} else {
|
||||
const auto cextp = classp->extendsp();
|
||||
UASSERT_OBJ(cextp, nodep, "Bad super extends link");
|
||||
const auto sclassp = cextp->classp();
|
||||
UASSERT_OBJ(sclassp, nodep, "Bad superclass");
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(sclassp);
|
||||
UINFO(8, " super. " << m_ds.ascii() << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
|
||||
|
|
@ -2527,12 +2530,14 @@ private:
|
|||
string expectWhat;
|
||||
bool allowScope = false;
|
||||
bool allowVar = false;
|
||||
bool staticAccess = false;
|
||||
if (m_ds.m_dotPos == DP_PACKAGE) {
|
||||
// {package}::{a}
|
||||
AstNodeModule* classOrPackagep = nullptr;
|
||||
expectWhat = "scope/variable";
|
||||
allowScope = true;
|
||||
allowVar = true;
|
||||
staticAccess = true;
|
||||
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
||||
"Bad package link");
|
||||
AstClassOrPackageRef* const cpackagerefp
|
||||
|
|
@ -2660,6 +2665,11 @@ private:
|
|||
newp = refp;
|
||||
}
|
||||
} else {
|
||||
if (staticAccess && !varp->lifetime().isStatic() && !varp->isParam()) {
|
||||
// TODO bug4077
|
||||
// nodep->v3error("Static access to non-static member variable "
|
||||
// << varp->prettyNameQ() << endl);
|
||||
}
|
||||
AstVarRef* const refp = new AstVarRef{
|
||||
nodep->fileline(), varp, VAccess::READ}; // lvalue'ness computed later
|
||||
refp->classOrPackagep(foundp->classOrPackagep());
|
||||
|
|
@ -2745,11 +2755,14 @@ private:
|
|||
m_ds.m_dotSymp = foundp;
|
||||
ok = m_ds.m_dotPos == DP_SCOPE;
|
||||
} else if (const AstNodeFTask* const ftaskp = VN_CAST(foundp->nodep(), NodeFTask)) {
|
||||
if (!ftaskp->isFunction()) {
|
||||
|
||||
if (!ftaskp->isFunction() || ftaskp->classMethod()) {
|
||||
ok = m_ds.m_dotPos == DP_NONE;
|
||||
if (ok) {
|
||||
// The condition is true for tasks, properties and void functions.
|
||||
// The condition is true for tasks,
|
||||
// properties and void functions.
|
||||
// In these cases, the parentheses may be skipped.
|
||||
// Also SV class methods can be called without parens
|
||||
AstFuncRef* const funcRefp
|
||||
= new AstFuncRef{nodep->fileline(), nodep->name(), nullptr};
|
||||
nodep->replaceWith(funcRefp);
|
||||
|
|
@ -2757,8 +2770,10 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
if (!ok) {
|
||||
// Don't throw error ifthe reference is inside a class that extends a param, because
|
||||
// some members can't be linked in such a case. m_insideClassExtParam may be true only
|
||||
// in the first stage of linking.
|
||||
if (!ok && !m_insideClassExtParam) {
|
||||
// Cells/interfaces can't be implicit
|
||||
const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false;
|
||||
const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell);
|
||||
|
|
@ -2973,6 +2988,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
bool staticAccess = false;
|
||||
if (m_ds.m_unresolvedClass) {
|
||||
// Unable to link before V3Param
|
||||
return;
|
||||
|
|
@ -2988,6 +3004,7 @@ private:
|
|||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
|
||||
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
||||
"Bad package link");
|
||||
staticAccess = true;
|
||||
AstClassOrPackageRef* const cpackagerefp
|
||||
= VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
||||
if (cpackagerefp->name() == "local") {
|
||||
|
|
@ -3059,9 +3076,18 @@ private:
|
|||
AstNodeFTask* const taskp
|
||||
= foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr
|
||||
if (taskp) {
|
||||
if (staticAccess && !taskp->lifetime().isStatic()) {
|
||||
// TODO bug4077
|
||||
// nodep->v3error("Static access to non-static task/function "
|
||||
// << taskp->prettyNameQ() << endl);
|
||||
}
|
||||
nodep->taskp(taskp);
|
||||
nodep->classOrPackagep(foundp->classOrPackagep());
|
||||
UINFO(7, " Resolved " << nodep << endl); // Also prints taskp
|
||||
} else if (m_insideClassExtParam) {
|
||||
// The reference may point to a method declared in a super class, which is proved
|
||||
// by a parameter. In such a case, it can't be linked at the first stage.
|
||||
return;
|
||||
} else {
|
||||
// Note ParseRef has similar error handling/message output
|
||||
UINFO(7, " ErrFtask curSymp=se" << cvtToHex(m_curSymp) << " dotSymp=se"
|
||||
|
|
@ -3083,6 +3109,8 @@ private:
|
|||
}
|
||||
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
|
||||
// Resolved in V3Width
|
||||
} else if (nodep->name() == "randomize" || nodep->name() == "srandom") {
|
||||
// Resolved in V3Width
|
||||
} else if (nodep->dotted() == "") {
|
||||
if (nodep->pli()) {
|
||||
if (v3Global.opt.bboxSys()) {
|
||||
|
|
@ -3244,124 +3272,134 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstClass* nodep) override {
|
||||
nodep->user3SetOnce();
|
||||
if (nodep->user3SetOnce()) return;
|
||||
UINFO(5, " " << nodep << endl);
|
||||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_ifClassImpNames);
|
||||
VL_RESTORER(m_insideClassExtParam);
|
||||
{
|
||||
m_ds.init(m_curSymp);
|
||||
// Until overridden by a SCOPE
|
||||
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep);
|
||||
m_modp = nodep;
|
||||
int next = 0;
|
||||
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstClassExtends* const cextp = VN_CAST(itemp, ClassExtends)) {
|
||||
// Replace abstract reference with hard pointer
|
||||
// Will need later resolution when deal with parameters
|
||||
if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) {
|
||||
cextp->v3error("Multiple inheritance illegal on non-interface classes"
|
||||
" (IEEE 1800-2017 8.13)");
|
||||
}
|
||||
if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted
|
||||
if (VN_IS(cextp->classOrPkgsp(), Dot)) {
|
||||
itemp->v3warn(E_UNSUPPORTED, "Unsupported: Hierarchical class references");
|
||||
continue;
|
||||
}
|
||||
AstClassOrPackageRef* const cpackagerefp
|
||||
= VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef);
|
||||
if (VL_UNCOVERABLE(!cpackagerefp)) {
|
||||
// Linking the extend gives an error before this is hit
|
||||
cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE
|
||||
for (AstClassExtends* cextp = nodep->extendsp(); cextp;
|
||||
cextp = VN_AS(cextp->nextp(), ClassExtends)) {
|
||||
// Replace abstract reference with hard pointer
|
||||
// Will need later resolution when deal with parameters
|
||||
if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) {
|
||||
cextp->v3error("Multiple inheritance illegal on non-interface classes"
|
||||
" (IEEE 1800-2017 8.13)");
|
||||
}
|
||||
if (cextp->childDTypep() || cextp->dtypep()) {
|
||||
// Already converted. Update symbol table to link unlinked members.
|
||||
// Base class has to be visited in a case if its extends statement
|
||||
// needs to be handled. Recursive inheritance was already checked.
|
||||
iterate(cextp->classp());
|
||||
importSymbolsFromExtended(nodep, cextp);
|
||||
continue;
|
||||
}
|
||||
AstNode* cprp = cextp->classOrPkgsp();
|
||||
VSymEnt* lookSymp = m_curSymp;
|
||||
if (AstDot* const dotp = VN_CAST(cprp, Dot)) {
|
||||
dotp->user3(true);
|
||||
if (AstClassOrPackageRef* lookNodep
|
||||
= VN_CAST(dotp->lhsp(), ClassOrPackageRef)) {
|
||||
iterate(lookNodep);
|
||||
cprp = dotp->rhsp();
|
||||
lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep());
|
||||
} else {
|
||||
VSymEnt* const foundp = m_curSymp->findIdFallback(cpackagerefp->name());
|
||||
if (foundp) {
|
||||
AstClassRefDType* classRefDtypep = nullptr;
|
||||
AstClass* classp = VN_CAST(foundp->nodep(), Class);
|
||||
if (classp) {
|
||||
if (classp != nodep) {
|
||||
// Case with recursive inheritance is handled later in this
|
||||
// function
|
||||
iterate(classp);
|
||||
}
|
||||
if (classp->user5()) {
|
||||
// Has a parameter as its base class
|
||||
nodep->user5(true);
|
||||
return;
|
||||
}
|
||||
AstPin* paramsp = cpackagerefp->paramsp();
|
||||
if (paramsp) paramsp = paramsp->cloneTree(true);
|
||||
classRefDtypep
|
||||
= new AstClassRefDType{nodep->fileline(), classp, paramsp};
|
||||
} else if (AstParamTypeDType* const paramp
|
||||
= VN_CAST(foundp->nodep(), ParamTypeDType)) {
|
||||
if (m_statep->forPrimary()) {
|
||||
// Extending has to be handled after V3Param.cpp, but the type
|
||||
// reference has to be visited
|
||||
iterate(paramp);
|
||||
nodep->user5(true);
|
||||
return;
|
||||
} else {
|
||||
AstNodeDType* const paramTypep = paramp->getChildDTypep();
|
||||
classRefDtypep
|
||||
= VN_CAST(paramTypep->cloneTree(false), ClassRefDType);
|
||||
if (!classRefDtypep) {
|
||||
paramTypep->v3error(
|
||||
"Attempting to extend using non-class");
|
||||
} else {
|
||||
classp = classRefDtypep->classp();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cextp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: " << foundp->nodep()->prettyTypeName()
|
||||
<< " in AstClassExtends");
|
||||
dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE
|
||||
" using non-class under dot");
|
||||
}
|
||||
}
|
||||
AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef);
|
||||
if (VL_UNCOVERABLE(!cpackagerefp)) {
|
||||
// Linking the extend gives an error before this is hit
|
||||
cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE
|
||||
} else {
|
||||
VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name());
|
||||
if (foundp) {
|
||||
AstClassRefDType* classRefDtypep = nullptr;
|
||||
AstClass* classp = VN_CAST(foundp->nodep(), Class);
|
||||
if (classp) {
|
||||
if (classp != nodep) {
|
||||
// Case with recursive inheritance is handled later in this
|
||||
// function
|
||||
iterate(classp);
|
||||
}
|
||||
|
||||
if (classp) {
|
||||
UINFO(8, "Import to " << nodep << " from export class " << classp
|
||||
<< endl);
|
||||
if (classp == nodep) {
|
||||
cextp->v3error("Attempting to extend class "
|
||||
<< nodep->prettyNameQ() << " from itself");
|
||||
} else if (cextp->isImplements() && !classp->isInterfaceClass()) {
|
||||
cextp->v3error(
|
||||
"Attempting to implement from non-interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'extends'");
|
||||
} else if (!cextp->isImplements() && !nodep->isInterfaceClass()
|
||||
&& classp->isInterfaceClass()) {
|
||||
cextp->v3error("Attempting to extend from interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'implements'");
|
||||
if (m_statep->forPrimary()
|
||||
&& m_extendsParam.find(classp) != m_extendsParam.end()) {
|
||||
// Has a parameter as its base class
|
||||
m_extendsParam.insert(nodep);
|
||||
m_insideClassExtParam = true;
|
||||
}
|
||||
AstPin* paramsp = cpackagerefp->paramsp();
|
||||
if (paramsp) paramsp = paramsp->cloneTree(true);
|
||||
classRefDtypep
|
||||
= new AstClassRefDType{nodep->fileline(), classp, paramsp};
|
||||
} else if (AstParamTypeDType* const paramp
|
||||
= VN_CAST(foundp->nodep(), ParamTypeDType)) {
|
||||
if (m_statep->forPrimary()) {
|
||||
// Extending has to be handled after V3Param.cpp
|
||||
m_extendsParam.insert(nodep);
|
||||
m_insideClassExtParam = true;
|
||||
continue;
|
||||
} else {
|
||||
AstNodeDType* const paramTypep = paramp->subDTypep();
|
||||
classRefDtypep
|
||||
= VN_CAST(paramTypep->cloneTree(false), ClassRefDType);
|
||||
if (!classRefDtypep) {
|
||||
paramTypep->v3error("Attempting to extend using non-class");
|
||||
} else {
|
||||
cextp->childDTypep(classRefDtypep);
|
||||
classp->isExtended(true);
|
||||
nodep->isExtended(true);
|
||||
VSymEnt* const srcp = m_statep->getNodeSym(classp);
|
||||
if (classp->isInterfaceClass()) {
|
||||
importImplementsClass(nodep, srcp, classp);
|
||||
}
|
||||
if (!cextp->isImplements()) {
|
||||
m_curSymp->importFromClass(m_statep->symsp(), srcp);
|
||||
}
|
||||
VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(),
|
||||
cpackagerefp);
|
||||
classp = classRefDtypep->classp();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const string suggest = m_statep->suggestSymFallback(
|
||||
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
|
||||
cpackagerefp->v3error(
|
||||
"Class for '"
|
||||
<< cextp->verilogKwd() // extends/implements
|
||||
<< "' not found: " << cpackagerefp->prettyNameQ() << '\n'
|
||||
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
|
||||
cextp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: " << foundp->nodep()->prettyTypeName()
|
||||
<< " in AstClassExtends");
|
||||
}
|
||||
|
||||
if (classp) {
|
||||
UINFO(8, "Import to " << nodep << " from export class " << classp
|
||||
<< endl);
|
||||
if (classp == nodep) {
|
||||
cextp->v3error("Attempting to extend class "
|
||||
<< nodep->prettyNameQ() << " from itself");
|
||||
} else if (cextp->isImplements() && !classp->isInterfaceClass()) {
|
||||
cextp->v3error("Attempting to implement from non-interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'extends'");
|
||||
} else if (!cextp->isImplements() && !nodep->isInterfaceClass()
|
||||
&& classp->isInterfaceClass()) {
|
||||
cextp->v3error("Attempting to extend from interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'implements'");
|
||||
} else {
|
||||
cextp->childDTypep(classRefDtypep);
|
||||
classp->isExtended(true);
|
||||
nodep->isExtended(true);
|
||||
importSymbolsFromExtended(nodep, cextp);
|
||||
VL_DO_DANGLING(cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(),
|
||||
cpackagerefp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const string suggest = m_statep->suggestSymFallback(
|
||||
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
|
||||
cpackagerefp->v3error(
|
||||
"Class for '"
|
||||
<< cextp->verilogKwd() // extends/implements
|
||||
<< "' not found: " << cpackagerefp->prettyNameQ() << '\n'
|
||||
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ds.m_dotSymp = m_curSymp;
|
||||
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
// V3Width when determines types needs to find enum values and such
|
||||
|
|
|
|||
|
|
@ -240,11 +240,12 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
const AstNodeVarRef* varrefp = nullptr;
|
||||
if (m_unsupportedHere || !(varrefp = VN_CAST(nodep->rhsp(), VarRef))) {
|
||||
if (m_unsupportedHere) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Incrementation in this context.");
|
||||
return;
|
||||
}
|
||||
AstNodeExpr* const readp = nodep->rhsp();
|
||||
AstNodeExpr* const writep = nodep->thsp();
|
||||
|
||||
AstConst* const constp = VN_AS(nodep->lhsp(), Const);
|
||||
UASSERT_OBJ(nodep, constp, "Expecting CONST");
|
||||
|
|
@ -253,9 +254,10 @@ private:
|
|||
|
||||
// Prepare a temporary variable
|
||||
FileLine* const fl = backp->fileline();
|
||||
const string name = string("__Vincrement") + cvtToStr(++m_modIncrementsNum);
|
||||
AstVar* const varp = new AstVar{fl, VVarType::BLOCKTEMP, name, VFlagChildDType{},
|
||||
varrefp->varp()->subDTypep()->cloneTree(true)};
|
||||
const string name = string{"__Vincrement"} + cvtToStr(++m_modIncrementsNum);
|
||||
AstVar* const varp = new AstVar{
|
||||
fl, VVarType::BLOCKTEMP, name, VFlagChildDType{},
|
||||
new AstRefDType{fl, AstRefDType::FlagTypeOfExpr{}, readp->cloneTree(true)}};
|
||||
if (m_ftaskp) varp->funcLocal(true);
|
||||
|
||||
// Declare the variable
|
||||
|
|
@ -264,30 +266,29 @@ private:
|
|||
// Define what operation will we be doing
|
||||
AstNodeExpr* operp;
|
||||
if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) {
|
||||
operp = new AstSub{fl, new AstVarRef{fl, varrefp->varp(), VAccess::READ}, newconstp};
|
||||
operp = new AstSub{fl, readp->cloneTree(true), newconstp};
|
||||
} else {
|
||||
operp = new AstAdd{fl, new AstVarRef{fl, varrefp->varp(), VAccess::READ}, newconstp};
|
||||
operp = new AstAdd{fl, readp->cloneTree(true), newconstp};
|
||||
}
|
||||
|
||||
if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) {
|
||||
// PreAdd/PreSub operations
|
||||
// Immediately after declaration - increment it by one
|
||||
varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varrefp->varp(), VAccess::WRITE},
|
||||
varp->addNextHere(new AstAssign{fl, writep->cloneTree(true),
|
||||
new AstVarRef{fl, varp, VAccess::READ}});
|
||||
// Immediately after incrementing - assign it to the original variable
|
||||
varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, operp});
|
||||
} else {
|
||||
// PostAdd/PostSub operations
|
||||
// assign the original variable to the temporary one
|
||||
varp->addNextHere(
|
||||
new AstAssign{fl, new AstVarRef{fl, varrefp->varp(), VAccess::WRITE}, operp});
|
||||
varp->addNextHere(new AstAssign{fl, writep->cloneTree(true), operp});
|
||||
// Increment the original variable by one
|
||||
varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
||||
new AstVarRef{fl, varrefp->varp(), VAccess::READ}});
|
||||
readp->cloneTree(true)});
|
||||
}
|
||||
|
||||
// Replace the node with the temporary
|
||||
nodep->replaceWith(new AstVarRef{varrefp->fileline(), varp, VAccess::READ});
|
||||
nodep->replaceWith(new AstVarRef{readp->fileline(), varp, VAccess::READ});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void visit(AstPreAdd* nodep) override { prepost_visit(nodep); }
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "V3LinkJump.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3AstUserAllocator.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
|
@ -46,6 +47,12 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
|
||||
class LinkJumpVisitor final : public VNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> AstJumpLabel*, for this block if endOfIter
|
||||
// AstNode::user2() -> AstJumpLabel*, for this block if !endOfIter
|
||||
const VNUser1InUse m_user1InUse;
|
||||
const VNUser2InUse m_user2InUse;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
|
|
@ -61,6 +68,13 @@ private:
|
|||
UINFO(4, "Create label for " << nodep << endl);
|
||||
if (VN_IS(nodep, JumpLabel)) return VN_AS(nodep, JumpLabel); // Done
|
||||
|
||||
// Made it previously? We always jump to the end, so this works out
|
||||
if (endOfIter) {
|
||||
if (nodep->user1p()) return VN_AS(nodep->user1p(), JumpLabel);
|
||||
} else {
|
||||
if (nodep->user2p()) return VN_AS(nodep->user2p(), JumpLabel);
|
||||
}
|
||||
|
||||
AstNode* underp = nullptr;
|
||||
bool under_and_next = true;
|
||||
if (VN_IS(nodep, NodeBlock)) {
|
||||
|
|
@ -125,9 +139,27 @@ private:
|
|||
}
|
||||
// Label goes last
|
||||
blockp->addEndStmtsp(labelp);
|
||||
if (endOfIter) {
|
||||
nodep->user1p(labelp);
|
||||
} else {
|
||||
nodep->user2p(labelp);
|
||||
}
|
||||
return labelp;
|
||||
}
|
||||
}
|
||||
void addPrefixToBlocksRecurse(AstNode* nodep) {
|
||||
// Add do_while_ prefix to blocks
|
||||
// Used to not have blocks with duplicated names
|
||||
if (AstBegin* const beginp = VN_CAST(nodep, Begin)) {
|
||||
if (beginp->name() != "") beginp->name("__Vdo_while_" + beginp->name());
|
||||
}
|
||||
|
||||
if (nodep->op1p()) addPrefixToBlocksRecurse(nodep->op1p());
|
||||
if (nodep->op2p()) addPrefixToBlocksRecurse(nodep->op2p());
|
||||
if (nodep->op3p()) addPrefixToBlocksRecurse(nodep->op3p());
|
||||
if (nodep->op4p()) addPrefixToBlocksRecurse(nodep->op4p());
|
||||
if (nodep->nextp()) addPrefixToBlocksRecurse(nodep->nextp());
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
|
|
@ -160,7 +192,7 @@ private:
|
|||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
const string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++);
|
||||
const string name = string{"__Vrepeat"} + cvtToStr(m_modRepeatNum++);
|
||||
// Spec says value is integral, if negative is ignored
|
||||
AstVar* const varp
|
||||
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()};
|
||||
|
|
@ -200,23 +232,21 @@ private:
|
|||
void visit(AstDoWhile* nodep) override {
|
||||
// It is converted to AstWhile in this visit method
|
||||
VL_RESTORER(m_loopp);
|
||||
VL_RESTORER(m_loopInc);
|
||||
{
|
||||
m_loopp = nodep;
|
||||
m_loopInc = false;
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
m_loopInc = true;
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
}
|
||||
AstNodeExpr* const condp = nodep->condp() ? nodep->condp()->unlinkFrBack() : nullptr;
|
||||
AstNode* const bodyp = nodep->stmtsp() ? nodep->stmtsp()->unlinkFrBack() : nullptr;
|
||||
AstNode* const incsp = nodep->incsp() ? nodep->incsp()->unlinkFrBack() : nullptr;
|
||||
AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp, incsp};
|
||||
AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp};
|
||||
nodep->replaceWith(whilep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (bodyp) whilep->addHereThisAsNext(bodyp->cloneTree(false));
|
||||
if (bodyp) {
|
||||
AstNode* const copiedBodyp = bodyp->cloneTree(false);
|
||||
addPrefixToBlocksRecurse(copiedBodyp);
|
||||
whilep->addHereThisAsNext(copiedBodyp);
|
||||
}
|
||||
}
|
||||
void visit(AstForeach* nodep) override {
|
||||
VL_RESTORER(m_loopp);
|
||||
|
|
|
|||
|
|
@ -116,83 +116,43 @@ private:
|
|||
iterateAndNextNull(nodep->top());
|
||||
}
|
||||
}
|
||||
void visit(AstFOpen* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
iterateAndNextNull(nodep->modep());
|
||||
}
|
||||
}
|
||||
void visit(AstFOpenMcd* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
}
|
||||
}
|
||||
void visit(AstFClose* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
void visit(AstFError* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->strp());
|
||||
}
|
||||
}
|
||||
void visit(AstFFlush* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
void visit(AstFGetC* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
void visit(AstFGetS* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->strgp());
|
||||
}
|
||||
}
|
||||
void visit(AstFRead* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
void visit(AstFScanF* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
}
|
||||
}
|
||||
void visit(AstFUngetC* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void V3LinkLevel::modSortByLevel() {
|
|||
if (tops.size() >= 2) {
|
||||
const AstNode* const secp = tops[1]; // Complain about second one, as first often intended
|
||||
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
|
||||
auto warnTopModules = [](std::string warnMore, ModVec tops)
|
||||
auto warnTopModules = [](const std::string& warnMore, ModVec tops)
|
||||
VL_REQUIRES(V3Error::s().m_mutex) -> std::string {
|
||||
std::stringstream ss;
|
||||
for (AstNode* alsop : tops) {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ private:
|
|||
int m_genblkAbove = 0; // Begin block number of if/case/for above
|
||||
int m_genblkNum = 0; // Begin block number, 0=none seen
|
||||
VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime
|
||||
bool m_insideLoop = false; // True if the node is inside a loop
|
||||
|
||||
// METHODS
|
||||
void cleanFileline(AstNode* nodep) {
|
||||
|
|
@ -134,6 +135,9 @@ private:
|
|||
// VISITs
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
if (!nodep->user1SetOnce()) { // Process only once.
|
||||
// Mark class methods
|
||||
if (VN_IS(m_modp, Class)) nodep->classMethod(true);
|
||||
|
||||
V3Config::applyFTask(m_modp, nodep);
|
||||
cleanFileline(nodep);
|
||||
VL_RESTORER(m_ftaskp);
|
||||
|
|
@ -222,6 +226,14 @@ private:
|
|||
|
||||
void visit(AstVar* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
if (nodep->lifetime().isStatic() && m_insideLoop && nodep->valuep()) {
|
||||
nodep->lifetime(VLifetime::AUTOMATIC);
|
||||
nodep->v3warn(STATICVAR, "Static variable with assignment declaration declared in a "
|
||||
"loop converted to automatic");
|
||||
}
|
||||
if (m_ftaskp && m_ftaskp->classMethod() && nodep->lifetime().isNone()) {
|
||||
nodep->lifetime(VLifetime::AUTOMATIC);
|
||||
}
|
||||
if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) {
|
||||
nodep->lifetime(m_lifetime);
|
||||
}
|
||||
|
|
@ -248,7 +260,10 @@ private:
|
|||
// Maybe this variable has a signal attribute
|
||||
V3Config::applyVarAttr(m_modp, m_ftaskp, nodep);
|
||||
|
||||
if (v3Global.opt.publicFlatRW()) {
|
||||
if (v3Global.opt.publicFlatRW()
|
||||
|| (v3Global.opt.publicDepth() && m_modp
|
||||
&& (m_modp->level() - 1) <= v3Global.opt.publicDepth())) {
|
||||
|
||||
switch (nodep->varType()) {
|
||||
case VVarType::VAR: // FALLTHRU
|
||||
case VVarType::GPARAM: // FALLTHRU
|
||||
|
|
@ -259,6 +274,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
if (v3Global.opt.publicParams() && nodep->isParam()) nodep->sigUserRWPublic(true);
|
||||
|
||||
// We used modTrace before leveling, and we may now
|
||||
// want to turn it off now that we know the levelizations
|
||||
if (v3Global.opt.traceDepth() && m_modp
|
||||
|
|
@ -454,6 +471,8 @@ private:
|
|||
// 2. ASTSELBIT(first, var0))
|
||||
// 3. ASTSELLOOPVARS(first, var0..var1))
|
||||
// 4. DOT(DOT(first, second), ASTSELBIT(third, var0))
|
||||
VL_RESTORER(m_insideLoop);
|
||||
m_insideLoop = true;
|
||||
AstNode* bracketp = nodep->arrayp();
|
||||
while (AstDot* dotp = VN_CAST(bracketp, Dot)) bracketp = dotp->rhsp();
|
||||
if (AstSelBit* const selp = VN_CAST(bracketp, SelBit)) {
|
||||
|
|
@ -466,14 +485,34 @@ private:
|
|||
} else if (VN_IS(bracketp, SelLoopVars)) {
|
||||
// Ok
|
||||
} else {
|
||||
nodep->v3error(
|
||||
"Syntax error; foreach missing bracketed loop variable (IEEE 1800-2017 12.7.3)");
|
||||
nodep->v3error("Syntax error; foreach missing bracketed loop variable (IEEE "
|
||||
"1800-2017 12.7.3)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstRepeat* nodep) override {
|
||||
VL_RESTORER(m_insideLoop);
|
||||
{
|
||||
m_insideLoop = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstDoWhile* nodep) override {
|
||||
VL_RESTORER(m_insideLoop);
|
||||
{
|
||||
m_insideLoop = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
VL_RESTORER(m_insideLoop);
|
||||
{
|
||||
m_insideLoop = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
V3Config::applyModule(nodep);
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ private:
|
|||
if (m_underGenerate) nodep->underGenerate(true);
|
||||
// Remember the existing symbol table scope
|
||||
if (m_classp) {
|
||||
if (nodep->name() == "randomize") {
|
||||
if (nodep->name() == "randomize" || nodep->name() == "srandom") {
|
||||
nodep->v3error(nodep->prettyNameQ()
|
||||
<< " is a predefined class method; redefinition not allowed"
|
||||
" (IEEE 1800-2017 18.6.3)");
|
||||
|
|
@ -318,14 +318,6 @@ private:
|
|||
if (filep && filep->varp()) filep->varp()->attrFileDescr(true);
|
||||
}
|
||||
|
||||
void visit(AstFOpen* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
void visit(AstFOpenMcd* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
void visit(AstFClose* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
|
|
@ -454,7 +446,7 @@ public:
|
|||
// Recurses cells backwards, so we can pick up those things that propagate
|
||||
// from child cells up to the top module.
|
||||
|
||||
class LinkBotupVisitor final : public VNVisitor {
|
||||
class LinkBotupVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
|
|
@ -462,14 +454,12 @@ private:
|
|||
// VISITs
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Iterate modules backwards, in bottom-up order.
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = nodep;
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCell* nodep) override {
|
||||
// Parent module inherits child's publicity
|
||||
|
|
@ -477,11 +467,11 @@ private:
|
|||
//** No iteration for speed
|
||||
}
|
||||
void visit(AstNodeExpr*) override {} // Accelerate
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit LinkBotupVisitor(AstNetlist* rootp) { iterate(rootp); }
|
||||
explicit LinkBotupVisitor(AstNetlist* rootp) { iterateConst(rootp); }
|
||||
~LinkBotupVisitor() override = default;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ using StmtPropertiesAllocator = AstUser3Allocator<AstNodeStmt, StmtProperties>;
|
|||
|
||||
// Pure analysis visitor that build the StmtProperties for each statement in the given
|
||||
// AstNode list (following AstNode::nextp())
|
||||
class CodeMotionAnalysisVisitor final : public VNVisitor {
|
||||
class CodeMotionAnalysisVisitor final : public VNVisitorConst {
|
||||
// NODE STATE
|
||||
// AstNodeStmt::user3 -> StmtProperties (accessed via m_stmtProperties, managed externally,
|
||||
// see MergeCondVisitor::process)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,164 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Thread pool for Verilator itself
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2023 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.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator Mutex and LockGuard used only in verilator.
|
||||
///
|
||||
/// This file defines Mutex and LockGuard that is used in verilator
|
||||
/// source code. It shouldn't be used by verilated code.
|
||||
/// In contrast to VerilatedMutex that is used by verilated code,
|
||||
/// this mutex can be configured and disabled when verilation is using
|
||||
/// single thread.
|
||||
///
|
||||
/// This implementation also allows using different base mutex class in
|
||||
/// wrapper V3Mutex class.
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3MUTEX_H_
|
||||
#define VERILATOR_V3MUTEX_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
|
||||
|
||||
// MutexConfig class that allows to configure how mutex and lockgurads behave
|
||||
// once configured and locked, it cannot be changed. Configuration and lock needs to be
|
||||
// done before starting any additional threads.
|
||||
class V3MutexConfig final {
|
||||
private:
|
||||
// Allows to disable mutexes and lockguards.
|
||||
// Use carefully as it can cause undefined behavior when used inappropriately.
|
||||
// All mutexes needs to be unlocked.
|
||||
bool m_enable = false; // Allows locking on mutexes, default don't lock mutexes
|
||||
bool m_lockConfig = false; // After set, configuration cannot be changed
|
||||
|
||||
V3MutexConfig() = default;
|
||||
~V3MutexConfig() = default;
|
||||
|
||||
public:
|
||||
static V3MutexConfig& s() VL_MT_SAFE {
|
||||
static V3MutexConfig s;
|
||||
return s;
|
||||
}
|
||||
|
||||
// configures class
|
||||
void configure(bool enable) VL_MT_UNSAFE {
|
||||
if (!s().m_lockConfig) {
|
||||
s().m_enable = enable;
|
||||
s().m_lockConfig = true;
|
||||
} else {
|
||||
// requires <iostream>
|
||||
// avoided to reduce compile time
|
||||
// std::cerr << "%Error: V3Mutex already configured." << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
bool lockConfig() VL_MT_SAFE { return m_lockConfig; }
|
||||
bool enable() VL_MT_SAFE { return m_enable; }
|
||||
};
|
||||
|
||||
/// Mutex, wrapped to allow -fthread_safety checks
|
||||
template <typename T>
|
||||
class VL_CAPABILITY("mutex") V3MutexImp final {
|
||||
private:
|
||||
T m_mutex; // Mutex
|
||||
|
||||
public:
|
||||
/// Construct mutex (without locking it)
|
||||
V3MutexImp() = default;
|
||||
~V3MutexImp() = default;
|
||||
const V3MutexImp& operator!() const { return *this; } // For -fthread_safety
|
||||
/// Acquire/lock mutex
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE {
|
||||
if (V3MutexConfig::s().enable()) {
|
||||
// Try to acquire the lock by spinning. If the wait is short,
|
||||
// avoids a trap to the OS plus OS scheduler overhead.
|
||||
if (VL_LIKELY(try_lock())) return; // Short circuit loop
|
||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(try_lock())) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
// Spinning hasn't worked, pay the cost of blocking.
|
||||
m_mutex.lock();
|
||||
}
|
||||
}
|
||||
/// Release/unlock mutex
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE {
|
||||
if (V3MutexConfig::s().enable()) { m_mutex.unlock(); }
|
||||
}
|
||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE {
|
||||
return V3MutexConfig::s().enable() ? m_mutex.try_lock() : true;
|
||||
}
|
||||
/// Acquire/lock mutex and check for stop request
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
if (V3MutexConfig::s().enable()) {
|
||||
while (true) {
|
||||
checkStopRequestFunction();
|
||||
if (m_mutex.try_lock()) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
template <typename T>
|
||||
class VL_SCOPED_CAPABILITY V3LockGuardImp final {
|
||||
VL_UNCOPYABLE(V3LockGuardImp);
|
||||
|
||||
private:
|
||||
T& m_mutexr;
|
||||
|
||||
public:
|
||||
/// Construct and hold given mutex lock until destruction or unlock()
|
||||
explicit V3LockGuardImp(T& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE
|
||||
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
|
||||
m_mutexr.lock();
|
||||
}
|
||||
/// Destruct and unlock the mutex
|
||||
~V3LockGuardImp() VL_RELEASE() { m_mutexr.unlock(); }
|
||||
/// Lock the mutex
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||
/// Unlock the mutex
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
|
||||
/// Acquire/lock mutex and check for stop request.
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
m_mutexr.lockCheckStopRequest(checkStopRequestFunction);
|
||||
}
|
||||
};
|
||||
|
||||
using V3Mutex = V3MutexImp<std::mutex>;
|
||||
using V3RecursiveMutex = V3MutexImp<std::recursive_mutex>;
|
||||
using V3LockGuard = V3LockGuardImp<V3Mutex>;
|
||||
using V3RecursiveLockGuard = V3LockGuardImp<V3RecursiveMutex>;
|
||||
|
||||
#endif // guard
|
||||
|
|
@ -103,13 +103,19 @@ private:
|
|||
}
|
||||
void visit(AstMemberDType* nodep) override {
|
||||
if (!nodep->user1()) {
|
||||
rename(nodep, false);
|
||||
rename(nodep, true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
if (!nodep->user1()) {
|
||||
rename(nodep, false);
|
||||
rename(nodep, true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstStructSel* nodep) override {
|
||||
if (!nodep->user1()) {
|
||||
rename(nodep, true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue