Merge from master for release.

This commit is contained in:
Wilson Snyder 2023-04-30 07:09:22 -04:00
commit c37ec19751
383 changed files with 10129 additions and 3651 deletions

View File

@ -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
View File

@ -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]

View File

@ -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

View File

@ -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 ;;

View File

@ -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?

View File

@ -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

View File

@ -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)
==================================

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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) {

View File

@ -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 )

View File

@ -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);

View File

@ -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;
}

View File

@ -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); }

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 )

View File

@ -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,

View File

@ -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;
}

View File

@ -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)"

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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);
}

View File

@ -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(); }

View File

@ -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>); }

View File

@ -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";

View File

@ -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; }

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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();
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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()) {

View File

@ -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

View File

@ -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});

View File

@ -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

View File

@ -23,6 +23,7 @@
#include "V3Ast.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Mutex.h"
//######################################################################

View File

@ -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

View File

@ -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(),

View File

@ -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

View File

@ -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: ");

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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("}");

View File

@ -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)) {

View File

@ -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(),

View File

@ -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;
};

View File

@ -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));

View File

@ -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);

View File

@ -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()}; }
}

View File

@ -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

View File

@ -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); }

View File

@ -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) + "(");

View File

@ -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");

View File

@ -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);
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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");
}
}

View File

@ -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__)}; \

View File

@ -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) {

View File

@ -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);
};

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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();
}

View File

@ -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> {

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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

View File

@ -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); }

View File

@ -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);

View File

@ -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());
}
}

View File

@ -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) {

View File

@ -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);

View File

@ -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;
};

View File

@ -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)

164
src/V3Mutex.h Normal file
View File

@ -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

View File

@ -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