Merge from master for release.
This commit is contained in:
commit
141c5da3f9
|
|
@ -13,4 +13,6 @@ Can you attach an example that shows the issue? (Must be openly licensed, ideal
|
|||
|
||||
What 'verilator --version' are you using? Did you try it with the git master version?
|
||||
|
||||
What OS and distribution are you using?
|
||||
|
||||
Would you be willing to try to fix Verilator yourself with assistance?
|
||||
|
|
|
|||
|
|
@ -39,3 +39,4 @@ verilator-config-version.cmake
|
|||
**/__pycache__/*
|
||||
**/_build/*
|
||||
**/obj_dir/*
|
||||
/.vscode/
|
||||
|
|
|
|||
35
Changes
35
Changes
|
|
@ -8,10 +8,45 @@ The changes in each Verilator version are described below. The
|
|||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 4.216 2021-12-05
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* Add --lib-create, similar to --protect-lib but without protections.
|
||||
* Support tracing through --hierarchical/--lib-create libraries (#3200).
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Internal code cleanups and improvements. [Geza Lore]
|
||||
* Improve --thread verilation-time performance.
|
||||
* Support task name in $display %m (#3211). [Julie Schwartz]
|
||||
* Make 'bit', 'logic' and 'time' types unsigned by default. [Geza Lore]
|
||||
* Optimize $random concatenates/selects (#3114).
|
||||
* Fix array method names with parenthesis (#3181) (#3183). [Teng Huang]
|
||||
* Fix split_var assign merging (#3177) (#3179). [Yutetsu TAKATSUKASA]
|
||||
* Fix wrong bit op tree optimization (#3185). [Yutetsu TAKATSUKASA]
|
||||
* Fix some SliceSels not being constants (#3186) (#3218). [Michaël Lefebvre]
|
||||
* Fix nested generate if genblk naming (#3189). [yanx21]
|
||||
* Fix hang on recursive definition error (#3199). [Jonathan Kimmitt]
|
||||
* Fix display of signed without format (#3204). [Julie Schwartz]
|
||||
* Fix display of empty string constant (#3207) (#3215). [Julie Schwartz]
|
||||
* Fix incorrect width after and-or optimization (#3208). [Julie Schwartz]
|
||||
* Fix $fopen etc on integer arrays (#3214). [adrienlemasle]
|
||||
* Fix $size on dynamic strings (#3216).
|
||||
* Fix %0 format on $value$plusargs (#3217).
|
||||
* Fix timescale portability on Arm64 (#3222).
|
||||
|
||||
|
||||
Verilator 4.214 2021-10-17
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* Add profile-guided optmization of mtasks (#3150).
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Verilator_gantt has removed the ASCII graphics, use the VCD output instead.
|
||||
* Verilator_gantt now shows the predicted mtask times, eval times, and additional statistics.
|
||||
* Verilator_gantt data files now include processor information, to allow later processing.
|
||||
|
|
|
|||
|
|
@ -336,6 +336,7 @@ detailed descriptions of these arguments.
|
|||
-LDFLAGS <flags> Linker pre-object arguments for makefile
|
||||
--l2-name <value> Verilog scope name of the top module
|
||||
--language <lang> Default language standard to parse
|
||||
--lib-create <name> Create a DPI library
|
||||
+libext+<ext>+[ext]... Extensions for finding modules
|
||||
--lint-only Lint, but do not make output
|
||||
-MAKEFLAGS <flags> Arguments to pass to make during --build
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.214 2021-10-17],
|
||||
AC_INIT([Verilator],[4.216 2021-12-05],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ John Coiner
|
|||
John Demme
|
||||
Jonathan Drolet
|
||||
Josh Redford
|
||||
Julie Schwartz
|
||||
Julien Margetts
|
||||
Kaleb Barrett
|
||||
Kanad Kanhere
|
||||
|
|
@ -63,6 +64,7 @@ Marshal Qiao
|
|||
Martin Schmidt
|
||||
Matthew Ballance
|
||||
Michael Killough
|
||||
Michaël Lefebvre
|
||||
Mike Popoloski
|
||||
Miodrag Milanović
|
||||
Morten Borup Petersen
|
||||
|
|
@ -88,6 +90,7 @@ Sergi Granell
|
|||
Stefan Wallentowitz
|
||||
Stephen Henry
|
||||
Steven Hugg
|
||||
Teng Huang
|
||||
Tim Snyder
|
||||
Tobias Rosenkranz
|
||||
Tobias Wölfel
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ The following deprecated items are scheduled for future removal:
|
|||
C++11 compiler support
|
||||
Verilator currently requires C++11 or newer compilers. Verilator will
|
||||
require C++14 or newer compilers for both compiling Verilator and
|
||||
compiling Verilated models no sooner than January 2022.
|
||||
compiling Verilated models no sooner than January 2023.
|
||||
|
||||
Verilated_heavy.h
|
||||
The legacy "verilated_heavy.h" include was replaced with just including
|
||||
|
|
|
|||
|
|
@ -158,41 +158,26 @@ Summary:
|
|||
|
||||
.. option:: --clk <signal-name>
|
||||
|
||||
Sometimes it is quite difficult for Verilator to distinguish clock
|
||||
signals from other data signals. Occasionally the clock signals can end
|
||||
up in the checking list of signals which determines if further
|
||||
evaluation is needed. This will heavily degrade the performance of a
|
||||
Verilated model.
|
||||
|
||||
With :vlopt:`--clk`, the specified signal-name is taken as a root clock
|
||||
into the model, then Verilator will mark the signal as clocker and
|
||||
propagate the clocker attribute automatically to other signals derived
|
||||
from that. In this way, Verilator will try to avoid taking the clocker
|
||||
signal into checking list.
|
||||
into the model; Verilator will mark the signal as clocker and
|
||||
propagate the clocker attribute automatically to other signals downstream in
|
||||
that clock tree.
|
||||
|
||||
Note signal-name is specified by the RTL hierarchy path. For example,
|
||||
v.foo.bar. If the signal is the input to top-module, the directly the
|
||||
signal name. If you find it difficult to find the exact name, try to use
|
||||
a :option:`/*verilator&32;clocker*/` metacomment in RTL file to mark the
|
||||
The provided signal-name is specified using a RTL hierarchy path. For
|
||||
example, v.foo.bar. If the signal is the input to top-module, then
|
||||
directly provide the signal name. Alternatively, use a
|
||||
:option:`/*verilator&32;clocker*/` metacomment in RTL file to mark the
|
||||
signal directly.
|
||||
|
||||
If clock signals are assigned to vectors and then later used
|
||||
individually, Verilator will attempt to decompose the vector and connect
|
||||
the single-bit clock signals directly. This should be transparent to
|
||||
the user.
|
||||
If clock signals are assigned to vectors and then later used as
|
||||
individual bits, Verilator will attempt to decompose the vector and
|
||||
connect the single-bit clock signals.
|
||||
|
||||
.. option:: --make <build-tool>
|
||||
|
||||
Generates a script for the specified build tool.
|
||||
|
||||
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
|
||||
Both can be specified together. If no build tool is specified, gmake is
|
||||
assumed. The executable of gmake can be configured via environment
|
||||
variable "MAKE".
|
||||
|
||||
When using :vlopt:`--build` Verilator takes over the responsibility of
|
||||
building the model library/executable. For this reason :option:`--make`
|
||||
cannot be specified when using :vlopt:`--build`.
|
||||
The clocker attribute is useful in cases where Verilator does not
|
||||
properly distinguish clock signals from other data signals. Using
|
||||
clocker will cause the signal indicated to be considered a clock, and
|
||||
remove it from the combinatorial logic reevaluation checking code. This
|
||||
may greatly improve performance.
|
||||
|
||||
.. option:: --compiler <compiler-name>
|
||||
|
||||
|
|
@ -590,6 +575,23 @@ Summary:
|
|||
"+libext+" is fairly standard across Verilog tools. Defaults to
|
||||
".v+.sv".
|
||||
|
||||
.. option:: --lib-create <name>
|
||||
|
||||
Produces C++, Verilog wrappers and a Makefile which can in turn produce
|
||||
a DPI library which can be used by Verilator or other simulators along
|
||||
with the corresponding Verilog wrapper. The Makefile will build both a
|
||||
static and dynamic version of the library named :file:`lib<name>.a` and
|
||||
:file:`lib<name>.so` respectively. This is done because some simulators
|
||||
require a dynamic library, but the static library is arguably easier to
|
||||
use if possible. :vlopt:`--protect-lib` implies :vlopt:`--protect-ids`.
|
||||
|
||||
When using :vlopt:`--lib-create` it is advised to also use
|
||||
:vlopt:`--timescale-override /1fs <--timescale-override>` to ensure the
|
||||
model has a time resolution that is always compatible with the time
|
||||
precision of the upper instantiating module.
|
||||
|
||||
See also :vlopt:`--protect-lib`.
|
||||
|
||||
.. option:: --lint-only
|
||||
|
||||
Check the files for lint violations only, do not create any other
|
||||
|
|
@ -601,6 +603,19 @@ Summary:
|
|||
If the design is not to be completely Verilated see also the
|
||||
:vlopt:`--bbox-sys` and :vlopt:`--bbox-unsup` options.
|
||||
|
||||
.. option:: --make <build-tool>
|
||||
|
||||
Generates a script for the specified build tool.
|
||||
|
||||
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
|
||||
Both can be specified together. If no build tool is specified, gmake is
|
||||
assumed. The executable of gmake can be configured via environment
|
||||
variable "MAKE".
|
||||
|
||||
When using :vlopt:`--build` Verilator takes over the responsibility of
|
||||
building the model library/executable. For this reason :option:`--make`
|
||||
cannot be specified when using :vlopt:`--build`.
|
||||
|
||||
.. option:: -MAKEFLAGS <string>
|
||||
|
||||
When using :vlopt:`--build`, add the specified argument to the invoked
|
||||
|
|
@ -874,24 +889,15 @@ Summary:
|
|||
|
||||
.. option:: --protect-lib <name>
|
||||
|
||||
Produces C++, Verilog wrappers and a Makefile which can in turn produce
|
||||
a DPI library which can be used by Verilator or other simulators along
|
||||
with the corresponding Verilog wrapper. The Makefile will build both a
|
||||
static and dynamic version of the library named :file:`lib<name>.a` and
|
||||
:file:`lib<name>.so` respectively. This is done because some simulators
|
||||
require a dynamic library, but the static library is arguably easier to
|
||||
use if possible. :vlopt:`--protect-lib` implies :vlopt:`--protect-ids`.
|
||||
Produces a DPI library similar to :vlopt:`--lib-create`, but hides
|
||||
internal design details. :vlopt:`--protect-lib` implies
|
||||
:vlopt:`--protect-ids`, and :vlopt:`--lib-create`.
|
||||
|
||||
This allows for the secure delivery of sensitive IP without the need for
|
||||
encrypted RTL (i.e. IEEE P1735). See :file:`examples/make_protect_lib`
|
||||
in the distribution for a demonstration of how to build and use the DPI
|
||||
library.
|
||||
|
||||
When using :vlopt:`--protect-lib` it is advised to also use
|
||||
:vlopt:`--timescale-override /1fs <--timescale-override>` to ensure the
|
||||
model has a time resolution that is always compatible with the time
|
||||
precision of the upper instantiating module.
|
||||
|
||||
.. option:: --private
|
||||
|
||||
Opposite of :vlopt:`--public`. Is the default; this option exists for
|
||||
|
|
@ -1167,9 +1173,9 @@ Summary:
|
|||
|
||||
.. option:: --trace-underscore
|
||||
|
||||
Enable tracing of signals that start with an underscore. Normally, these
|
||||
signals are not output during tracing. See also
|
||||
:vlopt:`--coverage-underscore` option.
|
||||
Enable tracing of signals or modules that start with an
|
||||
underscore. Normally, these signals are not output during tracing. See
|
||||
also :vlopt:`--coverage-underscore` option.
|
||||
|
||||
.. option:: -U<var>
|
||||
|
||||
|
|
@ -1506,9 +1512,9 @@ The grammar of configuration commands is as follows:
|
|||
|
||||
.. option:: no_clocker -module "<modulename>" [-function "<funcname>"] -var "<signame>"
|
||||
|
||||
Indicate the signal is used as clock or not. This information is used by
|
||||
Verilator to mark the signal as clocker and propagate the clocker
|
||||
attribute automatically to derived signals. See :vlopt:`--clk`.
|
||||
Indicates that the signal is used as clock or not. This information is
|
||||
used by Verilator to mark the signal and any derrived signals as
|
||||
clocker. See :vlopt:`--clk`.
|
||||
|
||||
Same as :option:`/*verilator&32;clocker*/` metacomment.
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,14 @@ or "`ifdef`"'s may break other tools.
|
|||
Verilog functions where the variable is flattened out, and also enable
|
||||
other optimizations.
|
||||
|
||||
Verilator does not use any text inside the quotes for
|
||||
ordering/scheduling. If you need the $c to be called at a specific
|
||||
time, e.g. when a variable changes, then the $c must be under an
|
||||
appropriate sensitivity statement, e.g. :code:`always @(posedge clk)
|
||||
$c("func()")` to call it on every edge, or e.g. :code:`always @*
|
||||
c("func(",a,")")` to call it when :code:`a` changes (the latter working
|
||||
because :code:`a` is outside the quotes).
|
||||
|
||||
If you will be reading or writing any Verilog variables inside the C++
|
||||
functions, the Verilog signals must be declared with
|
||||
:option:`/*verilator&32;public*/` metacomments.
|
||||
|
|
@ -176,10 +184,9 @@ or "`ifdef`"'s may break other tools.
|
|||
|
||||
.. option:: /*verilator&32;no_clocker*/
|
||||
|
||||
Used after a signal declaration to indicate the signal is used as clock
|
||||
or not. This information is used by Verilator to mark the signal as
|
||||
clocker and propagate the clocker attribute automatically to derived
|
||||
signals. See :vlopt:`--clk`.
|
||||
Specifies that the signal is used as clock or not. This information is
|
||||
used by Verilator to mark the signal and any derrived signals as
|
||||
clocker. See :vlopt:`--clk`.
|
||||
|
||||
Same as :option:`clocker` and :option:`no_clocker` in configuration
|
||||
files.
|
||||
|
|
@ -482,6 +489,13 @@ or "`ifdef`"'s may break other tools.
|
|||
Verilator) text that should be passed through to the XML output as a tag,
|
||||
for use by downstream applications.
|
||||
|
||||
.. option:: /*verilator&32;trace_init_task*/
|
||||
|
||||
Attached to a DPI import to indicate that function should be called when
|
||||
initializing tracing. This attribute is indented only to be used
|
||||
internally in code that Verilator generates when :vlopt:`--lib-create`
|
||||
or :vlopt:`--hierarchical` is used along with :vlopt:`--trace`.
|
||||
|
||||
.. option:: /*verilator&32;tracing_off*/
|
||||
|
||||
Disable waveform tracing for all future signals that are declared in
|
||||
|
|
|
|||
|
|
@ -35,8 +35,10 @@ simulators.
|
|||
Does Verilator run under Windows?
|
||||
"""""""""""""""""""""""""""""""""
|
||||
|
||||
Yes, using Cygwin. Verilated output also compiles under Microsoft Visual
|
||||
C++, but this is not tested every release.
|
||||
Yes, ideally run Ubuntu under Windows Subsystem for Linux (WSL2).
|
||||
Alternatively use Cygwin, though this tends to be slower and is not
|
||||
regurally tested. Verilated output also compiles under Microsoft Visual
|
||||
C++, but this is also not regurally tested.
|
||||
|
||||
|
||||
Can you provide binaries?
|
||||
|
|
|
|||
|
|
@ -78,10 +78,10 @@ OS Requirements
|
|||
|
||||
Verilator is developed and has primary testing on Ubuntu, with additional
|
||||
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
|
||||
Linux, HPUX and Solaris. It should run with minor porting on any
|
||||
GNU/Linux-ish platform. Verilator also works on Windows under Cygwin, and
|
||||
Windows under MinGW (gcc -mno-cygwin). Verilated output (not Verilator
|
||||
itself) compiles under all the options above, plus using MSVC++.
|
||||
Linux, and other flavors of GNU/Linux-ish platforms. Verilator also works
|
||||
on Windows Subsystem for Linux (WSL2), Windows under Cygwin, and Windows
|
||||
under MinGW (gcc -mno-cygwin). Verilated output (not Verilator itself)
|
||||
compiles under all the options above, plus using MSVC++.
|
||||
|
||||
|
||||
Install Prerequisites
|
||||
|
|
|
|||
|
|
@ -70,10 +70,9 @@ Verilator is run in hierarchical mode on the whole SoC. Verilator will
|
|||
make two models, one for the CPU hierarchy block, and one for the SoC. The
|
||||
Verialted code for the SoC will automatically call the CPU Verilated model.
|
||||
|
||||
The current hierarchical Verilation is based on protect-lib. Each hierarchy
|
||||
block is Verilated to a protect-lib. User modules of the hierarchy blocks
|
||||
will see a tiny wrapper generated by protect-lib instead of the actual
|
||||
design.
|
||||
The current hierarchical Verilation is based on :vlopt:`--lib-create`. Each
|
||||
hierarchy block is Verilated into a library. User modules of the hierarchy
|
||||
blocks will see a tiny wrapper generated by :vlopt:`--lib-create`.
|
||||
|
||||
|
||||
Usage
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ run:
|
|||
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "Note: Once this example is understood, see examples/cmake_tracing_sc."
|
||||
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
|
||||
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
clean mostlyclean distclean maintainer-clean:
|
||||
@rm -rf build logs
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ default:
|
|||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "Note: Once this example is understood, see examples/make_tracing_c."
|
||||
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
|
||||
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
// any use, without warranty, 2017 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// See also the EXAMPLE section in the verilator manpage/document.
|
||||
// See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
$display("Hello World!");
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ run:
|
|||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "Note: Once this example is understood, see examples/make_tracing_sc."
|
||||
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
|
||||
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
// any use, without warranty, 2017 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// See also the EXAMPLE section in the verilator manpage/document.
|
||||
// See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
$display("Hello World!");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
// any use, without warranty, 2019 by Todd Strader.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// See also the EXAMPLE section in the verilator manpage/document.
|
||||
// See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
module top (input clk);
|
||||
|
||||
integer cyc = 0;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
//=========================================================================
|
||||
// Internal note:
|
||||
//
|
||||
// verilated.o may exist both in protect-lib (incrementally linked .a/.so)
|
||||
// verilated.o may exist both in --lib-create (incrementally linked .a/.so)
|
||||
// and the main module. Both refer the same instance of static
|
||||
// variables/VL_THREAD_LOCAL in verilated.o such as Verilated, or
|
||||
// VerilatedImpData. This is important to share that state, but the
|
||||
|
|
@ -208,7 +208,7 @@ void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char
|
|||
std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
|
||||
va_list aq;
|
||||
va_copy(aq, ap);
|
||||
size_t len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
|
||||
const size_t len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
|
||||
va_end(aq);
|
||||
if (VL_UNLIKELY(len < 1)) return "";
|
||||
|
||||
|
|
@ -308,27 +308,22 @@ vluint64_t vl_rand64() VL_MT_SAFE {
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
|
||||
// LCOV_EXCL_START
|
||||
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = vl_rand64();
|
||||
outwp[VL_WORDS_I(obits) - 1] = vl_rand64() & VL_MASK_E(obits);
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = vl_rand64();
|
||||
// Last word is unclean
|
||||
return outwp;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
#endif
|
||||
|
||||
IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE {
|
||||
IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->randSeed(static_cast<int>(seed));
|
||||
return VL_RANDOM_I(obits);
|
||||
return VL_RANDOM_I();
|
||||
}
|
||||
|
||||
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
IData data = ~0;
|
||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
||||
data = VL_RANDOM_I(obits);
|
||||
data = VL_RANDOM_I();
|
||||
}
|
||||
data &= VL_MASK_I(obits);
|
||||
return data;
|
||||
|
|
@ -337,7 +332,7 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
|||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
QData data = ~0ULL;
|
||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
||||
data = VL_RANDOM_Q(obits);
|
||||
data = VL_RANDOM_Q();
|
||||
}
|
||||
data &= VL_MASK_Q(obits);
|
||||
return data;
|
||||
|
|
@ -387,7 +382,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
|
|||
if (vw == 1) { // Single divisor word breaks rest of algorithm
|
||||
vluint64_t k = 0;
|
||||
for (int j = uw - 1; j >= 0; --j) {
|
||||
vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
|
||||
const vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
|
||||
owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]);
|
||||
k = unw64 - static_cast<vluint64_t>(owp[j]) * static_cast<vluint64_t>(rwp[0]);
|
||||
}
|
||||
|
|
@ -444,7 +439,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
|
|||
vlsint64_t t = 0; // Must be signed
|
||||
vluint64_t k = 0;
|
||||
for (int i = 0; i < vw; ++i) {
|
||||
vluint64_t p = qhat * vn[i]; // Multiply by estimate
|
||||
const vluint64_t p = qhat * vn[i]; // Multiply by estimate
|
||||
t = un[i + j] - k - (p & 0xFFFFFFFFULL); // Subtract
|
||||
un[i + j] = t;
|
||||
k = (p >> 32ULL) - (t >> 32ULL);
|
||||
|
|
@ -698,8 +693,8 @@ std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t w
|
|||
}
|
||||
}
|
||||
} else {
|
||||
double shiftd = vl_time_multiplier(shift);
|
||||
double scaled = ld * shiftd;
|
||||
const double shiftd = vl_time_multiplier(shift);
|
||||
const double scaled = ld * shiftd;
|
||||
const double fracDiv = vl_time_multiplier(fracDigits);
|
||||
const double whole = scaled / fracDiv;
|
||||
if (!fracDigits) {
|
||||
|
|
@ -749,7 +744,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
}
|
||||
} else { // Format character
|
||||
inPct = false;
|
||||
char fmt = pos[0];
|
||||
const char fmt = pos[0];
|
||||
switch (fmt) {
|
||||
case '0': // FALLTHRU
|
||||
case '1': // FALLTHRU
|
||||
|
|
@ -809,7 +804,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
output += _vl_vsformat_time(t_tmp, d, timeunit, left, width);
|
||||
} else {
|
||||
const size_t len = pos - pctp + 1;
|
||||
std::string fmts{pctp, len};
|
||||
const std::string fmts{pctp, len};
|
||||
VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d);
|
||||
output += t_tmp;
|
||||
}
|
||||
|
|
@ -869,7 +864,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
}
|
||||
digits = append.length();
|
||||
}
|
||||
int needmore = width - digits;
|
||||
const int needmore = width - digits;
|
||||
std::string padding;
|
||||
if (needmore > 0) {
|
||||
if (pctp && pctp[0] && pctp[1] == '0') { // %0
|
||||
|
|
@ -892,7 +887,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
append = VL_DECIMAL_NW(lbits, lwp);
|
||||
digits = append.length();
|
||||
}
|
||||
int needmore = width - digits;
|
||||
const int needmore = width - digits;
|
||||
std::string padding;
|
||||
if (needmore > 0) {
|
||||
if (pctp && pctp[0] && pctp[1] == '0') { // %0
|
||||
|
|
@ -953,7 +948,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||
case 'x':
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 4) * 4; // Next digit
|
||||
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
|
||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
|
||||
output += "0123456789abcdef"[charval];
|
||||
}
|
||||
break;
|
||||
|
|
@ -1027,7 +1022,7 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp,
|
|||
}
|
||||
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
|
||||
const std::string& fstr, char* beginp, std::size_t n,
|
||||
bool inhibit = false) {
|
||||
const bool inhibit = false) {
|
||||
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized
|
||||
// specifically for block reads of N bytes (read operations are not demarcated by
|
||||
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
|
||||
|
|
@ -1041,9 +1036,7 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
|
|||
}
|
||||
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
|
||||
IData ld) VL_MT_SAFE {
|
||||
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
|
||||
VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1);
|
||||
}
|
||||
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) { VL_ASSIGNBIT_WI(lsb, owp, ld & 1); }
|
||||
}
|
||||
static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp,
|
||||
size_t posstart, size_t posend) VL_MT_SAFE {
|
||||
|
|
@ -1100,16 +1093,16 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
} else if (!inPct) { // Expected Format
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
if (c != pos[0]) goto done;
|
||||
_vl_vsss_advance(fp, floc);
|
||||
} else { // Format character
|
||||
// Skip loading spaces
|
||||
inPct = false;
|
||||
char fmt = pos[0];
|
||||
const char fmt = pos[0];
|
||||
switch (fmt) {
|
||||
case '%': {
|
||||
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
if (c != '%') goto done;
|
||||
_vl_vsss_advance(fp, floc);
|
||||
break;
|
||||
|
|
@ -1139,7 +1132,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
switch (fmt) {
|
||||
case 'c': {
|
||||
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
if (c == EOF) goto done;
|
||||
_vl_vsss_advance(fp, floc);
|
||||
owp[0] = c;
|
||||
|
|
@ -1292,7 +1285,7 @@ void _vl_vint_to_string(int obits, char* destoutp, const WDataInP sourcep) VL_MT
|
|||
char* destp = destoutp;
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 8) * 8; // Next digit
|
||||
IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff;
|
||||
const IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff;
|
||||
if (!start || charval) {
|
||||
*destp++ = (charval == 0) ? ' ' : charval;
|
||||
start = false; // Drop leading 0s
|
||||
|
|
@ -1530,16 +1523,16 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
|
|||
// Prep for reading
|
||||
IData read_count = 0;
|
||||
IData read_elements = 0;
|
||||
int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
|
||||
const int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
|
||||
int shift = start_shift;
|
||||
// Read the data
|
||||
// We process a character at a time, as then we don't need to deal
|
||||
// with changing buffer sizes dynamically, etc.
|
||||
while (true) {
|
||||
int c = std::fgetc(fp);
|
||||
const int c = std::fgetc(fp);
|
||||
if (VL_UNLIKELY(c == EOF)) break;
|
||||
// Shift value in
|
||||
IData entry = read_elements + start - array_lsb;
|
||||
const IData entry = read_elements + start - array_lsb;
|
||||
if (width <= 8) {
|
||||
CData* const datap = &(reinterpret_cast<CData*>(memp))[entry];
|
||||
if (shift == start_shift) *datap = 0;
|
||||
|
|
@ -1600,6 +1593,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
|
|||
inPct = true;
|
||||
} else if (!inPct) { // Normal text
|
||||
prefix += *posp;
|
||||
} else if (inPct && posp[0] == '0') { // %0
|
||||
} else { // Format character
|
||||
switch (std::tolower(*posp)) {
|
||||
case '%':
|
||||
|
|
@ -1727,14 +1721,14 @@ std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
|
|||
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_MT_SAFE {
|
||||
// See also _vl_vint_to_string
|
||||
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
|
||||
int obits = lwords * VL_EDATASIZE;
|
||||
const int obits = lwords * VL_EDATASIZE;
|
||||
int lsb = obits - 1;
|
||||
bool start = true;
|
||||
char* destp = destout;
|
||||
size_t len = 0;
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 8) * 8; // Next digit
|
||||
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||
if (!start || charval) {
|
||||
*destp++ = (charval == 0) ? ' ' : charval;
|
||||
++len;
|
||||
|
|
@ -2068,7 +2062,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary
|
|||
VL_FATAL_MT(filename.c_str(), rmem.linenum(), "",
|
||||
"$readmem file address beyond bounds of array");
|
||||
} else {
|
||||
QData entry = addr - array_lsb;
|
||||
const QData entry = addr - array_lsb;
|
||||
if (bits <= 8) {
|
||||
CData* const datap = &(reinterpret_cast<CData*>(memp))[entry];
|
||||
rmem.setData(datap, value);
|
||||
|
|
@ -2103,7 +2097,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary
|
|||
QData start, // First array row address to write
|
||||
QData end // Last address to write, or ~0 when not specified
|
||||
) VL_MT_SAFE {
|
||||
QData addr_max = array_lsb + depth - 1;
|
||||
const QData addr_max = array_lsb + depth - 1;
|
||||
if (start < static_cast<QData>(array_lsb)) start = array_lsb;
|
||||
if (end > addr_max) end = addr_max;
|
||||
|
||||
|
|
@ -2827,7 +2821,7 @@ size_t VerilatedVarProps::totalSize() const {
|
|||
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
|
||||
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
|
||||
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
|
||||
int indxAdj = indx - low(dim);
|
||||
const int indxAdj = indx - low(dim);
|
||||
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
|
||||
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
|
||||
size_t slicesz = entSize();
|
||||
|
|
@ -2872,7 +2866,7 @@ void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const
|
|||
void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE {
|
||||
// Slowpath - called once/scope*export at construction
|
||||
// Insert a exported function into scope table
|
||||
int funcnum = VerilatedImp::exportInsert(namep);
|
||||
const int funcnum = VerilatedImp::exportInsert(namep);
|
||||
if (!finalize) {
|
||||
// Need two passes so we know array size to create
|
||||
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
||||
|
|
@ -2914,7 +2908,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, boo
|
|||
} else {
|
||||
// We could have a linked list of ranges, but really this whole thing needs
|
||||
// to be generalized to support structs and unions, etc.
|
||||
std::string msg
|
||||
const std::string msg
|
||||
= std::string{"Unsupported multi-dimensional public varInsert: "} + namep;
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
}
|
||||
|
|
@ -2961,7 +2955,7 @@ void VerilatedScope::scopeDump() const {
|
|||
VerilatedImp::exportName(i));
|
||||
}
|
||||
}
|
||||
if (VerilatedVarNameMap* const varsp = this->varsp()) {
|
||||
if (const VerilatedVarNameMap* const varsp = this->varsp()) {
|
||||
for (const auto& i : *varsp) VL_PRINTF_MT(" VAR %p: %s\n", &(i.second), i.first);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,7 +359,7 @@ protected:
|
|||
} m_args VL_GUARDED_BY(m_argMutex);
|
||||
|
||||
// Implementation details
|
||||
std::unique_ptr<VerilatedContextImpData> m_impdatap;
|
||||
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
|
||||
// Coverage access
|
||||
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()
|
||||
|
||||
|
|
|
|||
|
|
@ -206,9 +206,9 @@ private:
|
|||
}
|
||||
|
||||
// Forward to . so we have a whole word
|
||||
std::string suffix = *bpost ? std::string{bpost + 1} : "";
|
||||
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
|
||||
|
||||
std::string out = prefix + "*" + suffix;
|
||||
const std::string out = prefix + "*" + suffix;
|
||||
|
||||
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
|
||||
// <<"\ncho="<<out<<endl;
|
||||
|
|
@ -219,7 +219,7 @@ private:
|
|||
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
|
||||
// We don't compare keys, only values
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
const std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
if (std::string::npos != val.find(match)) { // Found
|
||||
return true;
|
||||
}
|
||||
|
|
@ -302,7 +302,7 @@ public:
|
|||
// First two key/vals are filename
|
||||
ckeyps[0] = "filename";
|
||||
valps[0] = m_insertFilenamep;
|
||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||
const std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||
ckeyps[1] = "lineno";
|
||||
valps[1] = linestr.c_str();
|
||||
// Default page if not specified
|
||||
|
|
@ -342,7 +342,7 @@ public:
|
|||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||
++addKeynum;
|
||||
if (VL_UNCOVERABLE(!legalKey(key))) {
|
||||
std::string msg
|
||||
const std::string msg
|
||||
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
|
||||
+ key); // LCOV_EXCL_LINE
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
|
|
@ -380,8 +380,9 @@ public:
|
|||
|
||||
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
|
||||
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
const std::string key
|
||||
= VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||
const std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
if (key == VL_CIK_PER_INSTANCE) {
|
||||
if (val != "0") per_instance = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
|
|||
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1));
|
||||
}
|
||||
|
||||
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); }
|
||||
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(bit, dp, s); }
|
||||
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
|
||||
// Verilator doesn't support X/Z so only aval
|
||||
dp[VL_BITWORD_I(bit)].aval = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
|
||||
|
|
@ -428,13 +428,13 @@ void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
|
|||
switch (varp->udims()) {
|
||||
case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
const int indx2 = va_arg(ap, int);
|
||||
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
const int indx2 = va_arg(ap, int);
|
||||
const int indx3 = va_arg(ap, int);
|
||||
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,14 +73,13 @@ extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
|||
/// Print a debug message from internals with standard prefix, with printf style format
|
||||
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||
|
||||
inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
|
||||
inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
|
||||
#ifndef VL_NO_LEGACY
|
||||
// EMIT_RULE: VL_RANDOM: oclean=dirty
|
||||
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
|
||||
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
|
||||
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp);
|
||||
#endif
|
||||
extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE;
|
||||
extern IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE;
|
||||
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
|
||||
vluint64_t rnd = vl_rand64();
|
||||
const vluint64_t rnd = vl_rand64();
|
||||
if (VL_LIKELY(hi > lo)) {
|
||||
// (hi - lo + 1) can be zero when hi is UINT_MAX and lo is zero
|
||||
if (VL_UNLIKELY(hi - lo + 1 == 0)) return rnd;
|
||||
|
|
@ -363,13 +362,13 @@ vluint64_t vl_time_pow10(int n) VL_PURE;
|
|||
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits))
|
||||
|
||||
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
|
||||
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (obits), (owp), (lwp))
|
||||
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (owp), (lwp))
|
||||
static inline WDataOutP _vl_clean_inplace_w(int obits, WDataOutP owp) VL_MT_SAFE {
|
||||
const int words = VL_WORDS_I(obits);
|
||||
owp[words - 1] &= VL_MASK_E(obits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CLEAN_WW(int obits, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
|
||||
const int words = VL_WORDS_I(obits);
|
||||
for (int i = 0; (i < (words - 1)); ++i) owp[i] = lwp[i];
|
||||
owp[words - 1] = lwp[words - 1] & VL_MASK_E(obits);
|
||||
|
|
@ -397,37 +396,37 @@ static inline WDataOutP VL_ASSIGN_W(int obits, WDataOutP owp, WDataInP const lwp
|
|||
}
|
||||
|
||||
// EMIT_RULE: VL_ASSIGNBIT: rclean=clean;
|
||||
static inline void VL_ASSIGNBIT_II(int, int bit, CData& lhsr, IData rhs) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_II(int bit, CData& lhsr, IData rhs) VL_PURE {
|
||||
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_II(int, int bit, SData& lhsr, IData rhs) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_II(int bit, SData& lhsr, IData rhs) VL_PURE {
|
||||
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_II(int, int bit, IData& lhsr, IData rhs) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_II(int bit, IData& lhsr, IData rhs) VL_PURE {
|
||||
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_QI(int bit, QData& lhsr, QData rhs) VL_PURE {
|
||||
lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
|
||||
EData orig = owp[VL_BITWORD_E(bit)];
|
||||
static inline void VL_ASSIGNBIT_WI(int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
|
||||
const EData orig = owp[VL_BITWORD_E(bit)];
|
||||
owp[VL_BITWORD_E(bit)] = ((orig & ~(VL_EUL(1) << VL_BITBIT_E(bit)))
|
||||
| (static_cast<EData>(rhs) << VL_BITBIT_E(bit)));
|
||||
}
|
||||
// Alternative form that is an instruction faster when rhs is constant one.
|
||||
static inline void VL_ASSIGNBIT_IO(int, int bit, CData& lhsr, IData) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_IO(int bit, CData& lhsr) VL_PURE {
|
||||
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_IO(int, int bit, SData& lhsr, IData) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_IO(int bit, SData& lhsr) VL_PURE {
|
||||
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_IO(int, int bit, IData& lhsr, IData) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_IO(int bit, IData& lhsr) VL_PURE {
|
||||
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
|
||||
static inline void VL_ASSIGNBIT_QO(int bit, QData& lhsr) VL_PURE {
|
||||
lhsr = (lhsr | (1ULL << VL_BITBIT_Q(bit)));
|
||||
}
|
||||
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
|
||||
static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
||||
const EData orig = owp[VL_BITWORD_E(bit)];
|
||||
owp[VL_BITWORD_E(bit)] = (orig | (VL_EUL(1) << VL_BITBIT_E(bit)));
|
||||
}
|
||||
|
|
@ -588,9 +587,9 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp,
|
|||
// REDUCTION OPERATORS
|
||||
|
||||
// EMIT_RULE: VL_REDAND: oclean=clean; lclean==clean; obits=1;
|
||||
#define VL_REDAND_II(obits, lbits, lhs) ((lhs) == VL_MASK_I(lbits))
|
||||
#define VL_REDAND_IQ(obits, lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
|
||||
static inline IData VL_REDAND_IW(int, int lbits, WDataInP const lwp) VL_MT_SAFE {
|
||||
#define VL_REDAND_II(lbits, lhs) ((lhs) == VL_MASK_I(lbits))
|
||||
#define VL_REDAND_IQ(lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
|
||||
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_MT_SAFE {
|
||||
const int words = VL_WORDS_I(lbits);
|
||||
EData combine = lwp[0];
|
||||
for (int i = 1; i < words - 1; ++i) combine &= lwp[i];
|
||||
|
|
@ -696,11 +695,11 @@ static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
|||
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
|
||||
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
|
||||
IData ctrl2) VL_PURE {
|
||||
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
|
||||
const int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
|
||||
if (ctrlSum == 3) {
|
||||
return VL_COUNTONES_I(lhs);
|
||||
} else if (ctrlSum == 0) {
|
||||
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
|
||||
const IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
|
||||
return VL_COUNTONES_I(~lhs & mask);
|
||||
} else {
|
||||
return (lbits == 32) ? 32 : lbits;
|
||||
|
|
@ -771,7 +770,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
|
|||
return shifts;
|
||||
}
|
||||
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
|
||||
const EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
|
||||
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
|
||||
|
|
@ -862,52 +861,52 @@ static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) V
|
|||
return 0; // ==
|
||||
}
|
||||
|
||||
#define VL_LTS_IWW(obits, lbits, rbbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) < 0)
|
||||
#define VL_LTES_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) <= 0)
|
||||
#define VL_GTS_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) > 0)
|
||||
#define VL_GTES_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) >= 0)
|
||||
#define VL_LTS_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) < 0)
|
||||
#define VL_LTES_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) <= 0)
|
||||
#define VL_GTS_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) > 0)
|
||||
#define VL_GTES_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) >= 0)
|
||||
|
||||
static inline IData VL_GTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
|
||||
static inline IData VL_GTS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
// For lbits==32, this becomes just a single instruction, otherwise ~5.
|
||||
// GCC 3.3.4 sign extension bugs on AMD64 architecture force us to use quad logic
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
|
||||
return lhs_signed > rhs_signed;
|
||||
}
|
||||
static inline IData VL_GTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
|
||||
static inline IData VL_GTS_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed > rhs_signed;
|
||||
}
|
||||
|
||||
static inline IData VL_GTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
|
||||
static inline IData VL_GTES_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
|
||||
return lhs_signed >= rhs_signed;
|
||||
}
|
||||
static inline IData VL_GTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
|
||||
static inline IData VL_GTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed >= rhs_signed;
|
||||
}
|
||||
|
||||
static inline IData VL_LTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
|
||||
static inline IData VL_LTS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
|
||||
return lhs_signed < rhs_signed;
|
||||
}
|
||||
static inline IData VL_LTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
|
||||
static inline IData VL_LTS_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed < rhs_signed;
|
||||
}
|
||||
|
||||
static inline IData VL_LTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
|
||||
static inline IData VL_LTES_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
|
||||
return lhs_signed <= rhs_signed;
|
||||
}
|
||||
static inline IData VL_LTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
|
||||
static inline IData VL_LTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed <= rhs_signed;
|
||||
|
|
@ -943,7 +942,7 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp
|
|||
static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE {
|
||||
EData carry = 1;
|
||||
for (int i = 0; i < words; ++i) {
|
||||
EData word = ~owp_lwp[i] + carry;
|
||||
const EData word = ~owp_lwp[i] + carry;
|
||||
carry = (word < ~owp_lwp[i]);
|
||||
owp_lwp[i] = word;
|
||||
}
|
||||
|
|
@ -1002,18 +1001,18 @@ static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP const lwp,
|
|||
return owp;
|
||||
}
|
||||
|
||||
static inline IData VL_MULS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
|
||||
static inline IData VL_MULS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
const vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
|
||||
const vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
|
||||
return lhs_signed * rhs_signed;
|
||||
}
|
||||
static inline QData VL_MULS_QQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
|
||||
static inline QData VL_MULS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed * rhs_signed;
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP const lwp,
|
||||
static inline WDataOutP VL_MULS_WWW(int lbits, WDataOutP owp, WDataInP const lwp,
|
||||
WDataInP const rwp) VL_MT_SAFE {
|
||||
const int words = VL_WORDS_I(lbits);
|
||||
// cppcheck-suppress variableScope
|
||||
|
|
@ -1022,13 +1021,13 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
|
|||
WData rwstore[VL_MULS_MAX_WORDS];
|
||||
WDataInP lwusp = lwp;
|
||||
WDataInP rwusp = rwp;
|
||||
EData lneg = VL_SIGN_E(lbits, lwp[words - 1]);
|
||||
const EData lneg = VL_SIGN_E(lbits, lwp[words - 1]);
|
||||
if (lneg) { // Negate lhs
|
||||
lwusp = lwstore;
|
||||
VL_NEGATE_W(words, lwstore, lwp);
|
||||
lwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
|
||||
}
|
||||
EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
|
||||
const EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
|
||||
if (rneg) { // Negate rhs
|
||||
rwusp = rwstore;
|
||||
VL_NEGATE_W(words, rwstore, rwp);
|
||||
|
|
@ -1221,31 +1220,27 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp, boo
|
|||
|
||||
// INTERNAL: Stuff LHS bit 0++ into OUTPUT at specified offset
|
||||
// ld may be "dirty", output is clean
|
||||
static inline void _vl_insert_II(int, CData& lhsr, IData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
static inline void _vl_insert_II(CData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
|
||||
const IData cleanmask = VL_MASK_I(rbits);
|
||||
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _vl_insert_II(int, SData& lhsr, IData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
static inline void _vl_insert_II(SData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
|
||||
const IData cleanmask = VL_MASK_I(rbits);
|
||||
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _vl_insert_II(int, IData& lhsr, IData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
static inline void _vl_insert_II(IData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
|
||||
const IData cleanmask = VL_MASK_I(rbits);
|
||||
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _vl_insert_QQ(int, QData& lhsr, QData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
static inline void _vl_insert_QQ(QData& lhsr, QData ld, int hbit, int lbit, int rbits) VL_PURE {
|
||||
const QData cleanmask = VL_MASK_Q(rbits);
|
||||
const QData insmask = (VL_MASK_Q(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _vl_insert_WI(int, WDataOutP owp, IData ld, int hbit, int lbit,
|
||||
static inline void _vl_insert_WI(WDataOutP owp, IData ld, int hbit, int lbit,
|
||||
int rbits = 0) VL_MT_SAFE {
|
||||
const int hoffset = VL_BITBIT_E(hbit);
|
||||
const int loffset = VL_BITBIT_E(lbit);
|
||||
|
|
@ -1278,7 +1273,7 @@ static inline void _vl_insert_WI(int, WDataOutP owp, IData ld, int hbit, int lbi
|
|||
|
||||
// INTERNAL: Stuff large LHS bit 0++ into OUTPUT at specified offset
|
||||
// lwp may be "dirty"
|
||||
static inline void _vl_insert_WW(int, WDataOutP owp, WDataInP const lwp, int hbit, int lbit,
|
||||
static inline void _vl_insert_WW(WDataOutP owp, WDataInP const lwp, int hbit, int lbit,
|
||||
int rbits = 0) VL_MT_SAFE {
|
||||
const int hoffset = VL_BITBIT_E(hbit);
|
||||
const int loffset = VL_BITBIT_E(lbit);
|
||||
|
|
@ -1334,19 +1329,19 @@ static inline void _vl_insert_WW(int, WDataOutP owp, WDataInP const lwp, int hbi
|
|||
}
|
||||
}
|
||||
|
||||
static inline void _vl_insert_WQ(int obits, WDataOutP owp, QData ld, int hbit, int lbit,
|
||||
static inline void _vl_insert_WQ(WDataOutP owp, QData ld, int hbit, int lbit,
|
||||
int rbits = 0) VL_MT_SAFE {
|
||||
VlWide<VL_WQ_WORDS_E> lwp;
|
||||
VL_SET_WQ(lwp, ld);
|
||||
_vl_insert_WW(obits, owp, lwp, hbit, lbit, rbits);
|
||||
_vl_insert_WW(owp, lwp, hbit, lbit, rbits);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_REPLICATE: oclean=clean>width32, dirty<=width32; lclean=clean; rclean==clean;
|
||||
// RHS MUST BE CLEAN CONSTANT.
|
||||
#define VL_REPLICATE_IOI(obits, lbits, rbits, ld, rep) (-(ld)) // Iff lbits==1
|
||||
#define VL_REPLICATE_QOI(obits, lbits, rbits, ld, rep) (-(static_cast<QData>(ld))) // Iff lbits==1
|
||||
#define VL_REPLICATE_IOI(lbits, ld, rep) (-(ld)) // Iff lbits==1
|
||||
#define VL_REPLICATE_QOI(lbits, ld, rep) (-(static_cast<QData>(ld))) // Iff lbits==1
|
||||
|
||||
static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) VL_PURE {
|
||||
static inline IData VL_REPLICATE_III(int lbits, IData ld, IData rep) VL_PURE {
|
||||
IData returndata = ld;
|
||||
for (unsigned i = 1; i < rep; ++i) {
|
||||
returndata = returndata << lbits;
|
||||
|
|
@ -1354,7 +1349,7 @@ static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) V
|
|||
}
|
||||
return returndata;
|
||||
}
|
||||
static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) VL_PURE {
|
||||
static inline QData VL_REPLICATE_QII(int lbits, IData ld, IData rep) VL_PURE {
|
||||
QData returndata = ld;
|
||||
for (unsigned i = 1; i < rep; ++i) {
|
||||
returndata = returndata << lbits;
|
||||
|
|
@ -1362,27 +1357,27 @@ static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) V
|
|||
}
|
||||
return returndata;
|
||||
}
|
||||
static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld,
|
||||
static inline WDataOutP VL_REPLICATE_WII(int lbits, WDataOutP owp, IData ld,
|
||||
IData rep) VL_MT_SAFE {
|
||||
owp[0] = ld;
|
||||
for (unsigned i = 1; i < rep; ++i) {
|
||||
_vl_insert_WI(obits, owp, ld, i * lbits + lbits - 1, i * lbits);
|
||||
_vl_insert_WI(owp, ld, i * lbits + lbits - 1, i * lbits);
|
||||
}
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld,
|
||||
static inline WDataOutP VL_REPLICATE_WQI(int lbits, WDataOutP owp, QData ld,
|
||||
IData rep) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp, ld);
|
||||
for (unsigned i = 1; i < rep; ++i) {
|
||||
_vl_insert_WQ(obits, owp, ld, i * lbits + lbits - 1, i * lbits);
|
||||
_vl_insert_WQ(owp, ld, i * lbits + lbits - 1, i * lbits);
|
||||
}
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp,
|
||||
WDataInP const lwp, IData rep) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_REPLICATE_WWI(int lbits, WDataOutP owp, WDataInP const lwp,
|
||||
IData rep) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i];
|
||||
for (unsigned i = 1; i < rep; ++i) {
|
||||
_vl_insert_WW(obits, owp, lwp, i * lbits + lbits - 1, i * lbits);
|
||||
_vl_insert_WW(owp, lwp, i * lbits + lbits - 1, i * lbits);
|
||||
}
|
||||
return owp;
|
||||
}
|
||||
|
|
@ -1391,7 +1386,7 @@ static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP ow
|
|||
// Special "fast" versions for slice sizes that are a power of 2. These use
|
||||
// shifts and masks to execute faster than the slower for-loop approach where a
|
||||
// subset of bits is copied in during each iteration.
|
||||
static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_log2) VL_PURE {
|
||||
static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_PURE {
|
||||
// Pre-shift bits in most-significant slice:
|
||||
//
|
||||
// If lbits is not a multiple of the slice size (i.e., lbits % rd != 0),
|
||||
|
|
@ -1429,7 +1424,7 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_
|
|||
return ret >> (VL_IDATASIZE - lbits);
|
||||
}
|
||||
|
||||
static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_log2) VL_PURE {
|
||||
static inline QData VL_STREAML_FAST_QQI(int lbits, QData ld, IData rd_log2) VL_PURE {
|
||||
// Pre-shift bits in most-significant slice (see comment in VL_STREAML_FAST_III)
|
||||
QData ret = ld;
|
||||
if (rd_log2) {
|
||||
|
|
@ -1461,7 +1456,7 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
|
|||
}
|
||||
|
||||
// Regular "slow" streaming operators
|
||||
static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_PURE {
|
||||
static inline IData VL_STREAML_III(int lbits, IData ld, IData rd) VL_PURE {
|
||||
IData ret = 0;
|
||||
// Slice size should never exceed the lhs width
|
||||
const IData mask = VL_MASK_I(rd);
|
||||
|
|
@ -1473,7 +1468,7 @@ static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_P
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_PURE {
|
||||
static inline QData VL_STREAML_QQI(int lbits, QData ld, IData rd) VL_PURE {
|
||||
QData ret = 0;
|
||||
// Slice size should never exceed the lhs width
|
||||
const QData mask = VL_MASK_Q(rd);
|
||||
|
|
@ -1485,7 +1480,7 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_P
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP const lwp,
|
||||
static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const lwp,
|
||||
IData rd) VL_MT_SAFE {
|
||||
VL_ZERO_W(lbits, owp);
|
||||
// Slice size should never exceed the lhs width
|
||||
|
|
@ -1496,7 +1491,8 @@ static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WData
|
|||
for (int sbit = 0; sbit < ssize && sbit < lbits - istart; ++sbit) {
|
||||
// Extract a single bit from lwp and shift it to the correct
|
||||
// location for owp.
|
||||
EData bit = (VL_BITRSHIFT_W(lwp, (istart + sbit)) & 1) << VL_BITBIT_E(ostart + sbit);
|
||||
const EData bit = (VL_BITRSHIFT_W(lwp, (istart + sbit)) & 1)
|
||||
<< VL_BITBIT_E(ostart + sbit);
|
||||
owp[VL_BITWORD_E(ostart + sbit)] |= bit;
|
||||
}
|
||||
}
|
||||
|
|
@ -1522,63 +1518,63 @@ static inline WDataOutP VL_CONCAT_WII(int obits, int lbits, int rbits, WDataOutP
|
|||
IData rd) VL_MT_SAFE {
|
||||
owp[0] = rd;
|
||||
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WWI(int obits, int lbits, int rbits, WDataOutP owp,
|
||||
WDataInP const lwp, IData rd) VL_MT_SAFE {
|
||||
owp[0] = rd;
|
||||
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WIW(int obits, int lbits, int rbits, WDataOutP owp, IData ld,
|
||||
WDataInP const rwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
|
||||
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WIQ(int obits, int lbits, int rbits, WDataOutP owp, IData ld,
|
||||
QData rd) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp, rd);
|
||||
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WQI(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
|
||||
IData rd) VL_MT_SAFE {
|
||||
owp[0] = rd;
|
||||
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WQQ(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
|
||||
QData rd) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp, rd);
|
||||
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WWQ(int obits, int lbits, int rbits, WDataOutP owp,
|
||||
WDataInP const lwp, QData rd) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp, rd);
|
||||
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WQW(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
|
||||
WDataInP const rwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
|
||||
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WWW(int obits, int lbits, int rbits, WDataOutP owp,
|
||||
WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
|
||||
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
|
||||
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
|
|
@ -1613,7 +1609,7 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits, int, int, WDataOutP owp, WDataI
|
|||
for (int i = word_shift; i < VL_WORDS_I(obits); ++i) owp[i] = lwp[i - word_shift];
|
||||
} else {
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_vl_insert_WW(obits, owp, lwp, obits - 1, rd);
|
||||
_vl_insert_WW(owp, lwp, obits - 1, rd);
|
||||
}
|
||||
return owp;
|
||||
}
|
||||
|
|
@ -1766,7 +1762,8 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits, int lbits, int, WDataOutP owp,
|
|||
owp[lmsw] &= VL_MASK_E(lbits);
|
||||
} else {
|
||||
const int loffset = rd & VL_SIZEBITS_E;
|
||||
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
|
||||
const int nbitsonright
|
||||
= VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
|
||||
// Middle words
|
||||
const int words = VL_WORDS_I(obits - rd);
|
||||
for (int i = 0; i < words; ++i) {
|
||||
|
|
@ -1835,14 +1832,13 @@ static inline QData VL_SHIFTRS_QQQ(int obits, int lbits, int rbits, QData lhs, Q
|
|||
// Bit selection
|
||||
|
||||
// EMIT_RULE: VL_BITSEL: oclean=dirty; rclean==clean;
|
||||
#define VL_BITSEL_IIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
|
||||
#define VL_BITSEL_QIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
|
||||
#define VL_BITSEL_QQII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
|
||||
#define VL_BITSEL_IQII(obits, lbits, rbits, zbits, lhs, rhs) (static_cast<IData>((lhs) >> (rhs)))
|
||||
#define VL_BITSEL_IIII(lbits, lhs, rhs) ((lhs) >> (rhs))
|
||||
#define VL_BITSEL_QIII(lbits, lhs, rhs) ((lhs) >> (rhs))
|
||||
#define VL_BITSEL_QQII(lbits, lhs, rhs) ((lhs) >> (rhs))
|
||||
#define VL_BITSEL_IQII(lbits, lhs, rhs) (static_cast<IData>((lhs) >> (rhs)))
|
||||
|
||||
static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP const lwp,
|
||||
IData rd) VL_MT_SAFE {
|
||||
int word = VL_BITWORD_E(rd);
|
||||
static inline IData VL_BITSEL_IWII(int lbits, WDataInP const lwp, IData rd) VL_MT_SAFE {
|
||||
const int word = VL_BITWORD_E(rd);
|
||||
if (VL_UNLIKELY(rd > static_cast<IData>(lbits))) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
// We return all 1's as that's more likely to find bugs (?) than 0's.
|
||||
|
|
@ -1853,27 +1849,24 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP const lwp,
|
|||
|
||||
// EMIT_RULE: VL_RANGE: oclean=lclean; out=dirty
|
||||
// <msb> & <lsb> MUST BE CLEAN (currently constant)
|
||||
#define VL_SEL_IIII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb))
|
||||
#define VL_SEL_QQII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb))
|
||||
#define VL_SEL_IQII(obits, lbits, rbits, tbits, lhs, lsb, width) \
|
||||
(static_cast<IData>((lhs) >> (lsb)))
|
||||
#define VL_SEL_IIII(lbits, lhs, lsb, width) ((lhs) >> (lsb))
|
||||
#define VL_SEL_QQII(lbits, lhs, lsb, width) ((lhs) >> (lsb))
|
||||
#define VL_SEL_IQII(lbits, lhs, lsb, width) (static_cast<IData>((lhs) >> (lsb)))
|
||||
|
||||
static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP const lwp, IData lsb,
|
||||
IData width) VL_MT_SAFE {
|
||||
int msb = lsb + width - 1;
|
||||
static inline IData VL_SEL_IWII(int lbits, WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
const int msb = lsb + width - 1;
|
||||
if (VL_UNLIKELY(msb >= lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
} else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast<int>(lsb))) {
|
||||
return VL_BITRSHIFT_W(lwp, lsb);
|
||||
} else {
|
||||
// 32 bit extraction may span two words
|
||||
int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word
|
||||
const int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word
|
||||
return ((lwp[VL_BITWORD_E(msb)] << nbitsfromlow) | VL_BITRSHIFT_W(lwp, lsb));
|
||||
}
|
||||
}
|
||||
|
||||
static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, IData lsb,
|
||||
IData width) VL_MT_SAFE {
|
||||
static inline QData VL_SEL_QWII(int lbits, WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
const int msb = lsb + width - 1;
|
||||
if (VL_UNLIKELY(msb > lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
|
|
@ -1886,7 +1879,7 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, ID
|
|||
return (hi << nbitsfromlow) | lo;
|
||||
} else {
|
||||
// 64 bit extraction may span three words
|
||||
int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb);
|
||||
const int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb);
|
||||
const QData hi = (lwp[VL_BITWORD_E(msb)]);
|
||||
const QData mid = (lwp[VL_BITWORD_E(lsb) + 1]);
|
||||
const QData lo = VL_BITRSHIFT_W(lwp, lsb);
|
||||
|
|
@ -1894,8 +1887,8 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, ID
|
|||
}
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP owp,
|
||||
WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataInP const lwp,
|
||||
IData lsb, IData width) VL_MT_SAFE {
|
||||
const int msb = lsb + width - 1;
|
||||
const int word_shift = VL_BITWORD_E(lsb);
|
||||
if (VL_UNLIKELY(msb > lbits)) { // Outside bounds,
|
||||
|
|
@ -1927,7 +1920,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP ow
|
|||
|
||||
// Return QData from double (numeric)
|
||||
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
|
||||
static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
|
||||
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
|
||||
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
|
||||
// This does not need to support subnormals as they are sub-integral
|
||||
lhs = VL_ROUND(lhs);
|
||||
|
|
@ -1944,8 +1937,8 @@ static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
|
|||
if (lhs < 0) out = -out;
|
||||
return out;
|
||||
}
|
||||
static inline IData VL_RTOIROUND_I_D(int bits, double lhs) VL_PURE {
|
||||
return static_cast<IData>(VL_RTOIROUND_Q_D(bits, lhs));
|
||||
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE {
|
||||
return static_cast<IData>(VL_RTOIROUND_Q_D(lhs));
|
||||
}
|
||||
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_PURE {
|
||||
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
|
||||
|
|
@ -1959,7 +1952,7 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
|
|||
if (lsb < 0) {
|
||||
VL_SET_WQ(owp, mantissa >> -lsb);
|
||||
} else if (lsb < obits) {
|
||||
_vl_insert_WQ(obits, owp, mantissa, lsb + 52, lsb);
|
||||
_vl_insert_WQ(owp, mantissa, lsb + 52, lsb);
|
||||
}
|
||||
if (lhs < 0) VL_NEGATE_INPLACE_W(VL_WORDS_I(obits), owp);
|
||||
return owp;
|
||||
|
|
@ -1971,48 +1964,48 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
|
|||
// EMIT_RULE: VL_ASSIGNRANGE: rclean=dirty;
|
||||
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, CData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, SData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, IData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_QIII(int rbits, int obits, int lsb, QData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_QQII(int rbits, int obits, int lsb, QData& lhsr,
|
||||
QData rhs) VL_PURE {
|
||||
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_QIIQ(int rbits, int obits, int lsb, QData& lhsr,
|
||||
QData rhs) VL_PURE {
|
||||
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
// static inline void VL_ASSIGNSEL_IIIW(int obits, int lsb, IData& lhsr, WDataInP const rwp)
|
||||
// VL_MT_SAFE { Illegal, as lhs width >= rhs width
|
||||
static inline void VL_ASSIGNSEL_WIII(int rbits, int obits, int lsb, WDataOutP owp,
|
||||
IData rhs) VL_MT_SAFE {
|
||||
_vl_insert_WI(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_WI(owp, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_WIIQ(int rbits, int obits, int lsb, WDataOutP owp,
|
||||
QData rhs) VL_MT_SAFE {
|
||||
_vl_insert_WQ(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_WQ(owp, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_WIIW(int rbits, int obits, int lsb, WDataOutP owp,
|
||||
WDataInP const rwp) VL_MT_SAFE {
|
||||
_vl_insert_WW(obits, owp, rwp, lsb + obits - 1, lsb, rbits);
|
||||
_vl_insert_WW(owp, rwp, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Triops
|
||||
|
||||
static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, WDataOutP owp, int cond,
|
||||
WDataInP const w1p, WDataInP const w2p) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_COND_WIWW(int obits, WDataOutP owp, int cond, WDataInP const w1p,
|
||||
WDataInP const w2p) VL_MT_SAFE {
|
||||
const int words = VL_WORDS_I(obits);
|
||||
for (int i = 0; i < words; ++i) owp[i] = cond ? w1p[i] : w2p[i];
|
||||
return owp;
|
||||
|
|
@ -2187,15 +2180,14 @@ inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
|
|||
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
|
||||
return lhs + rhs;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNQ(int, int, int, const std::string& lhs, IData rep) VL_PURE {
|
||||
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;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNI(int obits, int lbits, int rbits, const std::string& lhs,
|
||||
IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(obits, lbits, rbits, lhs, rep);
|
||||
inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(lhs, rep);
|
||||
}
|
||||
|
||||
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
||||
|
|
@ -2220,31 +2212,31 @@ extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suff
|
|||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE {
|
||||
VlWide<2> rwp;
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
if (got) rdr = rwp[0];
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, SData& rdr) VL_MT_SAFE {
|
||||
VlWide<2> rwp;
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
if (got) rdr = rwp[0];
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
|
||||
VlWide<2> rwp;
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
if (got) rdr = rwp[0];
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) VL_MT_SAFE {
|
||||
VlWide<2> rwp;
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
if (got) rdr = VL_SET_QW(rwp);
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, double& rdr) VL_MT_SAFE {
|
||||
VlWide<2> rwp;
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
|
||||
if (got) rdr = VL_CVT_D_Q(VL_SET_QW(rwp));
|
||||
return got;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ public: // But only for verilated*.cpp
|
|||
IData fdNewMcd(const char* filenamep) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
|
||||
const VerilatedLockGuard lock{m_fdMutex};
|
||||
if (m_fdFreeMct.empty()) return 0;
|
||||
IData idx = m_fdFreeMct.back();
|
||||
const IData idx = m_fdFreeMct.back();
|
||||
m_fdFreeMct.pop_back();
|
||||
m_fdps[idx] = std::fopen(filenamep, "w");
|
||||
if (VL_UNLIKELY(!m_fdps[idx])) return 0;
|
||||
|
|
@ -299,7 +299,7 @@ public: // But only for verilated*.cpp
|
|||
m_fdFree[i] = id;
|
||||
}
|
||||
}
|
||||
IData idx = m_fdFree.back();
|
||||
const IData idx = m_fdFree.back();
|
||||
m_fdFree.pop_back();
|
||||
m_fdps[idx] = fp;
|
||||
return (idx | (1UL << 31)); // bit 31 indicates not MCD
|
||||
|
|
@ -334,7 +334,7 @@ public: // But only for verilated*.cpp
|
|||
const VerilatedLockGuard lock{m_fdMutex};
|
||||
if (VL_BITISSET_I(fdi, 31)) {
|
||||
// Non-MCD case
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
const IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(idx >= m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr
|
||||
if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
// Profile record, private class used only by this header
|
||||
class VerilatedProfilerRec final {
|
||||
std::string m_name; // Hashed name of mtask/etc
|
||||
size_t m_counterNumber = 0; // Which counter has data
|
||||
const std::string m_name; // Hashed name of mtask/etc
|
||||
const size_t m_counterNumber = 0; // Which counter has data
|
||||
public:
|
||||
// METHODS
|
||||
VerilatedProfilerRec(size_t counterNumber, const std::string& name)
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
|
|||
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
vluint8_t* wp = m_bufp;
|
||||
const vluint8_t* wp = m_bufp;
|
||||
while (true) {
|
||||
const ssize_t remaining = (m_cp - wp);
|
||||
if (remaining == 0) break;
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
|
|||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, const std::string& rhs) {
|
||||
vluint32_t len = rhs.length();
|
||||
const vluint32_t len = rhs.length();
|
||||
os << len;
|
||||
return os.write(rhs.data(), len);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,8 +192,8 @@ public:
|
|||
|
||||
class VerilatedDpiOpenVar final {
|
||||
// MEMBERS
|
||||
const VerilatedVarProps* m_propsp; // Variable properties
|
||||
void* m_datap; // Location of data (local to thread always, so safe)
|
||||
const VerilatedVarProps* const m_propsp; // Variable properties
|
||||
void* const m_datap; // Location of data (local to thread always, so safe)
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
|
||||
|
|
@ -230,10 +230,10 @@ public:
|
|||
|
||||
class VerilatedVar final : public VerilatedVarProps {
|
||||
// MEMBERS
|
||||
void* m_datap; // Location of data
|
||||
const char* m_namep; // Name - slowpath
|
||||
void* const m_datap; // Location of data
|
||||
const char* const m_namep; // Name - slowpath
|
||||
protected:
|
||||
bool m_isParam;
|
||||
const bool m_isParam;
|
||||
friend class VerilatedScope;
|
||||
// CONSTRUCTORS
|
||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||
|
|
|
|||
|
|
@ -217,12 +217,12 @@ private:
|
|||
// Store the size atomically, so we can spin wait
|
||||
std::atomic<size_t> m_ready_size;
|
||||
|
||||
VlThreadPool* m_poolp; // Our associated thread pool
|
||||
VlThreadPool* const m_poolp; // Our associated thread pool
|
||||
|
||||
bool m_profiling; // Is profiling enabled?
|
||||
const bool m_profiling; // Is profiling enabled?
|
||||
std::atomic<bool> m_exiting; // Worker thread should exit
|
||||
std::thread m_cthread; // Underlying C++ thread record
|
||||
VerilatedContext* m_contextp; // Context for spawned thread
|
||||
VerilatedContext* const m_contextp; // Context for spawned thread
|
||||
|
||||
VL_UNCOPYABLE(VlWorkerThread);
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ class VlThreadPool final {
|
|||
|
||||
// MEMBERS
|
||||
std::vector<VlWorkerThread*> m_workers; // our workers
|
||||
bool m_profiling; // is profiling enabled?
|
||||
const bool m_profiling; // is profiling enabled?
|
||||
|
||||
// Support profiling -- we can append records of profiling events
|
||||
// to this vector with very low overhead, and then dump them out
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flushBase() {
|
|||
// Callbacks to run on global events
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
|
||||
// This calls 'flush' on the derived classo (which must then get any mutex)
|
||||
// This calls 'flush' on the derived class (which must then get any mutex)
|
||||
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,10 +79,10 @@ public:
|
|||
// Readmem/Writemem operation classes
|
||||
|
||||
class VlReadMem final {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
const bool m_hex; // Hex format
|
||||
const int m_bits; // Bit width of values
|
||||
const std::string& m_filename; // Filename
|
||||
QData m_end; // End address (as specified by user)
|
||||
const QData m_end; // End address (as specified by user)
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to read
|
||||
int m_linenum; // Line number last read from file
|
||||
|
|
@ -96,8 +96,8 @@ public:
|
|||
};
|
||||
|
||||
class VlWriteMem final {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
const bool m_hex; // Hex format
|
||||
const int m_bits; // Bit width of values
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to write
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
|
|||
// minsize is size of largest write. We buffer at least 8 times as much data,
|
||||
// writing when we are 3/4 full (with thus 2*minsize remaining free)
|
||||
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
|
||||
char* oldbufp = m_wrBufp;
|
||||
const char* oldbufp = m_wrBufp;
|
||||
m_wrChunkSize = minsize * 2;
|
||||
m_wrBufp = new char[m_wrChunkSize * 8];
|
||||
std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
|
||||
|
|
@ -298,7 +298,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
|
|||
// When it gets nearly full we dump it using this routine which calls write()
|
||||
// This is much faster than using buffered I/O
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
char* wp = m_wrBufp;
|
||||
const char* wp = m_wrBufp;
|
||||
while (true) {
|
||||
const ssize_t remaining = (m_writep - wp);
|
||||
if (remaining == 0) break;
|
||||
|
|
@ -311,7 +311,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
|
|||
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
|
||||
// LCOV_EXCL_START
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg
|
||||
const std::string msg
|
||||
= std::string{"VerilatedVcd::bufferFlush: "} + std::strerror(errno);
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
closeErr();
|
||||
|
|
@ -386,7 +386,7 @@ void VerilatedVcd::dumpHeader() {
|
|||
const std::string& decl = i.second;
|
||||
|
||||
// Determine difference between the old and new names
|
||||
const char* hiername = hiernamestr.c_str();
|
||||
const char* const hiername = hiernamestr.c_str();
|
||||
const char* lp = lastName;
|
||||
const char* np = hiername;
|
||||
lastName = hiername;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ private:
|
|||
int m_modDepth = 0; // Depth of module hierarchy
|
||||
|
||||
char* m_wrBufp; // Output buffer
|
||||
char* m_wrFlushp; // Output buffer flush trigger location
|
||||
const char* m_wrFlushp; // Output buffer flush trigger location
|
||||
char* m_writep; // Write pointer into output buffer
|
||||
vluint64_t m_wrChunkSize; // Output buffer size
|
||||
vluint64_t m_wroteBytes = 0; // Number of bytes written to this file
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ public:
|
|||
class VerilatedVpioTimedCb final : public VerilatedVpio {
|
||||
// A handle to a timed callback created with vpi_register_cb
|
||||
// User can call vpi_remove_cb or vpi_release_handle on it
|
||||
vluint64_t m_id; // Unique id/sequence number to find schedule's event
|
||||
QData m_time;
|
||||
const vluint64_t m_id; // Unique id/sequence number to find schedule's event
|
||||
const QData m_time;
|
||||
|
||||
public:
|
||||
VerilatedVpioTimedCb(vluint64_t id, QData time)
|
||||
|
|
@ -141,8 +141,8 @@ public:
|
|||
class VerilatedVpioReasonCb final : public VerilatedVpio {
|
||||
// A handle to a non-timed callback created with vpi_register_cb
|
||||
// User can call vpi_remove_cb or vpi_release_handle on it
|
||||
vluint64_t m_id; // Unique id/sequence number to find schedule's event
|
||||
PLI_INT32 m_reason; // VPI callback reason code
|
||||
const vluint64_t m_id; // Unique id/sequence number to find schedule's event
|
||||
const PLI_INT32 m_reason; // VPI callback reason code
|
||||
|
||||
public:
|
||||
// cppcheck-suppress uninitVar // m_value
|
||||
|
|
@ -158,7 +158,7 @@ public:
|
|||
};
|
||||
|
||||
class VerilatedVpioConst final : public VerilatedVpio {
|
||||
vlsint32_t m_num;
|
||||
const vlsint32_t m_num;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioConst(vlsint32_t num)
|
||||
|
|
@ -219,7 +219,7 @@ public:
|
|||
};
|
||||
|
||||
class VerilatedVpioRange final : public VerilatedVpio {
|
||||
const VerilatedRange* m_range;
|
||||
const VerilatedRange* const m_range;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioRange(const VerilatedRange* range)
|
||||
|
|
@ -235,7 +235,7 @@ public:
|
|||
|
||||
class VerilatedVpioRangeIter final : public VerilatedVpio {
|
||||
// Only supports 1 dimension
|
||||
const VerilatedRange* m_range;
|
||||
const VerilatedRange* const m_range;
|
||||
bool m_done = false;
|
||||
|
||||
public:
|
||||
|
|
@ -258,7 +258,7 @@ public:
|
|||
|
||||
class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio {
|
||||
protected:
|
||||
const VerilatedScope* m_scopep;
|
||||
const VerilatedScope* const m_scopep;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioScope(const VerilatedScope* scopep)
|
||||
|
|
@ -352,7 +352,7 @@ public:
|
|||
};
|
||||
|
||||
class VerilatedVpioVarIter final : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
const VerilatedScope* const m_scopep;
|
||||
VerilatedVarNameMap::const_iterator m_it;
|
||||
bool m_started = false;
|
||||
|
||||
|
|
@ -389,9 +389,9 @@ public:
|
|||
|
||||
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
|
||||
const vpiHandle m_handle;
|
||||
const VerilatedVar* m_varp;
|
||||
const VerilatedVar* const m_varp;
|
||||
vlsint32_t m_iteration;
|
||||
vlsint32_t m_direction;
|
||||
const vlsint32_t m_direction;
|
||||
bool m_done = false;
|
||||
|
||||
public:
|
||||
|
|
@ -413,7 +413,7 @@ public:
|
|||
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
||||
return nullptr;
|
||||
}
|
||||
vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
|
||||
const vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
|
||||
iterationInc();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -457,7 +457,7 @@ public:
|
|||
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
||||
return nullptr;
|
||||
}
|
||||
const VerilatedScope* modp = *m_it++;
|
||||
const VerilatedScope* const modp = *m_it++;
|
||||
return (new VerilatedVpioModule{modp})->castVpiHandle();
|
||||
}
|
||||
};
|
||||
|
|
@ -595,7 +595,7 @@ public:
|
|||
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
||||
for (auto it = cbObjList.begin(); true;) {
|
||||
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
|
||||
bool was_last = it == last;
|
||||
const bool was_last = it == last;
|
||||
if (VL_UNLIKELY(it->invalid())) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
if (was_last) break;
|
||||
|
|
@ -1111,7 +1111,7 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
|
|||
|
||||
#define SELF_CHECK_RESULT_CSTR(got, exp) \
|
||||
if (0 != std::strcmp((got), (exp))) { \
|
||||
std::string msg \
|
||||
const std::string msg \
|
||||
= std::string{"%Error: "} + "GOT = '" + (got) + "'" + " EXP = '" + (exp) + "'"; \
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
|
||||
}
|
||||
|
|
@ -1305,7 +1305,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
|||
QData time = 0;
|
||||
if (cb_data_p->time) time = VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
|
||||
const QData abstime = VL_TIME_Q() + time;
|
||||
vluint64_t id = VerilatedVpiImp::nextCallbackId();
|
||||
const vluint64_t id = VerilatedVpiImp::nextCallbackId();
|
||||
VerilatedVpioTimedCb* const vop = new VerilatedVpioTimedCb{id, abstime};
|
||||
VerilatedVpiImp::cbTimedAdd(id, cb_data_p, abstime);
|
||||
return vop->castVpiHandle();
|
||||
|
|
@ -1410,7 +1410,7 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
|||
VerilatedVpiImp::assertOneCheck();
|
||||
VL_VPI_ERROR_RESET_();
|
||||
// Memory words are not indexable
|
||||
VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
|
||||
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
|
||||
if (VL_UNLIKELY(vop)) return nullptr;
|
||||
const VerilatedVpioVar* const varop = VerilatedVpioVar::castp(object);
|
||||
if (VL_LIKELY(varop)) {
|
||||
|
|
@ -1442,10 +1442,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||
VL_VPI_ERROR_RESET_();
|
||||
switch (type) {
|
||||
case vpiLeftRange: {
|
||||
if (VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
|
||||
if (const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
|
||||
} else if (VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
|
||||
} else if (const VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
|
||||
}
|
||||
|
|
@ -1455,10 +1455,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||
return nullptr;
|
||||
}
|
||||
case vpiRightRange: {
|
||||
if (VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
|
||||
if (const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
|
||||
} else if (VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
|
||||
} else if (const VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
|
||||
}
|
||||
|
|
@ -1468,18 +1468,18 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||
return nullptr;
|
||||
}
|
||||
case vpiIndex: {
|
||||
VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
const vlsint32_t val = vop->index();
|
||||
return (new VerilatedVpioConst{val})->castVpiHandle();
|
||||
}
|
||||
case vpiScope: {
|
||||
VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
|
||||
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return (new VerilatedVpioScope{vop->scopep()})->castVpiHandle();
|
||||
}
|
||||
case vpiParent: {
|
||||
VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
|
||||
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return (new VerilatedVpioVar{vop->varp(), vop->scopep()})->castVpiHandle();
|
||||
}
|
||||
|
|
@ -1697,7 +1697,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
// Maximum required size is for binary string, one byte per bit plus null termination
|
||||
static VL_THREAD_LOCAL char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
|
||||
// cppcheck-suppress variableScope
|
||||
static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
|
||||
const static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
|
||||
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||
// This may cause backward compatibility issues with older code.
|
||||
if (valuep->format == vpiVectorVal) {
|
||||
|
|
@ -1718,14 +1718,14 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
QData data = *(reinterpret_cast<QData*>(varDatap));
|
||||
const QData data = *(reinterpret_cast<QData*>(varDatap));
|
||||
t_out[1].aval = static_cast<IData>(data >> 32ULL);
|
||||
t_out[1].bval = 0;
|
||||
t_out[0].aval = static_cast<IData>(data);
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_WDATA) {
|
||||
int words = VL_WORDS_I(varp->packed().elements());
|
||||
const int words = VL_WORDS_I(varp->packed().elements());
|
||||
if (VL_UNCOVERABLE(words >= VL_VALUE_STRING_MAX_WORDS)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"vpi_get_value with more than VL_VALUE_STRING_MAX_WORDS; increase and "
|
||||
|
|
@ -1741,7 +1741,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
} else if (valuep->format == vpiBinStrVal) {
|
||||
valuep->value.str = t_outStr;
|
||||
int bits = varp->packed().elements();
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (bits > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
|
|
@ -1754,7 +1754,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
VL_VALUE_STRING_MAX_WORDS, bits);
|
||||
}
|
||||
for (i = 0; i < bits; ++i) {
|
||||
char val = (datap[i >> 3] >> (i & 7)) & 1;
|
||||
const char val = (datap[i >> 3] >> (i & 7)) & 1;
|
||||
t_outStr[bits - i - 1] = val ? '1' : '0';
|
||||
}
|
||||
t_outStr[i] = '\0';
|
||||
|
|
@ -1763,7 +1763,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
valuep->value.str = t_outStr;
|
||||
int chars = (varp->packed().elements() + 2) / 3;
|
||||
const int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (chars > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
|
|
@ -1788,7 +1788,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
if (i == (chars - 1)) {
|
||||
// most signifcant char, mask off non existant bits when vector
|
||||
// size is not a multiple of 3
|
||||
unsigned int rem = varp->packed().elements() % 3;
|
||||
const unsigned int rem = varp->packed().elements() % 3;
|
||||
if (rem) {
|
||||
// generate bit mask & zero non existant bits
|
||||
val &= (1 << rem) - 1;
|
||||
|
|
@ -1821,7 +1821,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
} else if (valuep->format == vpiHexStrVal) {
|
||||
valuep->value.str = t_outStr;
|
||||
int chars = (varp->packed().elements() + 3) >> 2;
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (chars > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
|
|
@ -1855,7 +1855,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
} else {
|
||||
valuep->value.str = t_outStr;
|
||||
int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (bytes > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
|
|
@ -1899,13 +1899,13 @@ void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
|
|||
VL_VPI_ERROR_RESET_();
|
||||
if (VL_UNLIKELY(!valuep)) return;
|
||||
|
||||
if (VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
|
||||
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
|
||||
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
|
||||
return;
|
||||
} else if (const VerilatedVpioParam* const vop = VerilatedVpioParam::castp(object)) {
|
||||
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
|
||||
return;
|
||||
} else if (VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
|
||||
} else if (const VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
|
||||
if (valuep->format == vpiIntVal) {
|
||||
valuep->value.integer = vop->num();
|
||||
return;
|
||||
|
|
@ -1970,9 +1970,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
} else if (valuep->format == vpiBinStrVal) {
|
||||
const int bits = vop->varp()->packed().elements();
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i = 0; i < bits; ++i) {
|
||||
char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
|
||||
const char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
|
||||
// zero bits 7:1 of byte when assigning to bit 0, else
|
||||
// or in 1 if bit set
|
||||
if (i & 7) {
|
||||
|
|
@ -1986,7 +1986,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
const int chars = (vop->varp()->packed().elements() + 2) / 3;
|
||||
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
div_t idx;
|
||||
datap[0] = 0; // reset zero'th byte
|
||||
for (int i = 0; i < chars; ++i) {
|
||||
|
|
@ -1997,7 +1997,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
idx = div(i * 3, 8);
|
||||
if (i < len) {
|
||||
// ignore illegal chars
|
||||
char digit = valuep->value.str[len - i - 1];
|
||||
const char digit = valuep->value.str[len - i - 1];
|
||||
if (digit >= '0' && digit <= '7') {
|
||||
val.half = digit - '0';
|
||||
} else {
|
||||
|
|
@ -2064,8 +2064,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
}
|
||||
} else if (valuep->format == vpiHexStrVal) {
|
||||
const int chars = (vop->varp()->packed().elements() + 3) >> 2;
|
||||
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
char* val = valuep->value.str;
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
const char* val = valuep->value.str;
|
||||
// skip hex ident if one is detected at the start of the string
|
||||
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2;
|
||||
const int len = std::strlen(val);
|
||||
|
|
@ -2073,7 +2073,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
char hex;
|
||||
// compute hex digit value
|
||||
if (i < len) {
|
||||
char digit = val[len - i - 1];
|
||||
const char digit = val[len - i - 1];
|
||||
if (digit >= '0' && digit <= '9') {
|
||||
hex = digit - '0';
|
||||
} else if (digit >= 'a' && digit <= 'f') {
|
||||
|
|
@ -2105,7 +2105,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
} else if (valuep->format == vpiStringVal) {
|
||||
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i = 0; i < bytes; ++i) {
|
||||
// prepend with 0 values before placing string the least significant bytes
|
||||
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
|
||||
|
|
@ -2167,7 +2167,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
|
|||
return;
|
||||
} else if (time_p->type == vpiScaledRealTime) {
|
||||
double dtime = VL_TIME_D();
|
||||
if (VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object)) {
|
||||
if (const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object)) {
|
||||
const int scalePow10
|
||||
= Verilated::threadContextp()->timeprecision() - vop->scopep()->timeunit();
|
||||
const double scale = vl_time_multiplier(scalePow10); // e.g. 0.0001
|
||||
|
|
@ -2287,7 +2287,7 @@ PLI_INT32 vpi_release_handle(vpiHandle object) {
|
|||
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) VL_MT_SAFE {
|
||||
VerilatedVpiImp::assertOneCheck();
|
||||
VL_VPI_ERROR_RESET_();
|
||||
auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();
|
||||
const auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();
|
||||
vlog_info_p->argc = argc_argv.first;
|
||||
vlog_info_p->argv = argc_argv.second;
|
||||
vlog_info_p->product = const_cast<PLI_BYTE8*>(Verilated::productName());
|
||||
|
|
|
|||
|
|
@ -333,7 +333,8 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
|||
# include <stdint.h> // Linux and most flavors
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
# include <unistd.h> // ssize_t
|
||||
typedef char vlsint8_t; ///< 8-bit signed type
|
||||
// Arm64 gcc 9.3.0 defaults to unsigned char, not signed char
|
||||
typedef signed char vlsint8_t; ///< 8-bit signed type
|
||||
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
|
||||
typedef short vlsint16_t; ///< 16-bit signed type
|
||||
typedef uint16_t vluint16_t; ///< 16-bit unsigned type
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ source_globs("include/*/*.c")
|
|||
# Note *'s are removed when using fastcov
|
||||
remove_source("/usr/*")
|
||||
remove_source("*/include/sysc/*")
|
||||
remove_source("*/V3ClkGater.cpp")
|
||||
remove_source("*/V3ClkGater.h")
|
||||
remove_source("*/V3GraphDfa.cpp")
|
||||
remove_source("*/V3GraphDfa.h")
|
||||
remove_source("*/V3Lexer_pregen.yy.cpp")
|
||||
remove_source("*/V3PreLex_pregen.yy.cpp")
|
||||
remove_source("*/verilog.c")
|
||||
|
|
|
|||
|
|
@ -203,7 +203,6 @@ RAW_OBJS = \
|
|||
V3Graph.o \
|
||||
V3GraphAlg.o \
|
||||
V3GraphAcyc.o \
|
||||
V3GraphDfa.o \
|
||||
V3GraphPathChecker.o \
|
||||
V3GraphTest.o \
|
||||
V3Hash.o \
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ public:
|
|||
enum VertexType : uint8_t { VT_BLOCK, VT_BRANCH, VT_OUTPUT };
|
||||
|
||||
private:
|
||||
string m_name; // Only used for .dot file generation
|
||||
VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
|
||||
const string m_name; // Only used for .dot file generation
|
||||
const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
|
||||
|
||||
string typestr() const { // "
|
||||
switch (m_type) {
|
||||
|
|
@ -108,9 +108,10 @@ protected:
|
|||
}
|
||||
break;
|
||||
case LatchDetectGraphVertex::VT_BRANCH: // (AND of both sibling)
|
||||
// A BRANCH vertex always has exactly 2 siblings
|
||||
LatchDetectGraphVertex* ifp = castVertexp(vertexp->outBeginp()->top());
|
||||
LatchDetectGraphVertex* elsp = castVertexp(vertexp->outBeginp()->outNextp()->top());
|
||||
// A BRANCH vertex always has exactly 2 siblings
|
||||
LatchDetectGraphVertex* const ifp = castVertexp(vertexp->outBeginp()->top());
|
||||
LatchDetectGraphVertex* const elsp
|
||||
= castVertexp(vertexp->outBeginp()->outNextp()->top());
|
||||
result = latchCheckInternal(ifp) && latchCheckInternal(elsp);
|
||||
break;
|
||||
}
|
||||
|
|
@ -151,7 +152,7 @@ public:
|
|||
// Add a new output variable vertex and store a pointer to it in the user1 field of the
|
||||
// variables AstNode
|
||||
LatchDetectGraphVertex* addOutputVertex(AstVarRef* nodep) {
|
||||
LatchDetectGraphVertex* outVertexp
|
||||
LatchDetectGraphVertex* const outVertexp
|
||||
= new LatchDetectGraphVertex{this, nodep->name(), LatchDetectGraphVertex::VT_OUTPUT};
|
||||
nodep->varp()->user1p(outVertexp);
|
||||
m_outputs.push_back(nodep);
|
||||
|
|
@ -172,7 +173,7 @@ public:
|
|||
void latchCheck(AstNode* nodep, bool latch_expected) {
|
||||
bool latch_detected = false;
|
||||
for (const auto& vrp : m_outputs) {
|
||||
LatchDetectGraphVertex* vertp = castVertexp(vrp->varp()->user1p());
|
||||
LatchDetectGraphVertex* const vertp = castVertexp(vrp->varp()->user1p());
|
||||
vertp->user(true); // Identify the output vertex we are checking paths _to_
|
||||
if (!latchCheckInternal(castVertexp(verticesBeginp()))) latch_detected = true;
|
||||
if (latch_detected && !latch_expected) {
|
||||
|
|
@ -262,7 +263,7 @@ public:
|
|||
// Return a sentree in this scope that matches given sense list.
|
||||
|
||||
AstActive* activep = nullptr;
|
||||
AstSenTree* activeSenp = m_activeSens.find(sensesp);
|
||||
AstSenTree* const activeSenp = m_activeSens.find(sensesp);
|
||||
if (activeSenp) {
|
||||
const auto it = m_activeMap.find(activeSenp);
|
||||
UASSERT(it != m_activeMap.end(), "Corrupt active map");
|
||||
|
|
@ -271,7 +272,7 @@ public:
|
|||
|
||||
// Not found, form a new one
|
||||
if (!activep) {
|
||||
AstSenTree* newsenp = sensesp->cloneTree(false);
|
||||
AstSenTree* const newsenp = sensesp->cloneTree(false);
|
||||
activep = new AstActive(fl, "sequent", newsenp);
|
||||
activep->sensesStorep(activep->sensesp());
|
||||
UINFO(8, " New ACTIVE " << activep << endl);
|
||||
|
|
@ -298,20 +299,20 @@ private:
|
|||
// NODE STATE
|
||||
// Input:
|
||||
// AstVar::user1p // V2LatchGraphVertex* The vertex handling this node
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
// STATE
|
||||
LatchDetectGraph m_graph; // Graph used to detect latches in combo always
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
AstVar* varp = nodep->varp();
|
||||
const AstVar* const varp = nodep->varp();
|
||||
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) {
|
||||
m_graph.addAssignment(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
if (!nodep->isBoundsCheck()) {
|
||||
LatchDetectGraphVertex* parentp = m_graph.currentp();
|
||||
LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
|
||||
LatchDetectGraphVertex* const parentp = m_graph.currentp();
|
||||
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
|
||||
m_graph.addPathVertex(branchp, "IF");
|
||||
iterateAndNextNull(nodep->ifsp());
|
||||
m_graph.addPathVertex(branchp, "ELSE");
|
||||
|
|
@ -340,9 +341,9 @@ public:
|
|||
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||
|
||||
private:
|
||||
CheckType m_check; // Combo logic or other
|
||||
AstNode* m_alwaysp; // Always we're under
|
||||
AstNode* m_assignp = nullptr; // In assign
|
||||
const CheckType m_check; // Combo logic or other
|
||||
const AstNode* const m_alwaysp; // Always we're under
|
||||
const AstNode* m_assignp = nullptr; // In assign
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignDly* nodep) override {
|
||||
if (m_check != CT_SEQ) {
|
||||
|
|
@ -355,7 +356,7 @@ private:
|
|||
} else if (m_check == CT_LATCH) {
|
||||
// Suppress. Shouldn't matter that the interior of the latch races
|
||||
} else if (!(VN_IS(nodep->lhsp(), VarRef)
|
||||
&& VN_CAST(nodep->lhsp(), VarRef)->varp()->isLatched())) {
|
||||
&& VN_AS(nodep->lhsp(), VarRef)->varp()->isLatched())) {
|
||||
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
|
||||
" (non flop or latch) block\n"
|
||||
<< nodep->warnMore()
|
||||
|
|
@ -363,8 +364,8 @@ private:
|
|||
// Conversely, we could also suggest latches use delayed assignments, as
|
||||
// recommended by Cliff Cummings?
|
||||
}
|
||||
AstNode* newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
AstNode* const newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
|
@ -377,7 +378,7 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
AstVar* varp = nodep->varp();
|
||||
const AstVar* const varp = nodep->varp();
|
||||
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
|
||||
&& !varp->isTemp()) {
|
||||
// Allow turning off warnings on the always, or the variable also
|
||||
|
|
@ -437,29 +438,29 @@ private:
|
|||
virtual void visit(AstInitial* nodep) override {
|
||||
// Relink to IACTIVE, unless already under it
|
||||
UINFO(4, " INITIAL " << nodep << endl);
|
||||
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
|
||||
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
|
||||
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
|
||||
AstActive* const wantactivep = m_namer.getIActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4, " COVERTOGGLE " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
|
|
@ -470,7 +471,7 @@ private:
|
|||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
|
||||
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
|
||||
if (!m_scopeFinalp) {
|
||||
m_scopeFinalp = new AstCFunc(
|
||||
nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep());
|
||||
|
|
@ -489,8 +490,7 @@ private:
|
|||
// METHODS
|
||||
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem)
|
||||
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
|
||||
if (oldsensesp && oldsensesp->sensesp() && oldsensesp->sensesp()->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
|
||||
"Never senitem should be alone, else the never should be eliminated.");
|
||||
|
|
@ -540,14 +540,14 @@ private:
|
|||
|
||||
// Warn and/or convert any delayed assignments
|
||||
if (combo && !sequent) {
|
||||
ActiveLatchCheckVisitor latchvisitor{nodep, kwd};
|
||||
const ActiveLatchCheckVisitor latchvisitor{nodep, kwd};
|
||||
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
||||
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_LATCH};
|
||||
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_LATCH};
|
||||
} else {
|
||||
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_COMBO};
|
||||
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_COMBO};
|
||||
}
|
||||
} else if (!combo && sequent) {
|
||||
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_SEQ};
|
||||
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_SEQ};
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
|
|
@ -578,7 +578,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
if (nodep->varrefp()) {
|
||||
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||
if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||
if (basicp->isEventValue()) {
|
||||
// Events need to be treated as active high so we only activate on event being
|
||||
// 1
|
||||
|
|
@ -620,6 +620,6 @@ public:
|
|||
|
||||
void V3Active::activeAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ActiveVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ ActiveVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,22 +42,15 @@ private:
|
|||
// AstNode::user() bool. True if processed
|
||||
// Each call to V3Const::constify
|
||||
// AstNode::user4() Used by V3Const::constify, called below
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstTopScope* m_topscopep = nullptr; // Top scope for adding sentrees under
|
||||
SenTreeFinder m_finder; // Find global sentree's and add them
|
||||
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
m_topscopep = nodep;
|
||||
m_finder.init(m_topscopep);
|
||||
iterateChildren(nodep);
|
||||
m_topscopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// Create required actives and add to module
|
||||
// We can start ordering at a module, or a scope
|
||||
|
|
@ -68,10 +61,9 @@ private:
|
|||
UINFO(4, " ACTIVE " << nodep << endl);
|
||||
// Remove duplicate clocks and such; sensesp() may change!
|
||||
V3Const::constifyExpensiveEdit(nodep);
|
||||
AstSenTree* sensesp = nodep->sensesp();
|
||||
AstSenTree* const sensesp = nodep->sensesp();
|
||||
UASSERT_OBJ(sensesp, nodep, "nullptr");
|
||||
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
|
||||
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
|
||||
if (sensesp->sensesp() && sensesp->sensesp()->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
|
||||
"Never senitem should be alone, else the never should be eliminated.");
|
||||
|
|
@ -80,16 +72,16 @@ private:
|
|||
}
|
||||
// Copy combo tree to settlement tree with duplicated statements
|
||||
if (sensesp->hasCombo()) {
|
||||
AstSenTree* newsentreep = new AstSenTree(
|
||||
AstSenTree* const newsentreep = new AstSenTree(
|
||||
nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
|
||||
AstActive* newp = new AstActive(nodep->fileline(), "settle", newsentreep);
|
||||
AstActive* const newp = new AstActive(nodep->fileline(), "settle", newsentreep);
|
||||
newp->sensesStorep(newsentreep);
|
||||
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
|
||||
nodep->addNextHere(newp);
|
||||
}
|
||||
// Move the SENTREE for each active up to the global level.
|
||||
// This way we'll easily see what clock domains are identical
|
||||
AstSenTree* wantp = m_finder.getSenTree(sensesp);
|
||||
AstSenTree* const wantp = m_finder.getSenTree(sensesp);
|
||||
UINFO(4, " lookdone\n");
|
||||
if (wantp != sensesp) {
|
||||
// Move the active's contents to the other active
|
||||
|
|
@ -136,6 +128,6 @@ public:
|
|||
|
||||
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ActiveTopVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ ActiveTopVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "V3Global.h"
|
||||
#include "V3Assert.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3GraphDfa.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -31,11 +30,11 @@ private:
|
|||
// NODE STATE/TYPES
|
||||
// Cleared on netlist
|
||||
// AstNode::user() -> bool. True if processed
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Last module
|
||||
AstBegin* m_beginp = nullptr; // Last begin
|
||||
const AstBegin* m_beginp = nullptr; // Last begin
|
||||
unsigned m_monitorNum = 0; // Global $monitor numbering (not per module)
|
||||
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
|
||||
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
|
||||
|
|
@ -56,14 +55,14 @@ private:
|
|||
nodep->displayType(AstDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
// cppcheck-suppress nullPointer
|
||||
AstNode* timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
|
||||
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
|
||||
AstNode* const timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
|
||||
if (AstNode* const timesp = nodep->fmtp()->exprsp()) {
|
||||
timesp->unlinkFrBackWithNext();
|
||||
timenewp->addNext(timesp);
|
||||
}
|
||||
nodep->fmtp()->addExprsp(timenewp);
|
||||
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
|
||||
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
nodep->fmtp()->scopeNamep(new AstScopeName{nodep->fileline(), true});
|
||||
}
|
||||
}
|
||||
AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) {
|
||||
|
|
@ -89,8 +88,8 @@ private:
|
|||
AstNode* newIfAssertOn(AstNode* nodep, bool force) {
|
||||
// Add a internal if to check assertions are on.
|
||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* newp = new AstIf(
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const newp = new AstIf(
|
||||
fl,
|
||||
(force ? new AstConst(fl, AstConst::BitTrue())
|
||||
: // If assertions are off, have constant propagation rip them out later
|
||||
|
|
@ -106,10 +105,10 @@ private:
|
|||
|
||||
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
||||
// Like newFireAssert() but omits the asserts-on check
|
||||
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message,
|
||||
nullptr, nullptr);
|
||||
AstDisplay* const dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR,
|
||||
message, nullptr, nullptr);
|
||||
dispp->fmtp()->timeunit(m_modp->timeunit());
|
||||
AstNode* bodysp = dispp;
|
||||
AstNode* const bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop(nodep->fileline(), true));
|
||||
return bodysp;
|
||||
|
|
@ -124,8 +123,8 @@ private:
|
|||
void newPslAssertion(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
|
||||
AstNode* propp = nodep->propp()->unlinkFrBackWithNext();
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
AstNode* const propp = nodep->propp()->unlinkFrBackWithNext();
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
const string& message = nodep->name();
|
||||
AstNode* passsp = nodep->passsp();
|
||||
if (passsp) passsp->unlinkFrBackWithNext();
|
||||
|
|
@ -141,13 +140,13 @@ private:
|
|||
AstNode* bodysp = nullptr;
|
||||
bool selfDestruct = false;
|
||||
AstIf* ifp = nullptr;
|
||||
if (AstCover* snodep = VN_CAST(nodep, Cover)) {
|
||||
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
|
||||
++m_statCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
selfDestruct = true;
|
||||
} else {
|
||||
// V3Coverage assigned us a bucket to increment.
|
||||
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
|
||||
AstCoverInc* const covincp = VN_AS(snodep->coverincp(), CoverInc);
|
||||
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||
if (message != "") covincp->declp()->comment(message);
|
||||
|
|
@ -199,13 +198,13 @@ private:
|
|||
virtual void visit(AstIf* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
AstNodeIf* ifp = nodep;
|
||||
const AstNodeIf* ifp = nodep;
|
||||
AstNode* propp = nullptr;
|
||||
bool hasDefaultElse = false;
|
||||
do {
|
||||
// If this statement ends with 'else if', then nextIf will point to the
|
||||
// nextIf statement. Otherwise it will be null.
|
||||
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
|
||||
const AstNodeIf* const nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
|
||||
iterateAndNextNull(ifp->condp());
|
||||
|
||||
// Recurse into the true case.
|
||||
|
|
@ -217,7 +216,7 @@ private:
|
|||
}
|
||||
|
||||
// Build a bitmask of the true predicates
|
||||
AstNode* predp = ifp->condp()->cloneTree(false);
|
||||
AstNode* const predp = ifp->condp()->cloneTree(false);
|
||||
if (propp) {
|
||||
propp = new AstConcat(nodep->fileline(), predp, propp);
|
||||
} else {
|
||||
|
|
@ -230,7 +229,7 @@ private:
|
|||
ifp = nextifp;
|
||||
} while (ifp);
|
||||
|
||||
AstNode* newifp = nodep->cloneTree(false);
|
||||
AstNode* const newifp = nodep->cloneTree(false);
|
||||
const bool allow_none = nodep->unique0Pragma();
|
||||
|
||||
// Empty case means no property
|
||||
|
|
@ -238,10 +237,11 @@ private:
|
|||
|
||||
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
||||
// predicates evaluates to true.
|
||||
AstNode* ohot = ((allow_none || hasDefaultElse)
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* checkifp
|
||||
AstNode* const ohot
|
||||
= ((allow_none || hasDefaultElse)
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* const checkifp
|
||||
= new AstIf(nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep, "'unique if' statement violated"), newifp);
|
||||
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
|
|
@ -258,7 +258,7 @@ private:
|
|||
if (!nodep->user1SetOnce()) {
|
||||
bool has_default = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
if (itemp->isDefault()) has_default = true;
|
||||
}
|
||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||
|
|
@ -279,10 +279,10 @@ private:
|
|||
} else {
|
||||
AstNode* propp = nullptr;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
AstNode* onep;
|
||||
if (AstInsideRange* rcondp = VN_CAST(icondp, InsideRange)) {
|
||||
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
|
||||
onep = rcondp->newAndFromInside(nodep->exprp(),
|
||||
rcondp->lhsp()->cloneTree(true),
|
||||
rcondp->rhsp()->cloneTree(true));
|
||||
|
|
@ -306,11 +306,11 @@ private:
|
|||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
|
||||
|
||||
const bool allow_none = has_default || nodep->unique0Pragma();
|
||||
AstNode* ohot
|
||||
AstNode* const ohot
|
||||
= (allow_none
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* ifp = new AstIf(
|
||||
AstIf* const ifp = new AstIf(
|
||||
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep,
|
||||
"synthesis parallel_case, but multiple matches found"),
|
||||
|
|
@ -329,22 +329,22 @@ private:
|
|||
if (nodep->ticksp()) {
|
||||
UASSERT_OBJ(VN_IS(nodep->ticksp(), Const), nodep,
|
||||
"Expected constant ticks, checked in V3Width");
|
||||
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
|
||||
ticks = VN_AS(nodep->ticksp(), Const)->toUInt();
|
||||
}
|
||||
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
||||
AstNode* inp = nodep->exprp()->unlinkFrBack();
|
||||
AstVar* invarp = nullptr;
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
sentreep->unlinkFrBack();
|
||||
AstAlways* alwaysp
|
||||
AstAlways* const alwaysp
|
||||
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
|
||||
m_modp->addStmtp(alwaysp);
|
||||
for (uint32_t i = 0; i < ticks; ++i) {
|
||||
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
|
||||
inp->dtypep());
|
||||
AstVar* const outvarp = new AstVar(
|
||||
nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep());
|
||||
m_modp->addStmtp(outvarp);
|
||||
AstNode* assp = new AstAssignDly(
|
||||
AstNode* const assp = new AstAssignDly(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
|
||||
alwaysp->addStmtp(assp);
|
||||
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
|
||||
|
|
@ -378,15 +378,15 @@ private:
|
|||
new AstConst{fl, monNum}};
|
||||
nodep->replaceWith(newsetp);
|
||||
// Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);"
|
||||
AstNode* stmtsp = nodep;
|
||||
AstIf* ifp = new AstIf{
|
||||
AstNode* const stmtsp = nodep;
|
||||
AstIf* const ifp = new AstIf{
|
||||
fl,
|
||||
new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)},
|
||||
new AstEq{fl, new AstConst{fl, monNum},
|
||||
newMonitorNumVarRefp(nodep, VAccess::READ)}},
|
||||
stmtsp, nullptr};
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
|
||||
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
|
||||
m_modp->addStmtp(newp);
|
||||
} else if (nodep->displayType() == AstDisplayType::DT_STROBE) {
|
||||
nodep->displayType(AstDisplayType::DT_DISPLAY);
|
||||
|
|
@ -401,10 +401,11 @@ private:
|
|||
new AstConst{fl, AstConst::BitTrue{}}};
|
||||
nodep->replaceWith(newsetp);
|
||||
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
|
||||
AstNode* stmtsp = nodep;
|
||||
AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
|
||||
AstNode* const stmtsp = nodep;
|
||||
AstIf* const ifp
|
||||
= new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
|
||||
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
|
||||
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitFalse{}}});
|
||||
m_modp->addStmtp(newp);
|
||||
|
|
@ -474,6 +475,6 @@ public:
|
|||
|
||||
void V3Assert::assertAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ AssertVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ AssertVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,10 +97,10 @@ private:
|
|||
virtual void visit(AstFell* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
AstNode* const past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
|
||||
exprp->dtypeSetBit();
|
||||
|
|
@ -116,10 +116,10 @@ private:
|
|||
virtual void visit(AstRose* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
AstNode* const past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
|
||||
exprp->dtypeSetBit();
|
||||
|
|
@ -130,9 +130,9 @@ private:
|
|||
virtual void visit(AstStable* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
AstNode* const past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past, exprp->cloneTree(false));
|
||||
exprp->dtypeSetBit();
|
||||
|
|
@ -144,15 +144,15 @@ private:
|
|||
virtual void visit(AstImplication* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
||||
if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp);
|
||||
|
||||
AstNode* past = new AstPast(fl, lhsp, nullptr);
|
||||
AstNode* const past = new AstPast(fl, lhsp, nullptr);
|
||||
past->dtypeFrom(lhsp);
|
||||
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
AstNode* const exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
|
|
@ -205,6 +205,6 @@ public:
|
|||
|
||||
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ AssertPreVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ AssertPreVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ AstNode* AstNode::abovep() const {
|
|||
// Avoid supporting at other locations as would require walking
|
||||
// list which is likely to cause performance issues.
|
||||
UASSERT_OBJ(!m_nextp || firstAbovep(), this, "abovep() not allowed when in midlist");
|
||||
const AstNode* firstp = firstAbovep() ? this : m_headtailp;
|
||||
const AstNode* const firstp = firstAbovep() ? this : m_headtailp;
|
||||
return firstp->backp();
|
||||
}
|
||||
|
||||
|
|
@ -277,8 +277,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
|
|||
oldtailp->m_nextp = newp;
|
||||
newp->m_backp = oldtailp;
|
||||
// New tail needs the head
|
||||
AstNode* newtailp = newp->m_headtailp;
|
||||
AstNode* headp = oldtailp->m_headtailp;
|
||||
AstNode* const newtailp = newp->m_headtailp;
|
||||
AstNode* const headp = oldtailp->m_headtailp;
|
||||
oldtailp->m_headtailp = nullptr; // May be written again as new head
|
||||
newp->m_headtailp = nullptr; // May be written again as new tail
|
||||
newtailp->m_headtailp = headp;
|
||||
|
|
@ -305,11 +305,11 @@ void AstNode::addNextHere(AstNode* newp) {
|
|||
debugTreeChange(newp, "-addHereNew: ", __LINE__, true);
|
||||
newp->editCountInc();
|
||||
|
||||
AstNode* addlastp = newp->m_headtailp; // Last node in list to be added
|
||||
AstNode* const addlastp = newp->m_headtailp; // Last node in list to be added
|
||||
UASSERT(!addlastp->m_nextp, "Headtailp tail isn't at the tail");
|
||||
|
||||
// Forward links
|
||||
AstNode* oldnextp = this->m_nextp;
|
||||
AstNode* const oldnextp = this->m_nextp;
|
||||
this->m_nextp = newp;
|
||||
addlastp->m_nextp = oldnextp; // Perhaps null if 'this' is not list
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ void AstNode::addNextHere(AstNode* newp) {
|
|||
newp->m_backp = this;
|
||||
|
||||
// Head/tail
|
||||
AstNode* oldheadtailp = this->m_headtailp;
|
||||
AstNode* const oldheadtailp = this->m_headtailp;
|
||||
// (!oldheadtailp) // this was&is middle of list
|
||||
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
|
||||
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not
|
||||
|
|
@ -455,10 +455,10 @@ void AstNRelinker::dump(std::ostream& str) const {
|
|||
|
||||
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||
debugTreeChange(this, "-unlinkWNextThs: ", __LINE__, true);
|
||||
AstNode* oldp = this;
|
||||
AstNode* const oldp = this;
|
||||
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
|
||||
oldp->editCountInc();
|
||||
AstNode* backp = oldp->m_backp;
|
||||
AstNode* const backp = oldp->m_backp;
|
||||
if (linkerp) {
|
||||
linkerp->m_oldp = oldp;
|
||||
linkerp->m_backp = backp;
|
||||
|
|
@ -487,7 +487,7 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
|||
AstNode* oldtailp = oldp;
|
||||
while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp;
|
||||
// Create new head/tail of old list
|
||||
AstNode* oldheadp = oldtailp->m_headtailp;
|
||||
AstNode* const oldheadp = oldtailp->m_headtailp;
|
||||
oldheadp->m_headtailp = oldp->m_backp;
|
||||
oldheadp->m_headtailp->m_headtailp = oldheadp;
|
||||
// Create new head/tail of extracted list
|
||||
|
|
@ -515,10 +515,10 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
|||
|
||||
AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
||||
debugTreeChange(this, "-unlinkFrBkThs: ", __LINE__, true);
|
||||
AstNode* oldp = this;
|
||||
AstNode* const oldp = this;
|
||||
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
|
||||
oldp->editCountInc();
|
||||
AstNode* backp = oldp->m_backp;
|
||||
AstNode* const backp = oldp->m_backp;
|
||||
if (linkerp) {
|
||||
linkerp->m_oldp = oldp;
|
||||
linkerp->m_backp = backp;
|
||||
|
|
@ -560,7 +560,7 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
|||
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
}
|
||||
if (oldp->m_nextp) {
|
||||
AstNode* newheadp = oldp->m_nextp;
|
||||
AstNode* const newheadp = oldp->m_nextp;
|
||||
newheadp->m_backp = backp;
|
||||
newheadp->m_headtailp = oldp->m_headtailp;
|
||||
newheadp->m_headtailp->m_headtailp = newheadp;
|
||||
|
|
@ -582,7 +582,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
|||
UINFO(0, " EDIT: relink: ");
|
||||
dumpPtrs();
|
||||
}
|
||||
AstNode* newp = this;
|
||||
AstNode* const newp = this;
|
||||
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
|
||||
UASSERT(!newp->backp(), "New node already linked?");
|
||||
newp->editCountInc();
|
||||
|
|
@ -592,7 +592,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
|||
cout << endl;
|
||||
}
|
||||
|
||||
AstNode* backp = linkerp->m_backp;
|
||||
AstNode* const backp = linkerp->m_backp;
|
||||
debugTreeChange(this, "-relinkNew: ", __LINE__, true);
|
||||
debugTreeChange(backp, "-relinkTre: ", __LINE__, true);
|
||||
|
||||
|
|
@ -631,10 +631,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
|
|||
// Likewise there may be a old list.
|
||||
// Insert the whole old list following the new node's list.
|
||||
// Thus a unlink without next, followed by relink, gives the same list.
|
||||
AstNode* newlistlastp = newp->m_headtailp;
|
||||
AstNode* const newlistlastp = newp->m_headtailp;
|
||||
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp,
|
||||
"Headtailp tail isn't at the tail");
|
||||
AstNode* oldlistlastp = pointpr->m_headtailp;
|
||||
AstNode* const oldlistlastp = pointpr->m_headtailp;
|
||||
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp,
|
||||
"Old headtailp tail isn't at the tail");
|
||||
// Next links
|
||||
|
|
@ -671,7 +671,7 @@ void AstNode::swapWith(AstNode* bp) {
|
|||
|
||||
AstNode* AstNode::cloneTreeIter() {
|
||||
// private: Clone single node and children
|
||||
AstNode* newp = this->clone();
|
||||
AstNode* const newp = this->clone();
|
||||
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList());
|
||||
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
|
||||
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
|
||||
|
|
@ -688,7 +688,7 @@ AstNode* AstNode::cloneTreeIterList() {
|
|||
AstNode* newtailp = nullptr;
|
||||
// Audited to make sure this is never nullptr
|
||||
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
|
||||
AstNode* newp = oldp->cloneTreeIter();
|
||||
AstNode* const newp = oldp->cloneTreeIter();
|
||||
newp->m_headtailp = nullptr;
|
||||
newp->m_backp = newtailp;
|
||||
if (newtailp) newtailp->m_nextp = newp;
|
||||
|
|
@ -777,14 +777,14 @@ void AstNode::deleteTree() {
|
|||
#ifdef VL_LEAK_CHECKS
|
||||
void* AstNode::operator new(size_t size) {
|
||||
// Optimization note: Aligning to cache line is a loss, due to lost packing
|
||||
AstNode* objp = static_cast<AstNode*>(::operator new(size));
|
||||
const AstNode* const objp = static_cast<AstNode*>(::operator new(size));
|
||||
V3Broken::addNewed(objp);
|
||||
return objp;
|
||||
}
|
||||
|
||||
void AstNode::operator delete(void* objp, size_t size) {
|
||||
if (!objp) return;
|
||||
AstNode* nodep = static_cast<AstNode*>(objp);
|
||||
const AstNode* const nodep = static_cast<AstNode*>(objp);
|
||||
V3Broken::deleted(nodep);
|
||||
::operator delete(objp);
|
||||
}
|
||||
|
|
@ -877,7 +877,7 @@ void AstNode::iterateAndNextConst(AstNVisitor& v) {
|
|||
// Keep following the current list even if edits change it
|
||||
AstNode* nodep = this;
|
||||
do {
|
||||
AstNode* nnextp = nodep->m_nextp;
|
||||
AstNode* const nnextp = nodep->m_nextp;
|
||||
ASTNODE_PREFETCH(nnextp);
|
||||
nodep->accept(v);
|
||||
nodep = nnextp;
|
||||
|
|
@ -898,7 +898,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||
} else if (!nodep->backp()) {
|
||||
// Calling on standalone tree; insert a shim node so we can keep
|
||||
// track, then delete it on completion
|
||||
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
||||
AstBegin* const tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
||||
{
|
||||
VL_DO_DANGLING(tempp->stmtsp()->accept(v),
|
||||
nodep); // nodep to null as may be replaced
|
||||
|
|
@ -994,8 +994,8 @@ void AstNode::checkTreeIter(AstNode* backp) {
|
|||
void AstNode::checkTreeIterList(AstNode* backp) {
|
||||
// private: Check a (possible) list of nodes, this is always the head of the list
|
||||
// Audited to make sure this is never nullptr
|
||||
AstNode* headp = this;
|
||||
AstNode* tailp = this;
|
||||
AstNode* const headp = this;
|
||||
const AstNode* tailp = this;
|
||||
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
|
||||
nodep->checkTreeIter(backp);
|
||||
UASSERT_OBJ(headp == this || !nextp(), this,
|
||||
|
|
@ -1143,7 +1143,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
|
|||
checkTree();
|
||||
// Broken isn't part of check tree because it can munge iterp's
|
||||
// set by other steps if it is called in the middle of other operations
|
||||
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
|
||||
if (AstNetlist* const netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1164,7 +1164,7 @@ string AstNode::locationStr() const {
|
|||
return ""; // LCOV_EXCL_LINE
|
||||
}
|
||||
const AstScope* scopep;
|
||||
if ((scopep = VN_CAST_CONST(backp, Scope))) {
|
||||
if ((scopep = VN_CAST(backp, Scope))) {
|
||||
// The design is flattened and there are no useful scopes
|
||||
// This is probably because of inlining
|
||||
if (scopep->isTop()) break;
|
||||
|
|
@ -1178,10 +1178,10 @@ string AstNode::locationStr() const {
|
|||
while (backp) {
|
||||
const AstModule* modp;
|
||||
const AstNodeVarRef* nvrp;
|
||||
if ((modp = VN_CAST_CONST(backp, Module)) && !modp->hierName().empty()) {
|
||||
if ((modp = VN_CAST(backp, Module)) && !modp->hierName().empty()) {
|
||||
str += modp->hierName();
|
||||
return str;
|
||||
} else if ((nvrp = VN_CAST_CONST(backp, NodeVarRef))) {
|
||||
} else if ((nvrp = VN_CAST(backp, NodeVarRef))) {
|
||||
const string prettyName = nvrp->prettyName();
|
||||
// VarRefs have not been flattened yet and do not contain location information
|
||||
if (prettyName != nvrp->name()) {
|
||||
|
|
@ -1276,9 +1276,9 @@ AstNodeDType* AstNode::findVoidDType() const {
|
|||
}
|
||||
|
||||
//######################################################################
|
||||
// AstNVisitor
|
||||
// AstNDeleter
|
||||
|
||||
void AstNVisitor::doDeletes() {
|
||||
for (AstNode* nodep : m_deleteps) nodep->deleteTree();
|
||||
void AstNDeleter::doDeletes() {
|
||||
for (AstNode* const nodep : m_deleteps) nodep->deleteTree();
|
||||
m_deleteps.clear();
|
||||
}
|
||||
|
|
|
|||
171
src/V3Ast.h
171
src/V3Ast.h
|
|
@ -56,23 +56,26 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
|
|||
// For broken() function, return error string if a base of this class has a match
|
||||
#define BROKEN_BASE_RTN(test) \
|
||||
do { \
|
||||
const char* reasonp = (test); \
|
||||
const char* const reasonp = (test); \
|
||||
if (VL_UNCOVERABLE(reasonp)) return reasonp; \
|
||||
} while (false)
|
||||
|
||||
// (V)erilator (N)ode is: Returns true iff AstNode is of the given AstNode subtype, and not
|
||||
// nullptr.
|
||||
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename>(nodep))
|
||||
// (V)erilator (N)ode is: Returns true if and only if AstNode is of the given AstNode subtype,
|
||||
// and not nullptr.
|
||||
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename, decltype(nodep)>(nodep))
|
||||
|
||||
// (V)erilator (N)ode cast: More efficient but otherwise same as dynamic_cast, use this instead.
|
||||
// Cast to given type if node is of such type, otherwise returns nullptr.
|
||||
#define VN_CAST(nodep, nodetypename) (AstNode::privateCast<Ast##nodetypename>(nodep))
|
||||
#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateCastConst<Ast##nodetypename>(nodep))
|
||||
// (V)erilator (N)ode cast: Similar to dynamic_cast, but more efficient, use this instead.
|
||||
// Cast to given type if node is of such type, otherwise returns nullptr. If 'nodep' is nullptr,
|
||||
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*',
|
||||
// a 'const Ast<nodetypename>*' is returned.
|
||||
#define VN_CAST(nodep, nodetypename) \
|
||||
(AstNode::privateCast<Ast##nodetypename, decltype(nodep)>(nodep))
|
||||
|
||||
// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Node can be nullptr.
|
||||
// Use this to downcast instead of VN_CAST when you know the true type of the node.
|
||||
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename>(nodep))
|
||||
#define VN_AS_CONST(nodep, nodetypename) (AstNode::privateAsConst<Ast##nodetypename>(nodep))
|
||||
// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Use this to
|
||||
// downcast instead of VN_CAST when you know the true type of the node. If 'nodep' is nullptr,
|
||||
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*', a 'const
|
||||
// Ast<nodetypename>*' is returned.
|
||||
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
|
||||
|
||||
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
|
||||
#define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
|
||||
|
|
@ -501,7 +504,8 @@ public:
|
|||
}
|
||||
bool isUnsigned() const {
|
||||
return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR
|
||||
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64;
|
||||
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64 || m_e == BIT || m_e == LOGIC
|
||||
|| m_e == TIME;
|
||||
}
|
||||
bool isFourstate() const {
|
||||
return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
|
||||
|
|
@ -514,9 +518,6 @@ public:
|
|||
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|
||||
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
|
||||
}
|
||||
bool isSloppy() const { // Don't be as anal about width warnings
|
||||
return !(m_e == LOGIC || m_e == BIT);
|
||||
}
|
||||
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
|
||||
return (m_e == LOGIC || m_e == BIT);
|
||||
}
|
||||
|
|
@ -1007,7 +1008,7 @@ public:
|
|||
// MEMBERS
|
||||
void init(int hi, int lo, bool littleEndian) {
|
||||
if (lo > hi) {
|
||||
int t = hi;
|
||||
const int t = hi;
|
||||
hi = lo;
|
||||
lo = t;
|
||||
}
|
||||
|
|
@ -1026,9 +1027,6 @@ public:
|
|||
int hiMaxSelect() const {
|
||||
return (lo() < 0 ? hi() - lo() : hi());
|
||||
} // Maximum value a [] select may index
|
||||
bool representableByWidth() const { // Could be represented by just width=1, or [width-1:0]
|
||||
return (!m_ranged || (m_right == 0 && m_left >= 1));
|
||||
}
|
||||
void dump(std::ostream& str) const {
|
||||
if (ranged()) {
|
||||
str << "[" << left() << ":" << right() << "]";
|
||||
|
|
@ -1079,11 +1077,11 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
|
|||
|
||||
class VBasicTypeKey final {
|
||||
public:
|
||||
int m_width; // From AstNodeDType: Bit width of operation
|
||||
int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
|
||||
VSigning m_numeric; // From AstNodeDType: Node is signed
|
||||
AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
|
||||
VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
|
||||
const int m_width; // From AstNodeDType: Bit width of operation
|
||||
const int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
|
||||
const VSigning m_numeric; // From AstNodeDType: Node is signed
|
||||
const AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
|
||||
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
|
||||
bool operator==(const VBasicTypeKey& rhs) const {
|
||||
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
|
||||
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
|
||||
|
|
@ -1248,31 +1246,39 @@ public:
|
|||
// clang-format on
|
||||
|
||||
//######################################################################
|
||||
// AstNVisitor -- Allows new functions to be called on each node
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
// Node deleter, deletes all enqueued AstNode* on destruction, or when
|
||||
// explicitly told to do so. This is useful when the deletion of removed
|
||||
// nodes needs to be deferred to a later time, because pointers to the
|
||||
// removed nodes might still exist.
|
||||
|
||||
class AstNVisitor VL_NOT_FINAL {
|
||||
private:
|
||||
class AstNDeleter VL_NOT_FINAL {
|
||||
// MEMBERS
|
||||
std::vector<AstNode*> m_deleteps; // Nodes to delete when doDeletes() called
|
||||
protected:
|
||||
friend class AstNode;
|
||||
std::vector<AstNode*> m_deleteps; // Nodes to delete
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
/// At the end of the visitor (or doDeletes()), delete this pushed node
|
||||
/// along with all children and next(s). This is often better to use
|
||||
/// than an immediate deleteTree, as any pointers into this node will
|
||||
/// persist for the lifetime of the visitor
|
||||
|
||||
// Enqueue node for deletion on next 'doDelete' (or destruction)
|
||||
void pushDeletep(AstNode* nodep) {
|
||||
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
|
||||
m_deleteps.push_back(nodep);
|
||||
}
|
||||
/// Call deleteTree on all previously pushDeletep()'ed nodes
|
||||
|
||||
// Delete all previously pushed nodes (by callint deleteTree)
|
||||
void doDeletes();
|
||||
|
||||
// Do the deletions on destruction
|
||||
virtual ~AstNDeleter() { doDeletes(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// AstNVisitor -- Allows new functions to be called on each node
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
|
||||
class AstNVisitor VL_NOT_FINAL : public AstNDeleter {
|
||||
friend class AstNode;
|
||||
|
||||
public:
|
||||
virtual ~AstNVisitor() { doDeletes(); }
|
||||
/// Call visit()s on nodep
|
||||
void iterate(AstNode* nodep);
|
||||
/// Call visit()s on nodep
|
||||
|
|
@ -1847,28 +1853,54 @@ private:
|
|||
// For internal use only.
|
||||
template <typename T> inline static bool privateTypeTest(const AstNode* nodep);
|
||||
|
||||
template <typename TargetType, typename DeclType> constexpr static bool uselessCast() {
|
||||
using NonRef = typename std::remove_reference<DeclType>::type;
|
||||
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
||||
using NonCV = typename std::remove_cv<NonPtr>::type;
|
||||
return std::is_base_of<TargetType, NonCV>::value;
|
||||
}
|
||||
|
||||
template <typename TargetType, typename DeclType> constexpr static bool impossibleCast() {
|
||||
using NonRef = typename std::remove_reference<DeclType>::type;
|
||||
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
||||
using NonCV = typename std::remove_cv<NonPtr>::type;
|
||||
return !std::is_base_of<NonCV, TargetType>::value;
|
||||
}
|
||||
|
||||
public:
|
||||
// For use via the VN_IS macro only
|
||||
template <typename T> inline static bool privateIs(const AstNode* nodep) {
|
||||
template <typename T, typename E> inline static bool privateIs(const AstNode* nodep) {
|
||||
static_assert(!uselessCast<T, E>(), "Unnecessary VN_IS, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_IS, node cannot be this type.");
|
||||
return nodep && privateTypeTest<T>(nodep);
|
||||
}
|
||||
|
||||
// For use via the VN_CAST macro only
|
||||
template <typename T> inline static T* privateCast(AstNode* nodep) {
|
||||
return privateIs<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
|
||||
template <typename T, typename E> inline static T* privateCast(AstNode* nodep) {
|
||||
static_assert(!uselessCast<T, E>(),
|
||||
"Unnecessary VN_CAST, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
|
||||
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
|
||||
}
|
||||
// For use via the VN_CAST_CONST macro only
|
||||
template <typename T> inline static const T* privateCastConst(const AstNode* nodep) {
|
||||
return privateIs<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
|
||||
template <typename T, typename E> inline static const T* privateCast(const AstNode* nodep) {
|
||||
static_assert(!uselessCast<T, E>(),
|
||||
"Unnecessary VN_CAST, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
|
||||
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
|
||||
}
|
||||
|
||||
// For use via the VN_AS macro only
|
||||
template <typename T> inline static T* privateAs(AstNode* nodep) {
|
||||
template <typename T, typename E> inline static T* privateAs(AstNode* nodep) {
|
||||
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,
|
||||
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
|
||||
<< "'");
|
||||
return reinterpret_cast<T*>(nodep);
|
||||
}
|
||||
// For use via the VN_AS_CONST macro only
|
||||
template <typename T> inline static const T* privateAsConst(const AstNode* nodep) {
|
||||
template <typename T, typename E> inline static const T* privateAs(const AstNode* nodep) {
|
||||
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,
|
||||
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
|
||||
<< "'");
|
||||
|
|
@ -1922,7 +1954,7 @@ public:
|
|||
virtual bool cleanOut() const = 0; // True if output has extra upper bits zero
|
||||
// Someday we will generically support data types on every math node
|
||||
// Until then isOpaque indicates we shouldn't constant optimize this node type
|
||||
bool isOpaque() { return VN_IS(this, CvtPackString); }
|
||||
bool isOpaque() const { return VN_IS(this, CvtPackString); }
|
||||
};
|
||||
|
||||
class AstNodeTermop VL_NOT_FINAL : public AstNodeMath {
|
||||
|
|
@ -2111,9 +2143,7 @@ public:
|
|||
AstNode* expr1p() const { return op2p(); } // op2 = If true...
|
||||
AstNode* expr2p() const { return op3p(); } // op3 = If false...
|
||||
virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
|
||||
virtual string emitC() override {
|
||||
return "VL_COND_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)";
|
||||
}
|
||||
virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
|
||||
virtual bool cleanOut() const override { return false; } // clean if e1 & e2 clean
|
||||
virtual bool cleanLhs() const override { return true; }
|
||||
virtual bool cleanRhs() const override { return false; }
|
||||
|
|
@ -2166,7 +2196,7 @@ public:
|
|||
AstNode* fromp() const { return op1p(); }
|
||||
AstNode* rhsp() const { return op2p(); }
|
||||
AstNode* thsp() const { return op3p(); }
|
||||
AstAttrOf* attrp() const { return VN_CAST(op4p(), AttrOf); }
|
||||
AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); }
|
||||
void fromp(AstNode* nodep) { return setOp1p(nodep); }
|
||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
||||
|
|
@ -2304,7 +2334,7 @@ public:
|
|||
virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||
AstNode* exprp() const { return op1p(); } // op1 = case condition <expression>
|
||||
AstCaseItem* itemsp() const {
|
||||
return VN_CAST(op2p(), CaseItem);
|
||||
return VN_AS(op2p(), CaseItem);
|
||||
} // op2 = list of case expressions
|
||||
AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's
|
||||
void addItemsp(AstNode* nodep) { addOp2p(nodep); }
|
||||
|
|
@ -2518,10 +2548,10 @@ public:
|
|||
// For basicp() we reuse the size to indicate a "fake" basic type of same size
|
||||
virtual AstBasicDType* basicp() const override {
|
||||
return (isFourstate()
|
||||
? VN_CAST(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
BasicDType)
|
||||
: VN_CAST(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
BasicDType));
|
||||
? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
BasicDType)
|
||||
: VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
BasicDType));
|
||||
}
|
||||
virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
|
|
@ -2537,7 +2567,7 @@ public:
|
|||
virtual string name() const override { return m_name; }
|
||||
virtual void name(const string& flag) override { m_name = flag; }
|
||||
AstMemberDType* membersp() const {
|
||||
return VN_CAST(op1p(), MemberDType);
|
||||
return VN_AS(op1p(), MemberDType);
|
||||
} // op1 = AstMember list
|
||||
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
bool packed() const { return m_packed; }
|
||||
|
|
@ -2580,18 +2610,18 @@ public:
|
|||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
|
||||
&& rangenp()->sameTree(asamep->rangenp()));
|
||||
} // HashedDT doesn't recurse, so need to check children
|
||||
virtual bool similarDType(AstNodeDType* samep) const override {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return (asamep && type() == samep->type() && hi() == asamep->hi()
|
||||
&& rangenp()->sameTree(asamep->rangenp())
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
||||
AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); }
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
virtual AstNodeDType* subDTypep() const override {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
|
|
@ -2599,7 +2629,7 @@ public:
|
|||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Array(s) of variable
|
||||
AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Array(s) of variable
|
||||
void rangep(AstRange* nodep);
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() const override {
|
||||
|
|
@ -2673,7 +2703,7 @@ public:
|
|||
virtual const char* broken() const override;
|
||||
virtual int instrCount() const override { return INSTR_COUNT_CALL; }
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstNodeCCall* asamep = static_cast<const AstNodeCCall*>(samep);
|
||||
const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
|
||||
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
|
||||
}
|
||||
AstNode* exprsp() const { return op2p(); } // op2 = expressions to print
|
||||
|
|
@ -2705,6 +2735,7 @@ private:
|
|||
bool m_dpiContext : 1; // DPI import context
|
||||
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
|
||||
bool m_dpiTask : 1; // DPI import task (vs. void function)
|
||||
bool m_dpiTraceInit : 1; // DPI trace_init
|
||||
bool m_isConstructor : 1; // Class constructor
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
|
|
@ -2728,6 +2759,7 @@ protected:
|
|||
, m_dpiContext{false}
|
||||
, m_dpiOpenChild{false}
|
||||
, m_dpiTask{false}
|
||||
, m_dpiTraceInit{false}
|
||||
, m_isConstructor{false}
|
||||
, m_isHideLocal{false}
|
||||
, m_isHideProtected{false}
|
||||
|
|
@ -2762,7 +2794,7 @@ public:
|
|||
AstNode* stmtsp() const { return op3p(); } // op3 = List of statements
|
||||
void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
|
||||
// op4 = scope name
|
||||
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
|
||||
AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
|
||||
// MORE ACCESSORS
|
||||
void dpiOpenParentInc() { ++m_dpiOpenParent; }
|
||||
void dpiOpenParentClear() { m_dpiOpenParent = 0; }
|
||||
|
|
@ -2790,6 +2822,8 @@ public:
|
|||
bool dpiOpenChild() const { return m_dpiOpenChild; }
|
||||
void dpiTask(bool flag) { m_dpiTask = flag; }
|
||||
bool dpiTask() const { return m_dpiTask; }
|
||||
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
|
||||
bool dpiTraceInit() const { return m_dpiTraceInit; }
|
||||
void isConstructor(bool flag) { m_isConstructor = flag; }
|
||||
bool isConstructor() const { return m_isConstructor; }
|
||||
bool isHideLocal() const { return m_isHideLocal; }
|
||||
|
|
@ -2842,7 +2876,6 @@ public:
|
|||
return m_taskp && m_taskp->isGateOptimizable();
|
||||
}
|
||||
string dotted() const { return m_dotted; } // * = Scope name or ""
|
||||
string prettyDotted() const { return prettyName(dotted()); }
|
||||
string inlinedDots() const { return m_inlinedDots; }
|
||||
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
|
||||
AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable
|
||||
|
|
@ -2860,7 +2893,7 @@ public:
|
|||
AstNode* pinsp() const { return op3p(); }
|
||||
void addPinsp(AstNode* nodep) { addOp3p(nodep); }
|
||||
// op4 = scope tracking
|
||||
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
|
||||
AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
|
||||
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
|
||||
};
|
||||
|
||||
|
|
@ -2870,7 +2903,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
|
|||
// excluding $unit package stuff
|
||||
private:
|
||||
string m_name; // Name of the module
|
||||
string m_origName; // Name of the module, ignoring name() changes, for dot lookup
|
||||
const string m_origName; // Name of the module, ignoring name() changes, for dot lookup
|
||||
string m_hierName; // Hierarchical name for errors, etc.
|
||||
bool m_modPublic : 1; // Module has public references
|
||||
bool m_modTrace : 1; // Tracing this module
|
||||
|
|
@ -2881,7 +2914,6 @@ private:
|
|||
bool m_recursive : 1; // Recursive module
|
||||
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
|
||||
int m_level = 0; // 1=top module, 2=cell off top module, ...
|
||||
int m_typeNum = 0; // Incrementing implicit type number
|
||||
VLifetime m_lifetime; // Lifetime
|
||||
VTimescale m_timeunit; // Global time unit
|
||||
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
|
||||
|
|
@ -2906,7 +2938,7 @@ public:
|
|||
virtual string name() const override { return m_name; }
|
||||
virtual bool timescaleMatters() const = 0;
|
||||
AstNode* stmtsp() const { return op2p(); } // op2 = List of statements
|
||||
AstActive* activesp() const { return VN_CAST(op3p(), Active); } // op3 = List of i/sblocks
|
||||
AstActive* activesp() const { return VN_AS(op3p(), Active); } // op3 = List of i/sblocks
|
||||
// METHODS
|
||||
void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
|
||||
void addStmtp(AstNode* nodep) { addNOp2p(nodep); }
|
||||
|
|
@ -2921,7 +2953,6 @@ public:
|
|||
void level(int level) { m_level = level; }
|
||||
int level() const { return m_level; }
|
||||
bool isTop() const { return level() == 1; }
|
||||
int typeNumGetInc() { return ++m_typeNum; }
|
||||
void modPublic(bool flag) { m_modPublic = flag; }
|
||||
bool modPublic() const { return m_modPublic; }
|
||||
void modTrace(bool flag) { m_modTrace = flag; }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ inline int AstNode::widthInstrs() const {
|
|||
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
|
||||
}
|
||||
inline bool AstNode::isDouble() const {
|
||||
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble();
|
||||
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
|
||||
}
|
||||
inline bool AstNode::isString() const {
|
||||
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
|
||||
|
|
@ -42,19 +42,19 @@ inline bool AstNode::isString() const {
|
|||
inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
|
||||
|
||||
inline bool AstNode::isZero() const {
|
||||
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero());
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
|
||||
}
|
||||
inline bool AstNode::isNeqZero() const {
|
||||
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero());
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNeqZero());
|
||||
}
|
||||
inline bool AstNode::isOne() const {
|
||||
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne());
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne());
|
||||
}
|
||||
inline bool AstNode::isAllOnes() const {
|
||||
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes());
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnes());
|
||||
}
|
||||
inline bool AstNode::isAllOnesV() const {
|
||||
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV());
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnesV());
|
||||
}
|
||||
inline bool AstNode::sameTree(const AstNode* node2p) const {
|
||||
return sameTreeIter(this, node2p, true, false);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ const char* AstIfaceRefDType::broken() const {
|
|||
}
|
||||
|
||||
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
|
||||
return ((m_cellp && m_cellp->modp()) ? VN_CAST(m_cellp->modp(), Iface) : m_ifacep);
|
||||
return ((m_cellp && m_cellp->modp()) ? VN_AS(m_cellp->modp(), Iface) : m_ifacep);
|
||||
}
|
||||
|
||||
const char* AstNodeVarRef::broken() const {
|
||||
|
|
@ -73,13 +73,13 @@ const char* AstAddrOfCFunc::broken() const {
|
|||
}
|
||||
|
||||
int AstNodeSel::bitConst() const {
|
||||
AstConst* constp = VN_CAST(bitp(), Const);
|
||||
const AstConst* const constp = VN_AS(bitp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
|
||||
void AstNodeUOrStructDType::repairMemberCache() {
|
||||
clearCache();
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
if (m_members.find(itemp->name()) != m_members.end()) {
|
||||
itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ());
|
||||
} else {
|
||||
|
|
@ -90,7 +90,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
|
|||
|
||||
const char* AstNodeUOrStructDType::broken() const {
|
||||
std::unordered_set<AstMemberDType*> exists;
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
exists.insert(itemp);
|
||||
}
|
||||
for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) {
|
||||
|
|
@ -197,30 +197,6 @@ AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
|||
}
|
||||
}
|
||||
|
||||
AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
if (lhsp->isString() && rhsp->isString()) {
|
||||
return new AstGteN(fl, lhsp, rhsp);
|
||||
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
||||
return new AstGteD(fl, lhsp, rhsp);
|
||||
} else if (lhsp->isSigned() && rhsp->isSigned()) {
|
||||
return new AstGteS(fl, lhsp, rhsp);
|
||||
} else {
|
||||
return new AstGte(fl, lhsp, rhsp);
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
if (lhsp->isString() && rhsp->isString()) {
|
||||
return new AstLteN(fl, lhsp, rhsp);
|
||||
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
||||
return new AstLteD(fl, lhsp, rhsp);
|
||||
} else if (lhsp->isSigned() && rhsp->isSigned()) {
|
||||
return new AstLteS(fl, lhsp, rhsp);
|
||||
} else {
|
||||
return new AstLte(fl, lhsp, rhsp);
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
if (lhsp->isString() && rhsp->isString()) {
|
||||
return new AstEqN(fl, lhsp, rhsp);
|
||||
|
|
@ -238,11 +214,11 @@ AstExecGraph::AstExecGraph(FileLine* fileline)
|
|||
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
|
||||
|
||||
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
|
||||
AstNode* ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
|
||||
AstNode* bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
|
||||
AstNode* const ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
|
||||
AstNode* const bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
|
||||
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
||||
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
||||
AstNode* newp = new AstAnd(fileline(), ap, bp);
|
||||
AstNode* const newp = new AstAnd(fileline(), ap, bp);
|
||||
return newp;
|
||||
}
|
||||
|
||||
|
|
@ -250,11 +226,11 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
|||
bool success = false;
|
||||
if (literal[0] == '"') {
|
||||
// This is a string
|
||||
string v = literal.substr(1, literal.find('"', 1) - 1);
|
||||
const string v = literal.substr(1, literal.find('"', 1) - 1);
|
||||
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
|
||||
} else if (literal.find_first_of(".eEpP") != string::npos) {
|
||||
// This may be a real
|
||||
double v = VString::parseDouble(literal, &success);
|
||||
const double v = VString::parseDouble(literal, &success);
|
||||
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
|
||||
}
|
||||
if (!success) {
|
||||
|
|
@ -266,7 +242,7 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
|||
// the string after the number, this is invalid C and we try
|
||||
// the Verilog literal parser.
|
||||
char* endp;
|
||||
int v = strtol(literal.c_str(), &endp, 0);
|
||||
const int v = strtol(literal.c_str(), &endp, 0);
|
||||
if ((v != 0) && (endp[0] == 0)) { // C literal
|
||||
return new AstConst(fl, AstConst::Signed32(), v);
|
||||
} else { // Try a Verilog literal (fatals if not)
|
||||
|
|
@ -360,7 +336,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
|
|||
|
||||
string AstVar::vlEnumType() const {
|
||||
string arg;
|
||||
AstBasicDType* bdtypep = basicp();
|
||||
const AstBasicDType* const bdtypep = basicp();
|
||||
const bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING;
|
||||
if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
|
||||
return "VLVT_PTR";
|
||||
|
|
@ -401,7 +377,7 @@ string AstVar::vlEnumDir() const {
|
|||
out += "|VLVF_PUB_RD";
|
||||
}
|
||||
//
|
||||
if (AstBasicDType* bdtypep = basicp()) {
|
||||
if (const AstBasicDType* const bdtypep = basicp()) {
|
||||
if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY";
|
||||
}
|
||||
return out;
|
||||
|
|
@ -413,7 +389,7 @@ string AstVar::vlPropDecl(const string& propName) const {
|
|||
std::vector<int> ulims; // Unpacked dimension limits
|
||||
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
||||
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
||||
ulims.push_back(adtypep->declRange().left());
|
||||
ulims.push_back(adtypep->declRange().right());
|
||||
dtp = adtypep->subDTypep();
|
||||
|
|
@ -499,7 +475,7 @@ public:
|
|||
string convert(const AstVar* varp) const {
|
||||
if (varp->isDpiOpenArray()) {
|
||||
return openArray(varp);
|
||||
} else if (const AstBasicDType* basicp = varp->basicp()) {
|
||||
} else if (const AstBasicDType* const basicp = varp->basicp()) {
|
||||
if (basicp->isDpiBitVec() || basicp->isDpiLogicVec()) {
|
||||
return bitLogicVector(varp, basicp->isDpiBitVec());
|
||||
} else {
|
||||
|
|
@ -539,9 +515,9 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|||
|
||||
string AstVar::dpiTmpVarType(const string& varName) const {
|
||||
class converter final : public dpiTypesToStringConverter {
|
||||
string m_name;
|
||||
const string m_name;
|
||||
string arraySuffix(const AstVar* varp, size_t n) const {
|
||||
if (AstUnpackArrayDType* unpackp
|
||||
if (AstUnpackArrayDType* const unpackp
|
||||
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
// Convert multi dimensional unpacked array to 1D array
|
||||
if (n == 0) n = 1;
|
||||
|
|
@ -607,15 +583,15 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
|||
// See if this is a SC assignment; if so return that type
|
||||
// Historically sc variables are identified by a variable
|
||||
// attribute. TODO it would better be a data type attribute.
|
||||
if (AstVar* anodep = VN_CAST(nodep, Var)) {
|
||||
if (AstVar* const anodep = VN_CAST(nodep, Var)) {
|
||||
if (anodep->isSc()) {
|
||||
return anodep;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (VN_IS(nodep, VarRef)) {
|
||||
if (VN_CAST(nodep, VarRef)->varp()->isSc()) {
|
||||
return VN_CAST(nodep, VarRef)->varp();
|
||||
if (VN_AS(nodep, VarRef)->varp()->isSc()) {
|
||||
return VN_AS(nodep, VarRef)->varp();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -666,29 +642,29 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
|||
// Legacy compound argument currently just passed through and unused
|
||||
CTypeRecursed info;
|
||||
|
||||
const AstNodeDType* dtypep = this->skipRefp();
|
||||
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
|
||||
const AstNodeDType* const dtypep = this->skipRefp();
|
||||
if (const auto* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
|
||||
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
||||
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlQueue<" + sub.m_type + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlQueue<" + sub.m_type;
|
||||
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
||||
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
|
||||
info.m_type += ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
||||
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (adtypep->isCompound()) compound = true;
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
||||
info.m_type = "VlUnpacked<" + sub.m_type;
|
||||
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
|
||||
info.m_type += ">";
|
||||
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
|
||||
} 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
|
||||
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
|
||||
|
|
@ -728,7 +704,7 @@ uint32_t AstNodeDType::arrayUnpackedElements() {
|
|||
uint32_t entries = 1;
|
||||
for (AstNodeDType* dtypep = this; dtypep;) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
entries *= adtypep->elementsConst();
|
||||
dtypep = adtypep->subDTypep();
|
||||
} else {
|
||||
|
|
@ -745,7 +721,7 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
|||
uint32_t unpacked = 0;
|
||||
for (AstNodeDType* dtypep = this; dtypep;) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
if (VN_IS(adtypep, PackArrayDType)) {
|
||||
++packed;
|
||||
} else {
|
||||
|
|
@ -753,11 +729,11 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
|||
}
|
||||
dtypep = adtypep->subDTypep();
|
||||
continue;
|
||||
} else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
} else if (const AstQueueDType* const qdtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
unpacked++;
|
||||
dtypep = qdtypep->subDTypep();
|
||||
continue;
|
||||
} else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
} else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
|
||||
} else if (VN_IS(dtypep, StructDType)) {
|
||||
packed++;
|
||||
|
|
@ -769,7 +745,7 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
|||
|
||||
int AstNodeDType::widthPow2() const {
|
||||
// I.e. width 30 returns 32, width 32 returns 32.
|
||||
uint32_t width = this->width();
|
||||
const uint32_t width = this->width();
|
||||
for (int p2 = 30; p2 >= 0; p2--) {
|
||||
if (width > (1UL << p2)) return (1UL << (p2 + 1));
|
||||
}
|
||||
|
|
@ -777,11 +753,11 @@ int AstNodeDType::widthPow2() const {
|
|||
}
|
||||
|
||||
bool AstNodeDType::isLiteralType() const {
|
||||
if (auto* const dtypep = VN_CAST_CONST(skipRefp(), BasicDType)) {
|
||||
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
|
||||
return dtypep->keyword().isLiteralType();
|
||||
} else if (auto* const dtypep = VN_CAST_CONST(skipRefp(), UnpackArrayDType)) {
|
||||
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
|
||||
return dtypep->basicp()->isLiteralType();
|
||||
} else if (auto* const dtypep = VN_CAST_CONST(skipRefp(), StructDType)) {
|
||||
} else if (const auto* const dtypep = VN_CAST(skipRefp(), StructDType)) {
|
||||
// Currently all structs are packed, later this can be expanded to
|
||||
// 'forall members _.isLiteralType()'
|
||||
return dtypep->packed();
|
||||
|
|
@ -795,25 +771,25 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
|||
// Else AstArraySel etc; search for the base
|
||||
while (nodep) {
|
||||
if (VN_IS(nodep, ArraySel)) {
|
||||
nodep = VN_CAST(nodep, ArraySel)->fromp();
|
||||
nodep = VN_AS(nodep, ArraySel)->fromp();
|
||||
continue;
|
||||
} else if (VN_IS(nodep, Sel)) {
|
||||
nodep = VN_CAST(nodep, Sel)->fromp();
|
||||
nodep = VN_AS(nodep, Sel)->fromp();
|
||||
continue;
|
||||
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
||||
nodep = VN_CAST(nodep, MemberSel)->fromp();
|
||||
nodep = VN_AS(nodep, MemberSel)->fromp();
|
||||
continue;
|
||||
}
|
||||
// AstNodeSelPre stashes the associated variable under an ATTROF
|
||||
// of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
|
||||
else if (VN_IS(nodep, AttrOf)) {
|
||||
nodep = VN_CAST(nodep, AttrOf)->fromp();
|
||||
nodep = VN_AS(nodep, AttrOf)->fromp();
|
||||
continue;
|
||||
} else if (VN_IS(nodep, NodePreSel)) {
|
||||
if (VN_CAST(nodep, NodePreSel)->attrp()) {
|
||||
nodep = VN_CAST(nodep, NodePreSel)->attrp();
|
||||
if (VN_AS(nodep, NodePreSel)->attrp()) {
|
||||
nodep = VN_AS(nodep, NodePreSel)->attrp();
|
||||
} else {
|
||||
nodep = VN_CAST(nodep, NodePreSel)->fromp();
|
||||
nodep = VN_AS(nodep, NodePreSel)->fromp();
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
|
|
@ -854,7 +830,7 @@ string AstScope::nameDotless() const {
|
|||
|
||||
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
|
||||
string out;
|
||||
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
|
||||
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
|
||||
out += textp->text();
|
||||
}
|
||||
// TOP will be replaced by top->name()
|
||||
|
|
@ -865,7 +841,7 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
|
|||
}
|
||||
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
||||
string out;
|
||||
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
|
||||
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
|
||||
out += textp->text();
|
||||
}
|
||||
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
|
||||
|
|
@ -879,28 +855,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
|||
|
||||
bool AstSenTree::hasClocked() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||
if (senp->isClocked()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasSettle() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||
if (senp->isSettle()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasInitial() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||
if (senp->isInitial()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasCombo() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||
if (senp->isCombo()) return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -918,7 +894,7 @@ void AstTypeTable::clearCache() {
|
|||
m_detailedMap.clear();
|
||||
// Clear generic()'s so dead detection will work
|
||||
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
|
||||
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -926,7 +902,7 @@ void AstTypeTable::repairCache() {
|
|||
// After we mass-change widthMin in V3WidthCommit, we need to correct the table.
|
||||
clearCache();
|
||||
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
|
||||
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) {
|
||||
(void)findInsertSameDType(bdtypep);
|
||||
}
|
||||
}
|
||||
|
|
@ -934,7 +910,7 @@ void AstTypeTable::repairCache() {
|
|||
|
||||
AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
|
||||
if (VL_UNLIKELY(!m_emptyQueuep)) {
|
||||
AstEmptyQueueDType* newp = new AstEmptyQueueDType{fl};
|
||||
AstEmptyQueueDType* const newp = new AstEmptyQueueDType{fl};
|
||||
addTypesp(newp);
|
||||
m_emptyQueuep = newp;
|
||||
}
|
||||
|
|
@ -943,7 +919,7 @@ AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
|
|||
|
||||
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
||||
if (VL_UNLIKELY(!m_voidp)) {
|
||||
AstVoidDType* newp = new AstVoidDType{fl};
|
||||
AstVoidDType* const newp = new AstVoidDType{fl};
|
||||
addTypesp(newp);
|
||||
m_voidp = newp;
|
||||
}
|
||||
|
|
@ -952,7 +928,7 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|||
|
||||
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
||||
if (VL_UNLIKELY(!m_queueIndexp)) {
|
||||
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
|
||||
AstQueueDType* const newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
|
||||
addTypesp(newp);
|
||||
m_queueIndexp = newp;
|
||||
}
|
||||
|
|
@ -962,11 +938,11 @@ AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
|||
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
|
||||
if (m_basicps[kwd]) return m_basicps[kwd];
|
||||
//
|
||||
AstBasicDType* new1p = new AstBasicDType(fl, kwd);
|
||||
AstBasicDType* const new1p = new AstBasicDType(fl, kwd);
|
||||
// Because the detailed map doesn't update this map,
|
||||
// check the detailed map for this same node
|
||||
// Also adds this new node to the detailed map
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
AstBasicDType* const newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) {
|
||||
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
||||
} else {
|
||||
|
|
@ -979,8 +955,8 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd)
|
|||
|
||||
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width,
|
||||
int widthMin, VSigning numeric) {
|
||||
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
|
||||
AstBasicDType* const newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) {
|
||||
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
||||
} else {
|
||||
|
|
@ -992,8 +968,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
|
|||
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
|
||||
const VNumRange& range, int widthMin,
|
||||
VSigning numeric) {
|
||||
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
|
||||
AstBasicDType* const newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) {
|
||||
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
||||
} else {
|
||||
|
|
@ -1003,8 +979,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
|
|||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
||||
VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
||||
nodep->nrange());
|
||||
const VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
||||
nodep->nrange());
|
||||
DetailedMap& mapr = m_detailedMap;
|
||||
const auto it = mapr.find(key);
|
||||
if (it != mapr.end()) return it->second;
|
||||
|
|
@ -1041,10 +1017,8 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
|
|||
// - the default/inititem children might be in different order yet still yield the same table
|
||||
// See note in AstInitArray::same about the same. This function instead compares by initializer
|
||||
// value, rather than by tree structure.
|
||||
const AstUnpackArrayDType* const aDTypep = VN_CAST(ap->dtypep(), UnpackArrayDType);
|
||||
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
|
||||
UASSERT_STATIC(aDTypep, "Bad type in array initializer");
|
||||
UASSERT_STATIC(bDTypep, "Bad type in array initializer");
|
||||
const AstUnpackArrayDType* const aDTypep = VN_AS(ap->dtypep(), UnpackArrayDType);
|
||||
const AstUnpackArrayDType* const bDTypep = VN_AS(bp->dtypep(), UnpackArrayDType);
|
||||
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) { // Element types differ
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1063,14 +1037,14 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
|
|||
}
|
||||
|
||||
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
|
||||
AstNode* const defaultp = initp->defaultp();
|
||||
const AstNode* const defaultp = initp->defaultp();
|
||||
// Verify initializer is well formed
|
||||
UASSERT_OBJ(VN_IS(initp->dtypep(), UnpackArrayDType), initp,
|
||||
"Const pool table must have AstUnpackArrayDType dtype");
|
||||
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
|
||||
"Const pool table default must be Const");
|
||||
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {
|
||||
AstNode* const valuep = VN_CAST(nodep, InitItem)->valuep();
|
||||
const AstNode* const valuep = VN_AS(nodep, InitItem)->valuep();
|
||||
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
|
||||
}
|
||||
// Try to find an existing table with the same content
|
||||
|
|
@ -1078,7 +1052,7 @@ AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
|
|||
const auto& er = m_tables.equal_range(hash.value());
|
||||
for (auto it = er.first; it != er.second; ++it) {
|
||||
AstVarScope* const varScopep = it->second;
|
||||
const AstInitArray* const init2p = VN_CAST(varScopep->varp()->valuep(), InitArray);
|
||||
const AstInitArray* const init2p = VN_AS(varScopep->varp()->valuep(), InitArray);
|
||||
if (sameInit(initp, init2p)) {
|
||||
return varScopep; // Found identical table
|
||||
}
|
||||
|
|
@ -1107,7 +1081,7 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
|
|||
const auto& er = m_consts.equal_range(hash.value());
|
||||
for (auto it = er.first; it != er.second; ++it) {
|
||||
AstVarScope* const varScopep = it->second;
|
||||
const AstConst* const init2p = VN_CAST(varScopep->varp()->valuep(), Const);
|
||||
const AstConst* const init2p = VN_AS(varScopep->varp()->valuep(), Const);
|
||||
if (sameInit(initp, init2p)
|
||||
&& (mergeDType || varScopep->dtypep()->sameTree(initp->dtypep()))) {
|
||||
return varScopep; // Found identical constant
|
||||
|
|
@ -1218,7 +1192,7 @@ void AstNode::dump(std::ostream& str) const {
|
|||
} else {
|
||||
str << " @dt=" << nodeAddr(dtypep()) << "@";
|
||||
}
|
||||
if (AstNodeDType* dtp = dtypep()) dtp->dumpSmall(str);
|
||||
if (AstNodeDType* const dtp = dtypep()) dtp->dumpSmall(str);
|
||||
} else { // V3Broken will throw an error
|
||||
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
|
||||
}
|
||||
|
|
@ -1284,9 +1258,8 @@ const char* AstClassPackage::broken() const {
|
|||
return nullptr;
|
||||
}
|
||||
void AstClass::insertCache(AstNode* nodep) {
|
||||
const bool doit
|
||||
= (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|
||||
|| (VN_IS(nodep, NodeFTask) && !VN_CAST(nodep, NodeFTask)->isExternProto()));
|
||||
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|
||||
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()));
|
||||
if (doit) {
|
||||
if (m_members.find(nodep->name()) != m_members.end()) {
|
||||
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
|
||||
|
|
@ -1312,9 +1285,9 @@ void AstClass::dump(std::ostream& str) const {
|
|||
if (isVirtual()) str << " [VIRT]";
|
||||
}
|
||||
AstClass* AstClassExtends::classp() const {
|
||||
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
||||
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
||||
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
||||
refp = VN_CAST(childDTypep(), ClassRefDType);
|
||||
refp = VN_AS(childDTypep(), ClassRefDType);
|
||||
}
|
||||
UASSERT_OBJ(refp, this, "class extends non-ref");
|
||||
return refp->classp();
|
||||
|
|
@ -1501,7 +1474,7 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
|||
void AstNodeDType::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (generic()) str << " [GENERIC]";
|
||||
if (AstNodeDType* dtp = virtRefDTypep()) {
|
||||
if (AstNodeDType* const dtp = virtRefDTypep()) {
|
||||
str << " refdt=" << nodeAddr(dtp);
|
||||
dtp->dumpSmall(str);
|
||||
}
|
||||
|
|
@ -1515,7 +1488,7 @@ void AstNodeDType::dumpSmall(std::ostream& str) const {
|
|||
}
|
||||
void AstNodeArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
if (auto* adtypep = VN_CAST_CONST(this, UnpackArrayDType)) {
|
||||
if (auto* const adtypep = VN_CAST(this, UnpackArrayDType)) {
|
||||
// uc = packed compound object, u = unpacked POD
|
||||
str << (adtypep->isCompound() ? "uc" : "u");
|
||||
} else {
|
||||
|
|
@ -1551,7 +1524,7 @@ std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
|
|||
std::vector<AstUnpackArrayDType*> dims;
|
||||
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
|
||||
dims.push_back(unpackp);
|
||||
if (AstNodeDType* subp = unpackp->subDTypep()) {
|
||||
if (AstNodeDType* const subp = unpackp->subDTypep()) {
|
||||
unpackp = VN_CAST(subp, UnpackArrayDType);
|
||||
} else {
|
||||
unpackp = nullptr;
|
||||
|
|
@ -1608,7 +1581,7 @@ void AstMTaskBody::dump(std::ostream& str) const {
|
|||
void AstTypeTable::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
|
||||
if (AstBasicDType* subnodep = m_basicps[i]) {
|
||||
if (AstBasicDType* const subnodep = m_basicps[i]) {
|
||||
str << '\n'; // Newline from caller, so newline first
|
||||
str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii();
|
||||
str << " -> ";
|
||||
|
|
@ -1618,7 +1591,7 @@ void AstTypeTable::dump(std::ostream& str) const {
|
|||
{
|
||||
const DetailedMap& mapr = m_detailedMap;
|
||||
for (const auto& itr : mapr) {
|
||||
AstBasicDType* dtypep = itr.second;
|
||||
AstBasicDType* const dtypep = itr.second;
|
||||
str << '\n'; // Newline from caller, so newline first
|
||||
str << "\t\tdetailed -> ";
|
||||
dtypep->dump(str);
|
||||
|
|
@ -1727,6 +1700,11 @@ void AstScope::dump(std::ostream& str) const {
|
|||
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
|
||||
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
|
||||
}
|
||||
void AstScopeName::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (dpiExport()) str << " [DPIEX]";
|
||||
if (forFormat()) str << " [FMT]";
|
||||
}
|
||||
void AstSenTree::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isMulti()) str << " [MULTI]";
|
||||
|
|
|
|||
381
src/V3AstNodes.h
381
src/V3AstNodes.h
File diff suppressed because it is too large
Load Diff
|
|
@ -103,7 +103,7 @@ public:
|
|||
|
||||
// Get a reference to the user data
|
||||
T_Data& operator()(const T_Node* nodep) {
|
||||
T_Data* userp = getUserp(nodep);
|
||||
T_Data* const userp = getUserp(nodep);
|
||||
UASSERT_OBJ(userp, nodep, "Missing User data on const AstNode");
|
||||
return *userp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNodeFTask::user1 -> bool, 1=processed
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
bool m_anyFuncInBegin = false;
|
||||
|
||||
public:
|
||||
|
|
@ -59,10 +59,11 @@ public:
|
|||
class BeginVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
BeginState* m_statep; // Current global state
|
||||
BeginState* const m_statep; // Current global state
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
|
||||
string m_displayScope; // Name of %m in $display/AstScopeName
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_ifDepth = 0; // Current if depth
|
||||
|
|
@ -111,9 +112,11 @@ private:
|
|||
// naming; so that any begin's inside the function will rename
|
||||
// inside the function.
|
||||
// Process children
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
{
|
||||
m_displayScope = dot(m_displayScope, nodep->name());
|
||||
m_namedScope = "";
|
||||
m_unnamedScope = "";
|
||||
m_ftaskp = nodep;
|
||||
|
|
@ -134,6 +137,7 @@ private:
|
|||
virtual void visit(AstBegin* nodep) override {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8, " " << nodep << endl);
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
{
|
||||
|
|
@ -145,11 +149,14 @@ private:
|
|||
while ((pos = dottedname.find("__DOT__")) != string::npos) {
|
||||
const string ident = dottedname.substr(0, pos);
|
||||
dottedname = dottedname.substr(pos + strlen("__DOT__"));
|
||||
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
|
||||
if (nodep->name() != "") {
|
||||
m_displayScope = dot(m_displayScope, ident);
|
||||
m_namedScope = dot(m_namedScope, ident);
|
||||
}
|
||||
m_unnamedScope = dot(m_unnamedScope, ident);
|
||||
// Create CellInline for dotted var resolution
|
||||
if (!m_ftaskp) {
|
||||
AstCellInline* inlinep = new AstCellInline(
|
||||
AstCellInline* const inlinep = new AstCellInline(
|
||||
nodep->fileline(), m_unnamedScope, "__BEGIN__", m_modp->timeunit());
|
||||
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
|
||||
}
|
||||
|
|
@ -162,7 +169,7 @@ private:
|
|||
|
||||
// Cleanup
|
||||
AstNode* addsp = nullptr;
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
if (AstNode* const stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
if (addsp) {
|
||||
addsp = addsp->addNextNull(stmtsp);
|
||||
|
|
@ -220,11 +227,13 @@ private:
|
|||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Inline
|
||||
if (nodep->user1SetOnce()) return; // Don't double-add text's
|
||||
if (m_namedScope != "") {
|
||||
// DPI svGetScope doesn't include function name, but %m does
|
||||
const string scname = nodep->forFormat() ? m_displayScope : m_namedScope;
|
||||
if (!scname.empty()) {
|
||||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
AstNode* const afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__") + m_namedScope));
|
||||
nodep->scopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -308,8 +317,8 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
|
|||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
BeginState state;
|
||||
{ BeginVisitor bvisitor{nodep, &state}; }
|
||||
if (state.anyFuncInBegin()) { BeginRelinkVisitor brvisitor(nodep, &state); }
|
||||
{ BeginVisitor{nodep, &state}; }
|
||||
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstFTask::user1() -> int. Number of references
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
int m_likely = false; // Excuses for branch likely taken
|
||||
|
|
@ -123,5 +123,5 @@ public:
|
|||
|
||||
void V3Branch::branchAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
BranchVisitor visitor{nodep};
|
||||
{ BranchVisitor{nodep}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,13 +191,13 @@ private:
|
|||
|
||||
void processEnter(AstNode* nodep) {
|
||||
nodep->brokenState(m_brokenCntCurrentUnder);
|
||||
const char* whyp = nodep->broken();
|
||||
const char* const whyp = nodep->broken();
|
||||
UASSERT_OBJ(!whyp, nodep,
|
||||
"Broken link in node (or something without maybePointedTo): " << whyp);
|
||||
if (nodep->dtypep()) {
|
||||
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
|
||||
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
|
||||
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep,
|
||||
"Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
|
||||
}
|
||||
if (v3Global.assertDTypesResolved()) {
|
||||
|
|
@ -210,7 +210,8 @@ private:
|
|||
}
|
||||
UASSERT_OBJ(!nodep->getChildDTypep(), nodep,
|
||||
"childDTypep() non-null on node after should have removed");
|
||||
if (const AstNodeDType* dnodep = VN_CAST(nodep, NodeDType)) checkWidthMin(dnodep);
|
||||
if (const AstNodeDType* const dnodep = VN_CAST(nodep, NodeDType))
|
||||
checkWidthMin(dnodep);
|
||||
}
|
||||
checkWidthMin(nodep);
|
||||
}
|
||||
|
|
@ -242,7 +243,7 @@ private:
|
|||
processAndIterate(nodep);
|
||||
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
|
||||
&& VN_IS(nodep->lhsp(), NodeVarRef)
|
||||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
|
||||
&& !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
|
||||
nodep, "Assignment LHS is not an lvalue");
|
||||
}
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
|
|
@ -342,8 +343,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
|
|||
UINFO(1, "Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
|
||||
} else {
|
||||
inBroken = true;
|
||||
BrokenMarkVisitor mvisitor{nodep};
|
||||
BrokenCheckVisitor cvisitor{nodep};
|
||||
const BrokenMarkVisitor mvisitor{nodep};
|
||||
const BrokenCheckVisitor cvisitor{nodep};
|
||||
s_allocTable.checkForLeaks();
|
||||
s_linkableTable.clear();
|
||||
s_brokenCntGlobal.inc();
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
enum en : uint8_t { MODULE, CLASS, COVERAGE };
|
||||
|
||||
private:
|
||||
enum en m_e;
|
||||
const enum en m_e;
|
||||
|
||||
public:
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
|
|
@ -139,7 +139,8 @@ void V3CCtors::evalAsserts() {
|
|||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* const varp = VN_CAST(np, Var)) {
|
||||
if (varp->isPrimaryInish() && !varp->isSc()) {
|
||||
if (AstBasicDType* basicp = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
|
||||
if (const AstBasicDType* const basicp
|
||||
= VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
|
||||
const int storedWidth = basicp->widthAlignBytes() * 8;
|
||||
const int lastWordWidth = varp->width() % storedWidth;
|
||||
if (lastWordWidth != 0) {
|
||||
|
|
@ -175,7 +176,7 @@ void V3CCtors::cctorsAll() {
|
|||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
evalAsserts();
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
modp = VN_AS(modp->nextp(), NodeModule)) {
|
||||
// Process each module in turn
|
||||
{
|
||||
V3CCtorsBuilder var_reset{modp, "_ctor_var_reset",
|
||||
|
|
@ -200,7 +201,7 @@ void V3CCtors::cctorsAll() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
AstCFunc* const funcp = new AstCFunc{modp->fileline(), "~", nullptr, ""};
|
||||
funcp->isDestructor(true);
|
||||
funcp->isStatic(false);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
class CUseVisitor final : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> bool. True if already visited
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// MEMBERS
|
||||
bool m_impOnly = false; // In details needed only for implementation
|
||||
|
|
@ -100,7 +100,7 @@ void V3CUse::cUseAll() {
|
|||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// Call visitor separately for each module, so visitor state is cleared
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
modp = VN_AS(modp->nextp(), NodeModule)) {
|
||||
// Insert under this module; someday we should e.g. make Ast
|
||||
// for each output file and put under that
|
||||
CUseVisitor{modp};
|
||||
|
|
|
|||
|
|
@ -52,20 +52,20 @@
|
|||
|
||||
class CaseLintVisitor final : public AstNVisitor {
|
||||
private:
|
||||
AstNodeCase* m_caseExprp
|
||||
const AstNodeCase* m_caseExprp
|
||||
= nullptr; // Under a CASE value node, if so the relevant case statement
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
virtual void visit(AstNodeCase* nodep) override {
|
||||
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
|
||||
if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) {
|
||||
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
|
||||
}
|
||||
// Detect multiple defaults
|
||||
bool hitDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
if (itemp->isDefault()) {
|
||||
if (hitDefault) {
|
||||
itemp->v3error("Multiple default statements in case statement.");
|
||||
|
|
@ -79,7 +79,7 @@ private:
|
|||
m_caseExprp = nodep;
|
||||
iterate(nodep->exprp());
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
iterateAndNextNull(itemp->condsp());
|
||||
}
|
||||
m_caseExprp = nullptr;
|
||||
|
|
@ -91,11 +91,11 @@ private:
|
|||
if (VN_IS(m_caseExprp, GenCase)) {
|
||||
nodep->v3error("Use of x/? constant in generate case statement, "
|
||||
"(no such thing as 'generate casez')");
|
||||
} else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) {
|
||||
} else if (VN_IS(m_caseExprp, Case) && VN_AS(m_caseExprp, Case)->casex()) {
|
||||
// Don't sweat it, we already complained about casex in general
|
||||
} else if (VN_IS(m_caseExprp, Case)
|
||||
&& (VN_CAST(m_caseExprp, Case)->casez()
|
||||
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
|
||||
&& (VN_AS(m_caseExprp, Case)->casez()
|
||||
|| VN_AS(m_caseExprp, Case)->caseInside())) {
|
||||
if (nodep->num().isAnyX()) {
|
||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
|
||||
"(perhaps intended ?/z in constant)");
|
||||
|
|
@ -122,12 +122,12 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared each Case
|
||||
// AstIf::user3() -> bool. Set true to indicate clone not needed
|
||||
AstUser3InUse m_inuser3;
|
||||
const AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
VDouble0 m_statCaseFast; // Statistic tracking
|
||||
VDouble0 m_statCaseSlow; // Statistic tracking
|
||||
AstNode* m_alwaysp = nullptr; // Always in which case is located
|
||||
const AstNode* m_alwaysp = nullptr; // Always in which case is located
|
||||
|
||||
// Per-CASE
|
||||
int m_caseWidth = 0; // Width of valueItems
|
||||
|
|
@ -145,7 +145,7 @@ private:
|
|||
m_caseItems = 0;
|
||||
m_caseNoOverlapsAllCovered = true;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
if (icondp->width() > width) width = icondp->width();
|
||||
if (icondp->isDouble()) opaque = true;
|
||||
|
|
@ -159,7 +159,7 @@ private:
|
|||
return false; // Too wide for analysis
|
||||
}
|
||||
UINFO(8, "Simple case statement: " << nodep << endl);
|
||||
uint32_t numCases = 1UL << m_caseWidth;
|
||||
const uint32_t numCases = 1UL << m_caseWidth;
|
||||
// Zero list of items for each value
|
||||
for (uint32_t i = 0; i < numCases; ++i) m_valueItem[i] = nullptr;
|
||||
// Now pick up the values for each assignment
|
||||
|
|
@ -167,20 +167,20 @@ private:
|
|||
bool reportedOverlap = false;
|
||||
bool reportedSubcase = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
// if (debug() >= 9) icondp->dumpTree(cout, " caseitem: ");
|
||||
AstConst* iconstp = VN_CAST(icondp, Const);
|
||||
AstConst* const iconstp = VN_AS(icondp, Const);
|
||||
UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this");
|
||||
if (neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
} else {
|
||||
V3Number nummask(itemp, iconstp->width());
|
||||
nummask.opBitsNonX(iconstp->num());
|
||||
uint32_t mask = nummask.toUInt();
|
||||
const uint32_t mask = nummask.toUInt();
|
||||
V3Number numval(itemp, iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
uint32_t val = numval.toUInt();
|
||||
const uint32_t val = numval.toUInt();
|
||||
|
||||
uint32_t firstOverlap = 0;
|
||||
bool foundOverlap = false;
|
||||
|
|
@ -190,7 +190,7 @@ private:
|
|||
if (!m_valueItem[i]) {
|
||||
m_valueItem[i] = itemp;
|
||||
foundHit = true;
|
||||
} else if (!foundOverlap && !itemp->ignoreOverlap()) {
|
||||
} else if (!foundOverlap) {
|
||||
firstOverlap = i;
|
||||
foundOverlap = true;
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
|
|
@ -244,7 +244,7 @@ private:
|
|||
// Convert valueItem from AstCaseItem* to the expression
|
||||
// Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch
|
||||
for (uint32_t i = 0; i < numCases; ++i) {
|
||||
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
|
||||
m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->bodysp();
|
||||
}
|
||||
return true; // All is fine
|
||||
}
|
||||
|
|
@ -289,10 +289,11 @@ private:
|
|||
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
|
||||
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
|
||||
// new AstConst(cexprp->fileline(), nummask));
|
||||
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
|
||||
AstNode* eqp
|
||||
AstNode* const and1p
|
||||
= new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
|
||||
AstNode* const eqp
|
||||
= new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p);
|
||||
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
|
||||
AstIf* const ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
|
||||
ifp->user3(1); // So we don't bother to clone it
|
||||
return ifp;
|
||||
}
|
||||
|
|
@ -302,11 +303,11 @@ private:
|
|||
// CASEx(cexpr,....
|
||||
// -> tree of IF(msb, IF(msb-1, 11, 10)
|
||||
// IF(msb-1, 01, 00))
|
||||
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
|
||||
|
||||
if (debug() >= 9) { // LCOV_EXCL_START
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
if (AstNode* itemp = m_valueItem[i]) {
|
||||
if (const AstNode* const itemp = m_valueItem[i]) {
|
||||
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
|
||||
}
|
||||
}
|
||||
|
|
@ -335,13 +336,13 @@ private:
|
|||
// -> IF((cexpr==icond1),istmts1,
|
||||
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
|
||||
// ,istmts2, istmts3
|
||||
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
|
||||
// We'll do this in two stages. First stage, convert the conditions to
|
||||
// the appropriate IF AND terms.
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: ");
|
||||
bool hadDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->condsp()) {
|
||||
// Default clause. Just make true, we'll optimize it away later
|
||||
itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue()));
|
||||
|
|
@ -355,7 +356,7 @@ private:
|
|||
icondp->unlinkFrBack();
|
||||
|
||||
AstNode* condp = nullptr; // Default is to use and1p/and2p
|
||||
AstConst* iconstp = VN_CAST(icondp, Const);
|
||||
AstConst* const iconstp = VN_CAST(icondp, Const);
|
||||
if (iconstp && neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp);
|
||||
|
|
@ -363,7 +364,7 @@ private:
|
|||
// For simplicity, make expression that is not equal, and let later
|
||||
// optimizations remove it
|
||||
condp = new AstConst(itemp->fileline(), AstConst::BitFalse());
|
||||
} else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) {
|
||||
} else if (AstInsideRange* const irangep = VN_CAST(icondp, InsideRange)) {
|
||||
// Similar logic in V3Width::visit(AstInside)
|
||||
condp = irangep->newAndFromInside(cexprp, irangep->lhsp()->unlinkFrBack(),
|
||||
irangep->rhsp()->unlinkFrBack());
|
||||
|
|
@ -373,18 +374,19 @@ private:
|
|||
nummask.opBitsNonX(iconstp->num());
|
||||
V3Number numval(itemp, iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* and2p = new AstAnd(itemp->fileline(),
|
||||
new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* const and1p
|
||||
= new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* const and2p = new AstAnd(
|
||||
itemp->fileline(), new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp);
|
||||
VL_DANGLING(iconstp);
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
|
||||
AstNode* and1p = cexprp->cloneTree(false);
|
||||
AstNode* and2p = icondp;
|
||||
AstNode* const and1p = cexprp->cloneTree(false);
|
||||
AstNode* const and2p = icondp;
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
}
|
||||
if (!ifexprp) {
|
||||
|
|
@ -416,16 +418,16 @@ private:
|
|||
AstIf* groupnextp = nullptr;
|
||||
AstIf* itemnextp = nullptr;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
AstNode* const istmtsp = itemp->bodysp(); // Maybe null -- no action.
|
||||
if (istmtsp) istmtsp->unlinkFrBackWithNext();
|
||||
// Expressioned clause
|
||||
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
|
||||
AstNode* const ifexprp = itemp->condsp()->unlinkFrBack();
|
||||
{ // Prepare for next group
|
||||
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
|
||||
if (depth == 1) { // First group or starting new group
|
||||
itemnextp = nullptr;
|
||||
AstIf* newp
|
||||
AstIf* const newp
|
||||
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), nullptr, nullptr);
|
||||
if (groupnextp) {
|
||||
groupnextp->addElsesp(newp);
|
||||
|
|
@ -434,7 +436,7 @@ private:
|
|||
}
|
||||
groupnextp = newp;
|
||||
} else { // Continue group, modify if condition to OR in this new condition
|
||||
AstNode* condp = groupnextp->condp()->unlinkFrBack();
|
||||
AstNode* const condp = groupnextp->condp()->unlinkFrBack();
|
||||
groupnextp->condp(
|
||||
new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true)));
|
||||
}
|
||||
|
|
@ -446,7 +448,7 @@ private:
|
|||
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::BitTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
|
||||
AstIf* const newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
|
||||
if (itemnextp) {
|
||||
itemnextp->addElsesp(newp);
|
||||
} else {
|
||||
|
|
@ -474,7 +476,7 @@ private:
|
|||
// covered, we're done with it.
|
||||
// Else, convert to a normal statement parallel with the case statement.
|
||||
if (nodep->notParallelp() && !noOverlapsAllCovered) {
|
||||
AstNode* parp = nodep->notParallelp()->unlinkFrBackWithNext();
|
||||
AstNode* const parp = nodep->notParallelp()->unlinkFrBackWithNext();
|
||||
nodep->addNextHere(parp);
|
||||
}
|
||||
}
|
||||
|
|
@ -530,10 +532,10 @@ public:
|
|||
|
||||
void V3Case::caseAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CaseVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ CaseVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
void V3Case::caseLint(AstNodeCase* nodep) {
|
||||
UINFO(4, __FUNCTION__ << ": " << endl);
|
||||
CaseLintVisitor visitor{nodep};
|
||||
{ CaseLintVisitor{nodep}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNode::user() // bool. Indicates node is of known size
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
AstNode* const backp = nodep->backp();
|
||||
const AstNode* const backp = nodep->backp();
|
||||
if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath)
|
||||
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) && backp->width()
|
||||
&& castSize(nodep) != castSize(nodep->varp())) {
|
||||
|
|
@ -203,6 +203,6 @@ public:
|
|||
|
||||
void V3Cast::castAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CastVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ CastVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ public:
|
|||
// Graph support classes
|
||||
|
||||
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstScope* const m_scopep;
|
||||
AstNode* const m_nodep;
|
||||
AstSenTree* m_srcDomainp = nullptr;
|
||||
AstSenTree* m_dstDomainp = nullptr;
|
||||
bool m_srcDomainSet : 1;
|
||||
|
|
@ -84,7 +84,7 @@ public:
|
|||
};
|
||||
|
||||
class CdcVarVertex final : public CdcEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
AstVarScope* const m_varScp;
|
||||
int m_cntAsyncRst = 0;
|
||||
bool m_fromFlop = false;
|
||||
|
||||
|
|
@ -217,15 +217,15 @@ private:
|
|||
// AstVarScope::user2 -> bool Used in sensitivity list
|
||||
// {statement}Node::user1p -> CdcLogicVertex* for this statement
|
||||
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
const AstUser1InUse m_inuser1;
|
||||
const AstUser2InUse m_inuser2;
|
||||
const AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
|
||||
AstScope* m_scopep = nullptr; // Current scope being processed
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstSenTree* m_domainp = nullptr; // Current sentree
|
||||
bool m_inDly = false; // In delayed assign
|
||||
int m_inSenItem = 0; // Number of senitems
|
||||
|
|
@ -266,7 +266,7 @@ private:
|
|||
if (varscp->varp()->isPrimaryIO()) {
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are
|
||||
// now This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* ioVertexp
|
||||
CdcLogicVertex* const ioVertexp
|
||||
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), nullptr);
|
||||
if (varscp->varp()->isWritable()) {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
|
|
@ -337,7 +337,7 @@ private:
|
|||
|
||||
int filelineWidth() {
|
||||
if (!m_filelineWidth) {
|
||||
CdcWidthVisitor visitor{v3Global.rootp()};
|
||||
const CdcWidthVisitor visitor{v3Global.rootp()};
|
||||
m_filelineWidth = visitor.maxWidth();
|
||||
}
|
||||
return m_filelineWidth;
|
||||
|
|
@ -351,12 +351,12 @@ private:
|
|||
// userClearVertices is very slow, so we use a generation count instead
|
||||
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (vvertexp->cntAsyncRst()) {
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
UINFO(8, " Trace One async: " << vvertexp << endl);
|
||||
// Twice, as we need to detect, then propagate
|
||||
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
|
||||
CdcEitherVertex* const markp = traceAsyncRecurse(vvertexp, false);
|
||||
if (markp) { // Mark is non-nullptr if something bad on this path
|
||||
UINFO(9, " Trace One bad! " << vvertexp << endl);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
|
|
@ -381,17 +381,18 @@ private:
|
|||
// Clear out in prep for marking next path
|
||||
if (!mark) vertexp->asyncPath(false);
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Any logic considered bad, at the moment, anyhow
|
||||
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
|
||||
// And keep tracing back so the user can understand what's up
|
||||
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
} else if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
if (mark) vvertexp->asyncPath(true);
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
|
||||
// Show the source "input" statement if it exists
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* const eFromVertexp
|
||||
= static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -399,7 +400,8 @@ private:
|
|||
// Also ok if from flop, but partially trace the flop so more obvious to users
|
||||
if (vvertexp->fromFlop()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* const eFromVertexp
|
||||
= static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -407,8 +409,8 @@ private:
|
|||
}
|
||||
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
|
||||
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* const submarkp = traceAsyncRecurse(eFromVertexp, mark);
|
||||
if (submarkp && !mark_outp) mark_outp = submarkp;
|
||||
}
|
||||
|
||||
|
|
@ -417,14 +419,14 @@ private:
|
|||
}
|
||||
|
||||
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
|
||||
AstNode* nodep = vertexp->varScp();
|
||||
const AstNode* const nodep = vertexp->varScp();
|
||||
*m_ofp << "\n";
|
||||
*m_ofp << "\n";
|
||||
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
if (!eToVertexp) targetp = eToVertexp;
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (vvertexp->isFlop() // IE the target flop that is upsetting us
|
||||
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
|
||||
targetp = eToVertexp;
|
||||
|
|
@ -452,14 +454,14 @@ private:
|
|||
const string cont = prefix + sep;
|
||||
string nextsep = " ";
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
|
||||
}
|
||||
|
||||
// Dump single variable/logic block
|
||||
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
|
||||
AstNode* nodep = vertexp->nodep();
|
||||
string front
|
||||
AstNode* const nodep = vertexp->nodep();
|
||||
const string front
|
||||
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
|
||||
if (VN_IS(nodep, VarScope)) {
|
||||
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
|
||||
|
|
@ -473,7 +475,7 @@ private:
|
|||
if (level)
|
||||
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Now that we've printed a path with this hazard, don't bother to print any more
|
||||
// Otherwise, we'd get a path for almost every destination flop
|
||||
vvertexp->clearHazard();
|
||||
|
|
@ -499,7 +501,7 @@ private:
|
|||
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
|
||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
UINFO(9, " Trace One edge: " << vvertexp << endl);
|
||||
edgeDomainRecurse(vvertexp, traceDests, 0);
|
||||
}
|
||||
|
|
@ -514,8 +516,8 @@ private:
|
|||
|
||||
std::deque<string> report; // Sort output by name
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
const AstVar* const varp = vvertexp->varScp()->varp();
|
||||
{
|
||||
string what = "wire";
|
||||
if (varp->isPrimaryIO()) what = varp->direction().prettyName();
|
||||
|
|
@ -558,11 +560,11 @@ private:
|
|||
} // Fully computed
|
||||
|
||||
std::set<AstSenTree*> senouts; // List of all sensitivities for new signal
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (vvertexp) {} // Unused
|
||||
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
} else if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
// If primary I/O, give it domain of the input
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
const AstVar* const varp = vvertexp->varScp()->varp();
|
||||
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
|
||||
senouts.insert(new AstSenTree(
|
||||
varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
|
|
@ -572,13 +574,14 @@ private:
|
|||
// Now combine domains of sources/dests
|
||||
if (traceDests) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
|
||||
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
|
||||
}
|
||||
} else {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* const eFromVertexp
|
||||
= static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
|
||||
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
|
||||
}
|
||||
|
|
@ -599,7 +602,7 @@ private:
|
|||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
if (senedited) senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree);
|
||||
if (senedited) senoutp = VN_AS(V3Const::constifyExpensiveEdit(senoutp), SenTree);
|
||||
if (traceDests) {
|
||||
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->dstDomainp(senoutp);
|
||||
|
|
@ -653,9 +656,9 @@ private:
|
|||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
AstVarScope* const varscp = nodep->varScopep();
|
||||
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
CdcVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
CdcVarVertex* const varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5, " VARREF to " << varscp << endl);
|
||||
// We use weight of one for normal edges,
|
||||
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
|
||||
|
|
@ -758,5 +761,5 @@ public:
|
|||
|
||||
void V3Cdc::cdcAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
CdcVisitor visitor{nodep};
|
||||
{ CdcVisitor{nodep}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public:
|
|||
// Each change detection function needs at least one AstChangeDet
|
||||
// to ensure that V3EmitC outputs the necessary code.
|
||||
maybeCreateMidChg();
|
||||
m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr, false});
|
||||
m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr});
|
||||
}
|
||||
void maybeCreateMidChg() {
|
||||
// Don't create an extra function call if splitting is disabled
|
||||
|
|
@ -94,7 +94,7 @@ public:
|
|||
if (!m_tlChgFuncp->stmtsp()) {
|
||||
m_tlChgFuncp->addStmtsp(new AstCReturn{m_scopetopp->fileline(), callp});
|
||||
} else {
|
||||
AstCReturn* const returnp = VN_CAST(m_tlChgFuncp->stmtsp(), CReturn);
|
||||
AstCReturn* const returnp = VN_AS(m_tlChgFuncp->stmtsp(), CReturn);
|
||||
UASSERT_OBJ(returnp, m_scopetopp, "Lost CReturn in top change function");
|
||||
// This is currently using AstLogOr which will shortcut the
|
||||
// evaluation if any function returns true. This is likely what
|
||||
|
|
@ -146,7 +146,7 @@ private:
|
|||
m_statep->maybeCreateChgFuncp();
|
||||
|
||||
AstChangeDet* const changep = new AstChangeDet{
|
||||
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true), false};
|
||||
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true)};
|
||||
m_statep->m_chgFuncp->addStmtsp(changep);
|
||||
AstAssign* const initp = new AstAssign{m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
|
||||
m_varEqnp->cloneTree(true)};
|
||||
|
|
@ -154,7 +154,7 @@ private:
|
|||
|
||||
// Later code will expand words which adds to GCC compile time,
|
||||
// so add penalty based on word width also
|
||||
EmitCBaseCounterVisitor visitor{initp};
|
||||
const EmitCBaseCounterVisitor visitor{initp};
|
||||
m_statep->m_numStmts += visitor.count() + m_varEqnp->widthWords();
|
||||
}
|
||||
|
||||
|
|
@ -214,8 +214,8 @@ public:
|
|||
m_detects = 0;
|
||||
{
|
||||
AstVar* const varp = m_vscp->varp();
|
||||
string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
|
||||
+ varp->shortName()};
|
||||
const string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
|
||||
+ varp->shortName()};
|
||||
// Create: VARREF(_last)
|
||||
// ASSIGN(VARREF(_last), VARREF(var))
|
||||
// ...
|
||||
|
|
@ -247,17 +247,17 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstVarScope::user1() -> bool. True indicates processed
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
ChangedState* const m_statep; // Shared state across visitors
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void genChangeDet(AstVarScope* vscp) {
|
||||
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
|
||||
ChangedInsertVisitor visitor{vscp, m_statep};
|
||||
{ ChangedInsertVisitor{vscp, m_statep}; }
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
|
@ -304,7 +304,7 @@ void V3Changed::changedAll(AstNetlist* nodep) {
|
|||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
ChangedState state;
|
||||
ChangedVisitor visitor{nodep, &state};
|
||||
ChangedVisitor{nodep, &state};
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@
|
|||
class ClassVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// MEMBERS
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
string m_prefix; // String prefix to add to name based on hier
|
||||
AstScope* m_classScopep = nullptr; // Package moving scopes into
|
||||
const AstScope* m_classScopep = nullptr; // Package moving scopes into
|
||||
AstScope* m_packageScopep = nullptr; // Class package scope
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current task
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current task
|
||||
std::vector<std::pair<AstNode*, AstScope*>> m_moves;
|
||||
|
||||
// NODE STATE
|
||||
|
|
@ -53,27 +53,30 @@ private:
|
|||
v3Global.rootp()->addModulep(nodep);
|
||||
// Make containing package
|
||||
// Note origName is the same as the class origName so errors look correct
|
||||
AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName());
|
||||
AstClassPackage* const packagep
|
||||
= new AstClassPackage(nodep->fileline(), nodep->origName());
|
||||
packagep->name(nodep->name() + "__Vclpkg");
|
||||
nodep->classOrPackagep(packagep);
|
||||
packagep->classp(nodep);
|
||||
v3Global.rootp()->addModulep(packagep);
|
||||
// Add package to hierarchy
|
||||
AstCell* cellp = new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
|
||||
packagep->name(), nullptr, nullptr, nullptr);
|
||||
AstCell* const cellp
|
||||
= new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
|
||||
packagep->name(), nullptr, nullptr, nullptr);
|
||||
cellp->modp(packagep);
|
||||
v3Global.rootp()->topModulep()->addStmtp(cellp);
|
||||
// Find class's scope
|
||||
// Alternative would be to move this and related to V3Scope
|
||||
AstScope* classScopep = nullptr;
|
||||
const AstScope* classScopep = nullptr;
|
||||
for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) {
|
||||
if ((classScopep = VN_CAST(itp, Scope))) break;
|
||||
}
|
||||
UASSERT_OBJ(classScopep, nodep, "No scope under class");
|
||||
|
||||
// Add scope
|
||||
AstScope* scopep = new AstScope(nodep->fileline(), packagep, classScopep->name(),
|
||||
classScopep->aboveScopep(), classScopep->aboveCellp());
|
||||
AstScope* const scopep
|
||||
= new AstScope(nodep->fileline(), packagep, classScopep->name(),
|
||||
classScopep->aboveScopep(), classScopep->aboveCellp());
|
||||
packagep->addStmtp(scopep);
|
||||
// Iterate
|
||||
VL_RESTORER(m_prefix);
|
||||
|
|
@ -141,8 +144,9 @@ public:
|
|||
if (VN_IS(moved.first, NodeFTask)) {
|
||||
moved.second->addActivep(moved.first->unlinkFrBack());
|
||||
} else if (VN_IS(moved.first, Var)) {
|
||||
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
|
||||
moved.second->addVarp(scopep->unlinkFrBack());
|
||||
AstVarScope* const scopep = VN_AS(moved.first->user1p(), VarScope);
|
||||
scopep->unlinkFrBack();
|
||||
moved.second->addVarp(scopep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -153,6 +157,6 @@ public:
|
|||
|
||||
void V3Class::classAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ClassVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ ClassVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,15 +42,15 @@ private:
|
|||
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
|
||||
// AstNode::user2() -> bool. True indicates widthMin has been propagated
|
||||
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
const AstUser1InUse m_inuser1;
|
||||
const AstUser2InUse m_inuser2;
|
||||
const AstUser3InUse m_inuser3;
|
||||
|
||||
// TYPES
|
||||
enum CleanState : uint8_t { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr;
|
||||
const AstNodeModule* m_modp = nullptr;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -67,16 +67,16 @@ private:
|
|||
}
|
||||
void setCppWidth(AstNode* nodep) {
|
||||
nodep->user2(true); // Don't resize it again
|
||||
AstNodeDType* old_dtypep = nodep->dtypep();
|
||||
AstNodeDType* const old_dtypep = nodep->dtypep();
|
||||
const int width = cppWidth(nodep); // widthMin is unchanged
|
||||
if (old_dtypep->width() != width) {
|
||||
// Since any given dtype's cppWidth() is the same, we can just
|
||||
// remember one conversion for each, and reuse it
|
||||
if (AstNodeDType* new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
|
||||
if (AstNodeDType* const new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
|
||||
nodep->dtypep(new_dtypep);
|
||||
} else {
|
||||
nodep->dtypeChgWidth(width, nodep->widthMin());
|
||||
AstNodeDType* new_dtypep2 = nodep->dtypep();
|
||||
AstNodeDType* const new_dtypep2 = nodep->dtypep();
|
||||
UASSERT_OBJ(new_dtypep2 != old_dtypep, nodep,
|
||||
"Dtype didn't change when width changed");
|
||||
old_dtypep->user3p(new_dtypep2); // Remember for next time
|
||||
|
|
@ -126,7 +126,7 @@ private:
|
|||
computeCppWidth(nodep);
|
||||
V3Number mask(nodep, cppWidth(nodep));
|
||||
mask.setMask(nodep->widthMin());
|
||||
AstNode* cleanp
|
||||
AstNode* const cleanp
|
||||
= new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), mask), nodep);
|
||||
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
|
||||
relinkHandle.relink(cleanp);
|
||||
|
|
@ -138,7 +138,7 @@ private:
|
|||
void ensureCleanAndNext(AstNode* nodep) {
|
||||
// Editing list, careful looping!
|
||||
for (AstNode* exprp = nodep; exprp;) {
|
||||
AstNode* nextp = exprp->nextp();
|
||||
AstNode* const nextp = exprp->nextp();
|
||||
ensureClean(exprp);
|
||||
exprp = nextp;
|
||||
}
|
||||
|
|
@ -314,6 +314,6 @@ public:
|
|||
|
||||
void V3Clean::cleanAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CleanVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ CleanVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,11 +73,11 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared each Module:
|
||||
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstTopScope* m_topScopep = nullptr; // Current top scope
|
||||
const AstTopScope* m_topScopep = nullptr; // Current top scope
|
||||
AstScope* m_scopep = nullptr; // Current scope
|
||||
AstCFunc* m_evalFuncp = nullptr; // Top eval function we are creating
|
||||
AstCFunc* m_initFuncp = nullptr; // Top initial function we are creating
|
||||
|
|
@ -92,30 +92,30 @@ private:
|
|||
|
||||
AstVarScope* getCreateLastClk(AstVarScope* vscp) {
|
||||
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
|
||||
AstVar* varp = vscp->varp();
|
||||
const AstVar* const varp = vscp->varp();
|
||||
if (!varp->width1()) {
|
||||
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
|
||||
<< varp->prettyNameQ());
|
||||
}
|
||||
string newvarname
|
||||
const string newvarname
|
||||
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
|
||||
AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
|
||||
VFlagLogicPacked(), 1);
|
||||
AstVar* const newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
|
||||
VFlagLogicPacked(), 1);
|
||||
newvarp->noReset(true); // Reset by below assign
|
||||
m_modp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
|
||||
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
|
||||
vscp->user1p(newvscp);
|
||||
m_scopep->addVarp(newvscp);
|
||||
// Add init
|
||||
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
|
||||
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
|
||||
AstNode* newinitp = new AstAssign(
|
||||
AstNode* const newinitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
|
||||
addToInitial(newinitp);
|
||||
// At bottom, assign them
|
||||
AstAssign* finalp = new AstAssign(vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
AstAssign* const finalp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
m_evalFuncp->addFinalsp(finalp);
|
||||
//
|
||||
UINFO(4, "New Last: " << newvscp << endl);
|
||||
|
|
@ -137,16 +137,16 @@ private:
|
|||
return nullptr;
|
||||
}
|
||||
UASSERT_OBJ(nodep->varrefp(), nodep, "No clock found on sense item");
|
||||
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
||||
AstVarScope* const clkvscp = nodep->varrefp()->varScopep();
|
||||
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
|
|
@ -154,7 +154,7 @@ private:
|
|||
VAccess::READ)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstXor(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
|
||||
|
|
@ -172,7 +172,7 @@ private:
|
|||
AstNode* createSenseEquation(AstSenItem* nodesp) {
|
||||
// Nodep may be a list of elements; we need to walk it
|
||||
AstNode* senEqnp = nullptr;
|
||||
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||
AstNode* const senOnep = createSenItemEquation(senp);
|
||||
if (senEqnp) {
|
||||
// Add new OR to the sensitivity list equation
|
||||
|
|
@ -184,9 +184,9 @@ private:
|
|||
return senEqnp;
|
||||
}
|
||||
AstIf* makeActiveIf(AstSenTree* sensesp) {
|
||||
AstNode* senEqnp = createSenseEquation(sensesp->sensesp());
|
||||
AstNode* const senEqnp = createSenseEquation(sensesp->sensesp());
|
||||
UASSERT_OBJ(senEqnp, sensesp, "No sense equation, shouldn't be in sequent activation.");
|
||||
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
|
||||
AstIf* const newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
|
||||
return newifp;
|
||||
}
|
||||
void clearLastSen() {
|
||||
|
|
@ -215,11 +215,11 @@ private:
|
|||
AstCFunc* funcp = nullptr;
|
||||
|
||||
// Unlink all statements, then add item by item to new sub-functions
|
||||
AstBegin* tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
|
||||
ofuncp->stmtsp()->unlinkFrBackWithNext()};
|
||||
AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
|
||||
ofuncp->stmtsp()->unlinkFrBackWithNext()};
|
||||
if (ofuncp->finalsp()) tempp->addStmtsp(ofuncp->finalsp()->unlinkFrBackWithNext());
|
||||
while (tempp->stmtsp()) {
|
||||
AstNode* itemp = tempp->stmtsp()->unlinkFrBack();
|
||||
AstNode* const itemp = tempp->stmtsp()->unlinkFrBack();
|
||||
const int stmts = EmitCBaseCounterVisitor(itemp).count();
|
||||
if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) {
|
||||
// Make a new function
|
||||
|
|
@ -231,7 +231,7 @@ private:
|
|||
funcp->slow(ofuncp->slow());
|
||||
m_topScopep->scopep()->addActivep(funcp);
|
||||
//
|
||||
AstCCall* callp = new AstCCall{funcp->fileline(), funcp};
|
||||
AstCCall* const callp = new AstCCall{funcp->fileline(), funcp};
|
||||
ofuncp->addStmtsp(callp);
|
||||
func_stmts = 0;
|
||||
}
|
||||
|
|
@ -289,7 +289,7 @@ private:
|
|||
// UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
if (AstNode* movep = nodep->finalClksp()) {
|
||||
if (AstNode* const movep = nodep->finalClksp()) {
|
||||
UASSERT_OBJ(m_topScopep, nodep, "Final clocks under non-top scope");
|
||||
movep->unlinkFrBackWithNext();
|
||||
m_evalFuncp->addFinalsp(movep);
|
||||
|
|
@ -297,7 +297,7 @@ private:
|
|||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeProcedure* nodep) override {
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
if (AstNode* const stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
nodep->addNextHere(stmtsp);
|
||||
}
|
||||
|
|
@ -307,12 +307,12 @@ private:
|
|||
// nodep->dumpTree(cout, "ct:");
|
||||
// COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
AstNode* incp = nodep->incp()->unlinkFrBack();
|
||||
AstNode* origp = nodep->origp()->unlinkFrBack();
|
||||
AstNode* changeWrp = nodep->changep()->unlinkFrBack();
|
||||
AstNode* changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
|
||||
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changeRdp),
|
||||
incp, nullptr);
|
||||
AstNode* const incp = nodep->incp()->unlinkFrBack();
|
||||
AstNode* const origp = nodep->origp()->unlinkFrBack();
|
||||
AstNode* const changeWrp = nodep->changep()->unlinkFrBack();
|
||||
AstNode* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
|
||||
AstIf* const newp = new AstIf(
|
||||
nodep->fileline(), new AstXor(nodep->fileline(), origp, changeRdp), incp, nullptr);
|
||||
// We could add another IF to detect posedges, and only increment if so.
|
||||
// It's another whole branch though versus a potential memory miss.
|
||||
// We'll go with the miss.
|
||||
|
|
@ -325,7 +325,7 @@ private:
|
|||
// Link to global function
|
||||
if (nodep->formCallTree()) {
|
||||
UINFO(4, " formCallTree " << nodep << endl);
|
||||
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
|
||||
AstCCall* const callp = new AstCCall(nodep->fileline(), nodep);
|
||||
m_finalFuncp->addStmtsp(callp);
|
||||
}
|
||||
}
|
||||
|
|
@ -353,7 +353,7 @@ private:
|
|||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else if (m_mtaskBodyp) {
|
||||
UINFO(4, " TR ACTIVE " << nodep << endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (nodep->hasClocked()) {
|
||||
UASSERT_OBJ(!nodep->hasInitial(), nodep,
|
||||
"Initial block should not have clock sensitivity");
|
||||
|
|
@ -378,7 +378,7 @@ private:
|
|||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else {
|
||||
UINFO(4, " ACTIVE " << nodep << endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (nodep->hasClocked()) {
|
||||
// Remember the latest sensitivity so we can compare it next time
|
||||
UASSERT_OBJ(!nodep->hasInitial(), nodep,
|
||||
|
|
@ -412,8 +412,8 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) override {
|
||||
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
|
||||
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
|
||||
for (m_mtaskBodyp = VN_AS(nodep->op1p(), MTaskBody); m_mtaskBodyp;
|
||||
m_mtaskBodyp = VN_AS(m_mtaskBodyp->nextp(), MTaskBody)) {
|
||||
clearLastSen();
|
||||
iterate(m_mtaskBodyp);
|
||||
}
|
||||
|
|
@ -444,6 +444,6 @@ public:
|
|||
|
||||
void V3Clock::clockAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ClockVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ ClockVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ class CombineVisitor final : CombBaseVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
|
||||
const AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
|
||||
// AstUser4InUse part of V3Hasher in V3DupFinder
|
||||
|
||||
// STATE
|
||||
|
|
@ -132,7 +132,7 @@ private:
|
|||
// METHODS
|
||||
void walkEmptyFuncs() {
|
||||
for (const auto& itr : m_dupFinder) {
|
||||
AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc);
|
||||
AstCFunc* const oldfuncp = VN_AS(itr.second, CFunc);
|
||||
UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash");
|
||||
if (!oldfuncp->emptyBody()) continue;
|
||||
UASSERT_OBJ(!oldfuncp->dontCombine(), oldfuncp,
|
||||
|
|
@ -152,14 +152,14 @@ private:
|
|||
// Do non-slow first as then favors naming functions based on fast name
|
||||
for (const bool slow : {false, true}) {
|
||||
for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) {
|
||||
AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc);
|
||||
AstCFunc* const newfuncp = VN_AS(newIt->second, CFunc);
|
||||
UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash");
|
||||
if (newfuncp->user3()) continue; // Already replaced
|
||||
if (newfuncp->slow() != slow) continue;
|
||||
auto oldIt = newIt;
|
||||
++oldIt; // Skip over current position
|
||||
for (; oldIt != m_dupFinder.end(); ++oldIt) {
|
||||
AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc);
|
||||
AstCFunc* const oldfuncp = VN_AS(oldIt->second, CFunc);
|
||||
UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash");
|
||||
UASSERT_OBJ(newfuncp != oldfuncp, newfuncp,
|
||||
"Same function hashed multiple times");
|
||||
|
|
@ -223,6 +223,6 @@ public:
|
|||
|
||||
void V3Combine::combineAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CombineVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ CombineVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
|||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "std::string out;\n"});
|
||||
std::string comma;
|
||||
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
|
||||
if (auto* const varp = VN_CAST(itemp, Var)) {
|
||||
if (const auto* const varp = VN_CAST(itemp, Var)) {
|
||||
if (!varp->isParam()) {
|
||||
string stmt = "out += \"";
|
||||
stmt += comma;
|
||||
|
|
@ -109,7 +109,7 @@ void V3Common::commonAll() {
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstClass::user1() -> bool. True if class needs to_string dumper
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
// Create ToString methods
|
||||
makeVlToString(classp);
|
||||
makeToString(classp);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public:
|
|||
// Apply all attributes to the variable
|
||||
void apply(AstVar* varp) {
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
|
||||
AstNode* const newp = new AstAttrOf(varp->fileline(), it->m_type);
|
||||
varp->addAttrsp(newp);
|
||||
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
|
||||
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, nullptr));
|
||||
|
|
@ -190,13 +190,13 @@ public:
|
|||
|
||||
void apply(AstNodeModule* modp) {
|
||||
if (m_inline) {
|
||||
AstPragmaType type
|
||||
const AstPragmaType type
|
||||
= m_inlineValue ? AstPragmaType::INLINE_MODULE : AstPragmaType::NO_INLINE_MODULE;
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), type);
|
||||
AstNode* const nodep = new AstPragma(modp->fileline(), type);
|
||||
modp->addStmtp(nodep);
|
||||
}
|
||||
for (auto it = m_modPragmas.cbegin(); it != m_modPragmas.cend(); ++it) {
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), *it);
|
||||
AstNode* const nodep = new AstPragma(modp->fileline(), *it);
|
||||
modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
|
|
@ -223,9 +223,9 @@ using V3ConfigModuleResolver = V3ConfigWildcardResolver<V3ConfigModule>;
|
|||
// lint/coverage/tracing on/off
|
||||
class V3ConfigIgnoresLine final {
|
||||
public:
|
||||
int m_lineno; // Line number to make change at
|
||||
V3ErrorCode m_code; // Error code
|
||||
bool m_on; // True to enable message
|
||||
const int m_lineno; // Line number to make change at
|
||||
const V3ErrorCode m_code; // Error code
|
||||
const bool m_on; // True to enable message
|
||||
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
|
||||
: m_lineno{lineno}
|
||||
, m_code{code}
|
||||
|
|
@ -502,7 +502,7 @@ void V3Config::applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp) {
|
|||
const string& modname = modulep->name();
|
||||
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
|
||||
if (!modp) return;
|
||||
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
|
||||
const V3ConfigFTask* const ftp = modp->ftasks().resolve(ftaskp->name());
|
||||
if (ftp) ftp->apply(ftaskp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public:
|
|||
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
|
||||
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
|
||||
|
||||
static uint64_t getProfileData(const string& model, const string& key);
|
||||
static vluint64_t getProfileData(const string& model, const string& key);
|
||||
static FileLine* getProfileDataFileLine();
|
||||
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
|
||||
};
|
||||
|
|
|
|||
799
src/V3Const.cpp
799
src/V3Const.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -43,7 +43,7 @@ private:
|
|||
using LinenoSet = std::set<int>;
|
||||
|
||||
struct ToggleEnt {
|
||||
string m_comment; // Comment for coverage dump
|
||||
const string m_comment; // Comment for coverage dump
|
||||
AstNode* m_varRefp; // How to get to this element
|
||||
AstNode* m_chgRefp; // How to get to this element
|
||||
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
|
||||
|
|
@ -73,7 +73,7 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstIf::user1() -> bool. True indicates ifelse processed
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
CheckState m_state; // State save-restored on each new coverage scope/block
|
||||
|
|
@ -116,20 +116,20 @@ private:
|
|||
// Someday the user might be allowed to specify a different page suffix
|
||||
const string page = page_prefix + "/" + m_modp->prettyName();
|
||||
|
||||
AstCoverDecl* declp = new AstCoverDecl(fl, page, comment, linescov, offset);
|
||||
AstCoverDecl* const declp = new AstCoverDecl(fl, page, comment, linescov, offset);
|
||||
declp->hier(hier);
|
||||
m_modp->addStmtp(declp);
|
||||
UINFO(9, "new " << declp << endl);
|
||||
|
||||
AstCoverInc* incp = new AstCoverInc(fl, declp);
|
||||
AstCoverInc* const incp = new AstCoverInc(fl, declp);
|
||||
if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) {
|
||||
AstVar* varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP, trace_var_name,
|
||||
incp->findUInt32DType());
|
||||
AstVar* const varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP,
|
||||
trace_var_name, incp->findUInt32DType());
|
||||
varp->trace(true);
|
||||
varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
|
||||
m_modp->addStmtp(varp);
|
||||
UINFO(5, "New coverage trace: " << varp << endl);
|
||||
AstAssign* assp = new AstAssign(
|
||||
AstAssign* const assp = new AstAssign(
|
||||
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
|
||||
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
|
||||
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
|
||||
|
|
@ -209,7 +209,7 @@ private:
|
|||
|
||||
// VISITORS - BOTH
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
const AstNodeModule* const origModp = m_modp;
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_state);
|
||||
{
|
||||
|
|
@ -240,14 +240,14 @@ private:
|
|||
iterateChildren(nodep);
|
||||
if (m_state.lineCoverageOn(nodep)) {
|
||||
lineTrack(nodep);
|
||||
AstNode* newp
|
||||
AstNode* const newp
|
||||
= newCoverInc(nodep->fileline(), "", "v_line", "block",
|
||||
linesCov(m_state, nodep), 0, traceNameForLine(nodep, "block"));
|
||||
if (AstNodeProcedure* itemp = VN_CAST(nodep, NodeProcedure)) {
|
||||
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
|
||||
itemp->addStmtp(newp);
|
||||
} else if (AstNodeFTask* itemp = VN_CAST(nodep, NodeFTask)) {
|
||||
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
|
||||
itemp->addStmtsp(newp);
|
||||
} else if (AstWhile* itemp = VN_CAST(nodep, While)) {
|
||||
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
|
||||
itemp->addBodysp(newp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad node type");
|
||||
|
|
@ -261,7 +261,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn()
|
||||
&& v3Global.opt.coverageToggle()) {
|
||||
const char* disablep = varIgnoreToggle(nodep);
|
||||
const char* const disablep = varIgnoreToggle(nodep);
|
||||
if (disablep) {
|
||||
UINFO(4, " Disable Toggle: " << disablep << " " << nodep << endl);
|
||||
} else {
|
||||
|
|
@ -279,7 +279,7 @@ private:
|
|||
|
||||
// Add signal to hold the old value
|
||||
const string newvarname = string("__Vtogcov__") + nodep->shortName();
|
||||
AstVar* chgVarp
|
||||
AstVar* const chgVarp
|
||||
= new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
|
||||
chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
|
||||
m_modp->addStmtp(chgVarp);
|
||||
|
|
@ -298,7 +298,7 @@ private:
|
|||
}
|
||||
|
||||
void toggleVarBottom(const ToggleEnt& above, const AstVar* varp) {
|
||||
AstCoverToggle* newp = new AstCoverToggle(
|
||||
AstCoverToggle* const newp = new AstCoverToggle(
|
||||
varp->fileline(),
|
||||
newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, "", 0,
|
||||
""),
|
||||
|
|
@ -308,7 +308,7 @@ private:
|
|||
|
||||
void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration
|
||||
const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant
|
||||
if (const AstBasicDType* bdtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
if (const AstBasicDType* const bdtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
if (bdtypep->isRanged()) {
|
||||
for (int index_docs = bdtypep->lo(); index_docs < bdtypep->hi() + 1;
|
||||
++index_docs) {
|
||||
|
|
@ -324,7 +324,7 @@ private:
|
|||
} else {
|
||||
toggleVarBottom(above, varp);
|
||||
}
|
||||
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
|
||||
const int index_code = index_docs - adtypep->lo();
|
||||
ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]",
|
||||
|
|
@ -336,9 +336,9 @@ private:
|
|||
chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
} else if (AstPackArrayDType* adtypep = VN_CAST(dtypep, PackArrayDType)) {
|
||||
} else if (const AstPackArrayDType* const adtypep = VN_CAST(dtypep, PackArrayDType)) {
|
||||
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
|
||||
AstNodeDType* subtypep = adtypep->subDTypep()->skipRefp();
|
||||
const AstNodeDType* const subtypep = adtypep->subDTypep()->skipRefp();
|
||||
const int index_code = index_docs - adtypep->lo();
|
||||
ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]",
|
||||
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
|
||||
|
|
@ -349,11 +349,11 @@ private:
|
|||
chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
} else if (AstStructDType* adtypep = VN_CAST(dtypep, StructDType)) {
|
||||
} else if (const AstStructDType* const adtypep = VN_CAST(dtypep, StructDType)) {
|
||||
// For now it's packed, so similar to array
|
||||
for (AstMemberDType* itemp = adtypep->membersp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
||||
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
|
||||
const int index_code = itemp->lsb();
|
||||
ToggleEnt newent(above.m_comment + string(".") + itemp->name(),
|
||||
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
|
||||
|
|
@ -363,10 +363,10 @@ private:
|
|||
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
} else if (AstUnionDType* adtypep = VN_CAST(dtypep, UnionDType)) {
|
||||
} else if (const AstUnionDType* const adtypep = VN_CAST(dtypep, UnionDType)) {
|
||||
// Arbitrarily handle only the first member of the union
|
||||
if (AstMemberDType* itemp = adtypep->membersp()) {
|
||||
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
|
||||
if (const AstMemberDType* const itemp = adtypep->membersp()) {
|
||||
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
|
||||
ToggleEnt newent(above.m_comment + string(".") + itemp->name(),
|
||||
above.m_varRefp->cloneTree(true),
|
||||
above.m_chgRefp->cloneTree(true));
|
||||
|
|
@ -387,7 +387,7 @@ private:
|
|||
// An else-if. When we iterate the if, use "elsif" marking
|
||||
const bool elsif
|
||||
= nodep->ifsp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp();
|
||||
if (elsif) VN_CAST(nodep->elsesp(), If)->user1(true);
|
||||
if (elsif) VN_AS(nodep->elsesp(), If)->user1(true);
|
||||
const bool first_elsif = !nodep->user1() && elsif;
|
||||
const bool cont_elsif = nodep->user1() && elsif;
|
||||
const bool final_elsif = nodep->user1() && !elsif && nodep->elsesp();
|
||||
|
|
@ -543,6 +543,6 @@ public:
|
|||
|
||||
void V3Coverage::coverage(AstNetlist* rootp) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CoverageVisitor visitor{rootp}; } // Destruct before checking
|
||||
{ CoverageVisitor{rootp}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("coverage", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,18 +60,18 @@ private:
|
|||
const auto dupit = dupFinder.findDuplicate(nodep->origp());
|
||||
if (dupit == dupFinder.end()) break;
|
||||
//
|
||||
AstNode* duporigp = dupit->second;
|
||||
const AstNode* const duporigp = dupit->second;
|
||||
// Note hashed will point to the original variable (what's
|
||||
// duplicated), not the covertoggle, but we need to get back to the
|
||||
// covertoggle which is immediately above, so:
|
||||
AstCoverToggle* removep = VN_CAST(duporigp->backp(), CoverToggle);
|
||||
AstCoverToggle* const removep = VN_AS(duporigp->backp(), CoverToggle);
|
||||
UASSERT_OBJ(removep, nodep, "CoverageJoin duplicate of wrong type");
|
||||
UINFO(8, " Orig " << nodep << " -->> " << nodep->incp()->declp() << endl);
|
||||
UINFO(8, " dup " << removep << " -->> " << removep->incp()->declp() << endl);
|
||||
// The CoverDecl the duplicate pointed to now needs to point to the
|
||||
// original's data. I.e. the duplicate will get the coverage number
|
||||
// from the non-duplicate
|
||||
AstCoverDecl* datadeclp = nodep->incp()->declp()->dataDeclThisp();
|
||||
AstCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
|
||||
removep->incp()->declp()->dataDeclp(datadeclp);
|
||||
UINFO(8, " new " << removep->incp()->declp() << endl);
|
||||
// Mark the found node as a duplicate of the first node
|
||||
|
|
@ -114,6 +114,6 @@ public:
|
|||
|
||||
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CoverageJoinVisitor visitor{rootp}; } // Destruct before checking
|
||||
{ CoverageJoinVisitor{rootp}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("coveragejoin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ private:
|
|||
// AstVar::user1() -> int. Count of number of references
|
||||
// AstVarScope::user1() -> int. Count of number of references
|
||||
// AstNodeDType::user1() -> int. Count of number of references
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
using AssignMap = std::multimap<AstVarScope*, AstNodeAssign*>;
|
||||
|
|
@ -102,9 +102,9 @@ private:
|
|||
|
||||
void checkAll(AstNode* nodep) {
|
||||
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
|
||||
if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc();
|
||||
if (AstNode* const subnodep = nodep->dtypep()) subnodep->user1Inc();
|
||||
}
|
||||
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
||||
if (AstNode* const subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
||||
}
|
||||
void checkVarRef(AstNodeVarRef* nodep) {
|
||||
if (nodep->classOrPackagep() && m_elimCells) nodep->classOrPackagep(nullptr);
|
||||
|
|
@ -116,8 +116,8 @@ private:
|
|||
) {
|
||||
m_dtypesp.push_back(nodep);
|
||||
}
|
||||
if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
|
||||
if (AstNode* subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
|
||||
if (AstNode* const subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
|
||||
if (AstNode* const subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
|
@ -129,7 +129,7 @@ private:
|
|||
if (!nodep->dead()) {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (AstClass* classp = VN_CAST(nodep, Class)) {
|
||||
if (AstClass* const classp = VN_CAST(nodep, Class)) {
|
||||
if (classp->extendsp()) classp->extendsp()->user1Inc();
|
||||
if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc();
|
||||
m_classesp.push_back(classp);
|
||||
|
|
@ -282,7 +282,7 @@ private:
|
|||
iterateAndNextNull(nodep->rhsp());
|
||||
checkAll(nodep);
|
||||
// Has to be direct assignment without any EXTRACTing.
|
||||
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
if (varrefp && !m_sideEffect
|
||||
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
|
||||
m_assignMap.emplace(varrefp->varScopep(), nodep);
|
||||
|
|
@ -310,7 +310,7 @@ private:
|
|||
retry = false;
|
||||
AstNodeModule* nextmodp;
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) {
|
||||
nextmodp = VN_CAST(modp->nextp(), NodeModule);
|
||||
nextmodp = VN_AS(modp->nextp(), NodeModule);
|
||||
if (modp->dead()
|
||||
|| (modp->level() > 2 && modp->user1() == 0 && !modp->internal())) {
|
||||
// > 2 because L1 is the wrapper, L2 is the top user module
|
||||
|
|
@ -318,7 +318,7 @@ private:
|
|||
// And its children may now be killable too; correct counts
|
||||
// Recurse, as cells may not be directly under the module but in a generate
|
||||
if (!modp->dead()) { // If was dead didn't increment user1's
|
||||
DeadModVisitor visitor{modp};
|
||||
DeadModVisitor{modp};
|
||||
}
|
||||
VL_DO_DANGLING(modp->unlinkFrBack()->deleteTree(), modp);
|
||||
retry = true;
|
||||
|
|
@ -338,7 +338,7 @@ private:
|
|||
retry = false;
|
||||
for (std::vector<AstScope*>::iterator it = m_scopesp.begin(); it != m_scopesp.end();
|
||||
++it) {
|
||||
AstScope* scp = *it;
|
||||
AstScope* const scp = *it;
|
||||
if (!scp) continue;
|
||||
if (scp->user1() == 0) {
|
||||
UINFO(4, " Dead AstScope " << scp << endl);
|
||||
|
|
@ -364,7 +364,7 @@ private:
|
|||
for (bool retry = true; retry;) {
|
||||
retry = false;
|
||||
for (auto& itr : m_classesp) {
|
||||
if (AstClass* nodep = itr) { // nullptr if deleted earlier
|
||||
if (AstClass* const nodep = itr) { // nullptr if deleted earlier
|
||||
if (nodep->user1() == 0) {
|
||||
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
|
||||
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(-1);
|
||||
|
|
@ -382,10 +382,10 @@ private:
|
|||
for (AstVarScope* vscp : m_vscsp) {
|
||||
if (vscp->user1() == 0) {
|
||||
UINFO(4, " Dead " << vscp << endl);
|
||||
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
|
||||
const std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
|
||||
= m_assignMap.equal_range(vscp);
|
||||
for (AssignMap::iterator itr = eqrange.first; itr != eqrange.second; ++itr) {
|
||||
AstNodeAssign* assp = itr->second;
|
||||
AstNodeAssign* const assp = itr->second;
|
||||
UINFO(4, " Dead assign " << assp << endl);
|
||||
assp->dtypep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
|
||||
|
|
@ -398,7 +398,7 @@ private:
|
|||
for (bool retry = true; retry;) {
|
||||
retry = false;
|
||||
for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) {
|
||||
AstVar* varp = *it;
|
||||
AstVar* const varp = *it;
|
||||
if (!varp) continue;
|
||||
if (varp->user1() == 0) {
|
||||
UINFO(4, " Dead " << varp << endl);
|
||||
|
|
@ -411,14 +411,14 @@ private:
|
|||
}
|
||||
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) {
|
||||
if ((*it)->user1() == 0) {
|
||||
AstNodeUOrStructDType* classp;
|
||||
const AstNodeUOrStructDType* classp;
|
||||
// It's possible that there if a reference to each individual member, but
|
||||
// not to the dtype itself. Check and don't remove the parent dtype if
|
||||
// members are still alive.
|
||||
if ((classp = VN_CAST((*it), NodeUOrStructDType))) {
|
||||
bool cont = true;
|
||||
for (AstMemberDType* memberp = classp->membersp(); memberp;
|
||||
memberp = VN_CAST(memberp->nextp(), MemberDType)) {
|
||||
memberp = VN_AS(memberp->nextp(), MemberDType)) {
|
||||
if (memberp->user1() != 0) {
|
||||
cont = false;
|
||||
break;
|
||||
|
|
@ -463,31 +463,31 @@ public:
|
|||
|
||||
void V3Dead::deadifyModules(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor{nodep, false, false, false, false}; } // Destruct before checking
|
||||
{ DeadVisitor{nodep, false, false, false, false}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor{nodep, false, true, false, false}; } // Destruct before checking
|
||||
{ DeadVisitor{nodep, false, true, false, false}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor{nodep, false, true, true, false}; } // Destruct before checking
|
||||
{ DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0,
|
||||
v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor{nodep, true, true, false, true}; } // Destruct before checking
|
||||
{ DeadVisitor{nodep, true, true, false, true}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor{nodep, true, true, true, true}; } // Destruct before checking
|
||||
{ DeadVisitor{nodep, true, true, true, true}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,15 +81,15 @@ private:
|
|||
// Cleared each scope/active:
|
||||
// AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign
|
||||
// AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
const AstUser1InUse m_inuser1;
|
||||
const AstUser2InUse m_inuser2;
|
||||
const AstUser3InUse m_inuser3;
|
||||
const AstUser4InUse m_inuser4;
|
||||
const AstUser5InUse m_inuser5;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep = nullptr; // Current activate
|
||||
AstCFunc* m_cfuncp = nullptr; // Current public C Function
|
||||
const AstCFunc* m_cfuncp = nullptr; // Current public C Function
|
||||
AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments
|
||||
bool m_inDly = false; // True in delayed assignments
|
||||
bool m_inLoop = false; // True in for loops
|
||||
|
|
@ -104,16 +104,16 @@ private:
|
|||
|
||||
void markVarUsage(AstNodeVarRef* nodep, bool blocking) {
|
||||
if (blocking) nodep->user5(true);
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
AstVarScope* const vscp = nodep->varScopep();
|
||||
// UINFO(4, " MVU " << blocking << " " << nodep << endl);
|
||||
AstNode* lastrefp = vscp->user5p();
|
||||
const AstNode* const lastrefp = vscp->user5p();
|
||||
if (!lastrefp) {
|
||||
vscp->user5p(nodep);
|
||||
} else {
|
||||
const bool last_was_blocking = lastrefp->user5();
|
||||
if (last_was_blocking != blocking) {
|
||||
AstNode* nonblockingp = blocking ? nodep : lastrefp;
|
||||
AstNode* blockingp = blocking ? lastrefp : nodep;
|
||||
const AstNode* const nonblockingp = blocking ? nodep : lastrefp;
|
||||
const AstNode* const blockingp = blocking ? lastrefp : nodep;
|
||||
vscp->v3warn(
|
||||
BLKANDNBLK,
|
||||
"Unsupported: Blocked and non-blocking assignments to same variable: "
|
||||
|
|
@ -131,7 +131,7 @@ private:
|
|||
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
|
||||
UASSERT_OBJ(oldvarscp->scopep(), oldvarscp, "Var unscoped");
|
||||
AstVar* varp;
|
||||
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
|
||||
AstNodeModule* const addmodp = oldvarscp->scopep()->modp();
|
||||
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
|
||||
const auto it = m_modVarMap.find(std::make_pair(addmodp, name));
|
||||
if (it != m_modVarMap.end()) {
|
||||
|
|
@ -152,13 +152,14 @@ private:
|
|||
m_modVarMap.emplace(std::make_pair(addmodp, name), varp);
|
||||
}
|
||||
|
||||
AstVarScope* varscp = new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
|
||||
AstVarScope* const varscp
|
||||
= new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
|
||||
oldvarscp->scopep()->addVarp(varscp);
|
||||
return varscp;
|
||||
}
|
||||
|
||||
AstActive* createActivePost(AstVarRef* varrefp) {
|
||||
AstActive* newactp
|
||||
AstActive* const newactp
|
||||
= new AstActive(varrefp->fileline(), "sequentdly", m_activep->sensesp());
|
||||
// Was addNext(), but addNextHere() avoids a linear search.
|
||||
m_activep->addNextHere(newactp);
|
||||
|
|
@ -184,11 +185,11 @@ private:
|
|||
UINFO(4, " Act: " << m_activep << endl);
|
||||
UINFO(4, " Act: " << oldactivep << endl);
|
||||
// Make a new sensitivity list, which is the combination of both blocks
|
||||
AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena);
|
||||
AstSenItem* const sena = m_activep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenItem* const senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenTree* const treep = new AstSenTree(m_activep->fileline(), sena);
|
||||
if (senb) treep->addSensesp(senb);
|
||||
if (AstSenTree* storep = oldactivep->sensesStorep()) {
|
||||
if (AstSenTree* const storep = oldactivep->sensesStorep()) {
|
||||
storep->unlinkFrBack();
|
||||
pushDeletep(storep);
|
||||
}
|
||||
|
|
@ -203,13 +204,13 @@ private:
|
|||
// Return the new LHS for the assignment, Null = unlink
|
||||
// Find selects
|
||||
AstNode* newlhsp = nullptr; // nullptr = unlink old assign
|
||||
AstSel* bitselp = nullptr;
|
||||
const AstSel* bitselp = nullptr;
|
||||
AstArraySel* arrayselp = nullptr;
|
||||
if (VN_IS(lhsp, Sel)) {
|
||||
bitselp = VN_CAST(lhsp, Sel);
|
||||
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
|
||||
bitselp = VN_AS(lhsp, Sel);
|
||||
arrayselp = VN_AS(bitselp->fromp(), ArraySel);
|
||||
} else {
|
||||
arrayselp = VN_CAST(lhsp, ArraySel);
|
||||
arrayselp = VN_AS(lhsp, ArraySel);
|
||||
}
|
||||
UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?");
|
||||
UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep,
|
||||
|
|
@ -219,28 +220,28 @@ private:
|
|||
//=== Dimensions: __Vdlyvdim__
|
||||
std::deque<AstNode*> dimvalp; // Assignment value for each dimension of assignment
|
||||
AstNode* dimselp = arrayselp;
|
||||
for (; VN_IS(dimselp, ArraySel); dimselp = VN_CAST(dimselp, ArraySel)->fromp()) {
|
||||
AstNode* valp = VN_CAST(dimselp, ArraySel)->bitp()->unlinkFrBack();
|
||||
for (; VN_IS(dimselp, ArraySel); dimselp = VN_AS(dimselp, ArraySel)->fromp()) {
|
||||
AstNode* const valp = VN_AS(dimselp, ArraySel)->bitp()->unlinkFrBack();
|
||||
dimvalp.push_front(valp);
|
||||
}
|
||||
AstVarRef* varrefp = VN_CAST(dimselp, VarRef);
|
||||
AstVarRef* const varrefp = VN_AS(dimselp, VarRef);
|
||||
UASSERT_OBJ(varrefp, nodep, "No var underneath arraysels");
|
||||
UASSERT_OBJ(varrefp->varScopep(), varrefp, "Var didn't get varscoped in V3Scope.cpp");
|
||||
varrefp->unlinkFrBack();
|
||||
AstVar* oldvarp = varrefp->varp();
|
||||
const AstVar* const oldvarp = varrefp->varp();
|
||||
const int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
|
||||
//
|
||||
std::deque<AstNode*> dimreadps; // Read value for each dimension of assignment
|
||||
for (unsigned dimension = 0; dimension < dimvalp.size(); dimension++) {
|
||||
AstNode* dimp = dimvalp[dimension];
|
||||
AstNode* const dimp = dimvalp[dimension];
|
||||
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));
|
||||
AstVarScope* bitvscp
|
||||
AstVarScope* const bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
AstAssign* const bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
|
||||
dimp);
|
||||
nodep->addNextHere(bitassignp);
|
||||
|
|
@ -251,16 +252,16 @@ private:
|
|||
//=== Bitselect: __Vdlyvlsb__
|
||||
AstNode* bitreadp = nullptr; // Code to read Vdlyvlsb
|
||||
if (bitselp) {
|
||||
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
|
||||
AstNode* const lsbvaluep = bitselp->lsbp()->unlinkFrBack();
|
||||
if (VN_IS(bitselp->fromp(), Const)) {
|
||||
// vlsb = constant, can just push constant into where we use it
|
||||
bitreadp = lsbvaluep;
|
||||
} else {
|
||||
const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
|
||||
+ cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp
|
||||
AstVarScope* const bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
AstAssign* const bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
|
||||
lsbvaluep);
|
||||
nodep->addNextHere(bitassignp);
|
||||
|
|
@ -274,9 +275,9 @@ private:
|
|||
// vval = constant, can just push constant into where we use it
|
||||
valreadp = nodep->rhsp()->unlinkFrBack();
|
||||
} else {
|
||||
string valvarname
|
||||
const string valvarname
|
||||
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
AstVarScope* valvscp
|
||||
AstVarScope* const valvscp
|
||||
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
|
||||
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
|
||||
|
|
@ -291,16 +292,16 @@ private:
|
|||
// then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
|
||||
// This is good for code like:
|
||||
// for (i=0; i<5; i++) vector[i] <= something;
|
||||
setvscp = VN_CAST(nodep->user3p(), VarScope);
|
||||
setvscp = VN_AS(nodep->user3p(), VarScope);
|
||||
++m_statSharedSet;
|
||||
} else { // Create new one
|
||||
string setvarname
|
||||
const string setvarname
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
|
||||
setinitp = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
AstAssign* setassignp = new AstAssign(
|
||||
AstAssign* const setassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::BitTrue()));
|
||||
nodep->addNextHere(setassignp);
|
||||
|
|
@ -325,15 +326,15 @@ private:
|
|||
// Build "IF (changeit) ...
|
||||
UINFO(9, " For " << setvscp << endl);
|
||||
UINFO(9, " & " << varrefp << endl);
|
||||
AstAlwaysPost* finalp = VN_CAST(varrefp->varScopep()->user4p(), AlwaysPost);
|
||||
AstAlwaysPost* finalp = VN_AS(varrefp->varScopep()->user4p(), AlwaysPost);
|
||||
if (finalp) {
|
||||
AstActive* oldactivep = VN_CAST(finalp->user2p(), Active);
|
||||
AstActive* const oldactivep = VN_AS(finalp->user2p(), Active);
|
||||
checkActivePost(varrefp, oldactivep);
|
||||
if (setinitp) oldactivep->addStmtsp(setinitp);
|
||||
} else { // first time we've dealt with this memory
|
||||
finalp = new AstAlwaysPost(nodep->fileline(), nullptr /*sens*/, nullptr /*body*/);
|
||||
UINFO(9, " Created " << finalp << endl);
|
||||
AstActive* newactp = createActivePost(varrefp);
|
||||
AstActive* const newactp = createActivePost(varrefp);
|
||||
newactp->addStmtsp(finalp);
|
||||
varrefp->varScopep()->user4p(finalp);
|
||||
finalp->user2p(newactp);
|
||||
|
|
@ -343,7 +344,7 @@ private:
|
|||
if (finalp->user3p() == setvscp) {
|
||||
// Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
|
||||
// we can share the IF statement too
|
||||
postLogicp = VN_CAST(finalp->user4p(), If);
|
||||
postLogicp = VN_AS(finalp->user4p(), If);
|
||||
UASSERT_OBJ(postLogicp, nodep,
|
||||
"Delayed assignment misoptimized; prev var found w/o associated IF");
|
||||
} else {
|
||||
|
|
@ -397,14 +398,14 @@ private:
|
|||
}
|
||||
if (VN_IS(nodep->lhsp(), ArraySel)
|
||||
|| (VN_IS(nodep->lhsp(), Sel)
|
||||
&& VN_IS(VN_CAST(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newlhsp = createDlyArray(nodep, lhsp);
|
||||
&& VN_IS(VN_AS(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const newlhsp = createDlyArray(nodep, lhsp);
|
||||
if (m_inLoop) {
|
||||
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
|
||||
"loops (non-delayed is ok - see docs)");
|
||||
}
|
||||
AstBasicDType* basicp = lhsp->dtypep()->basicp();
|
||||
const AstBasicDType* const basicp = lhsp->dtypep()->basicp();
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays");
|
||||
}
|
||||
|
|
@ -432,18 +433,18 @@ private:
|
|||
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
|
||||
"have converted in V3Active");
|
||||
}
|
||||
AstVarScope* oldvscp = nodep->varScopep();
|
||||
AstVarScope* const oldvscp = nodep->varScopep();
|
||||
UASSERT_OBJ(oldvscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
AstVarScope* dlyvscp = VN_CAST(oldvscp->user1p(), VarScope);
|
||||
AstVarScope* dlyvscp = VN_AS(oldvscp->user1p(), VarScope);
|
||||
if (dlyvscp) { // Multiple use of delayed variable
|
||||
AstActive* oldactivep = VN_CAST(dlyvscp->user2p(), Active);
|
||||
AstActive* const oldactivep = VN_AS(dlyvscp->user2p(), Active);
|
||||
checkActivePost(nodep, oldactivep);
|
||||
}
|
||||
if (!dlyvscp) { // First use of this delayed variable
|
||||
const string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
|
||||
AstNodeAssign* prep;
|
||||
AstBasicDType* basicp = oldvscp->dtypep()->basicp();
|
||||
const AstBasicDType* const basicp = oldvscp->dtypep()->basicp();
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
// Events go to zero on next timestep unless reactivated
|
||||
prep = new AstAssignPre(
|
||||
|
|
@ -456,19 +457,20 @@ private:
|
|||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
|
||||
}
|
||||
AstNodeAssign* postp = new AstAssignPost(
|
||||
AstNodeAssign* const postp = new AstAssignPost(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
|
||||
postp->lhsp()->user2(true); // Don't detect this assignment
|
||||
oldvscp->user1p(dlyvscp); // So we can find it later
|
||||
// Make new ACTIVE with identical sensitivity tree
|
||||
AstActive* newactp = createActivePost(nodep);
|
||||
AstActive* const newactp = createActivePost(nodep);
|
||||
dlyvscp->user2p(newactp);
|
||||
newactp->addStmtsp(prep); // Add to FRONT of statements
|
||||
newactp->addStmtsp(postp);
|
||||
}
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
|
||||
AstVarRef* const newrefp
|
||||
= new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
|
||||
newrefp->user2(true); // No reason to do it again
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
|
@ -510,6 +512,6 @@ public:
|
|||
|
||||
void V3Delayed::delayedAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DelayedVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ DelayedVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,6 @@ public:
|
|||
|
||||
void V3Depth::depthAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DepthVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ DepthVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("depth", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ private:
|
|||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_cfuncp = nullptr; // Current function
|
||||
const AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstCFunc* m_cfuncp = nullptr; // Current function
|
||||
int m_depth = 0; // How deep in an expression
|
||||
int m_deepNum = 0; // How many functions made
|
||||
|
||||
|
|
@ -94,9 +94,9 @@ private:
|
|||
if (m_depth > v3Global.opt.compLimitBlocks()
|
||||
&& !VN_IS(nodep, NodeCCall)) { // Already done
|
||||
UINFO(4, "DeepBlocks " << m_depth << " " << nodep << endl);
|
||||
AstNode* backp = nodep->backp(); // Only for debug
|
||||
const AstNode* const backp = nodep->backp(); // Only for debug
|
||||
if (debug() >= 9) backp->dumpTree(cout, "- pre : ");
|
||||
AstCFunc* funcp = createDeepFunc(nodep);
|
||||
AstCFunc* const funcp = createDeepFunc(nodep);
|
||||
iterate(funcp);
|
||||
if (debug() >= 9) backp->dumpTree(cout, "- post: ");
|
||||
if (debug() >= 9) funcp->dumpTree(cout, "- func: ");
|
||||
|
|
@ -129,6 +129,6 @@ public:
|
|||
|
||||
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DepthBlockVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ DepthBlockVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deepblock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared entire netlist
|
||||
// AstCFunc::user() // bool. Indicates processing completed
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
using FuncMmap = std::multimap<std::string, AstCFunc*>;
|
||||
|
|
@ -107,14 +107,14 @@ private:
|
|||
// If multiple functions exist, we need to select the appropriate scope.
|
||||
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
|
||||
const string name = it->first;
|
||||
AstCFunc* topFuncp = it->second;
|
||||
AstCFunc* const topFuncp = it->second;
|
||||
auto nextIt1 = it;
|
||||
++nextIt1;
|
||||
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
|
||||
const bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
|
||||
if (moreOfSame1) {
|
||||
// Multiple functions under this name, need a wrapper function
|
||||
UINFO(6, " Wrapping " << name << " multifuncs\n");
|
||||
AstCFunc* newfuncp = topFuncp->cloneTree(false);
|
||||
AstCFunc* const newfuncp = topFuncp->cloneTree(false);
|
||||
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
|
|
@ -125,7 +125,7 @@ private:
|
|||
for (FuncMmap::iterator eachIt = it;
|
||||
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
|
||||
it = eachIt;
|
||||
AstCFunc* funcp = eachIt->second;
|
||||
AstCFunc* const funcp = eachIt->second;
|
||||
auto nextIt2 = eachIt;
|
||||
++nextIt2;
|
||||
const bool moreOfSame
|
||||
|
|
@ -138,21 +138,21 @@ private:
|
|||
funcp->declPrivate(true);
|
||||
AstNode* argsp = nullptr;
|
||||
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
AstNode* newp = new AstVarRef(portp->fileline(), portp,
|
||||
portp->isWritable() ? VAccess::WRITE
|
||||
: VAccess::READ);
|
||||
AstNode* const newp = new AstVarRef(
|
||||
portp->fileline(), portp,
|
||||
portp->isWritable() ? VAccess::WRITE : VAccess::READ);
|
||||
argsp = argsp ? argsp->addNextNull(newp) : newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* returnp = new AstCReturn(
|
||||
AstNode* const returnp = new AstCReturn(
|
||||
funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp));
|
||||
|
||||
if (moreOfSame) {
|
||||
AstIf* ifp = new AstIf(
|
||||
AstIf* const ifp = new AstIf(
|
||||
funcp->fileline(),
|
||||
new AstEq(
|
||||
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64),
|
||||
|
|
@ -289,6 +289,6 @@ public:
|
|||
|
||||
void V3Descope::descopeAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DescopeVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ DescopeVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ EmitCParentModule::EmitCParentModule() {
|
|||
}
|
||||
};
|
||||
for (AstNode* modp = v3Global.rootp()->modulesp(); modp; modp = modp->nextp()) {
|
||||
setAll(VN_CAST(modp, NodeModule));
|
||||
setAll(VN_AS(modp, NodeModule));
|
||||
}
|
||||
setAll(v3Global.rootp()->constPoolp()->modp());
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
|
|||
}
|
||||
|
||||
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) {
|
||||
AstCFile* cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
|
||||
AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
|
||||
cfilep->slow(slow);
|
||||
cfilep->source(source);
|
||||
v3Global.rootp()->addFilesp(cfilep);
|
||||
|
|
@ -78,7 +78,7 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
|
|||
}
|
||||
// Might be a user function with argument list.
|
||||
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) {
|
||||
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args += ", ";
|
||||
if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) {
|
||||
|
|
@ -134,9 +134,8 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
|||
|
||||
const auto emitDeclArrayBrackets = [this](const AstVar* nodep) -> void {
|
||||
// This isn't very robust and may need cleanup for other data types
|
||||
for (const AstUnpackArrayDType* arrayp
|
||||
= VN_CAST_CONST(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
||||
arrayp; arrayp = VN_CAST_CONST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
|
||||
for (const AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
||||
arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
|
||||
puts("[" + cvtToStr(arrayp->elementsConst()) + "]");
|
||||
}
|
||||
};
|
||||
|
|
@ -221,7 +220,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
|||
void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
||||
string nl;
|
||||
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCUse* usep = VN_CAST(itemp, CUse)) {
|
||||
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
||||
if (usep->useType() == useType) {
|
||||
if (usep->useType().isInclude()) {
|
||||
puts("#include \"" + prefixNameProtect(usep) + ".h\"\n");
|
||||
|
|
@ -239,7 +238,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType)
|
|||
void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, AstType type) {
|
||||
int last_line = -999;
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstNodeText* textp = VN_CAST(nodep, NodeText)) {
|
||||
if (const AstNodeText* const textp = VN_CAST(nodep, NodeText)) {
|
||||
if (nodep->type() == type) {
|
||||
if (last_line != nodep->fileline()->lineno()) {
|
||||
if (last_line < 0) {
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ class EmitCParentModule final {
|
|||
// NODE STATE
|
||||
// AstFunc::user4p() AstNodeModule* Parent module pointer
|
||||
// AstVar::user4p() AstNodeModule* Parent module pointer
|
||||
AstUser4InUse user4InUse;
|
||||
const AstUser4InUse user4InUse;
|
||||
|
||||
public:
|
||||
EmitCParentModule();
|
||||
VL_UNCOPYABLE(EmitCParentModule);
|
||||
|
||||
static const AstNodeModule* get(const AstNode* nodep) {
|
||||
return VN_CAST_CONST(nodep->user4p(), NodeModule);
|
||||
return VN_AS(nodep->user4p(), NodeModule);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ protected:
|
|||
// VISITORS
|
||||
virtual void visit(AstInitArray* nodep) override {
|
||||
const AstUnpackArrayDType* const dtypep
|
||||
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
||||
= VN_AS(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
||||
UASSERT_OBJ(dtypep, nodep, "Array initializer has non-array dtype");
|
||||
const uint32_t size = dtypep->elementsConst();
|
||||
const uint32_t elemBytes = dtypep->subDTypep()->widthTotalBytes();
|
||||
|
|
@ -72,7 +72,7 @@ protected:
|
|||
virtual void visit(AstConst* nodep) override {
|
||||
const V3Number& num = nodep->num();
|
||||
UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool");
|
||||
AstNodeDType* const dtypep = nodep->dtypep();
|
||||
const AstNodeDType* const dtypep = nodep->dtypep();
|
||||
if (num.isString()) {
|
||||
// Note: putsQuoted does not track indentation, so we use this instead
|
||||
puts("\"");
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class EmitCConstPool final : public EmitCConstInit {
|
|||
void emitVars(const AstConstPool* poolp) {
|
||||
std::vector<const AstVar*> varps;
|
||||
for (AstNode* nodep = poolp->modp()->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) { varps.push_back(varp); }
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) { varps.push_back(varp); }
|
||||
}
|
||||
|
||||
if (varps.empty()) return; // Constant pool is empty, so we are done
|
||||
|
|
|
|||
|
|
@ -197,12 +197,12 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
} else {
|
||||
// Format
|
||||
bool isStmt = false;
|
||||
if (const AstFScanF* dispp = VN_CAST(nodep, FScanF)) {
|
||||
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
|
||||
isStmt = false;
|
||||
puts("VL_FSCANF_IX(");
|
||||
iterate(dispp->filep());
|
||||
puts(",");
|
||||
} else if (const AstSScanF* dispp = VN_CAST(nodep, SScanF)) {
|
||||
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
|
||||
isStmt = false;
|
||||
checkMaxWords(dispp->fromp());
|
||||
puts("VL_SSCANF_I");
|
||||
|
|
@ -212,7 +212,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
puts(",");
|
||||
iterate(dispp->fromp());
|
||||
puts(",");
|
||||
} else if (const AstDisplay* dispp = VN_CAST(nodep, Display)) {
|
||||
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
|
||||
isStmt = true;
|
||||
if (dispp->filep()) {
|
||||
puts("VL_FWRITEF(");
|
||||
|
|
@ -221,7 +221,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
} else {
|
||||
puts("VL_WRITEF(");
|
||||
}
|
||||
} else if (const AstSFormat* dispp = VN_CAST(nodep, SFormat)) {
|
||||
} else if (const AstSFormat* const dispp = VN_CAST(nodep, SFormat)) {
|
||||
isStmt = true;
|
||||
puts("VL_SFORMAT_X(");
|
||||
puts(cvtToStr(dispp->lhsp()->widthMin()));
|
||||
|
|
@ -238,7 +238,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
// Arguments
|
||||
for (unsigned i = 0; i < emitDispState.m_argsp.size(); i++) {
|
||||
const char fmt = emitDispState.m_argsChar[i];
|
||||
AstNode* argp = emitDispState.m_argsp[i];
|
||||
AstNode* const argp = emitDispState.m_argsp[i];
|
||||
const string func = emitDispState.m_argsFunc[i];
|
||||
if (func != "" || argp) {
|
||||
puts(",");
|
||||
|
|
@ -315,13 +315,14 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
|
|||
}
|
||||
emitDispState.pushArg(fmtLetter, argp, "");
|
||||
if (fmtLetter == 't' || fmtLetter == '^') {
|
||||
AstSFormatF* fmtp = nullptr;
|
||||
if (AstDisplay* nodep = VN_CAST(dispp, Display))
|
||||
const AstSFormatF* fmtp = nullptr;
|
||||
if (const AstDisplay* const nodep = VN_CAST(dispp, Display)) {
|
||||
fmtp = nodep->fmtp();
|
||||
else if (AstSFormat* nodep = VN_CAST(dispp, SFormat))
|
||||
} else if (const AstSFormat* const nodep = VN_CAST(dispp, SFormat)) {
|
||||
fmtp = nodep->fmtp();
|
||||
else
|
||||
} else {
|
||||
fmtp = VN_CAST(dispp, SFormatF);
|
||||
}
|
||||
UASSERT_OBJ(fmtp, dispp,
|
||||
"Use of %t must be under AstDisplay, AstSFormat, or AstSFormatF");
|
||||
UASSERT_OBJ(!fmtp->timeunit().isNone(), fmtp, "timenunit must be set");
|
||||
|
|
@ -472,7 +473,7 @@ void EmitCFunc::emitDereference(const string& pointer) {
|
|||
}
|
||||
|
||||
void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
|
||||
if (const AstConst* constp = VN_CAST(nodep, Const)) {
|
||||
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
||||
putbs("std::string(");
|
||||
putsQuoted(constp->num().toString());
|
||||
puts(")");
|
||||
|
|
@ -533,13 +534,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
|
|||
puts(",");
|
||||
if (!assigntop) {
|
||||
puts(assignString);
|
||||
} else if (VN_IS(assigntop, VarRef)) {
|
||||
} else {
|
||||
if (!assigntop->selfPointer().empty()) {
|
||||
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
|
||||
}
|
||||
puts(assigntop->varp()->nameProtect());
|
||||
} else {
|
||||
iterateAndNextNull(assigntop);
|
||||
}
|
||||
for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) {
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
|
|
@ -558,13 +557,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
|
|||
puts(",");
|
||||
if (!assigntop) {
|
||||
puts(assignString);
|
||||
} else if (VN_IS(assigntop, VarRef)) {
|
||||
} else {
|
||||
if (!assigntop->selfPointer().empty()) {
|
||||
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
|
||||
}
|
||||
puts(assigntop->varp()->nameProtect());
|
||||
} else {
|
||||
iterateAndNextNull(assigntop);
|
||||
}
|
||||
for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) {
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
|
|
@ -584,14 +581,14 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
|
|||
ofp()->printf("%.17e", nodep->num().toDouble());
|
||||
}
|
||||
} else if (nodep->isQuad()) {
|
||||
vluint64_t num = nodep->toUQuad();
|
||||
const vluint64_t num = nodep->toUQuad();
|
||||
if (num < 10) {
|
||||
ofp()->printf("%" VL_PRI64 "uULL", num);
|
||||
} else {
|
||||
ofp()->printf("0x%" VL_PRI64 "xULL", num);
|
||||
}
|
||||
} else {
|
||||
uint32_t num = nodep->toUInt();
|
||||
const uint32_t num = nodep->toUInt();
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
if (num < 10) {
|
||||
puts(cvtToStr(num));
|
||||
|
|
@ -624,20 +621,19 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
|
|||
// If a simple CONST value we initialize it using an enum
|
||||
// If an ARRAYINIT we initialize it using an initial block similar to a signal
|
||||
// puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n");
|
||||
} else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
|
||||
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
} else if (const AstInitArray* const initarp = VN_CAST(varp->valuep(), InitArray)) {
|
||||
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (initarp->defaultp()) {
|
||||
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
|
||||
puts("; ++__Vi) {\n");
|
||||
emitSetVarConstant(varNameProtected + "[__Vi]",
|
||||
VN_CAST(initarp->defaultp(), Const));
|
||||
emitSetVarConstant(varNameProtected + "[__Vi]", VN_AS(initarp->defaultp(), Const));
|
||||
puts("}\n");
|
||||
}
|
||||
const AstInitArray::KeyItemMap& mapr = initarp->map();
|
||||
for (const auto& itr : mapr) {
|
||||
AstNode* valuep = itr.second->valuep();
|
||||
AstNode* const valuep = itr.second->valuep();
|
||||
emitSetVarConstant(varNameProtected + "[" + cvtToStr(itr.first) + "]",
|
||||
VN_CAST(valuep, Const));
|
||||
VN_AS(valuep, Const));
|
||||
}
|
||||
} else {
|
||||
varp->v3fatalSrc("InitArray under non-arrayed var");
|
||||
|
|
@ -650,26 +646,26 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
|
|||
string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameProtected,
|
||||
AstNodeDType* dtypep, int depth, const string& suffix) {
|
||||
dtypep = dtypep->skipRefp();
|
||||
AstBasicDType* basicp = dtypep->basicp();
|
||||
AstBasicDType* const basicp = dtypep->basicp();
|
||||
// Returns string to do resetting, empty to do nothing (which caller should handle)
|
||||
if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) {
|
||||
if (AstAssocArrayDType* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
|
||||
// Access std::array as C array
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
|
||||
suffix + ".atDefault()" + cvtarray);
|
||||
} else if (VN_IS(dtypep, ClassRefDType)) {
|
||||
return ""; // Constructor does it
|
||||
} else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
} else if (const AstDynArrayDType* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
// Access std::array as C array
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
|
||||
suffix + ".atDefault()" + cvtarray);
|
||||
} else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
} else if (const AstQueueDType* const adtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
// Access std::array as C array
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
|
||||
suffix + ".atDefault()" + cvtarray);
|
||||
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
} 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);
|
||||
|
|
@ -683,8 +679,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
|
|||
// String's constructor deals with it
|
||||
return "";
|
||||
} else if (basicp) {
|
||||
bool zeroit
|
||||
= (varp->attrFileDescr() // Zero so we don't core dump if never $fopen
|
||||
const bool zeroit
|
||||
= (varp->attrFileDescr() // Zero so we don't do file IO if never $fopen
|
||||
|| (basicp && basicp->isZeroInit())
|
||||
|| (v3Global.opt.underlineZero() && !varp->name().empty() && varp->name()[0] == '_')
|
||||
|| (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0"));
|
||||
|
|
@ -692,7 +688,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
|
|||
if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide
|
||||
string out;
|
||||
if (varp->valuep()) {
|
||||
AstConst* const constp = VN_CAST(varp->valuep(), Const);
|
||||
const AstConst* const constp = VN_AS(varp->valuep(), Const);
|
||||
if (!constp) varp->v3fatalSrc("non-const initializer for variable");
|
||||
for (int w = 0; w < varp->widthWords(); ++w) {
|
||||
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
|
||||
|
|
@ -737,8 +733,8 @@ void EmitCFunc::doubleOrDetect(AstChangeDet* changep, bool& gotOne) {
|
|||
}
|
||||
iterateAndNextNull(changep->lhsp());
|
||||
} else {
|
||||
AstNode* lhsp = changep->lhsp();
|
||||
AstNode* rhsp = changep->rhsp();
|
||||
AstNode* const lhsp = changep->lhsp();
|
||||
AstNode* const rhsp = changep->rhsp();
|
||||
UASSERT_OBJ(VN_IS(lhsp, VarRef) || VN_IS(lhsp, ArraySel), changep, "Not ref?");
|
||||
UASSERT_OBJ(VN_IS(rhsp, VarRef) || VN_IS(rhsp, ArraySel), changep, "Not ref?");
|
||||
for (int word = 0; word < (changep->lhsp()->isWide() ? changep->lhsp()->widthWords() : 1);
|
||||
|
|
@ -792,7 +788,7 @@ void EmitCFunc::emitChangeDet() {
|
|||
doubleOrDetect(nodep, gotOneIgnore);
|
||||
string varname;
|
||||
if (VN_IS(nodep->lhsp(), VarRef)) {
|
||||
varname = ": " + VN_CAST(nodep->lhsp(), VarRef)->varp()->prettyName();
|
||||
varname = ": " + VN_AS(nodep->lhsp(), VarRef)->varp()->prettyName();
|
||||
}
|
||||
puts(")) VL_DBG_MSGF(\" CHANGE: ");
|
||||
puts(protect(nodep->fileline()->filename()));
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ constexpr int EMITC_NUM_CONSTW = 8;
|
|||
class EmitCLazyDecls final : public AstNVisitor {
|
||||
// NODE STATE/TYPES
|
||||
// AstNode::user2() -> bool. Already emitted decl for symbols.
|
||||
AstUser2InUse m_inuser2;
|
||||
const AstUser2InUse m_inuser2;
|
||||
|
||||
// MEMBERS
|
||||
std::unordered_set<string> m_emittedManually; // Set of names already declared manually.
|
||||
|
|
@ -126,7 +126,7 @@ protected:
|
|||
EmitCLazyDecls m_lazyDecls; // Visitor for emitting lazy declarations
|
||||
bool m_useSelfForThis = false; // Replace "this" with "vlSelf"
|
||||
const AstNodeModule* m_modp = nullptr; // Current module being emitted
|
||||
AstCFunc* m_cfuncp = nullptr; // Current function being emitted
|
||||
const AstCFunc* m_cfuncp = nullptr; // Current function being emitted
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
|
|
@ -229,7 +229,7 @@ public:
|
|||
puts(nodep->nameProtect() + "\\n\"); );\n");
|
||||
|
||||
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(subnodep, Var)) {
|
||||
if (AstVar* const varp = VN_CAST(subnodep, Var)) {
|
||||
if (varp->isFuncReturn()) emitVarDecl(varp);
|
||||
}
|
||||
}
|
||||
|
|
@ -265,20 +265,21 @@ public:
|
|||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
bool paren = true;
|
||||
bool decind = false;
|
||||
if (AstSel* selp = VN_CAST(nodep->lhsp(), Sel)) {
|
||||
bool rhs = true;
|
||||
if (AstSel* const selp = VN_CAST(nodep->lhsp(), Sel)) {
|
||||
if (selp->widthMin() == 1) {
|
||||
putbs("VL_ASSIGNBIT_");
|
||||
emitIQW(selp->fromp());
|
||||
if (nodep->rhsp()->isAllOnesV()) {
|
||||
puts("O(");
|
||||
rhs = false;
|
||||
} else {
|
||||
puts("I(");
|
||||
}
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(selp->lsbp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->fromp());
|
||||
puts(", ");
|
||||
if (rhs) puts(", ");
|
||||
} else {
|
||||
putbs("VL_ASSIGNSEL_");
|
||||
emitIQW(selp->fromp());
|
||||
|
|
@ -292,7 +293,7 @@ public:
|
|||
iterateAndNextNull(selp->fromp());
|
||||
puts(", ");
|
||||
}
|
||||
} else if (AstGetcRefN* selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
|
||||
} else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
|
||||
iterateAndNextNull(selp->lhsp());
|
||||
puts(" = ");
|
||||
putbs("VL_PUTC_N(");
|
||||
|
|
@ -300,7 +301,7 @@ public:
|
|||
puts(", ");
|
||||
iterateAndNextNull(selp->rhsp());
|
||||
puts(", ");
|
||||
} else if (AstVar* varp = AstVar::scVarRecurse(nodep->lhsp())) {
|
||||
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) {
|
||||
putbs("VL_ASSIGN_"); // Set a systemC variable
|
||||
emitScIQW(varp);
|
||||
emitIQW(nodep);
|
||||
|
|
@ -308,7 +309,7 @@ public:
|
|||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else if (AstVar* varp = AstVar::scVarRecurse(nodep->rhsp())) {
|
||||
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) {
|
||||
putbs("VL_ASSIGN_"); // Get a systemC variable
|
||||
emitIQW(nodep);
|
||||
emitScIQW(varp);
|
||||
|
|
@ -323,7 +324,7 @@ public:
|
|||
&& !VN_IS(nodep->rhsp(), AssocSel) //
|
||||
&& !VN_IS(nodep->rhsp(), ArraySel)) {
|
||||
// Wide functions assign into the array directly, don't need separate assign statement
|
||||
m_wideTempRefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef);
|
||||
paren = false;
|
||||
} else if (nodep->isWide()) {
|
||||
putbs("VL_ASSIGN_W(");
|
||||
|
|
@ -339,7 +340,7 @@ public:
|
|||
if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak();
|
||||
puts("= ");
|
||||
}
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (rhs) iterateAndNextNull(nodep->rhsp());
|
||||
if (paren) puts(")");
|
||||
if (decind) ofp()->blockDec();
|
||||
puts(";\n");
|
||||
|
|
@ -348,7 +349,7 @@ public:
|
|||
virtual void visit(AstAssocSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
putbs(".at(");
|
||||
AstAssocArrayDType* adtypep = VN_CAST(nodep->fromp()->dtypep(), AssocArrayDType);
|
||||
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());
|
||||
|
|
@ -429,11 +430,11 @@ public:
|
|||
virtual void visit(AstWith* nodep) override {
|
||||
// With uses a C++11 lambda
|
||||
putbs("[=](");
|
||||
if (auto* argrefp = nodep->indexArgRefp()) {
|
||||
if (auto* const argrefp = nodep->indexArgRefp()) {
|
||||
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
|
||||
puts(",");
|
||||
}
|
||||
if (auto* argrefp = nodep->valueArgRefp()) {
|
||||
if (auto* const argrefp = nodep->valueArgRefp()) {
|
||||
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
|
||||
}
|
||||
// Probably fragile, V3Task may need to convert to a AstCReturn
|
||||
|
|
@ -632,12 +633,12 @@ public:
|
|||
puts(cvtToStr(nodep->memp()->dtypep()->subDTypep()->widthMin()));
|
||||
uint32_t array_lo = 0;
|
||||
{
|
||||
const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef);
|
||||
const AstVarRef* const varrefp = VN_CAST(nodep->memp(), VarRef);
|
||||
if (!varrefp) {
|
||||
nodep->v3error(nodep->verilogKwd() << " loading non-variable");
|
||||
} else if (VN_IS(varrefp->varp()->dtypeSkipRefp(), AssocArrayDType)) {
|
||||
// nodep->memp() below will when verilated code is compiled create a C++ template
|
||||
} else if (const AstUnpackArrayDType* adtypep
|
||||
} else if (const AstUnpackArrayDType* const adtypep
|
||||
= VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
putbs(", ");
|
||||
puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements()));
|
||||
|
|
@ -716,11 +717,11 @@ public:
|
|||
uint32_t array_lo = 0;
|
||||
uint32_t array_size = 0;
|
||||
{
|
||||
const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef);
|
||||
const AstVarRef* const varrefp = VN_CAST(nodep->memp(), VarRef);
|
||||
if (!varrefp) {
|
||||
nodep->v3error(nodep->verilogKwd() << " loading non-variable");
|
||||
} else if (VN_CAST(varrefp->varp()->dtypeSkipRefp(), BasicDType)) {
|
||||
} else if (const AstUnpackArrayDType* adtypep
|
||||
} else if (const AstUnpackArrayDType* const adtypep
|
||||
= VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
array_lo = adtypep->lo();
|
||||
array_size = adtypep->elementsConst();
|
||||
|
|
@ -898,7 +899,7 @@ public:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstTextBlock* nodep) override {
|
||||
visit(VN_CAST(nodep, NodeSimpleText));
|
||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterate(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
|
|
@ -978,9 +979,9 @@ public:
|
|||
}
|
||||
virtual void visit(AstRedXor* nodep) override {
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
visit(VN_CAST(nodep, NodeUniop));
|
||||
visit(static_cast<AstNodeUniop*>(nodep));
|
||||
} else {
|
||||
AstVarRef* const vrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
const AstVarRef* const vrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
const int widthPow2 = vrefp ? vrefp->varp()->dtypep()->widthPow2()
|
||||
: nodep->lhsp()->dtypep()->widthPow2();
|
||||
UASSERT_OBJ(widthPow2 > 1, nodep,
|
||||
|
|
@ -1042,16 +1043,14 @@ public:
|
|||
}
|
||||
virtual void visit(AstReplicate* nodep) override {
|
||||
if (nodep->lhsp()->widthMin() == 1 && !nodep->isWide()) {
|
||||
UASSERT_OBJ((static_cast<int>(VN_CAST(nodep->rhsp(), Const)->toUInt())
|
||||
UASSERT_OBJ((static_cast<int>(VN_AS(nodep->rhsp(), Const)->toUInt())
|
||||
* nodep->lhsp()->widthMin())
|
||||
== nodep->widthMin(),
|
||||
nodep, "Replicate non-constant or width miscomputed");
|
||||
puts("VL_REPLICATE_");
|
||||
emitIQW(nodep);
|
||||
puts("OI(");
|
||||
puts(cvtToStr(nodep->widthMin()));
|
||||
if (nodep->lhsp()) puts("," + cvtToStr(nodep->lhsp()->widthMin()));
|
||||
if (nodep->rhsp()) puts("," + cvtToStr(nodep->rhsp()->widthMin()));
|
||||
if (nodep->lhsp()) puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
|
|
@ -1064,26 +1063,24 @@ public:
|
|||
virtual void visit(AstStreamL* nodep) override {
|
||||
// Attempt to use a "fast" stream function for slice size = power of 2
|
||||
if (!nodep->isWide()) {
|
||||
uint32_t isPow2 = VN_CAST(nodep->rhsp(), Const)->num().countOnes() == 1;
|
||||
uint32_t sliceSize = VN_CAST(nodep->rhsp(), Const)->toUInt();
|
||||
const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1;
|
||||
const uint32_t sliceSize = VN_AS(nodep->rhsp(), Const)->toUInt();
|
||||
if (isPow2 && sliceSize <= (nodep->isQuad() ? sizeof(uint64_t) : sizeof(uint32_t))) {
|
||||
puts("VL_STREAML_FAST_");
|
||||
emitIQW(nodep);
|
||||
emitIQW(nodep->lhsp());
|
||||
puts("I(");
|
||||
puts(cvtToStr(nodep->widthMin()));
|
||||
puts("," + cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts("," + cvtToStr(nodep->rhsp()->widthMin()));
|
||||
puts(",");
|
||||
puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
uint32_t rd_log2 = V3Number::log2b(VN_CAST(nodep->rhsp(), Const)->toUInt());
|
||||
const uint32_t rd_log2 = V3Number::log2b(VN_AS(nodep->rhsp(), Const)->toUInt());
|
||||
puts(cvtToStr(rd_log2) + ")");
|
||||
return;
|
||||
}
|
||||
}
|
||||
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)", nodep->lhsp(),
|
||||
nodep->rhsp(), nullptr);
|
||||
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(),
|
||||
nullptr);
|
||||
}
|
||||
virtual void visit(AstCastDynamic* nodep) override {
|
||||
putbs("VL_CAST_DYNAMIC(");
|
||||
|
|
@ -1133,7 +1130,7 @@ public:
|
|||
}
|
||||
virtual void visit(AstAddrOfCFunc* nodep) override {
|
||||
// Note: Can be thought to handle more, but this is all that is needed right now
|
||||
AstCFunc* const funcp = nodep->funcp();
|
||||
const AstCFunc* const funcp = nodep->funcp();
|
||||
UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method");
|
||||
puts("&");
|
||||
puts(funcNameProtect(funcp));
|
||||
|
|
@ -1205,7 +1202,7 @@ public:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstCReset* nodep) override {
|
||||
AstVar* varp = nodep->varrefp()->varp();
|
||||
AstVar* const varp = nodep->varrefp()->varp();
|
||||
emitVarReset(varp);
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) override {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
void emitCellDecls(const AstNodeModule* modp) {
|
||||
bool first = true;
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) {
|
||||
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
|
||||
decorateFirst(first, "// CELLS\n");
|
||||
puts(prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n");
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
|
||||
// Emit variables in consecutive anon and non-anon batches
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isIO() || varp->isSignal() || varp->isClassMember() || varp->isTemp()) {
|
||||
const bool anon = isAnonOk(varp);
|
||||
if (anon != lastAnon) emitCurrentList();
|
||||
|
|
@ -179,7 +179,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
void emitEnums(const AstNodeModule* modp) {
|
||||
bool first = true;
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
const AstTypedef* const tdefp = VN_CAST_CONST(nodep, Typedef);
|
||||
const AstTypedef* const tdefp = VN_CAST(nodep, Typedef);
|
||||
if (!tdefp) continue;
|
||||
if (!tdefp->attrPublic()) continue;
|
||||
const AstEnumDType* const edtypep
|
||||
|
|
@ -191,7 +191,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
} else {
|
||||
puts("enum " + tdefp->name() + " {\n");
|
||||
for (const AstEnumItem* itemp = edtypep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), EnumItem)) {
|
||||
puts(itemp->nameProtect());
|
||||
puts(" = ");
|
||||
iterate(itemp->valuep());
|
||||
|
|
@ -206,7 +206,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
std::vector<const AstCFunc*> funcsp;
|
||||
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCFunc* const funcp = VN_CAST_CONST(nodep, CFunc)) {
|
||||
if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
|
||||
if (funcp->dpiImportPrototype()) // Declared in __Dpi.h
|
||||
continue;
|
||||
if (funcp->dpiExportDispatcher()) // Declared in __Dpi.h
|
||||
|
|
@ -230,7 +230,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
}
|
||||
void emitAll(const AstNodeModule* modp) {
|
||||
// Include files required by this AstNodeModule
|
||||
if (const AstClass* const classp = VN_CAST_CONST(modp, Class)) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (classp->extendsp())
|
||||
puts("#include \""
|
||||
+ prefixNameProtect(classp->extendsp()->classp()->classOrPackagep())
|
||||
|
|
@ -246,7 +246,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
emitTextSection(modp, AstType::atScHdr);
|
||||
|
||||
// Open class body {{{
|
||||
if (const AstClass* const classp = VN_CAST_CONST(modp, Class)) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
puts("class ");
|
||||
puts(prefixNameProtect(modp));
|
||||
if (classp->extendsp()) {
|
||||
|
|
@ -310,7 +310,7 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
|
||||
emitAll(modp);
|
||||
|
||||
if (const AstClassPackage* const packagep = VN_CAST_CONST(modp, ClassPackage)) {
|
||||
if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) {
|
||||
// Put the non-static class implementation in same h file for speed
|
||||
emitAll(packagep->classp());
|
||||
}
|
||||
|
|
@ -335,6 +335,6 @@ void V3EmitC::emitcHeaders() {
|
|||
// Process each module in turn
|
||||
for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) {
|
||||
if (VN_IS(nodep, Class)) continue; // Declared with the ClassPackage
|
||||
EmitCHeader::main(VN_CAST_CONST(nodep, NodeModule));
|
||||
EmitCHeader::main(VN_AS(nodep, NodeModule));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ class EmitCGatherDependencies final : AstNVisitor {
|
|||
// METHODS
|
||||
void addSymsDependency() { m_dependencies.insert(EmitCBaseVisitor::symClassName()); }
|
||||
void addModDependency(const AstNodeModule* modp) {
|
||||
if (const AstClass* const classp = VN_CAST_CONST(modp, Class)) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(classp->classOrPackagep()));
|
||||
} else {
|
||||
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(modp));
|
||||
}
|
||||
}
|
||||
void addDTypeDependency(const AstNodeDType* nodep) {
|
||||
if (const AstClassRefDType* const dtypep = VN_CAST_CONST(nodep, ClassRefDType)) {
|
||||
if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) {
|
||||
m_dependencies.insert(
|
||||
EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep()));
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ class EmitCGatherDependencies final : AstNVisitor {
|
|||
|
||||
public:
|
||||
static const std::set<std::string> gather(AstCFunc* cfuncp) {
|
||||
EmitCGatherDependencies visitor{cfuncp};
|
||||
const EmitCGatherDependencies visitor{cfuncp};
|
||||
return std::move(visitor.m_dependencies);
|
||||
}
|
||||
};
|
||||
|
|
@ -193,7 +193,7 @@ class EmitCImp final : EmitCFunc {
|
|||
// Emit static variable definitions
|
||||
const string modName = prefixNameProtect(modp);
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isStatic()) {
|
||||
puts(varp->vlArgType(true, false, false, modName));
|
||||
puts(";\n");
|
||||
|
|
@ -205,7 +205,7 @@ class EmitCImp final : EmitCFunc {
|
|||
const string modName = prefixNameProtect(modp);
|
||||
bool first = true;
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isParam()) {
|
||||
if (first) {
|
||||
puts("\n");
|
||||
|
|
@ -241,7 +241,7 @@ class EmitCImp final : EmitCFunc {
|
|||
|
||||
ofp()->indentInc();
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (const AstBasicDType* const dtypep
|
||||
= VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
|
||||
if (dtypep->keyword().isMTaskState()) {
|
||||
|
|
@ -348,7 +348,7 @@ class EmitCImp final : EmitCFunc {
|
|||
// just looking for loading the wrong model
|
||||
VHashSha256 hash;
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* varp = VN_CAST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
hash.insert(varp->name());
|
||||
hash.insert(varp->dtypep()->width());
|
||||
}
|
||||
|
|
@ -369,7 +369,7 @@ class EmitCImp final : EmitCFunc {
|
|||
|
||||
// Save all members
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* varp = VN_CAST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isIO() && modp->isTop() && optSystemC()) {
|
||||
// System C top I/O doesn't need loading, as the
|
||||
// lower level subinst code does it.
|
||||
|
|
@ -446,7 +446,7 @@ class EmitCImp final : EmitCFunc {
|
|||
}
|
||||
void emitCommonImp(const AstNodeModule* modp) {
|
||||
const AstClass* const classp
|
||||
= VN_IS(modp, ClassPackage) ? VN_CAST_CONST(modp, ClassPackage)->classp() : nullptr;
|
||||
= VN_IS(modp, ClassPackage) ? VN_AS(modp, ClassPackage)->classp() : nullptr;
|
||||
|
||||
if (hasCommonImp(modp) || hasCommonImp(classp)) {
|
||||
std::set<string> headers;
|
||||
|
|
@ -486,7 +486,7 @@ class EmitCImp final : EmitCFunc {
|
|||
};
|
||||
|
||||
gather(modp);
|
||||
if (const AstClassPackage* const packagep = VN_CAST_CONST(modp, ClassPackage)) {
|
||||
if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) {
|
||||
gather(packagep->classp());
|
||||
}
|
||||
|
||||
|
|
@ -556,7 +556,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
// NODE STATE/TYPES
|
||||
// Cleared on netlist
|
||||
// AstNode::user1() -> int. Enum number
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// MEMBERS
|
||||
const bool m_slow; // Making slow file
|
||||
|
|
@ -576,7 +576,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
if (m_slow) filename += "__Slow";
|
||||
filename += ".cpp";
|
||||
|
||||
AstCFile* cfilep = newCFile(filename, m_slow, true /*source*/);
|
||||
AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/);
|
||||
cfilep->support(true);
|
||||
|
||||
if (optSystemC()) {
|
||||
|
|
@ -595,23 +595,23 @@ class EmitCTrace final : EmitCFunc {
|
|||
}
|
||||
|
||||
bool emitTraceIsScBv(AstTraceInc* nodep) {
|
||||
const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
|
||||
const AstVarRef* const varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
|
||||
if (!varrefp) return false;
|
||||
AstVar* varp = varrefp->varp();
|
||||
AstVar* const varp = varrefp->varp();
|
||||
return varp->isSc() && varp->isScBv();
|
||||
}
|
||||
|
||||
bool emitTraceIsScBigUint(AstTraceInc* nodep) {
|
||||
const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
|
||||
const AstVarRef* const varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
|
||||
if (!varrefp) return false;
|
||||
AstVar* varp = varrefp->varp();
|
||||
AstVar* const varp = varrefp->varp();
|
||||
return varp->isSc() && varp->isScBigUint();
|
||||
}
|
||||
|
||||
bool emitTraceIsScUint(AstTraceInc* nodep) {
|
||||
const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
|
||||
const AstVarRef* const varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
|
||||
if (!varrefp) return false;
|
||||
AstVar* varp = varrefp->varp();
|
||||
AstVar* const varp = varrefp->varp();
|
||||
return varp->isSc() && varp->isScUint();
|
||||
}
|
||||
|
||||
|
|
@ -714,7 +714,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
if (v3Global.opt.traceFormat().fst()) {
|
||||
// Skip over refs-to-refs, but stop before final ref so can get data type name
|
||||
// Alternatively back in V3Width we could push enum names from upper typedefs
|
||||
if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
|
||||
if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
|
||||
int enumNum = enump->user1();
|
||||
if (!enumNum) {
|
||||
enumNum = ++m_enumNum;
|
||||
|
|
@ -724,7 +724,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
puts("const char* " + protect("__VenumItemNames") + "[]\n");
|
||||
puts("= {");
|
||||
for (AstEnumItem* itemp = enump->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
|
||||
itemp = VN_AS(itemp->nextp(), EnumItem)) {
|
||||
if (++nvals > 1) puts(", ");
|
||||
putbs("\"" + itemp->prettyName() + "\"");
|
||||
}
|
||||
|
|
@ -733,8 +733,8 @@ class EmitCTrace final : EmitCFunc {
|
|||
puts("const char* " + protect("__VenumItemValues") + "[]\n");
|
||||
puts("= {");
|
||||
for (AstEnumItem* itemp = enump->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
|
||||
AstConst* constp = VN_CAST(itemp->valuep(), Const);
|
||||
itemp = VN_AS(itemp->nextp(), EnumItem)) {
|
||||
AstConst* const constp = VN_AS(itemp->valuep(), Const);
|
||||
if (++nvals > 1) puts(", ");
|
||||
putbs("\"" + constp->num().displayed(nodep, "%0b") + "\"");
|
||||
}
|
||||
|
|
@ -785,7 +785,7 @@ class EmitCTrace final : EmitCFunc {
|
|||
|
||||
void emitTraceValue(AstTraceInc* nodep, int arrayindex) {
|
||||
if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) {
|
||||
AstVar* varp = varrefp->varp();
|
||||
AstVar* const varp = varrefp->varp();
|
||||
puts("(");
|
||||
if (emitTraceIsScBigUint(nodep)) {
|
||||
puts("(vluint32_t*)");
|
||||
|
|
@ -882,12 +882,12 @@ public:
|
|||
void V3EmitC::emitcImp() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// Make parent module pointers available.
|
||||
EmitCParentModule emitCParentModule;
|
||||
const EmitCParentModule emitCParentModule;
|
||||
|
||||
// Process each module in turn
|
||||
for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) {
|
||||
if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage
|
||||
const AstNodeModule* const modp = VN_CAST_CONST(nodep, NodeModule);
|
||||
const AstNodeModule* const modp = VN_AS(nodep, NodeModule);
|
||||
EmitCImp::main(modp, /* slow: */ true);
|
||||
EmitCImp::main(modp, /* slow: */ false);
|
||||
}
|
||||
|
|
@ -902,13 +902,13 @@ void V3EmitC::emitcImp() {
|
|||
void V3EmitC::emitcFiles() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
|
||||
filep = VN_CAST(filep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(filep, CFile);
|
||||
filep = VN_AS(filep->nextp(), NodeFile)) {
|
||||
AstCFile* const cfilep = VN_CAST(filep, CFile);
|
||||
if (cfilep && cfilep->tblockp()) {
|
||||
V3OutCFile of(cfilep->name());
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated C++\n");
|
||||
EmitCFunc visitor(cfilep->tblockp(), &of, true);
|
||||
const EmitCFunc visitor(cfilep->tblockp(), &of, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ class CMakeEmitter final {
|
|||
std::vector<string> support_slow;
|
||||
std::vector<string> global;
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(nodep, CFile);
|
||||
nodep = VN_AS(nodep->nextp(), NodeFile)) {
|
||||
const AstCFile* const cfilep = VN_CAST(nodep, CFile);
|
||||
if (cfilep && cfilep->source()) {
|
||||
if (cfilep->support()) {
|
||||
if (cfilep->slow()) {
|
||||
|
|
@ -178,8 +178,8 @@ class CMakeEmitter final {
|
|||
if (v3Global.opt.mtasks()) {
|
||||
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
|
||||
}
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
|
||||
if (!v3Global.opt.libCreate().empty()) {
|
||||
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.libCreate() + ".cpp");
|
||||
}
|
||||
|
||||
*of << "# Global classes, need linked once per executable\n";
|
||||
|
|
@ -199,7 +199,7 @@ class CMakeEmitter final {
|
|||
|
||||
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
|
||||
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
|
||||
if (const V3HierBlockPlan* planp = v3Global.hierPlanp()) {
|
||||
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
|
||||
*of << "# Verilate hierarchical blocks\n";
|
||||
// Sorted hierarchical blocks in order of leaf-first.
|
||||
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
||||
|
|
@ -238,7 +238,7 @@ class CMakeEmitter final {
|
|||
// with .so
|
||||
<< ")\n";
|
||||
}
|
||||
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
|
||||
*of << "\n# Verilate the top module that refers to lib-create wrappers of above\n";
|
||||
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
|
||||
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
|
||||
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
|
||||
|
|
@ -260,5 +260,5 @@ public:
|
|||
|
||||
void V3EmitCMake::emit() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
CMakeEmitter emitter;
|
||||
const CMakeEmitter emitter;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,14 +23,31 @@
|
|||
#include "V3UniqueNames.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class EmitCModel final : public EmitCFunc {
|
||||
// TYPES
|
||||
using CFuncVector = std::vector<const AstCFunc*>;
|
||||
|
||||
// MEMBERS
|
||||
V3UniqueNames m_uniqueNames; // For generating unique file names
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC;
|
||||
|
||||
CFuncVector findFuncps(std::function<bool(const AstCFunc*)> cb) {
|
||||
CFuncVector funcps;
|
||||
for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
|
||||
if (cb(funcp)) funcps.push_back(funcp);
|
||||
}
|
||||
}
|
||||
stable_sort(funcps.begin(), funcps.end(),
|
||||
[](const AstNode* ap, const AstNode* bp) { return ap->name() < bp->name(); });
|
||||
return funcps;
|
||||
}
|
||||
|
||||
void putSectionDelimiter(const string& name) {
|
||||
puts("\n");
|
||||
puts("//============================================================\n");
|
||||
|
|
@ -90,7 +107,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
"// The application code writes and reads these signals to\n"
|
||||
"// propagate new values into/out from the Verilated model.\n");
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isPrimaryIO()) { //
|
||||
emitVarDecl(varp, /* asRef: */ true);
|
||||
}
|
||||
|
|
@ -102,7 +119,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
"// Public to allow access to /* verilator public */ items.\n"
|
||||
"// Otherwise the application code can consider these internals.\n");
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) {
|
||||
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
|
||||
puts(prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect() + ";\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -136,7 +153,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts("\n");
|
||||
ofp()->putsPrivate(false); // public:
|
||||
puts("// API METHODS\n");
|
||||
string callEvalEndStep
|
||||
const string callEvalEndStep
|
||||
= (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : "";
|
||||
if (optSystemC()) {
|
||||
ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls.
|
||||
|
|
@ -187,22 +204,11 @@ class EmitCModel final : public EmitCFunc {
|
|||
|
||||
// Emit DPI export dispatcher declarations
|
||||
{
|
||||
std::vector<const AstCFunc*> funcps;
|
||||
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) {
|
||||
if (!funcp->dpiExportDispatcher()) continue;
|
||||
funcps.push_back(funcp);
|
||||
}
|
||||
}
|
||||
|
||||
stable_sort(funcps.begin(), funcps.end(), [](const AstNode* ap, const AstNode* bp) {
|
||||
return ap->name() < bp->name();
|
||||
});
|
||||
|
||||
const CFuncVector funcps
|
||||
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiExportDispatcher(); });
|
||||
if (!funcps.empty()) {
|
||||
puts("\n/// DPI Export functions\n");
|
||||
for (const AstCFunc* funcp : funcps) { emitCFuncDecl(funcp, modp); }
|
||||
for (const AstCFunc* funcp : funcps) emitCFuncDecl(funcp, modp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +243,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
|
||||
// Set up IO references
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isPrimaryIO()) {
|
||||
const string protName = varp->nameProtect();
|
||||
puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n");
|
||||
|
|
@ -247,7 +253,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
|
||||
// Setup cell pointers
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) {
|
||||
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
|
||||
const string protName = cellp->nameProtect();
|
||||
puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n");
|
||||
}
|
||||
|
|
@ -422,7 +428,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
+ "(vlSymsp);\n");
|
||||
|
||||
if (v3Global.opt.threads() == 1) {
|
||||
uint32_t mtaskId = 0;
|
||||
const uint32_t mtaskId = 0;
|
||||
putsDecoration("// MTask " + cvtToStr(mtaskId) + " start\n");
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask" + cvtToStr(mtaskId) + " starting\\n\"););\n");
|
||||
puts("Verilated::mtaskId(" + cvtToStr(mtaskId) + ");\n");
|
||||
|
|
@ -515,12 +521,6 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts("}\n");
|
||||
}
|
||||
|
||||
putSectionDelimiter("Invoke final blocks");
|
||||
// ::final
|
||||
puts("\nvoid " + topClassName() + "::final() {\n");
|
||||
puts(topModNameProtected + "__" + protect("_final") + "(&(vlSymsp->TOP));\n");
|
||||
puts("}\n");
|
||||
|
||||
putSectionDelimiter("Utilities");
|
||||
// ::contextp
|
||||
puts("\nVerilatedContext* " + topClassName() + "::contextp() const {\n");
|
||||
|
|
@ -533,6 +533,12 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts(/**/ "return vlSymsp->name();\n");
|
||||
puts("}\n");
|
||||
}
|
||||
|
||||
putSectionDelimiter("Invoke final blocks");
|
||||
// ::final
|
||||
puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n");
|
||||
puts(/**/ topModNameProtected + "__" + protect("_final") + "(&(vlSymsp->TOP));\n");
|
||||
puts("}\n");
|
||||
}
|
||||
|
||||
void emitTraceMethods(AstNodeModule* modp) {
|
||||
|
|
@ -546,7 +552,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
+ "* tracep);\n");
|
||||
|
||||
// Static helper function
|
||||
puts("\nstatic void " + protect("trace_init") + "(void* voidSelf, "
|
||||
puts("\nVL_ATTR_COLD static void " + protect("trace_init") + "(void* voidSelf, "
|
||||
+ v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n");
|
||||
putsDecoration("// Callback from tracep->open()\n");
|
||||
puts(voidSelfAssign(modp));
|
||||
|
|
@ -564,16 +570,42 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts("}\n");
|
||||
|
||||
// Forward declaration
|
||||
puts("\nvoid " + topModNameProtected + "__" + protect("trace_register") + "("
|
||||
puts("\nVL_ATTR_COLD void " + topModNameProtected + "__" + protect("trace_register") + "("
|
||||
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
|
||||
+ "* tracep);\n");
|
||||
|
||||
const CFuncVector traceInitFuncps
|
||||
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiTraceInit(); });
|
||||
for (const AstCFunc* const funcp : traceInitFuncps) emitCFuncDecl(funcp, modp);
|
||||
|
||||
// ::trace
|
||||
puts("\nvoid " + topClassName() + "::trace(");
|
||||
puts(v3Global.opt.traceClassBase() + "C* tfp, int, int) {\n");
|
||||
puts("tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
|
||||
puts(topModNameProtected + "__" + protect("trace_register")
|
||||
puts("\nVL_ATTR_COLD void " + topClassName() + "::trace(");
|
||||
puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n");
|
||||
puts(/**/ "if (false && levels && options) {} // Prevent unused\n");
|
||||
puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
|
||||
puts(/**/ topModNameProtected + "__" + protect("trace_register")
|
||||
+ "(&(vlSymsp->TOP), tfp->spTrace());\n");
|
||||
|
||||
if (!traceInitFuncps.empty()) {
|
||||
puts(/**/ "if (levels > 0) {\n");
|
||||
puts(/****/ "const QData tfpq = reinterpret_cast<QData>(tfp);\n");
|
||||
for (const AstCFunc* const funcp : traceInitFuncps) {
|
||||
// Some hackery to locate handle__V for trace_init_task
|
||||
// Considered a pragma on the handle, but that still doesn't help us attach it here
|
||||
string handle = funcp->name();
|
||||
const size_t wr_len = strlen("__Vdpiimwrap_");
|
||||
UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp,
|
||||
"Strange trace_init_task function name");
|
||||
handle = "vlSymsp->TOP." + handle.substr(wr_len);
|
||||
const string::size_type pos = handle.rfind("__DOT__");
|
||||
UASSERT_OBJ(pos != string::npos, funcp, "Strange trace_init_task function name");
|
||||
handle = handle.substr(0, pos) + "__DOT__handle___05FV";
|
||||
puts(funcNameProtect(funcp, modp) + "(" + handle
|
||||
+ ", tfpq, levels - 1, options);\n");
|
||||
}
|
||||
puts(/**/ "}\n");
|
||||
}
|
||||
|
||||
puts("}\n");
|
||||
}
|
||||
|
||||
|
|
@ -582,16 +614,16 @@ class EmitCModel final : public EmitCFunc {
|
|||
|
||||
puts("\nVerilatedSerialize& operator<<(VerilatedSerialize& os, " + topClassName()
|
||||
+ "& rhs) {\n");
|
||||
puts("Verilated::quiesce();\n");
|
||||
puts("rhs.vlSymsp->" + protect("__Vserialize") + "(os);\n");
|
||||
puts("return os;\n");
|
||||
puts(/**/ "Verilated::quiesce();\n");
|
||||
puts(/**/ "rhs.vlSymsp->" + protect("__Vserialize") + "(os);\n");
|
||||
puts(/**/ "return os;\n");
|
||||
puts("}\n");
|
||||
|
||||
puts("\nVerilatedDeserialize& operator>>(VerilatedDeserialize& os, " + topClassName()
|
||||
+ "& rhs) {\n");
|
||||
puts("Verilated::quiesce();\n");
|
||||
puts("rhs.vlSymsp->" + protect("__Vdeserialize") + "(os);\n");
|
||||
puts("return os;\n");
|
||||
puts(/**/ "Verilated::quiesce();\n");
|
||||
puts(/**/ "rhs.vlSymsp->" + protect("__Vdeserialize") + "(os);\n");
|
||||
puts(/**/ "return os;\n");
|
||||
puts("}\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
// NODE STATE
|
||||
// Cleared on Netlist
|
||||
// AstNodeModule::user1() -> bool. Set true __Vconfigure called
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
struct ScopeData {
|
||||
string m_symName;
|
||||
string m_prettyName;
|
||||
int m_timeunit;
|
||||
const string m_symName;
|
||||
const string m_prettyName;
|
||||
const int m_timeunit;
|
||||
string m_type;
|
||||
ScopeData(const string& symName, const string& prettyName, int timeunit,
|
||||
const string& type)
|
||||
|
|
@ -50,22 +50,22 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
, m_type{type} {}
|
||||
};
|
||||
struct ScopeFuncData {
|
||||
AstScopeName* m_scopep;
|
||||
AstCFunc* m_cfuncp;
|
||||
AstNodeModule* m_modp;
|
||||
AstScopeName* const m_scopep;
|
||||
AstCFunc* const m_cfuncp;
|
||||
AstNodeModule* const m_modp;
|
||||
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
||||
: m_scopep{scopep}
|
||||
, m_cfuncp{funcp}
|
||||
, m_modp{modp} {}
|
||||
};
|
||||
struct ScopeVarData {
|
||||
string m_scopeName;
|
||||
string m_varBasePretty;
|
||||
AstVar* m_varp;
|
||||
AstNodeModule* m_modp;
|
||||
AstScope* m_scopep;
|
||||
const string m_scopeName;
|
||||
const string m_varBasePretty;
|
||||
AstVar* const m_varp;
|
||||
const AstNodeModule* const m_modp;
|
||||
AstScope* const m_scopep;
|
||||
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp,
|
||||
AstNodeModule* modp, AstScope* scopep)
|
||||
const AstNodeModule* modp, AstScope* scopep)
|
||||
: m_scopeName{scopeName}
|
||||
, m_varBasePretty{varBasePretty}
|
||||
, m_varp{varp}
|
||||
|
|
@ -104,7 +104,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
|
||||
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
|
||||
int m_coverBins = 0; // Coverage bin number
|
||||
bool m_dpiHdrOnly; // Only emit the DPI header
|
||||
const bool m_dpiHdrOnly; // Only emit the DPI header
|
||||
int m_numStmts = 0; // Number of statements output
|
||||
int m_funcNum = 0; // CFunc split function number
|
||||
V3OutCFile* m_ofpBase = nullptr; // Base (not split) C file
|
||||
|
|
@ -124,8 +124,8 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
// Prevent GCC compile time error; name check all things that reach C++ code
|
||||
if (nodep->name() != ""
|
||||
&& !(VN_IS(nodep, CFunc)
|
||||
&& (VN_CAST(nodep, CFunc)->isConstructor()
|
||||
|| VN_CAST(nodep, CFunc)->isDestructor()))) {
|
||||
&& (VN_AS(nodep, CFunc)->isConstructor()
|
||||
|| VN_AS(nodep, CFunc)->isDestructor()))) {
|
||||
const string rsvd = V3LanguageWords::isKeyword(nodep->name());
|
||||
if (rsvd != "") {
|
||||
// Generally V3Name should find all of these and throw SYMRSVDWORD.
|
||||
|
|
@ -193,12 +193,12 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
// Someday. For now public isn't common.
|
||||
for (std::vector<ScopeModPair>::iterator itsc = m_scopes.begin(); itsc != m_scopes.end();
|
||||
++itsc) {
|
||||
AstScope* scopep = itsc->first;
|
||||
AstNodeModule* smodp = itsc->second;
|
||||
AstScope* const scopep = itsc->first;
|
||||
const AstNodeModule* const smodp = itsc->second;
|
||||
for (std::vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end();
|
||||
++it) {
|
||||
AstNodeModule* modp = it->first;
|
||||
AstVar* varp = it->second;
|
||||
const AstNodeModule* const modp = it->first;
|
||||
AstVar* const varp = it->second;
|
||||
if (modp == smodp) {
|
||||
// Need to split the module + var name into the
|
||||
// original-ish full scope and variable name under that scope.
|
||||
|
|
@ -208,7 +208,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
string scpName;
|
||||
string varBase;
|
||||
if (whole.substr(0, 10) == "__DOT__TOP") whole.replace(0, 10, "");
|
||||
string::size_type dpos = whole.rfind("__DOT__");
|
||||
const string::size_type dpos = whole.rfind("__DOT__");
|
||||
if (dpos != string::npos) {
|
||||
scpName = whole.substr(0, dpos);
|
||||
varBase = whole.substr(dpos + strlen("__DOT__"));
|
||||
|
|
@ -245,7 +245,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
if (above.substr(0, 4) == "TOP.") above.replace(0, 4, "");
|
||||
|
||||
while (!above.empty()) {
|
||||
string::size_type pos = above.rfind("__");
|
||||
const string::size_type pos = above.rfind("__");
|
||||
if (pos == string::npos) break;
|
||||
above.resize(pos);
|
||||
if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) {
|
||||
|
|
@ -402,7 +402,7 @@ void EmitCSyms::emitSymHdr() {
|
|||
|
||||
puts("\n// INCLUDE MODULE CLASSES\n");
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
|
||||
nodep = VN_AS(nodep->nextp(), NodeModule)) {
|
||||
if (VN_IS(nodep, Class)) continue; // Class included earlier
|
||||
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ void EmitCSyms::emitSymHdr() {
|
|||
puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n");
|
||||
std::map<const string, int> types; // Remove duplicates and sort
|
||||
for (const auto& itr : m_scopeFuncs) {
|
||||
AstCFunc* funcp = itr.second.m_cfuncp;
|
||||
const AstCFunc* const funcp = itr.second.m_cfuncp;
|
||||
if (funcp->dpiExportImpl()) {
|
||||
const string cbtype
|
||||
= protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t");
|
||||
|
|
@ -461,8 +461,8 @@ void EmitCSyms::emitSymHdr() {
|
|||
|
||||
puts("\n// MODULE INSTANCE STATE\n");
|
||||
for (const auto& i : m_scopes) {
|
||||
AstScope* scopep = i.first;
|
||||
AstNodeModule* modp = i.second;
|
||||
const AstScope* const scopep = i.first;
|
||||
const AstNodeModule* const modp = i.second;
|
||||
if (VN_IS(modp, Class)) continue;
|
||||
const string name = prefixNameProtect(modp);
|
||||
ofp()->printf("%-30s ", name.c_str());
|
||||
|
|
@ -484,7 +484,8 @@ void EmitCSyms::emitSymHdr() {
|
|||
for (const V3GraphVertex* vxp
|
||||
= v3Global.rootp()->execGraphp()->depGraphp()->verticesBeginp();
|
||||
vxp; vxp = vxp->verticesNextp()) {
|
||||
ExecMTask* mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
const ExecMTask* const mtp
|
||||
= dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
if (maxProfilerId < mtp->profilerId()) maxProfilerId = mtp->profilerId();
|
||||
}
|
||||
}
|
||||
|
|
@ -551,9 +552,9 @@ void EmitCSyms::checkSplit(bool usesVfinal) {
|
|||
v3Global.useParallelBuild(true);
|
||||
|
||||
m_numStmts = 0;
|
||||
string filename
|
||||
const string filename
|
||||
= v3Global.opt.makeDir() + "/" + symClassName() + "__" + cvtToStr(++m_funcNum) + ".cpp";
|
||||
AstCFile* cfilep = newCFile(filename, true /*slow*/, true /*source*/);
|
||||
AstCFile* const cfilep = newCFile(filename, true /*slow*/, true /*source*/);
|
||||
cfilep->support(true);
|
||||
m_usesVfinal[m_funcNum] = usesVfinal;
|
||||
closeSplit();
|
||||
|
|
@ -584,7 +585,7 @@ void EmitCSyms::emitSymImpPreamble() {
|
|||
puts("#include \"" + symClassName() + ".h\"\n");
|
||||
puts("#include \"" + topClassName() + ".h\"\n");
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
|
||||
nodep = VN_AS(nodep->nextp(), NodeModule)) {
|
||||
if (VN_IS(nodep, Class)) continue; // Class included earlier
|
||||
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
|
||||
}
|
||||
|
|
@ -636,7 +637,7 @@ void EmitCSyms::emitScopeHier(bool destroy) {
|
|||
void EmitCSyms::emitSymImp() {
|
||||
UINFO(6, __FUNCTION__ << ": " << endl);
|
||||
const string filename = v3Global.opt.makeDir() + "/" + symClassName() + ".cpp";
|
||||
AstCFile* cfilep = newCFile(filename, true /*slow*/, true /*source*/);
|
||||
AstCFile* const cfilep = newCFile(filename, true /*slow*/, true /*source*/);
|
||||
cfilep->support(true);
|
||||
|
||||
if (v3Global.opt.systemC()) {
|
||||
|
|
@ -746,7 +747,7 @@ void EmitCSyms::emitSymImp() {
|
|||
for (const V3GraphVertex* vxp
|
||||
= v3Global.rootp()->execGraphp()->depGraphp()->verticesBeginp();
|
||||
vxp; vxp = vxp->verticesNextp()) {
|
||||
ExecMTask* mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
ExecMTask* const mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
puts("_vm_profiler.addCounter(" + cvtToStr(mtp->profilerId()) + ", \""
|
||||
+ mtp->hashName() + "\");\n");
|
||||
}
|
||||
|
|
@ -788,8 +789,8 @@ void EmitCSyms::emitSymImp() {
|
|||
|
||||
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
|
||||
for (const auto& i : m_scopes) {
|
||||
AstScope* scopep = i.first;
|
||||
AstNodeModule* modp = i.second;
|
||||
AstScope* const scopep = i.first;
|
||||
AstNodeModule* const modp = i.second;
|
||||
checkSplit(false);
|
||||
// first is used by AstCoverDecl's call to __vlCoverInsert
|
||||
const bool first = !modp->user1();
|
||||
|
|
@ -823,9 +824,9 @@ void EmitCSyms::emitSymImp() {
|
|||
m_ofpBase->puts("// Setup export functions\n");
|
||||
m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
|
||||
for (auto it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
|
||||
AstScopeName* scopep = it->second.m_scopep;
|
||||
AstCFunc* funcp = it->second.m_cfuncp;
|
||||
AstNodeModule* modp = it->second.m_modp;
|
||||
AstScopeName* const scopep = it->second.m_scopep;
|
||||
AstCFunc* const funcp = it->second.m_cfuncp;
|
||||
AstNodeModule* const modp = it->second.m_modp;
|
||||
if (funcp->dpiExportImpl()) {
|
||||
checkSplit(true);
|
||||
puts(protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, ");
|
||||
|
|
@ -842,14 +843,14 @@ void EmitCSyms::emitSymImp() {
|
|||
// Someday. For now public isn't common.
|
||||
for (auto it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
|
||||
checkSplit(true);
|
||||
AstScope* scopep = it->second.m_scopep;
|
||||
AstVar* varp = it->second.m_varp;
|
||||
AstScope* const scopep = it->second.m_scopep;
|
||||
AstVar* const varp = it->second.m_varp;
|
||||
//
|
||||
int pwidth = 1;
|
||||
int pdim = 0;
|
||||
int udim = 0;
|
||||
string bounds;
|
||||
if (AstBasicDType* basicp = varp->basicp()) {
|
||||
if (AstBasicDType* const basicp = varp->basicp()) {
|
||||
// Range is always first, it's not in "C" order
|
||||
if (basicp->isRanged()) {
|
||||
bounds += " ,";
|
||||
|
|
@ -862,7 +863,7 @@ void EmitCSyms::emitSymImp() {
|
|||
for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) {
|
||||
dtypep
|
||||
= dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
bounds += " ,";
|
||||
bounds += cvtToStr(adtypep->left());
|
||||
bounds += ",";
|
||||
|
|
@ -964,7 +965,7 @@ void EmitCSyms::emitSymImp() {
|
|||
void EmitCSyms::emitDpiHdr() {
|
||||
UINFO(6, __FUNCTION__ << ": " << endl);
|
||||
const string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Dpi.h";
|
||||
AstCFile* cfilep = newCFile(filename, false /*slow*/, false /*source*/);
|
||||
AstCFile* const cfilep = newCFile(filename, false /*slow*/, false /*source*/);
|
||||
cfilep->support(true);
|
||||
V3OutCFile hf(filename);
|
||||
m_ofp = &hf;
|
||||
|
|
@ -1018,7 +1019,7 @@ void EmitCSyms::emitDpiHdr() {
|
|||
void EmitCSyms::emitDpiImp() {
|
||||
UINFO(6, __FUNCTION__ << ": " << endl);
|
||||
const string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Dpi.cpp";
|
||||
AstCFile* cfilep = newCFile(filename, false /*slow*/, true /*source*/);
|
||||
AstCFile* const cfilep = newCFile(filename, false /*slow*/, true /*source*/);
|
||||
cfilep->support(true);
|
||||
V3OutCFile hf(filename);
|
||||
m_ofp = &hf;
|
||||
|
|
@ -1052,7 +1053,7 @@ void EmitCSyms::emitDpiImp() {
|
|||
puts("return " + topClassName() + "::" + nodep->name() + "(");
|
||||
string args;
|
||||
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (const AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args += ", ";
|
||||
args += portp->name();
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@ public:
|
|||
} else if (support == 2 && slow) {
|
||||
} else {
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(nodep, CFile);
|
||||
nodep = VN_AS(nodep->nextp(), NodeFile)) {
|
||||
const AstCFile* const cfilep = VN_CAST(nodep, CFile);
|
||||
if (cfilep && cfilep->source() && cfilep->slow() == (slow != 0)
|
||||
&& cfilep->support() == (support != 0)) {
|
||||
putMakeClassEntry(of, cfilep->name());
|
||||
|
|
@ -145,8 +145,8 @@ public:
|
|||
|
||||
if (v3Global.opt.exe()) {
|
||||
of.puts("default: " + v3Global.opt.exeName() + "\n");
|
||||
} else if (!v3Global.opt.protectLib().empty()) {
|
||||
of.puts("default: lib" + v3Global.opt.protectLib() + "\n");
|
||||
} else if (!v3Global.opt.libCreate().empty()) {
|
||||
of.puts("default: lib" + v3Global.opt.libCreate() + "\n");
|
||||
} else {
|
||||
of.puts("default: " + v3Global.opt.prefix() + "__ALL.a\n");
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ public:
|
|||
|
||||
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
|
||||
of.puts("VM_USER_CFLAGS = \\\n");
|
||||
if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n");
|
||||
if (!v3Global.opt.libCreate().empty()) of.puts("\t-fPIC \\\n");
|
||||
const V3StringList& cFlags = v3Global.opt.cFlags();
|
||||
for (const string& i : cFlags) of.puts("\t" + i + " \\\n");
|
||||
of.puts("\n");
|
||||
|
|
@ -243,19 +243,19 @@ public:
|
|||
of.puts("\n");
|
||||
}
|
||||
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
const string protectLibDeps = "$(VK_OBJS) $(VK_GLOBAL_OBJS) "
|
||||
+ v3Global.opt.protectLib() + ".o $(VM_HIER_LIBS)";
|
||||
of.puts("\n### Library rules from --protect-lib\n");
|
||||
if (!v3Global.opt.libCreate().empty()) {
|
||||
const string libCreateDeps = "$(VK_OBJS) $(VK_GLOBAL_OBJS) " + v3Global.opt.libCreate()
|
||||
+ ".o $(VM_HIER_LIBS)";
|
||||
of.puts("\n### Library rules from --lib-create\n");
|
||||
// The rule to create .a is defined in verilated.mk, so just define dependency here.
|
||||
of.puts(v3Global.opt.protectLibName(false) + ": " + protectLibDeps + "\n");
|
||||
of.puts(v3Global.opt.libCreateName(false) + ": " + libCreateDeps + "\n");
|
||||
of.puts("\n");
|
||||
if (v3Global.opt.hierChild()) {
|
||||
// Hierarchical child does not need .so because hierTop() will create .so from .a
|
||||
of.puts("lib" + v3Global.opt.protectLib() + ": "
|
||||
+ v3Global.opt.protectLibName(false) + "\n");
|
||||
of.puts("lib" + v3Global.opt.libCreate() + ": " + v3Global.opt.libCreateName(false)
|
||||
+ "\n");
|
||||
} else {
|
||||
of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n");
|
||||
of.puts(v3Global.opt.libCreateName(true) + ": " + libCreateDeps + "\n");
|
||||
// Linker on mac emits an error if all symbols are not found here,
|
||||
// but some symbols that are referred as "DPI-C" can not be found at this moment.
|
||||
// So add dynamic_lookup
|
||||
|
|
@ -267,9 +267,8 @@ public:
|
|||
"\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n");
|
||||
of.puts("endif\n");
|
||||
of.puts("\n");
|
||||
of.puts("lib" + v3Global.opt.protectLib() + ": "
|
||||
+ v3Global.opt.protectLibName(false) + " "
|
||||
+ v3Global.opt.protectLibName(true) + "\n");
|
||||
of.puts("lib" + v3Global.opt.libCreate() + ": " + v3Global.opt.libCreateName(false)
|
||||
+ " " + v3Global.opt.libCreateName(true) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -408,7 +407,7 @@ public:
|
|||
|
||||
void V3EmitMk::emitmk() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
EmitMk emitter;
|
||||
const EmitMk emitter;
|
||||
}
|
||||
|
||||
void V3EmitMk::emitHierVerilation(const V3HierBlockPlan* planp) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
||||
// MEMBERS
|
||||
bool m_suppressSemi = false;
|
||||
bool m_suppressUnknown = false;
|
||||
const bool m_suppressUnknown = false;
|
||||
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
||||
|
||||
// METHODS
|
||||
|
|
@ -170,7 +170,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
}
|
||||
virtual void visit(AstNodeCase* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (const AstCase* casep = VN_CAST(nodep, Case)) {
|
||||
if (const AstCase* const casep = VN_CAST(nodep, Case)) {
|
||||
if (casep->priorityPragma()) puts("priority ");
|
||||
if (casep->uniquePragma()) puts("unique ");
|
||||
if (casep->unique0Pragma()) puts("unique0 ");
|
||||
|
|
@ -179,7 +179,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
puts(" (");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
puts(")\n");
|
||||
if (const AstCase* casep = VN_CAST(nodep, Case)) {
|
||||
if (const AstCase* const casep = VN_CAST(nodep, Case)) {
|
||||
if (casep->fullPragma() || casep->parallelPragma()) {
|
||||
puts(" // synopsys");
|
||||
if (casep->fullPragma()) puts(" full_case");
|
||||
|
|
@ -342,7 +342,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
}
|
||||
virtual void visit(AstNodeIf* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (const AstIf* ifp = VN_CAST(nodep, If)) {
|
||||
if (const AstIf* const ifp = VN_CAST(nodep, If)) {
|
||||
if (ifp->priorityPragma()) puts("priority ");
|
||||
if (ifp->uniquePragma()) puts("unique ");
|
||||
if (ifp->unique0Pragma()) puts("unique0 ");
|
||||
|
|
@ -382,7 +382,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
}
|
||||
}
|
||||
virtual void visit(AstTextBlock* nodep) override {
|
||||
visit(VN_CAST(nodep, NodeSimpleText));
|
||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||
{
|
||||
VL_RESTORER(m_suppressSemi);
|
||||
m_suppressVarSemi = nodep->commas();
|
||||
|
|
@ -416,7 +416,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
|
||||
// Operators
|
||||
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr,
|
||||
AstNode* rhsp = nullptr, AstNode* thsp = nullptr,
|
||||
AstNode* const rhsp = nullptr, AstNode* thsp = nullptr,
|
||||
AstNode* fhsp = nullptr) {
|
||||
// Look at emitVerilog() format for term/uni/dual/triops,
|
||||
// and write out appropriate text.
|
||||
|
|
@ -503,7 +503,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
if (comma++) putbs(", ");
|
||||
puts(cvtToStr(itr.first));
|
||||
puts(":");
|
||||
AstNode* valuep = itr.second->valuep();
|
||||
AstNode* const valuep = itr.second->valuep();
|
||||
iterate(valuep);
|
||||
}
|
||||
puts("}");
|
||||
|
|
@ -538,15 +538,15 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
if (VN_IS(nodep->lsbp(), Const)) {
|
||||
if (nodep->widthp()->isOne()) {
|
||||
if (VN_IS(nodep->lsbp(), Const)) {
|
||||
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
|
||||
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()));
|
||||
} else {
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
}
|
||||
} else {
|
||||
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()
|
||||
+ VN_CAST(nodep->widthp(), Const)->toSInt() - 1));
|
||||
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()
|
||||
+ VN_AS(nodep->widthp(), Const)->toSInt() - 1));
|
||||
puts(":");
|
||||
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
|
||||
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()));
|
||||
}
|
||||
} else {
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
|
|
@ -650,7 +650,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
|
|||
std::vector<const AstUnpackArrayDType*> unpackps;
|
||||
for (AstNodeDType* dtypep = nodep->dtypep(); dtypep;) {
|
||||
dtypep = dtypep->skipRefp();
|
||||
if (AstUnpackArrayDType* unpackp = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (const AstUnpackArrayDType* const unpackp = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
unpackps.push_back(unpackp);
|
||||
dtypep = unpackp->subDTypep();
|
||||
} else {
|
||||
|
|
@ -752,8 +752,8 @@ public:
|
|||
|
||||
class EmitVPrefixedFormatter final : public V3OutFormatter {
|
||||
std::ostream& m_os;
|
||||
string m_prefix; // What to print at beginning of each line
|
||||
int m_flWidth; // Padding of fileline
|
||||
const string m_prefix; // What to print at beginning of each line
|
||||
const int m_flWidth; // Padding of fileline
|
||||
int m_column; // Rough location; need just zero or non-zero
|
||||
FileLine* m_prefixFl;
|
||||
// METHODS
|
||||
|
|
@ -827,23 +827,25 @@ public:
|
|||
//######################################################################
|
||||
// EmitV class functions
|
||||
|
||||
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) { EmitVStreamVisitor(nodep, os); }
|
||||
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) {
|
||||
{ EmitVStreamVisitor{nodep, os}; }
|
||||
}
|
||||
|
||||
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
|
||||
int flWidth, AstSenTree* domainp, bool user3mark) {
|
||||
EmitVPrefixedVisitor{nodep, os, prefix, flWidth, domainp, user3mark};
|
||||
{ EmitVPrefixedVisitor{nodep, os, prefix, flWidth, domainp, user3mark}; }
|
||||
}
|
||||
|
||||
void V3EmitV::emitvFiles() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
|
||||
filep = VN_CAST(filep->nextp(), NodeFile)) {
|
||||
AstVFile* vfilep = VN_CAST(filep, VFile);
|
||||
filep = VN_AS(filep->nextp(), NodeFile)) {
|
||||
AstVFile* const vfilep = VN_CAST(filep, VFile);
|
||||
if (vfilep && vfilep->tblockp()) {
|
||||
V3OutVFile of(vfilep->name());
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated Verilog\n");
|
||||
EmitVFileVisitor visitor{vfilep->tblockp(), &of, true, false};
|
||||
{ EmitVFileVisitor{vfilep->tblockp(), &of, true, false}; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -853,5 +855,5 @@ void V3EmitV::debugEmitV(const string& stage) {
|
|||
const string filename
|
||||
= v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
|
||||
V3OutVFile of(filename);
|
||||
EmitVFileVisitor visitor{v3Global.rootp(), &of, true, true};
|
||||
{ EmitVFileVisitor{v3Global.rootp(), &of, true, true}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class EmitXmlFileVisitor final : public AstNVisitor {
|
|||
puts(" tag=");
|
||||
putsQuoted(nodep->tag());
|
||||
}
|
||||
if (AstNodeDType* dtp = VN_CAST(nodep, NodeDType)) {
|
||||
if (const AstNodeDType* const dtp = VN_CAST(nodep, NodeDType)) {
|
||||
if (dtp->subDTypep()) {
|
||||
puts(" sub_dtype_id=");
|
||||
outputId(dtp->subDTypep()->skipRefp());
|
||||
|
|
@ -409,7 +409,7 @@ private:
|
|||
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
|
||||
<< " submodname=\"" << nodep->modName() << "\""
|
||||
<< " hier=\"" << m_hier + nodep->name() << "\"";
|
||||
std::string hier = m_hier;
|
||||
const std::string hier = m_hier;
|
||||
m_hier += nodep->name() + ".";
|
||||
m_hasChildren = false;
|
||||
iterateChildren(nodep->modp());
|
||||
|
|
@ -455,10 +455,10 @@ void V3EmitXml::emitxml() {
|
|||
}
|
||||
{
|
||||
std::stringstream sstr;
|
||||
ModuleFilesXmlVisitor moduleFilesVisitor{v3Global.rootp(), sstr};
|
||||
HierCellsXmlVisitor cellsVisitor{v3Global.rootp(), sstr};
|
||||
const ModuleFilesXmlVisitor moduleFilesVisitor{v3Global.rootp(), sstr};
|
||||
const HierCellsXmlVisitor cellsVisitor{v3Global.rootp(), sstr};
|
||||
of.puts(sstr.str());
|
||||
}
|
||||
EmitXmlFileVisitor visitor{v3Global.rootp(), &of};
|
||||
const EmitXmlFileVisitor visitor{v3Global.rootp(), &of};
|
||||
of.puts("</verilator_xml>\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ v3errorIniter v3errorInit;
|
|||
V3ErrorCode::V3ErrorCode(const char* msgp) {
|
||||
// Return error encoding for given string, or ERROR, which is a bad code
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
const V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (0 == VL_STRCASECMP(msgp, code.ascii())) {
|
||||
m_e = code;
|
||||
return;
|
||||
|
|
@ -78,7 +78,7 @@ void V3Error::init() {
|
|||
|
||||
string V3Error::lineStr(const char* filename, int lineno) {
|
||||
std::ostringstream out;
|
||||
const char* fnslashp = std::strrchr(filename, '/');
|
||||
const char* const fnslashp = std::strrchr(filename, '/');
|
||||
if (fnslashp) filename = fnslashp + 1;
|
||||
out << filename << ":" << std::dec << lineno << ":";
|
||||
const char* const spaces = " ";
|
||||
|
|
@ -131,7 +131,7 @@ bool V3Error::isError(V3ErrorCode code, bool supp) {
|
|||
}
|
||||
|
||||
string V3Error::msgPrefix() {
|
||||
V3ErrorCode code = s_errorCode;
|
||||
const V3ErrorCode code = s_errorCode;
|
||||
const bool supp = s_errorSuppressed;
|
||||
if (supp) {
|
||||
return "-arning-suppressed: ";
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class ExpandVisitor final : public AstNVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> bool. Processed
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNode* m_stmtp = nullptr; // Current statement
|
||||
|
|
@ -109,7 +109,7 @@ private:
|
|||
static void fixCloneLvalue(AstNode* nodep) {
|
||||
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
|
||||
// but are now being used on the RHS of the assignment
|
||||
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ);
|
||||
if (VN_IS(nodep, VarRef)) VN_AS(nodep, VarRef)->access(VAccess::READ);
|
||||
// Iterate
|
||||
if (nodep->op1p()) fixCloneLvalue(nodep->op1p());
|
||||
if (nodep->op2p()) fixCloneLvalue(nodep->op2p());
|
||||
|
|
@ -183,8 +183,7 @@ private:
|
|||
AstNode* wordp;
|
||||
FileLine* const lfl = lsbp->fileline();
|
||||
if (VN_IS(lsbp, Const)) {
|
||||
wordp
|
||||
= new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_CAST(lsbp, Const)->toUInt())};
|
||||
wordp = new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_AS(lsbp, Const)->toUInt())};
|
||||
} else {
|
||||
wordp = new AstShiftR{lfl, lsbp->cloneTree(true),
|
||||
new AstConst{lfl, VL_EDATASIZE_LOG2}, VL_EDATASIZE};
|
||||
|
|
@ -202,8 +201,8 @@ private:
|
|||
// If there's a CONDBOUND safety to keep arrays in bounds,
|
||||
// we're going to AND it to a value that always fits inside a
|
||||
// word, so we don't need it.
|
||||
// if (VN_IS(nodep, CondBound) && VN_IS(VN_CAST(nodep, CondBound)->lhsp(), Lte)) {
|
||||
// nodep = VN_CAST(nodep, CondBound)->rhsp();
|
||||
// if (VN_IS(nodep, CondBound) && VN_IS(VN_AS(nodep, CondBound)->lhsp(), Lte)) {
|
||||
// nodep = VN_AS(nodep, CondBound)->rhsp();
|
||||
//}
|
||||
return nodep;
|
||||
}
|
||||
|
|
@ -212,7 +211,7 @@ private:
|
|||
// Return equation to get the VL_BITBIT of a constant or non-constant
|
||||
FileLine* const fl = lsbp->fileline();
|
||||
if (VN_IS(lsbp, Const)) {
|
||||
return new AstConst{fl, VL_BITBIT_E(VN_CAST(lsbp, Const)->toUInt())};
|
||||
return new AstConst{fl, VL_BITBIT_E(VN_AS(lsbp, Const)->toUInt())};
|
||||
} else {
|
||||
return new AstAnd{fl, new AstConst{fl, VL_EDATASIZE - 1},
|
||||
dropCondBound(lsbp)->cloneTree(true)};
|
||||
|
|
@ -346,7 +345,7 @@ private:
|
|||
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
||||
UASSERT_OBJ(nodep->widthMin() == nodep->widthConst(), nodep, "Width mismatch");
|
||||
if (VN_IS(nodep->backp(), NodeAssign)
|
||||
&& nodep == VN_CAST(nodep->backp(), NodeAssign)->lhsp()) {
|
||||
&& nodep == VN_AS(nodep->backp(), NodeAssign)->lhsp()) {
|
||||
// Sel is an LHS assignment select
|
||||
} else if (nodep->isWide()) {
|
||||
// See under ASSIGN(WIDE)
|
||||
|
|
@ -679,10 +678,10 @@ private:
|
|||
newp = new AstNegate{fl, lhsp};
|
||||
} else {
|
||||
UINFO(8, " REPLICATE " << nodep << endl);
|
||||
const AstConst* constp = VN_CAST(nodep->rhsp(), Const);
|
||||
const AstConst* const constp = VN_AS(nodep->rhsp(), Const);
|
||||
UASSERT_OBJ(constp, nodep,
|
||||
"Replication value isn't a constant. Checked earlier!");
|
||||
uint32_t times = constp->toUInt();
|
||||
const uint32_t times = constp->toUInt();
|
||||
if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; }
|
||||
newp = lhsp->cloneTree(true);
|
||||
for (unsigned repnum = 1; repnum < times; repnum++) {
|
||||
|
|
@ -707,7 +706,7 @@ private:
|
|||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const lhsp = rhsp->lhsp();
|
||||
const int lhswidth = lhsp->widthMin();
|
||||
const AstConst* const constp = VN_CAST(rhsp->rhsp(), Const);
|
||||
const AstConst* const constp = VN_AS(rhsp->rhsp(), Const);
|
||||
UASSERT_OBJ(constp, rhsp, "Replication value isn't a constant. Checked earlier!");
|
||||
const uint32_t times = constp->toUInt();
|
||||
for (int w = 0; w < rhsp->widthWords(); ++w) {
|
||||
|
|
@ -911,6 +910,6 @@ public:
|
|||
|
||||
void V3Expand::expandAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ExpandVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ ExpandVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ class V3FileDependImp final {
|
|||
// TYPES
|
||||
class DependFile final {
|
||||
// A single file
|
||||
bool m_target; // True if write, else read
|
||||
const bool m_target; // True if write, else read
|
||||
bool m_exists = true;
|
||||
string m_filename; // Filename
|
||||
const string m_filename; // Filename
|
||||
struct stat m_stat; // Stat information
|
||||
public:
|
||||
DependFile(const string& filename, bool target)
|
||||
|
|
@ -190,7 +190,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
|
|||
iter != m_filenameList.end(); ++iter) {
|
||||
// Read stats of files we create after we're done making them
|
||||
// (except for this file, of course)
|
||||
DependFile* dfp = const_cast<DependFile*>(&(*iter));
|
||||
DependFile* const dfp = const_cast<DependFile*>(&(*iter));
|
||||
V3Options::fileNfsFlush(dfp->filename());
|
||||
dfp->loadStats();
|
||||
off_t showSize = iter->size();
|
||||
|
|
@ -335,7 +335,7 @@ class VInFilterImp final {
|
|||
#ifdef INFILTER_PIPE
|
||||
pid_t m_pid = 0; // fork() process id
|
||||
#else
|
||||
int m_pid = 0; // fork() process id - always zero as disabled
|
||||
const int m_pid = 0; // fork() process id - always zero as disabled
|
||||
#endif
|
||||
bool m_pidExited = false;
|
||||
int m_pidStatus = 0;
|
||||
|
|
@ -394,8 +394,7 @@ private:
|
|||
#endif
|
||||
}
|
||||
|
||||
string readBlocks(int fd, int size, StrList& outl) {
|
||||
string out;
|
||||
void readBlocks(int fd, int size, StrList& outl) {
|
||||
char buf[INFILTER_IPC_BUFSIZ];
|
||||
ssize_t sizegot = 0;
|
||||
while (!m_readEof && (size < 0 || size > sizegot)) {
|
||||
|
|
@ -421,7 +420,6 @@ private:
|
|||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
// cppcheck-suppress unusedFunction unusedPrivateFunction
|
||||
string readFilterLine() {
|
||||
|
|
@ -634,7 +632,7 @@ string V3OutFormatter::indentSpaces(int num) {
|
|||
--num;
|
||||
}
|
||||
*cp++ = '\0';
|
||||
string st(str);
|
||||
string st{str}; // No const, move optimization
|
||||
return st;
|
||||
}
|
||||
|
||||
|
|
@ -1055,7 +1053,7 @@ public:
|
|||
private:
|
||||
void trySep(const string& old, string::size_type start, const string& trySep,
|
||||
string::size_type& posr, string& separatorr) {
|
||||
string::size_type trypos = old.find(trySep, start);
|
||||
const string::size_type trypos = old.find(trySep, start);
|
||||
if (trypos != string::npos) {
|
||||
if (posr == string::npos || (posr > trypos)) {
|
||||
posr = trypos;
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ public:
|
|||
|
||||
private:
|
||||
// MEMBERS
|
||||
string m_filename;
|
||||
Language m_lang; // Indenting Verilog code
|
||||
const string m_filename;
|
||||
const Language m_lang; // Indenting Verilog code
|
||||
int m_blockIndent; // Characters per block indent
|
||||
int m_commaWidth; // Width after which to break at ,'s
|
||||
int m_lineno = 1;
|
||||
|
|
|
|||
|
|
@ -101,9 +101,9 @@ void VFileContent::pushText(const string& text) {
|
|||
// Insert line-by-line
|
||||
string::size_type line_start = 0;
|
||||
while (true) {
|
||||
string::size_type line_end = leftover.find('\n', line_start);
|
||||
const string::size_type line_end = leftover.find('\n', line_start);
|
||||
if (line_end != string::npos) {
|
||||
string oneline(leftover, line_start, line_end - line_start + 1);
|
||||
const string oneline(leftover, line_start, line_end - line_start + 1);
|
||||
m_lines.push_back(oneline); // Keeps newline
|
||||
UINFO(9, "PushStream[ct" << m_id << "+" << (m_lines.size() - 1) << "]: " << oneline);
|
||||
line_start = line_end + 1;
|
||||
|
|
@ -148,7 +148,7 @@ FileLine::FileLine(FileLine::EmptySecret) {
|
|||
|
||||
m_warnOn = 0;
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
const V3ErrorCode code = V3ErrorCode(codei);
|
||||
warnOff(code, code.defaultsOff());
|
||||
}
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
|||
|
||||
// Grab linenumber
|
||||
bool fail = false;
|
||||
const char* ln = textp;
|
||||
const char* const ln = textp;
|
||||
while (*textp && !isspace(*textp)) textp++;
|
||||
if (isdigit(*ln)) {
|
||||
lineno(atoi(ln));
|
||||
|
|
@ -193,7 +193,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
|||
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
|
||||
|
||||
// Grab filename
|
||||
const char* fn = textp;
|
||||
const char* const fn = textp;
|
||||
while (*textp && !(isspace(*textp) || *textp == '"')) textp++;
|
||||
if (textp != fn) {
|
||||
string strfn = fn;
|
||||
|
|
@ -244,7 +244,7 @@ FileLine* FileLine::copyOrSameFileLine() {
|
|||
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
|
||||
return lastNewp;
|
||||
}
|
||||
FileLine* newp = new FileLine(this);
|
||||
FileLine* const newp = new FileLine(this);
|
||||
lastNewp = newp;
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -264,8 +264,8 @@ string FileLine::filebasenameNoExt() const {
|
|||
}
|
||||
|
||||
string FileLine::firstColumnLetters() const {
|
||||
char a = ((firstColumn() / 26) % 26) + 'a';
|
||||
char b = (firstColumn() % 26) + 'a';
|
||||
const char a = ((firstColumn() / 26) % 26) + 'a';
|
||||
const char b = (firstColumn() % 26) + 'a';
|
||||
return string(1, a) + string(1, b);
|
||||
}
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
|
|||
}
|
||||
|
||||
bool FileLine::warnOff(const string& msg, bool flag) {
|
||||
V3ErrorCode code(msg.c_str());
|
||||
const V3ErrorCode code(msg.c_str());
|
||||
if (code < V3ErrorCode::EC_FIRST_WARN) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -308,14 +308,14 @@ bool FileLine::warnOff(const string& msg, bool flag) {
|
|||
|
||||
void FileLine::warnLintOff(bool flag) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
const V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (code.lintError()) warnOff(code, flag);
|
||||
}
|
||||
}
|
||||
|
||||
void FileLine::warnStyleOff(bool flag) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
const V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (code.styleError()) warnOff(code, flag);
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +334,7 @@ bool FileLine::warnIsOff(V3ErrorCode code) const {
|
|||
void FileLine::modifyStateInherit(const FileLine* fromp) {
|
||||
// Any warnings that are off in "from", become off in "this".
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
const V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (fromp->warnIsOff(code)) warnOff(code, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -388,7 +388,7 @@ string FileLine::source() const {
|
|||
string FileLine::prettySource() const {
|
||||
string out = source();
|
||||
// Drop ignore trailing newline
|
||||
string::size_type pos = out.find('\n');
|
||||
const string::size_type pos = out.find('\n');
|
||||
if (pos != string::npos) out = string(out, 0, pos);
|
||||
// Column tracking counts tabs = 1, so match that when print source
|
||||
return VString::spaceUnprintable(out);
|
||||
|
|
@ -430,14 +430,14 @@ string FileLine::warnContext(bool secondary) const {
|
|||
std::unordered_set<FileLine*> fileLineLeakChecks;
|
||||
|
||||
void* FileLine::operator new(size_t size) {
|
||||
FileLine* objp = static_cast<FileLine*>(::operator new(size));
|
||||
FileLine* const objp = static_cast<FileLine*>(::operator new(size));
|
||||
fileLineLeakChecks.insert(objp);
|
||||
return objp;
|
||||
}
|
||||
|
||||
void FileLine::operator delete(void* objp, size_t size) {
|
||||
if (!objp) return;
|
||||
FileLine* flp = static_cast<FileLine*>(objp);
|
||||
FileLine* const flp = static_cast<FileLine*>(objp);
|
||||
const auto it = fileLineLeakChecks.find(flp);
|
||||
if (it != fileLineLeakChecks.end()) {
|
||||
fileLineLeakChecks.erase(it);
|
||||
|
|
|
|||
264
src/V3Gate.cpp
264
src/V3Gate.cpp
|
|
@ -67,7 +67,7 @@ public:
|
|||
// Support classes
|
||||
|
||||
class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
AstScope* m_scopep; // Scope vertex refers to
|
||||
AstScope* const m_scopep; // Scope vertex refers to
|
||||
bool m_reducible = true; // True if this node should be able to be eliminated
|
||||
bool m_dedupable = true; // True if this node should be able to be deduped
|
||||
bool m_consumed = false; // Output goes to something meaningful
|
||||
|
|
@ -124,7 +124,7 @@ public:
|
|||
};
|
||||
|
||||
class GateVarVertex final : public GateEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
AstVarScope* const m_varScp;
|
||||
bool m_isTop = false;
|
||||
bool m_isClock = false;
|
||||
AstNode* m_rstSyncNodep = nullptr; // Used as reset and not in SenItem, in clocked always
|
||||
|
|
@ -164,9 +164,9 @@ public:
|
|||
};
|
||||
|
||||
class GateLogicVertex final : public GateEitherVertex {
|
||||
AstNode* m_nodep;
|
||||
AstActive* m_activep; // Under what active; nullptr is ok (under cfunc or such)
|
||||
bool m_slow; // In slow block
|
||||
AstNode* const m_nodep;
|
||||
AstActive* const m_activep; // Under what active; nullptr is ok (under cfunc or such)
|
||||
const bool m_slow; // In slow block
|
||||
public:
|
||||
GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep,
|
||||
bool slow)
|
||||
|
|
@ -200,7 +200,8 @@ private:
|
|||
AstNode* m_substTreep = nullptr; // What to replace the variable with
|
||||
// STATE
|
||||
bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks)
|
||||
AstNodeVarRef* m_lhsVarRef = nullptr; // VarRef on lhs of assignment (what we're replacing)
|
||||
const AstNodeVarRef* m_lhsVarRef
|
||||
= nullptr; // VarRef on lhs of assignment (what we're replacing)
|
||||
bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable
|
||||
int m_ops = 0; // Operation count
|
||||
|
||||
|
|
@ -227,7 +228,7 @@ private:
|
|||
m_lhsVarRef = nodep;
|
||||
} else {
|
||||
if (m_rhsVarRefs.size() > 1) {
|
||||
AstNodeVarRef* lastRefp = m_rhsVarRefs.back();
|
||||
const AstNodeVarRef* const lastRefp = m_rhsVarRefs.back();
|
||||
if (m_buffersOnly) clearSimple(">1 rhs varRefs");
|
||||
if (!nodep->varScopep()->varp()->gateMultiInputOptimizable()
|
||||
// We didn't check multiInput on the first varref, so check it here
|
||||
|
|
@ -249,14 +250,12 @@ private:
|
|||
// This avoids a mess in computing what exactly a POSEDGE is
|
||||
// V3Const cleans up any NOTs by flipping the edges for us
|
||||
if (m_buffersOnly
|
||||
&& !(VN_IS(nodep->rhsp(), VarRef)
|
||||
// Avoid making non-clocked logic into clocked,
|
||||
// as it slows down the verilator_sim_benchmark
|
||||
|| (VN_IS(nodep->rhsp(), Not)
|
||||
&& VN_IS(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef)
|
||||
&& VN_CAST(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef)
|
||||
->varp()
|
||||
->isUsedClock()))) {
|
||||
&& !(
|
||||
VN_IS(nodep->rhsp(), VarRef)
|
||||
// Avoid making non-clocked logic into clocked,
|
||||
// as it slows down the verilator_sim_benchmark
|
||||
|| (VN_IS(nodep->rhsp(), Not) && VN_IS(VN_AS(nodep->rhsp(), Not)->lhsp(), VarRef)
|
||||
&& VN_AS(VN_AS(nodep->rhsp(), Not)->lhsp(), VarRef)->varp()->isUsedClock()))) {
|
||||
clearSimple("Not a buffer (goes to a clock)");
|
||||
}
|
||||
}
|
||||
|
|
@ -310,14 +309,14 @@ private:
|
|||
// AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement
|
||||
// AstVar::user2 -> bool: Warned about SYNCASYNCNET
|
||||
// AstNodeVarRef::user2 -> bool: ConcatOffset visited
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
const AstUser1InUse m_inuser1;
|
||||
const AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
GateLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
|
||||
AstScope* m_scopep = nullptr; // Current scope being processed
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstActive* m_activep = nullptr; // Current active
|
||||
bool m_activeReducible = true; // Is activation block reducible?
|
||||
bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks
|
||||
|
|
@ -442,9 +441,9 @@ private:
|
|||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
AstVarScope* const varscp = nodep->varScopep();
|
||||
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
GateVarVertex* vvertexp = makeVarVertex(varscp);
|
||||
GateVarVertex* const vvertexp = makeVarVertex(varscp);
|
||||
UINFO(5, " VARREF to " << varscp << endl);
|
||||
if (m_inSenItem) {
|
||||
vvertexp->setIsClock();
|
||||
|
|
@ -512,7 +511,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstConcat* nodep) override {
|
||||
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)
|
||||
&& VN_CAST(nodep->backp(), NodeAssign)->lhsp() == nodep),
|
||||
&& VN_AS(nodep->backp(), NodeAssign)->lhsp() == nodep),
|
||||
nodep, "Concat on LHS of assignment; V3Const should have deleted it");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -538,7 +537,7 @@ public:
|
|||
|
||||
void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (vvertexp->inEmpty()) {
|
||||
vvertexp->clearReducibleAndDedupable("inEmpty"); // Can't deal with no sources
|
||||
if (!vvertexp->isTop() // Ok if top inputs are driverless
|
||||
|
|
@ -564,13 +563,13 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
UINFO(8, "SigNotRed " << vvertexp->name() << endl);
|
||||
} else {
|
||||
UINFO(8, "Sig " << vvertexp->name() << endl);
|
||||
GateLogicVertex* logicVertexp
|
||||
GateLogicVertex* const logicVertexp
|
||||
= dynamic_cast<GateLogicVertex*>(vvertexp->inBeginp()->fromp());
|
||||
UINFO(8, " From " << logicVertexp->name() << endl);
|
||||
AstNode* logicp = logicVertexp->nodep();
|
||||
if (logicVertexp->reducible()) {
|
||||
// Can we eliminate?
|
||||
GateOkVisitor okVisitor{logicp, vvertexp->isClock(), false};
|
||||
const GateOkVisitor okVisitor{logicp, vvertexp->isClock(), false};
|
||||
const bool multiInputs = okVisitor.rhsVarRefs().size() > 1;
|
||||
// Was it ok?
|
||||
bool doit = okVisitor.isSimple();
|
||||
|
|
@ -580,7 +579,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
int n = 0;
|
||||
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;
|
||||
edgep = edgep->outNextp()) {
|
||||
GateLogicVertex* consumeVertexp
|
||||
const GateLogicVertex* const consumeVertexp
|
||||
= dynamic_cast<GateLogicVertex*>(edgep->top());
|
||||
if (!consumeVertexp->slow()) { // Not tracing or other slow path junk
|
||||
if (edgep->top()->outBeginp()) { // Destination is itself used
|
||||
|
|
@ -604,29 +603,29 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
<< " " << vvertexp->name() << endl);
|
||||
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;
|
||||
edgep = edgep->outNextp()) {
|
||||
GateLogicVertex* consumeVertexp
|
||||
const GateLogicVertex* const consumeVertexp
|
||||
= dynamic_cast<GateLogicVertex*>(edgep->top());
|
||||
UINFO(9, " edge " << edgep << " to: " << consumeVertexp->nodep()
|
||||
<< endl);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
GateLogicVertex* consumeVertexp
|
||||
const GateLogicVertex* const consumeVertexp
|
||||
= dynamic_cast<GateLogicVertex*>(edgep->fromp());
|
||||
UINFO(9, " edge " << edgep << " from: "
|
||||
<< consumeVertexp->nodep() << endl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AstNode* substp = okVisitor.substTree();
|
||||
AstNode* const substp = okVisitor.substTree();
|
||||
if (debug() >= 5) logicp->dumpTree(cout, " elimVar: ");
|
||||
if (debug() >= 5) substp->dumpTree(cout, " subst: ");
|
||||
++m_statSigs;
|
||||
bool removedAllUsages = true;
|
||||
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;) {
|
||||
GateLogicVertex* consumeVertexp
|
||||
GateLogicVertex* const consumeVertexp
|
||||
= dynamic_cast<GateLogicVertex*>(edgep->top());
|
||||
AstNode* consumerp = consumeVertexp->nodep();
|
||||
AstNode* const consumerp = consumeVertexp->nodep();
|
||||
if (!elimLogicOkOutputs(consumeVertexp, okVisitor /*ref*/)) {
|
||||
// Cannot optimize this replacement
|
||||
removedAllUsages = false;
|
||||
|
|
@ -638,9 +637,9 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
|
||||
for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
|
||||
it != rhsVarRefs.end(); ++it) {
|
||||
AstVarScope* newvarscp = (*it)->varScopep();
|
||||
AstVarScope* const newvarscp = (*it)->varScopep();
|
||||
UINFO(9, " Point-to-new vertex " << newvarscp << endl);
|
||||
GateVarVertex* varvertexp = makeVarVertex(newvarscp);
|
||||
GateVarVertex* const varvertexp = makeVarVertex(newvarscp);
|
||||
new V3GraphEdge(&m_graph, varvertexp, consumeVertexp, 1);
|
||||
// Propagate clock attribute onto generating node
|
||||
varvertexp->propagateAttrClocksFrom(vvertexp);
|
||||
|
|
@ -653,7 +652,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
}
|
||||
if (removedAllUsages) {
|
||||
// Remove input links
|
||||
while (V3GraphEdge* edgep = vvertexp->inBeginp()) {
|
||||
while (V3GraphEdge* const edgep = vvertexp->inBeginp()) {
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
// Clone tree so we remember it for tracing, and keep the pointer
|
||||
|
|
@ -687,12 +686,12 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
|
|||
// Replacement logic usually has shorter input list, so faster to build list based on it
|
||||
const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
|
||||
for (GateVarRefList::const_iterator it = rhsVarRefs.begin(); it != rhsVarRefs.end(); ++it) {
|
||||
AstVarScope* vscp = (*it)->varScopep();
|
||||
AstVarScope* const vscp = (*it)->varScopep();
|
||||
varscopes.insert(vscp);
|
||||
}
|
||||
for (V3GraphEdge* edgep = consumeVertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
GateVarVertex* consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top());
|
||||
AstVarScope* vscp = consVVertexp->varScp();
|
||||
const GateVarVertex* const consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top());
|
||||
AstVarScope* const vscp = consVVertexp->varScp();
|
||||
if (varscopes.find(vscp) != varscopes.end()) {
|
||||
UINFO(9, " Block-unopt, insertion generates input vscp " << vscp << endl);
|
||||
return false;
|
||||
|
|
@ -703,29 +702,29 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
|
|||
|
||||
void GateVisitor::replaceAssigns() {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
// Take the Comments/assigns that were moved to the VarScope and change them to a
|
||||
// simple value assignment
|
||||
AstVarScope* vscp = vvertexp->varScp();
|
||||
const AstVarScope* const vscp = vvertexp->varScp();
|
||||
if (vscp->valuep() && !VN_IS(vscp->valuep(), NodeMath)) {
|
||||
// if (debug() > 9) vscp->dumpTree(cout, "-vscPre: ");
|
||||
while (AstNode* delp = VN_CAST(vscp->valuep(), Comment)) {
|
||||
VL_DO_DANGLING(delp->unlinkFrBack()->deleteTree(), delp);
|
||||
}
|
||||
if (AstInitial* delp = VN_CAST(vscp->valuep(), Initial)) {
|
||||
AstNode* bodyp = delp->bodysp();
|
||||
if (AstInitial* const delp = VN_CAST(vscp->valuep(), Initial)) {
|
||||
AstNode* const bodyp = delp->bodysp();
|
||||
bodyp->unlinkFrBackWithNext();
|
||||
delp->replaceWith(bodyp);
|
||||
VL_DO_DANGLING(delp->deleteTree(), delp);
|
||||
}
|
||||
if (AstAlways* delp = VN_CAST(vscp->valuep(), Always)) {
|
||||
AstNode* bodyp = delp->bodysp();
|
||||
if (AstAlways* const delp = VN_CAST(vscp->valuep(), Always)) {
|
||||
AstNode* const bodyp = delp->bodysp();
|
||||
bodyp->unlinkFrBackWithNext();
|
||||
delp->replaceWith(bodyp);
|
||||
VL_DO_DANGLING(delp->deleteTree(), delp);
|
||||
}
|
||||
if (AstNodeAssign* delp = VN_CAST(vscp->valuep(), NodeAssign)) {
|
||||
AstNode* rhsp = delp->rhsp();
|
||||
if (AstNodeAssign* const delp = VN_CAST(vscp->valuep(), NodeAssign)) {
|
||||
AstNode* const rhsp = delp->rhsp();
|
||||
rhsp->unlinkFrBack();
|
||||
delp->replaceWith(rhsp);
|
||||
VL_DO_DANGLING(delp->deleteTree(), delp);
|
||||
|
|
@ -747,7 +746,7 @@ void GateVisitor::consumedMark() {
|
|||
m_graph.userClearVertices();
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
GateEitherVertex* evertexp = static_cast<GateEitherVertex*>(vertexp);
|
||||
GateEitherVertex* const evertexp = static_cast<GateEitherVertex*>(vertexp);
|
||||
if (!evertexp->user() && evertexp->consumed()) consumedMarkRecurse(evertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -758,7 +757,7 @@ void GateVisitor::consumedMarkRecurse(GateEitherVertex* vertexp) {
|
|||
if (!vertexp->consumed()) vertexp->setConsumed("propagated");
|
||||
// Walk sources and mark them too
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
GateEitherVertex* eFromVertexp = static_cast<GateEitherVertex*>(edgep->fromp());
|
||||
GateEitherVertex* const eFromVertexp = static_cast<GateEitherVertex*>(edgep->fromp());
|
||||
consumedMarkRecurse(eFromVertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -768,14 +767,14 @@ void GateVisitor::consumedMove() {
|
|||
// We need the "usually" block logic to do a better job at this
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
|
||||
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
|
||||
if (!vvertexp->consumed() && !vvertexp->user()) {
|
||||
UINFO(8, "Unconsumed " << vvertexp->varScp() << endl);
|
||||
}
|
||||
}
|
||||
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
|
||||
AstNode* nodep = lvertexp->nodep();
|
||||
AstActive* oldactp = lvertexp->activep(); // nullptr under cfunc
|
||||
if (const GateLogicVertex* const lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
|
||||
AstNode* const nodep = lvertexp->nodep();
|
||||
const AstActive* const oldactp = lvertexp->activep(); // nullptr under cfunc
|
||||
if (!lvertexp->consumed() && oldactp) {
|
||||
// Eventually: Move the statement to a new active block
|
||||
// with "tracing-on" sensitivity
|
||||
|
|
@ -792,10 +791,10 @@ void GateVisitor::consumedMove() {
|
|||
void GateVisitor::warnSignals() {
|
||||
AstNode::user2ClearTree();
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
AstVarScope* vscp = vvertexp->varScp();
|
||||
AstNode* sp = vvertexp->rstSyncNodep();
|
||||
AstNode* ap = vvertexp->rstAsyncNodep();
|
||||
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
const AstVarScope* const vscp = vvertexp->varScp();
|
||||
const AstNode* const sp = vvertexp->rstSyncNodep();
|
||||
const AstNode* const ap = vvertexp->rstAsyncNodep();
|
||||
if (ap && sp && !vscp->varp()->user2()) {
|
||||
// This is somewhat wrong, as marking one flop as ok for sync
|
||||
// may mean a different flop now fails. However it's a pain to
|
||||
|
|
@ -827,7 +826,7 @@ class GateElimVisitor final : public GateBaseVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
// STATE
|
||||
AstVarScope* m_elimVarScp; // Variable being eliminated
|
||||
const AstVarScope* m_elimVarScp; // Variable being eliminated
|
||||
AstNode* m_replaceTreep; // What to replace the variable with
|
||||
bool m_didReplace; // Did we do any replacements
|
||||
GateDedupeVarVisitor* m_varVisp; // Callback to keep hash up to date
|
||||
|
|
@ -844,11 +843,10 @@ private:
|
|||
m_didReplace = true;
|
||||
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
|
||||
"Can't replace lvalue assignments with const var");
|
||||
AstNode* substp = m_replaceTreep->cloneTree(false);
|
||||
UASSERT_OBJ(
|
||||
!(VN_IS(nodep, NodeVarRef) && VN_IS(substp, NodeVarRef) && nodep->same(substp)),
|
||||
// Prevent an infinite loop...
|
||||
substp, "Replacing node with itself; perhaps circular logic?");
|
||||
AstNode* const substp = m_replaceTreep->cloneTree(false);
|
||||
UASSERT_OBJ(!(VN_IS(substp, NodeVarRef) && nodep->same(substp)),
|
||||
// Prevent an infinite loop...
|
||||
substp, "Replacing node with itself; perhaps circular logic?");
|
||||
// Which fileline() to use?
|
||||
// If replacing with logic, an error/warning is likely to want to point to the logic
|
||||
// IE what we're replacing with.
|
||||
|
|
@ -856,7 +854,7 @@ private:
|
|||
// to throw warnings that point to a PIN rather than where the pin us used.
|
||||
if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline());
|
||||
// Make the substp an rvalue like nodep. This facilitates the hashing in dedupe.
|
||||
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef))
|
||||
if (AstNodeVarRef* const varrefp = VN_CAST(substp, NodeVarRef))
|
||||
varrefp->access(VAccess::READ);
|
||||
hashReplace(nodep, substp);
|
||||
nodep->replaceWith(substp);
|
||||
|
|
@ -884,7 +882,7 @@ public:
|
|||
|
||||
void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) {
|
||||
if (debug() >= 5) consumerp->dumpTree(cout, " elimUsePre: ");
|
||||
GateElimVisitor elimVisitor{consumerp, varscp, substp, nullptr};
|
||||
const GateElimVisitor elimVisitor{consumerp, varscp, substp, nullptr};
|
||||
if (elimVisitor.didReplace()) {
|
||||
if (debug() >= 9) consumerp->dumpTree(cout, " elimUseCns: ");
|
||||
// Caution: Can't let V3Const change our handle to consumerp, such as by
|
||||
|
|
@ -910,9 +908,9 @@ private:
|
|||
// Set to nullptr if this assign's tree was later replaced
|
||||
// AstUser1InUse m_inuser1; (Allocated for use in GateVisitor)
|
||||
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
|
||||
AstUser3InUse m_inuser3;
|
||||
const AstUser3InUse m_inuser3;
|
||||
// AstUser4InUse m_inuser4; (Allocated for use in V3Hasher via V3DupFinder)
|
||||
AstUser5InUse m_inuser5;
|
||||
const AstUser5InUse m_inuser5;
|
||||
|
||||
V3DupFinder m_dupFinder; // Duplicate finder for rhs of assigns
|
||||
std::unordered_set<AstNode*> m_nodeDeleteds; // Any node in this hash was deleted
|
||||
|
|
@ -964,8 +962,8 @@ public:
|
|||
bool isReplaced(AstNode* nodep) {
|
||||
// Assignment may have been hashReplaced, if so consider non-match (effectively removed)
|
||||
UASSERT_OBJ(!VN_IS(nodep, NodeAssign), nodep, "Dedup attempt on non-assign");
|
||||
AstNode* extra1p = nodep->user3p();
|
||||
AstNode* extra2p = nodep->user5p();
|
||||
AstNode* const extra1p = nodep->user3p();
|
||||
AstNode* const extra2p = nodep->user5p();
|
||||
return ((extra1p && m_nodeDeleteds.find(extra1p) != m_nodeDeleteds.end())
|
||||
|| (extra2p && m_nodeDeleteds.find(extra2p) != m_nodeDeleteds.end()));
|
||||
}
|
||||
|
|
@ -981,10 +979,11 @@ public:
|
|||
&& node1p->user2p()->type() == node2p->user2p()->type();
|
||||
}
|
||||
|
||||
AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) {
|
||||
const AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p,
|
||||
AstNode* extra2p) {
|
||||
// Legal for extra1p/2p to be nullptr, we'll compare with other assigns with extras also
|
||||
// nullptr
|
||||
AstNode* rhsp = assignp->rhsp();
|
||||
AstNode* const rhsp = assignp->rhsp();
|
||||
rhsp->user2p(assignp);
|
||||
rhsp->user3p(extra1p);
|
||||
rhsp->user5p(extra2p);
|
||||
|
|
@ -996,7 +995,7 @@ public:
|
|||
// So dupit is either a different, duplicate rhsp, or the end of the hash.
|
||||
if (dupit != m_dupFinder.end()) {
|
||||
m_dupFinder.erase(inserted);
|
||||
return VN_CAST(dupit->second->user2p(), NodeAssign);
|
||||
return VN_AS(dupit->second->user2p(), NodeAssign);
|
||||
}
|
||||
// Retain new inserted information
|
||||
return nullptr;
|
||||
|
|
@ -1004,9 +1003,9 @@ public:
|
|||
|
||||
void check() {
|
||||
for (const auto& itr : m_dupFinder) {
|
||||
AstNode* nodep = itr.second;
|
||||
AstNode* activep = nodep->user3p();
|
||||
AstNode* condVarp = nodep->user5p();
|
||||
AstNode* const nodep = itr.second;
|
||||
const AstNode* const activep = nodep->user3p();
|
||||
const AstNode* const condVarp = nodep->user5p();
|
||||
if (!isReplaced(nodep)) {
|
||||
// This class won't break if activep isn't an active, or
|
||||
// ifVar isn't a var, but this is checking the caller's construction.
|
||||
|
|
@ -1097,12 +1096,13 @@ public:
|
|||
m_dedupable = true;
|
||||
iterate(nodep);
|
||||
if (m_dedupable && m_assignp) {
|
||||
AstNode* lhsp = m_assignp->lhsp();
|
||||
const AstNode* const lhsp = m_assignp->lhsp();
|
||||
// Possible todo, handle more complex lhs expressions
|
||||
if (AstNodeVarRef* lhsVarRefp = VN_CAST(lhsp, NodeVarRef)) {
|
||||
if (const AstNodeVarRef* const lhsVarRefp = VN_CAST(lhsp, NodeVarRef)) {
|
||||
UASSERT_OBJ(lhsVarRefp->varScopep() == consumerVarScopep, consumerVarScopep,
|
||||
"Consumer doesn't match lhs of assign");
|
||||
if (AstNodeAssign* dup = m_ghash.hashAndFindDupe(m_assignp, activep, m_ifCondp)) {
|
||||
if (const AstNodeAssign* const dup
|
||||
= m_ghash.hashAndFindDupe(m_assignp, activep, m_ifCondp)) {
|
||||
return static_cast<AstNodeVarRef*>(dup->lhsp());
|
||||
}
|
||||
}
|
||||
|
|
@ -1140,26 +1140,26 @@ private:
|
|||
|
||||
m_depth++;
|
||||
if (vvertexp->inSize1()) {
|
||||
AstNodeVarRef* dupVarRefp = static_cast<AstNodeVarRef*>(
|
||||
AstNodeVarRef* const dupVarRefp = static_cast<AstNodeVarRef*>(
|
||||
vvertexp->iterateInEdges(*this, VNUser(vvertexp)).toNodep());
|
||||
if (dupVarRefp) { // visit(GateLogicVertex*...) returned match
|
||||
V3GraphEdge* edgep = vvertexp->inBeginp();
|
||||
GateLogicVertex* lvertexp = static_cast<GateLogicVertex*>(edgep->fromp());
|
||||
const V3GraphEdge* edgep = vvertexp->inBeginp();
|
||||
GateLogicVertex* const lvertexp = static_cast<GateLogicVertex*>(edgep->fromp());
|
||||
UASSERT_OBJ(vvertexp->dedupable(), vvertexp->varScp(),
|
||||
"GateLogicVertex* visit should have returned nullptr "
|
||||
"if consumer var vertex is not dedupable.");
|
||||
GateOkVisitor okVisitor{lvertexp->nodep(), false, true};
|
||||
const GateOkVisitor okVisitor{lvertexp->nodep(), false, true};
|
||||
if (okVisitor.isSimple()) {
|
||||
AstVarScope* dupVarScopep = dupVarRefp->varScopep();
|
||||
GateVarVertex* dupVvertexp
|
||||
const AstVarScope* const dupVarScopep = dupVarRefp->varScopep();
|
||||
GateVarVertex* const dupVvertexp
|
||||
= reinterpret_cast<GateVarVertex*>(dupVarScopep->user1p());
|
||||
UINFO(4, "replacing " << vvertexp << " with " << dupVvertexp << endl);
|
||||
++m_numDeduped;
|
||||
// Replace all of this varvertex's consumers with dupVarRefp
|
||||
for (V3GraphEdge* outedgep = vvertexp->outBeginp(); outedgep;) {
|
||||
GateLogicVertex* consumeVertexp
|
||||
const GateLogicVertex* const consumeVertexp
|
||||
= dynamic_cast<GateLogicVertex*>(outedgep->top());
|
||||
AstNode* consumerp = consumeVertexp->nodep();
|
||||
AstNode* const consumerp = consumeVertexp->nodep();
|
||||
// if (debug() >= 9) m_graphp->dumpDotFilePrefixed("gate_preelim");
|
||||
UINFO(9,
|
||||
"elim src vtx" << lvertexp << " node " << lvertexp->nodep() << endl);
|
||||
|
|
@ -1171,15 +1171,15 @@ private:
|
|||
if (lvertexp == consumeVertexp) {
|
||||
UINFO(9, "skipping as self-recirculates\n");
|
||||
} else {
|
||||
GateElimVisitor elimVisitor(consumerp, vvertexp->varScp(), dupVarRefp,
|
||||
&m_varVisitor);
|
||||
const GateElimVisitor elimVisitor(consumerp, vvertexp->varScp(),
|
||||
dupVarRefp, &m_varVisitor);
|
||||
}
|
||||
outedgep = outedgep->relinkFromp(dupVvertexp);
|
||||
}
|
||||
// Propagate attributes
|
||||
dupVvertexp->propagateAttrClocksFrom(vvertexp);
|
||||
// Remove inputs links
|
||||
while (V3GraphEdge* inedgep = vvertexp->inBeginp()) {
|
||||
while (V3GraphEdge* const inedgep = vvertexp->inBeginp()) {
|
||||
VL_DO_DANGLING(inedgep->unlinkDelete(), inedgep);
|
||||
}
|
||||
// replaceAssigns() does the deleteTree on lvertexNodep in a later step
|
||||
|
|
@ -1201,15 +1201,16 @@ private:
|
|||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
|
||||
lvertexp->iterateInEdges(*this);
|
||||
|
||||
GateVarVertex* consumerVvertexpp = static_cast<GateVarVertex*>(vu.toGraphVertex());
|
||||
const GateVarVertex* const consumerVvertexpp
|
||||
= static_cast<GateVarVertex*>(vu.toGraphVertex());
|
||||
if (lvertexp->dedupable() && consumerVvertexpp->dedupable()) {
|
||||
AstNode* nodep = lvertexp->nodep();
|
||||
AstVarScope* consumerVarScopep = consumerVvertexpp->varScp();
|
||||
AstNode* const nodep = lvertexp->nodep();
|
||||
AstVarScope* const consumerVarScopep = consumerVvertexpp->varScp();
|
||||
// TODO: Doing a simple pointer comparison of activep won't work
|
||||
// optimally for statements under generated clocks. Statements under
|
||||
// different generated clocks will never compare as equal, even if the
|
||||
// generated clocks are deduped into one clock.
|
||||
AstActive* activep = lvertexp->activep();
|
||||
AstActive* const activep = lvertexp->activep();
|
||||
return VNUser(m_varVisitor.findDupe(nodep, consumerVarScopep, activep));
|
||||
}
|
||||
return VNUser(0);
|
||||
|
|
@ -1230,14 +1231,14 @@ void GateVisitor::dedupe() {
|
|||
// Traverse starting from each of the clocks
|
||||
UINFO(9, "Gate dedupe() clocks:\n");
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (vvertexp->isClock()) deduper.dedupeTree(vvertexp);
|
||||
}
|
||||
}
|
||||
// Traverse starting from each of the outputs
|
||||
UINFO(9, "Gate dedupe() outputs:\n");
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) {
|
||||
deduper.dedupeTree(vvertexp);
|
||||
}
|
||||
|
|
@ -1253,21 +1254,21 @@ class GateMergeAssignsGraphVisitor final : public GateGraphBaseVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
AstNodeAssign* m_assignp = nullptr;
|
||||
AstActive* m_activep = nullptr;
|
||||
const AstActive* m_activep = nullptr;
|
||||
GateLogicVertex* m_logicvp = nullptr;
|
||||
VDouble0 m_numMergedAssigns; // Statistic tracking
|
||||
|
||||
// assemble two Sel into one if possible
|
||||
AstSel* merge(AstSel* pre, AstSel* cur) {
|
||||
AstVarRef* preVarRefp = VN_CAST(pre->fromp(), VarRef);
|
||||
AstVarRef* curVarRefp = VN_CAST(cur->fromp(), VarRef);
|
||||
const AstVarRef* const preVarRefp = VN_CAST(pre->fromp(), VarRef);
|
||||
AstVarRef* const curVarRefp = VN_CAST(cur->fromp(), VarRef);
|
||||
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) {
|
||||
return nullptr; // not the same var
|
||||
}
|
||||
const AstConst* pstart = VN_CAST(pre->lsbp(), Const);
|
||||
const AstConst* pwidth = VN_CAST(pre->widthp(), Const);
|
||||
const AstConst* cstart = VN_CAST(cur->lsbp(), Const);
|
||||
const AstConst* cwidth = VN_CAST(cur->widthp(), Const);
|
||||
const AstConst* const pstart = VN_CAST(pre->lsbp(), Const);
|
||||
const AstConst* const pwidth = VN_CAST(pre->widthp(), Const);
|
||||
const AstConst* const cstart = VN_CAST(cur->lsbp(), Const);
|
||||
const AstConst* const cwidth = VN_CAST(cur->widthp(), Const);
|
||||
if (!pstart || !pwidth || !cstart || !cwidth) return nullptr; // too complicated
|
||||
if (cur->lsbConst() + cur->widthConst() == pre->lsbConst()) {
|
||||
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false),
|
||||
|
|
@ -1281,12 +1282,13 @@ private:
|
|||
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) {
|
||||
V3GraphEdge* oldedgep = edgep;
|
||||
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
|
||||
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
|
||||
if (AstNodeAssign* assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) {
|
||||
if (GateLogicVertex* const lvertexp
|
||||
= dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
|
||||
if (AstNodeAssign* const assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) {
|
||||
// if (lvertexp->outSize1() && VN_IS(assignp->lhsp(), Sel)) {
|
||||
if (VN_IS(assignp->lhsp(), Sel) && lvertexp->outSize1()) {
|
||||
UINFO(9, "assing to the nodep["
|
||||
<< VN_CAST(assignp->lhsp(), Sel)->lsbConst() << "]" << endl);
|
||||
UINFO(9, "assing to the nodep[" << VN_AS(assignp->lhsp(), Sel)->lsbConst()
|
||||
<< "]" << endl);
|
||||
// first assign with Sel-lhs
|
||||
if (!m_activep) m_activep = lvertexp->activep();
|
||||
if (!m_logicvp) m_logicvp = lvertexp;
|
||||
|
|
@ -1300,20 +1302,20 @@ private:
|
|||
continue;
|
||||
}
|
||||
|
||||
AstSel* preselp = VN_CAST(m_assignp->lhsp(), Sel);
|
||||
AstSel* curselp = VN_CAST(assignp->lhsp(), Sel);
|
||||
AstSel* const preselp = VN_CAST(m_assignp->lhsp(), Sel);
|
||||
AstSel* const curselp = VN_CAST(assignp->lhsp(), Sel);
|
||||
if (!preselp || !curselp) continue;
|
||||
|
||||
if (AstSel* newselp = merge(preselp, curselp)) {
|
||||
if (AstSel* const newselp = merge(preselp, curselp)) {
|
||||
UINFO(5, "assemble to new sel: " << newselp << endl);
|
||||
// replace preSel with newSel
|
||||
preselp->replaceWith(newselp);
|
||||
VL_DO_DANGLING(preselp->deleteTree(), preselp);
|
||||
// create new rhs for pre assignment
|
||||
AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(),
|
||||
m_assignp->rhsp()->cloneTree(false),
|
||||
assignp->rhsp()->cloneTree(false));
|
||||
AstNode* oldrhsp = m_assignp->rhsp();
|
||||
AstNode* const newrhsp = new AstConcat(
|
||||
m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false),
|
||||
assignp->rhsp()->cloneTree(false));
|
||||
AstNode* const oldrhsp = m_assignp->rhsp();
|
||||
oldrhsp->replaceWith(newrhsp);
|
||||
VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp);
|
||||
m_assignp->dtypeChgWidthSigned(m_assignp->width() + assignp->width(),
|
||||
|
|
@ -1330,7 +1332,7 @@ private:
|
|||
for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep;) {
|
||||
V3GraphEdge* oedgep = ledgep;
|
||||
ledgep = ledgep->inNextp();
|
||||
GateEitherVertex* fromvp
|
||||
GateEitherVertex* const fromvp
|
||||
= dynamic_cast<GateEitherVertex*>(oedgep->fromp());
|
||||
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
|
||||
VL_DO_DANGLING(oedgep->unlinkDelete(), oedgep);
|
||||
|
|
@ -1369,7 +1371,7 @@ void GateVisitor::mergeAssigns() {
|
|||
UINFO(6, "mergeAssigns\n");
|
||||
GateMergeAssignsGraphVisitor merger{&m_graph};
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
merger.mergeAssignsTree(vvertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -1382,7 +1384,7 @@ void GateVisitor::mergeAssigns() {
|
|||
class GateConcatVisitor final : public GateBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
|
||||
const AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
|
||||
int m_offset = 0; // Current offset of varscope
|
||||
int m_found_offset = 0; // Found offset of varscope
|
||||
bool m_found = false; // Offset found
|
||||
|
|
@ -1432,8 +1434,8 @@ public:
|
|||
|
||||
class GateClkDecompState final {
|
||||
public:
|
||||
int m_offset;
|
||||
AstVarScope* m_last_vsp;
|
||||
const int m_offset;
|
||||
AstVarScope* const m_last_vsp;
|
||||
GateClkDecompState(int offset, AstVarScope* vsp)
|
||||
: m_offset{offset}
|
||||
, m_last_vsp{vsp} {}
|
||||
|
|
@ -1453,14 +1455,14 @@ private:
|
|||
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) override {
|
||||
// Check that we haven't been here before
|
||||
AstVarScope* vsp = vvertexp->varScp();
|
||||
AstVarScope* const vsp = vvertexp->varScp();
|
||||
if (vsp->user2SetOnce()) return VNUser(0);
|
||||
UINFO(9, "CLK DECOMP Var - " << vvertexp << " : " << vsp << endl);
|
||||
if (vsp->varp()->width() > 1) {
|
||||
m_seen_clk_vectors++;
|
||||
m_total_seen_clk_vectors++;
|
||||
}
|
||||
GateClkDecompState* currState = reinterpret_cast<GateClkDecompState*>(vu.c());
|
||||
const GateClkDecompState* const currState = reinterpret_cast<GateClkDecompState*>(vu.c());
|
||||
GateClkDecompState nextState(currState->m_offset, vsp);
|
||||
vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState));
|
||||
if (vsp->varp()->width() > 1) --m_seen_clk_vectors;
|
||||
|
|
@ -1469,13 +1471,13 @@ private:
|
|||
}
|
||||
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
|
||||
GateClkDecompState* currState = reinterpret_cast<GateClkDecompState*>(vu.c());
|
||||
const GateClkDecompState* const currState = reinterpret_cast<GateClkDecompState*>(vu.c());
|
||||
int clk_offset = currState->m_offset;
|
||||
if (const AstAssignW* assignp = VN_CAST(lvertexp->nodep(), AssignW)) {
|
||||
if (const AstAssignW* const assignp = VN_CAST(lvertexp->nodep(), AssignW)) {
|
||||
UINFO(9, "CLK DECOMP Logic (off = " << clk_offset << ") - " << lvertexp << " : "
|
||||
<< m_clk_vsp << endl);
|
||||
// RHS
|
||||
if (AstSel* rselp = VN_CAST(assignp->rhsp(), Sel)) {
|
||||
if (const AstSel* const rselp = VN_CAST(assignp->rhsp(), Sel)) {
|
||||
if (VN_IS(rselp->lsbp(), Const) && VN_IS(rselp->widthp(), Const)) {
|
||||
if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) {
|
||||
UINFO(9, "CLK DECOMP Sel [ " << rselp->msbConst() << " : "
|
||||
|
|
@ -1487,7 +1489,7 @@ private:
|
|||
} else {
|
||||
return VNUser(0);
|
||||
}
|
||||
} else if (AstConcat* catp = VN_CAST(assignp->rhsp(), Concat)) {
|
||||
} else if (AstConcat* const catp = VN_CAST(assignp->rhsp(), Concat)) {
|
||||
UINFO(9, "CLK DECOMP Concat searching - " << assignp->lhsp() << endl);
|
||||
int concat_offset;
|
||||
if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp,
|
||||
|
|
@ -1501,13 +1503,13 @@ private:
|
|||
return VNUser(0);
|
||||
}
|
||||
// LHS
|
||||
if (const AstSel* lselp = VN_CAST(assignp->lhsp(), Sel)) {
|
||||
if (const AstSel* const lselp = VN_CAST(assignp->lhsp(), Sel)) {
|
||||
if (VN_IS(lselp->lsbp(), Const) && VN_IS(lselp->widthp(), Const)) {
|
||||
clk_offset += lselp->lsbConst();
|
||||
} else {
|
||||
return VNUser(0);
|
||||
}
|
||||
} else if (const AstVarRef* vrp = VN_CAST(assignp->lhsp(), VarRef)) {
|
||||
} else if (const AstVarRef* const vrp = VN_CAST(assignp->lhsp(), VarRef)) {
|
||||
if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) {
|
||||
if (clk_offset != 0) {
|
||||
UINFO(9, "Should only make it here with clk_offset = 0" << endl);
|
||||
|
|
@ -1515,9 +1517,9 @@ private:
|
|||
}
|
||||
UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl);
|
||||
UINFO(9, " to - " << m_clk_vsp << endl);
|
||||
AstNode* rhsp = assignp->rhsp();
|
||||
AstNode* const rhsp = assignp->rhsp();
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ));
|
||||
while (V3GraphEdge* edgep = lvertexp->inBeginp()) {
|
||||
while (V3GraphEdge* const edgep = lvertexp->inBeginp()) {
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1);
|
||||
|
|
@ -1555,8 +1557,8 @@ void GateVisitor::decomposeClkVectors() {
|
|||
AstNode::user2ClearTree();
|
||||
GateClkDecompGraphVisitor decomposer{&m_graph};
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* vertp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
AstVarScope* vsp = vertp->varScp();
|
||||
if (GateVarVertex* const vertp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
const AstVarScope* const vsp = vertp->varScp();
|
||||
if (vsp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
||||
if (vsp->varp()->width() > 1) {
|
||||
UINFO(9, "Clocker > 1 bit, not decomposing: " << vsp << endl);
|
||||
|
|
@ -1576,9 +1578,9 @@ class GateDeassignVisitor final : public GateBaseVisitor {
|
|||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
if (AstNodeAssign* assp = VN_CAST(nodep->valuep(), NodeAssign)) {
|
||||
if (AstNodeAssign* const assp = VN_CAST(nodep->valuep(), NodeAssign)) {
|
||||
UINFO(5, " Removeassign " << assp << endl);
|
||||
AstNode* valuep = assp->rhsp();
|
||||
AstNode* const valuep = assp->rhsp();
|
||||
valuep->unlinkFrBack();
|
||||
assp->replaceWith(valuep);
|
||||
VL_DO_DANGLING(assp->deleteTree(), assp);
|
||||
|
|
@ -1601,8 +1603,8 @@ public:
|
|||
void V3Gate::gateAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
GateVisitor visitor{nodep};
|
||||
GateDeassignVisitor deassign{nodep};
|
||||
const GateVisitor visitor{nodep};
|
||||
GateDeassignVisitor{nodep};
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("gate", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,18 +43,18 @@ private:
|
|||
// Cleared on top scope
|
||||
// AstVarScope::user2() -> AstVarScope*. Signal replacing activation with
|
||||
// AstVarRef::user3() -> bool. Signal is replaced activation (already done)
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
const AstUser2InUse m_inuser2;
|
||||
const AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep = nullptr; // Inside activate statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp = nullptr; // Scope under TOPSCOPE
|
||||
const AstActive* m_activep = nullptr; // Inside activate statement
|
||||
AstNodeModule* const m_topModp; // Top module
|
||||
AstScope* const m_scopetopp = v3Global.rootp()->topScopep()->scopep(); // The top AstScope
|
||||
|
||||
// METHODS
|
||||
AstVarScope* genInpClk(AstVarScope* vscp) {
|
||||
if (vscp->user2p()) {
|
||||
return VN_CAST(vscp->user2p(), VarScope);
|
||||
return VN_AS(vscp->user2p(), VarScope);
|
||||
} else {
|
||||
// In order to create a __VinpClk* for a signal, it needs to be marked circular.
|
||||
// The DPI export trigger is never marked circular by V3Order (see comments in
|
||||
|
|
@ -69,18 +69,18 @@ private:
|
|||
// that might have dependents scheduled earlier.
|
||||
UASSERT_OBJ(vscp != v3Global.rootp()->dpiExportTriggerp(), vscp,
|
||||
"DPI export trigger should not need __VinpClk");
|
||||
AstVar* varp = vscp->varp();
|
||||
string newvarname
|
||||
AstVar* const varp = vscp->varp();
|
||||
const string newvarname
|
||||
= "__VinpClk__" + vscp->scopep()->nameDotless() + "__" + varp->name();
|
||||
// Create: VARREF(inpclk)
|
||||
// ...
|
||||
// ASSIGN(VARREF(inpclk), VARREF(var))
|
||||
AstVar* newvarp
|
||||
AstVar* const newvarp
|
||||
= new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
|
||||
m_topModp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
||||
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
||||
m_scopetopp->addVarp(newvscp);
|
||||
AstAssign* asninitp = new AstAssign(
|
||||
AstAssign* const asninitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
m_scopetopp->addFinalClkp(asninitp);
|
||||
|
|
@ -93,25 +93,21 @@ private:
|
|||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
AstNode::user2ClearTree(); // user2p() used on entire tree
|
||||
|
||||
AstScope* scopep = nodep->scopep();
|
||||
UASSERT_OBJ(scopep, nodep, "No scope found on top level");
|
||||
m_scopetopp = scopep;
|
||||
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//----
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
AstVarScope* const vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
if (m_activep && !nodep->user3()) {
|
||||
nodep->user3(true);
|
||||
if (vscp->isCircular()) {
|
||||
UINFO(8, " VarActReplace " << nodep << endl);
|
||||
// Replace with the new variable
|
||||
AstVarScope* newvscp = genInpClk(vscp);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
|
||||
AstVarScope* const newvscp = genInpClk(vscp);
|
||||
AstVarRef* const newrefp
|
||||
= new AstVarRef(nodep->fileline(), newvscp, nodep->access());
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
|
@ -120,7 +116,7 @@ private:
|
|||
virtual void visit(AstActive* nodep) override {
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
iterateChildren(nodep->sensesp()); // iterateAndNext?
|
||||
iterate(nodep->sensesp());
|
||||
m_activep = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -145,12 +141,12 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared on top scope
|
||||
// AstVarScope::user() -> bool. Set when the var has been used as clock
|
||||
AstUser1InUse m_inuser1;
|
||||
const AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
bool m_tracingCall = false; // Iterating into a call to a cfunc
|
||||
AstActive* m_activep = nullptr; // Inside activate statement
|
||||
AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
|
||||
const AstActive* m_activep = nullptr; // Inside activate statement
|
||||
const AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp = nullptr; // Top module
|
||||
|
||||
// VISITORS
|
||||
|
|
@ -160,7 +156,7 @@ private:
|
|||
{
|
||||
// Make the new clock signals and replace any activate references
|
||||
// See rename, it does some AstNode::userClearTree()'s
|
||||
GenClkRenameVisitor visitor{nodep, m_topModp};
|
||||
GenClkRenameVisitor{nodep, m_topModp};
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
|
|
@ -192,7 +188,7 @@ private:
|
|||
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
AstVarScope* const vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
if (m_activep) {
|
||||
UINFO(8, " VarAct " << nodep << endl);
|
||||
|
|
@ -215,7 +211,7 @@ private:
|
|||
UINFO(8, "ACTIVE " << nodep << endl);
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
iterateChildren(nodep->sensesp()); // iterateAndNext?
|
||||
iterate(nodep->sensesp());
|
||||
m_activep = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -235,6 +231,6 @@ public:
|
|||
|
||||
void V3GenClk::genClkAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ GenClkReadVisitor visitor{nodep}; } // Destruct before checking
|
||||
{ GenClkReadVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ void V3Global::checkTree() const { rootp()->checkTree(); }
|
|||
void V3Global::readFiles() {
|
||||
// NODE STATE
|
||||
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
|
||||
AstUser4InUse inuser4;
|
||||
const AstUser4InUse inuser4;
|
||||
|
||||
VInFilter filter(v3Global.opt.pipeFilter());
|
||||
V3ParseSym parseSyms(v3Global.rootp()); // Symbol table must be common across all parsing
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
|||
// List of all possible subgraphs
|
||||
std::multimap<std::string, V3GraphVertex*> subgraphs;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
string vertexSubgraph
|
||||
const string vertexSubgraph
|
||||
= (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : "";
|
||||
subgraphs.emplace(vertexSubgraph, vertexp);
|
||||
}
|
||||
|
|
@ -341,7 +341,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
|||
string subgr;
|
||||
for (auto it = subgraphs.cbegin(); it != subgraphs.cend(); ++it) {
|
||||
const string vertexSubgraph = it->first;
|
||||
V3GraphVertex* vertexp = it->second;
|
||||
const V3GraphVertex* vertexp = it->second;
|
||||
numMap[vertexp] = n;
|
||||
if (subgr != vertexSubgraph) {
|
||||
if (subgr != "") *logp << "\t};\n";
|
||||
|
|
|
|||
|
|
@ -88,10 +88,6 @@ protected:
|
|||
friend class V3GraphEdge;
|
||||
friend class GraphAcyc;
|
||||
// METHODS
|
||||
void acyclicDFS();
|
||||
void acyclicDFSIterate(V3GraphVertex* vertexp, int depth, uint32_t currentRank);
|
||||
void acyclicCut();
|
||||
void acyclicLoop(V3GraphVertex* vertexp, int depth);
|
||||
double orderDFSIterate(V3GraphVertex* vertexp);
|
||||
void dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep);
|
||||
void verticesUnlink() { m_vertices.reset(); }
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class GraphAcycEdge final : public V3GraphEdge {
|
|||
private:
|
||||
using OrigEdgeList = std::list<V3GraphEdge*>; // List of orig edges, see also GraphAcyc's decl
|
||||
V3GraphEdge* origEdgep() const {
|
||||
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(userp());
|
||||
const OrigEdgeList* const oEListp = static_cast<OrigEdgeList*>(userp());
|
||||
if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this);
|
||||
return (oEListp->front());
|
||||
}
|
||||
|
|
@ -102,7 +102,8 @@ private:
|
|||
V3Graph m_breakGraph; // Graph with only breakable edges represented
|
||||
V3List<GraphAcycVertex*> m_work; // List of vertices with optimization work left
|
||||
std::vector<OrigEdgeList*> m_origEdgeDelp; // List of deletions to do when done
|
||||
V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
|
||||
const V3EdgeFuncP
|
||||
m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
|
||||
uint32_t m_placeStep = 0; // Number that user() must be equal to to indicate processing
|
||||
|
||||
static int debug() { return V3Graph::debug(); }
|
||||
|
|
@ -127,8 +128,8 @@ private:
|
|||
}
|
||||
V3GraphEdge* edgeFromEdge(V3GraphEdge* oldedgep, V3GraphVertex* fromp, V3GraphVertex* top) {
|
||||
// Make new breakGraph edge, with old edge as a template
|
||||
GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top, oldedgep->weight(),
|
||||
oldedgep->cutable());
|
||||
GraphAcycEdge* const newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top,
|
||||
oldedgep->weight(), oldedgep->cutable());
|
||||
newEdgep->userp(oldedgep->userp()); // Keep pointer to OrigEdgeList
|
||||
return newEdgep;
|
||||
}
|
||||
|
|
@ -137,12 +138,12 @@ private:
|
|||
// Note addEdge may already have a bunch of similar linked edge representations. Yuk.
|
||||
UASSERT(addEdgep, "Adding nullptr");
|
||||
if (!toEdgep->userp()) {
|
||||
OrigEdgeList* oep = new OrigEdgeList;
|
||||
OrigEdgeList* const oep = new OrigEdgeList;
|
||||
m_origEdgeDelp.push_back(oep);
|
||||
toEdgep->userp(oep);
|
||||
}
|
||||
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(toEdgep->userp());
|
||||
if (OrigEdgeList* addListp = static_cast<OrigEdgeList*>(addEdgep->userp())) {
|
||||
OrigEdgeList* const oEListp = static_cast<OrigEdgeList*>(toEdgep->userp());
|
||||
if (OrigEdgeList* const addListp = static_cast<OrigEdgeList*>(addEdgep->userp())) {
|
||||
for (const auto& itr : *addListp) oEListp->push_back(itr);
|
||||
addListp->clear(); // Done with it
|
||||
} else {
|
||||
|
|
@ -153,7 +154,7 @@ private:
|
|||
// From the break edge, cut edges in original graph it represents
|
||||
UINFO(8, why << " CUT " << breakEdgep->fromp() << endl);
|
||||
breakEdgep->cut();
|
||||
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(breakEdgep->userp());
|
||||
const OrigEdgeList* const oEListp = static_cast<OrigEdgeList*>(breakEdgep->userp());
|
||||
if (!oEListp) {
|
||||
v3fatalSrc("No original edge associated with cutting edge " << breakEdgep);
|
||||
}
|
||||
|
|
@ -166,7 +167,7 @@ private:
|
|||
}
|
||||
// Work Queue
|
||||
void workPush(V3GraphVertex* vertexp) {
|
||||
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
|
||||
GraphAcycVertex* const avertexp = static_cast<GraphAcycVertex*>(vertexp);
|
||||
// Add vertex to list of nodes needing further optimization trials
|
||||
if (!avertexp->m_onWorkList) {
|
||||
avertexp->m_onWorkList = true;
|
||||
|
|
@ -175,7 +176,7 @@ private:
|
|||
}
|
||||
GraphAcycVertex* workBeginp() { return m_work.begin(); }
|
||||
void workPop() {
|
||||
GraphAcycVertex* avertexp = workBeginp();
|
||||
GraphAcycVertex* const avertexp = workBeginp();
|
||||
avertexp->m_onWorkList = false;
|
||||
avertexp->m_work.unlink(m_work, avertexp);
|
||||
}
|
||||
|
|
@ -204,7 +205,7 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
|
|||
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
|
||||
overtexp = overtexp->verticesNextp()) {
|
||||
if (overtexp->color()) {
|
||||
GraphAcycVertex* avertexp = new GraphAcycVertex(&m_breakGraph, overtexp);
|
||||
GraphAcycVertex* const avertexp = new GraphAcycVertex(&m_breakGraph, overtexp);
|
||||
overtexp->userp(avertexp); // Stash so can look up later
|
||||
}
|
||||
}
|
||||
|
|
@ -213,7 +214,7 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
|
|||
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
|
||||
overtexp = overtexp->verticesNextp()) {
|
||||
if (overtexp->color()) {
|
||||
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(overtexp->userp());
|
||||
GraphAcycVertex* const avertexp = static_cast<GraphAcycVertex*>(overtexp->userp());
|
||||
buildGraphIterate(overtexp, avertexp);
|
||||
}
|
||||
}
|
||||
|
|
@ -223,9 +224,10 @@ void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* aver
|
|||
// Make new edges
|
||||
for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (origFollowEdge(edgep)) { // not cut
|
||||
V3GraphVertex* toVertexp = edgep->top();
|
||||
const V3GraphVertex* toVertexp = edgep->top();
|
||||
if (toVertexp->color()) {
|
||||
GraphAcycVertex* toAVertexp = static_cast<GraphAcycVertex*>(toVertexp->userp());
|
||||
GraphAcycVertex* const toAVertexp
|
||||
= static_cast<GraphAcycVertex*>(toVertexp->userp());
|
||||
// Replicate the old edge into the new graph
|
||||
// There may be multiple edges between same pairs of vertices
|
||||
V3GraphEdge* breakEdgep = new GraphAcycEdge(&m_breakGraph, avertexp, toAVertexp,
|
||||
|
|
@ -266,7 +268,7 @@ void GraphAcyc::deleteMarked() {
|
|||
for (V3GraphVertex *nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp;
|
||||
vertexp = nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
|
||||
GraphAcycVertex* const avertexp = static_cast<GraphAcycVertex*>(vertexp);
|
||||
if (avertexp->isDelete()) {
|
||||
VL_DO_DANGLING(avertexp->unlinkDelete(&m_breakGraph), avertexp);
|
||||
}
|
||||
|
|
@ -281,13 +283,13 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) {
|
|||
UINFO(9, " SimplifyNoneRemove " << avertexp << endl);
|
||||
avertexp->setDelete(); // Mark so we won't delete it twice
|
||||
// Remove edges
|
||||
while (V3GraphEdge* edgep = avertexp->outBeginp()) {
|
||||
while (V3GraphEdge* const edgep = avertexp->outBeginp()) {
|
||||
V3GraphVertex* otherVertexp = edgep->top();
|
||||
// UINFO(9, " out " << otherVertexp << endl);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(otherVertexp);
|
||||
}
|
||||
while (V3GraphEdge* edgep = avertexp->inBeginp()) {
|
||||
while (V3GraphEdge* const edgep = avertexp->inBeginp()) {
|
||||
V3GraphVertex* otherVertexp = edgep->fromp();
|
||||
// UINFO(9, " in " << otherVertexp << endl);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
|
|
@ -483,7 +485,7 @@ void GraphAcyc::placeTryEdge(V3GraphEdge* edgep) {
|
|||
// Vertex::m_user begin: number indicates this edge was completed
|
||||
// Try to assign ranks, presuming this edge is in place
|
||||
// If we come across user()==placestep, we've detected a loop and must back out
|
||||
bool loop
|
||||
const bool loop
|
||||
= placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), edgep->fromp()->rank() + 1);
|
||||
if (!loop) {
|
||||
// No loop, we can keep it as uncutable
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
// Algorithms - weakly connected components
|
||||
|
||||
class GraphRemoveRedundant final : GraphAlg<> {
|
||||
bool m_sumWeights; ///< Sum, rather then maximize weights
|
||||
const bool m_sumWeights; ///< Sum, rather then maximize weights
|
||||
private:
|
||||
void main() {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
|
|
@ -213,7 +213,7 @@ private:
|
|||
}
|
||||
|
||||
void vertexIterate(V3GraphVertex* vertexp) {
|
||||
uint32_t thisDfsNum = m_currentDfs++;
|
||||
const uint32_t thisDfsNum = m_currentDfs++;
|
||||
vertexp->user(thisDfsNum);
|
||||
vertexp->color(0);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
template <class T_Graph = V3Graph> // Or sometimes const V3Graph
|
||||
class GraphAlg VL_NOT_FINAL {
|
||||
protected:
|
||||
T_Graph* m_graphp; // Graph we're operating upon
|
||||
V3EdgeFuncP m_edgeFuncp; // Function that says we follow this edge
|
||||
T_Graph* const m_graphp; // Graph we're operating upon
|
||||
const V3EdgeFuncP m_edgeFuncp; // Function that says we follow this edge
|
||||
// CONSTRUCTORS
|
||||
GraphAlg(T_Graph* graphp, V3EdgeFuncP edgeFuncp)
|
||||
: m_graphp{graphp}
|
||||
|
|
|
|||
|
|
@ -1,605 +0,0 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Graph optimizations
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2021 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
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3GraphDfa.h"
|
||||
#include "V3GraphAlg.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
// Algorithms - find starting node
|
||||
|
||||
DfaVertex* DfaGraph::findStart() {
|
||||
DfaVertex* startp = nullptr;
|
||||
for (V3GraphVertex* vertexp = this->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
|
||||
if (vvertexp->start()) {
|
||||
UASSERT_OBJ(!startp, vertexp, "Multiple start points in NFA graph");
|
||||
startp = vvertexp;
|
||||
}
|
||||
} else {
|
||||
vertexp->v3fatalSrc("Non DfaVertex in DfaGraph");
|
||||
}
|
||||
}
|
||||
if (!startp) v3fatalSrc("No start point in NFA graph");
|
||||
return startp;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
// Algorithms - convert NFA to a DFA
|
||||
// Uses the Subset Construction Algorithm
|
||||
|
||||
class GraphNfaToDfa final : GraphAlg<> {
|
||||
// We have two types of nodes in one graph, NFA and DFA nodes.
|
||||
// Edges from NFA to NFA come from the user, and indicate input or epsilon transitions
|
||||
// Edges from DFA to NFA indicate the NFA from which that DFA was formed.
|
||||
// Edges from DFA to DFA indicate a completed input transition
|
||||
private:
|
||||
// TYPES
|
||||
using DfaStates = std::deque<DfaVertex*>;
|
||||
using HashMap = std::multimap<vluint64_t, DfaVertex*>;
|
||||
|
||||
// MEMBERS
|
||||
uint32_t m_step; // Processing step, so we can avoid clearUser all the time
|
||||
HashMap m_hashMap; // Dfa Vertex for each set of NFA vertexes
|
||||
|
||||
#ifdef VL_CPPCHECK
|
||||
static int debug() { return 9; }
|
||||
#else
|
||||
static int debug() { return 0; }
|
||||
#endif
|
||||
|
||||
// METHODS
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
static bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; }
|
||||
// static bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; }
|
||||
|
||||
void nextStep() { m_step++; }
|
||||
|
||||
bool unseenNfaThisStep(V3GraphVertex* vertexp) {
|
||||
// A nfa node not already seen this processing step
|
||||
return (nfaState(vertexp) && !(vertexp->user() == m_step));
|
||||
}
|
||||
|
||||
DfaVertex* newDfaVertex(DfaVertex* nfaTemplatep = nullptr) {
|
||||
DfaVertex* vertexp = new DfaVertex(graphp());
|
||||
vertexp->color(1); // Mark as dfa
|
||||
if (nfaTemplatep && nfaTemplatep->start()) vertexp->start(true);
|
||||
if (nfaTemplatep && nfaTemplatep->accepting()) vertexp->accepting(true);
|
||||
UINFO(9, " New " << vertexp << endl);
|
||||
return vertexp;
|
||||
}
|
||||
|
||||
// Hashing
|
||||
static uint32_t hashVertex(V3GraphVertex* vertexp) {
|
||||
union {
|
||||
void* up;
|
||||
struct {
|
||||
uint32_t upper;
|
||||
uint32_t lower;
|
||||
} l;
|
||||
} u;
|
||||
u.l.upper = 0;
|
||||
u.l.lower = 0;
|
||||
u.up = vertexp;
|
||||
return u.l.upper ^ u.l.lower;
|
||||
}
|
||||
|
||||
uint32_t hashDfaOrigins(DfaVertex* dfaStatep) {
|
||||
// Find the NFA states this dfa came from,
|
||||
// Record a checksum, so we can search for it later by the list of nfa nodes.
|
||||
// The order of the nodes is not deterministic; the hash thus must
|
||||
// not depend on order of edges
|
||||
uint32_t hash = 0;
|
||||
// Foreach NFA state (this DFA state was formed from)
|
||||
if (debug()) nextStep();
|
||||
for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep;
|
||||
dfaEdgep = dfaEdgep->outNextp()) {
|
||||
if (nfaState(dfaEdgep->top())) {
|
||||
DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top());
|
||||
hash ^= hashVertex(nfaStatep);
|
||||
if (debug()) {
|
||||
UASSERT_OBJ(nfaStatep->user() != m_step, nfaStatep,
|
||||
"DFA state points to duplicate NFA state.");
|
||||
nfaStatep->user(m_step);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint32_t hashDfaOrigins(const DfaStates& nfasWithInput) {
|
||||
// Find the NFA states this dfa came from,
|
||||
uint32_t hash = 0;
|
||||
for (DfaVertex* nfaStatep : nfasWithInput) hash ^= hashVertex(nfaStatep);
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool compareDfaOrigins(const DfaStates& nfasWithInput, DfaVertex* dfa2p) {
|
||||
// Return true if the NFA nodes both DFAs came from are the same list
|
||||
// Assume there are no duplicates in either input list or NFAs under dfa2
|
||||
nextStep();
|
||||
// Mark all input vertexes
|
||||
int num1s = 0;
|
||||
for (DfaVertex* nfaStatep : nfasWithInput) {
|
||||
nfaStatep->user(m_step);
|
||||
num1s++;
|
||||
}
|
||||
if (!num1s) v3fatalSrc("DFA node construction that contains no NFA states");
|
||||
|
||||
// Check comparison; must all be marked
|
||||
// (Check all in dfa2p were in dfa1p)
|
||||
int num2s = 0;
|
||||
for (V3GraphEdge* dfaEdgep = dfa2p->outBeginp(); dfaEdgep;
|
||||
dfaEdgep = dfaEdgep->outNextp()) {
|
||||
if (nfaState(dfaEdgep->top())) {
|
||||
if (dfaEdgep->top()->user() != m_step) return false;
|
||||
num2s++;
|
||||
}
|
||||
}
|
||||
// If we saw all of the nodes, then they have the same number of hits
|
||||
// (Else something in dfa1p that wasn't in dfa2p)
|
||||
return (num1s == num2s);
|
||||
}
|
||||
|
||||
void insertDfaOrigins(DfaVertex* dfaStatep) {
|
||||
// Record the NFA states this dfa came from
|
||||
uint32_t hash = hashDfaOrigins(dfaStatep);
|
||||
m_hashMap.emplace(hash, dfaStatep);
|
||||
}
|
||||
|
||||
DfaVertex* findDfaOrigins(const DfaStates& nfasWithInput) {
|
||||
// Find another DFA state which comes from the identical set of NFA states
|
||||
// The order of the nodes is not deterministic; the hash thus must
|
||||
// not depend on order of edges
|
||||
uint32_t hash = hashDfaOrigins(nfasWithInput);
|
||||
|
||||
const auto eqrange = m_hashMap.equal_range(hash);
|
||||
for (auto it = eqrange.first; it != eqrange.second; ++it) {
|
||||
DfaVertex* testp = it->second;
|
||||
if (compareDfaOrigins(nfasWithInput, testp)) {
|
||||
UINFO(9, " DFA match for set: " << testp << endl);
|
||||
return testp; // Identical
|
||||
}
|
||||
}
|
||||
return nullptr; // No match
|
||||
}
|
||||
|
||||
void findNfasWithInput(DfaVertex* dfaStatep, const DfaInput& input, DfaStates& nfasWithInput) {
|
||||
// Return all NFA states, with the given input transition from
|
||||
// the nfa states a given dfa state was constructed from.
|
||||
nextStep();
|
||||
nfasWithInput.clear(); // NFAs with given input
|
||||
|
||||
// Foreach NFA state (this DFA state was formed from)
|
||||
for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep;
|
||||
dfaEdgep = dfaEdgep->outNextp()) {
|
||||
if (nfaState(dfaEdgep->top())) {
|
||||
DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top());
|
||||
// Foreach input transition (on this nfaStatep)
|
||||
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
|
||||
nfaEdgep = nfaEdgep->outNextp()) {
|
||||
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
|
||||
if (cNfaEdgep->input().toNodep() == input.toNodep()) {
|
||||
DfaVertex* nextStatep = static_cast<DfaVertex*>(cNfaEdgep->top());
|
||||
if (unseenNfaThisStep(nextStatep)) { // Not processed?
|
||||
nfasWithInput.push_back(nextStatep);
|
||||
nextStatep->user(m_step);
|
||||
UINFO(9, " Reachable " << nextStatep << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand the nfasWithInput list to include epsilon states
|
||||
// reachable by those on nfasWithInput
|
||||
{
|
||||
DfaStates nfasTodo = nfasWithInput;
|
||||
nfasWithInput.clear(); // Now the completed list
|
||||
while (!nfasTodo.empty()) {
|
||||
DfaVertex* nfaStatep = nfasTodo.front();
|
||||
nfasTodo.pop_front();
|
||||
nfasWithInput.push_back(nfaStatep);
|
||||
// Foreach epsilon-reachable (on this nfaStatep)
|
||||
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
|
||||
nfaEdgep = nfaEdgep->outNextp()) {
|
||||
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
|
||||
if (cNfaEdgep->epsilon()) {
|
||||
DfaVertex* nextStatep = static_cast<DfaVertex*>(cNfaEdgep->top());
|
||||
if (unseenNfaThisStep(nextStatep)) { // Not processed?
|
||||
nfasTodo.push_back(nextStatep);
|
||||
nextStatep->user(m_step);
|
||||
UINFO(9, " Epsilon Reachable " << nextStatep << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
UINFO(5, "Dfa to Nfa conversion...\n");
|
||||
// Vertex::color() begin: 1 indicates vertex on DFA graph, 0=NFA graph
|
||||
m_graphp->clearColors();
|
||||
// Vertex::m_user begin: # indicates processed this m_step number
|
||||
m_graphp->userClearVertices();
|
||||
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_nfa");
|
||||
|
||||
// Find NFA start
|
||||
DfaVertex* nfaStartp = graphp()->findStart();
|
||||
|
||||
// Create new DFA State (start state) from the NFA states
|
||||
DfaVertex* dfaStartp = newDfaVertex(nfaStartp);
|
||||
|
||||
DfaStates dfaUnprocps; // Unprocessed DFA nodes
|
||||
dfaUnprocps.push_back(dfaStartp);
|
||||
|
||||
UINFO(5, "Starting state conversion...\n");
|
||||
// Form DFA starting state from epsilon closure of NFA start
|
||||
nextStep();
|
||||
DfaStates workps;
|
||||
workps.push_back(nfaStartp);
|
||||
|
||||
while (!workps.empty()) { // While work
|
||||
DfaVertex* nfaStatep = workps.back();
|
||||
workps.pop_back();
|
||||
// UINFO(9," Processing "<<nfaStatep<<endl);
|
||||
nfaStatep->user(m_step); // Mark as processed
|
||||
// Add a edge so we can find NFAs from a given DFA.
|
||||
// The NFA will never see this edge, because we only look at TO edges.
|
||||
new DfaEdge(graphp(), dfaStartp, nfaStatep, DfaEdge::NA());
|
||||
// Find epsilon closure of this nfa node, and destinations to work list
|
||||
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
|
||||
nfaEdgep = nfaEdgep->outNextp()) {
|
||||
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
|
||||
DfaVertex* ecNfaStatep = static_cast<DfaVertex*>(nfaEdgep->top());
|
||||
// UINFO(9," Consider "<<nfaEdgep->top()<<" EP "<<cNfaEdgep->epsilon()<<endl);
|
||||
if (cNfaEdgep->epsilon() && unseenNfaThisStep(ecNfaStatep)) { // Not processed?
|
||||
workps.push_back(ecNfaStatep);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_start");
|
||||
insertDfaOrigins(dfaStartp);
|
||||
|
||||
int i = 0;
|
||||
UINFO(5, "Main state conversion...\n");
|
||||
while (!dfaUnprocps.empty()) {
|
||||
DfaVertex* dfaStatep = dfaUnprocps.back();
|
||||
dfaUnprocps.pop_back();
|
||||
UINFO(9, " On dfaState " << dfaStatep << endl);
|
||||
|
||||
// From this dfaState, what corresponding nfaStates have what inputs?
|
||||
std::unordered_set<int> inputs;
|
||||
// Foreach NFA state (this DFA state was formed from)
|
||||
for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep;
|
||||
dfaEdgep = dfaEdgep->outNextp()) {
|
||||
if (nfaState(dfaEdgep->top())) {
|
||||
DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top());
|
||||
// Foreach input on this nfaStatep
|
||||
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
|
||||
nfaEdgep = nfaEdgep->outNextp()) {
|
||||
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
|
||||
if (!cNfaEdgep->epsilon()) {
|
||||
if (inputs.find(cNfaEdgep->input().toInt()) == inputs.end()) {
|
||||
inputs.insert(cNfaEdgep->input().toInt());
|
||||
UINFO(9, " Input to " << dfaStatep << " is "
|
||||
<< (cNfaEdgep->input().toInt()) << " via "
|
||||
<< nfaStatep << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Foreach input state (NFA inputs of this DFA state)
|
||||
for (int inIt : inputs) {
|
||||
const DfaInput input = inIt;
|
||||
UINFO(9, " ===" << ++i << "=======================\n");
|
||||
UINFO(9, " On input " << cvtToHex(input.toNodep()) << endl);
|
||||
|
||||
// Find all states reachable for given input
|
||||
DfaStates nfasWithInput;
|
||||
findNfasWithInput(dfaStatep, input, nfasWithInput /*ref*/);
|
||||
|
||||
// nfasWithInput now maps to the DFA we want a transition to.
|
||||
// Does a DFA already exist with this, and only this subset of NFA's?
|
||||
DfaVertex* toDfaStatep = findDfaOrigins(nfasWithInput);
|
||||
if (!toDfaStatep) {
|
||||
// Doesn't exist, make new dfa state corresponding to this one,
|
||||
toDfaStatep = newDfaVertex();
|
||||
dfaUnprocps.push_back(toDfaStatep); // Add to process list
|
||||
// Track what nfa's point to it.
|
||||
for (DfaStates::const_iterator nfaIt = nfasWithInput.begin();
|
||||
nfaIt != nfasWithInput.end(); ++nfaIt) {
|
||||
UINFO(9, " NewContainsNfa " << *nfaIt << endl);
|
||||
new DfaEdge(graphp(), toDfaStatep, *nfaIt, DfaEdge::NA());
|
||||
if ((*nfaIt)->accepting()) toDfaStatep->accepting(true);
|
||||
}
|
||||
insertDfaOrigins(toDfaStatep);
|
||||
}
|
||||
// Add input transition
|
||||
new DfaEdge(graphp(), dfaStatep, toDfaStatep, input);
|
||||
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("step");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove old NFA states
|
||||
UINFO(5, "Removing NFA states...\n");
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_withnfa");
|
||||
for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
if (nfaState(vertexp)) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
|
||||
UINFO(5, "Done.\n");
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_done");
|
||||
}
|
||||
|
||||
public:
|
||||
GraphNfaToDfa(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
|
||||
: GraphAlg<>{graphp, edgeFuncp} {
|
||||
m_step = 0;
|
||||
main();
|
||||
}
|
||||
~GraphNfaToDfa() = default;
|
||||
};
|
||||
|
||||
void DfaGraph::nfaToDfa() { GraphNfaToDfa(this, &V3GraphEdge::followAlwaysTrue); }
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
// Algorithms - optimize a DFA structure
|
||||
//
|
||||
// Scan the DFA, cleaning up trailing states.
|
||||
|
||||
class DfaGraphReduce final : GraphAlg<> {
|
||||
private:
|
||||
// METHODS
|
||||
#ifdef VL_CPPCHECK
|
||||
static int debug() { return 9; }
|
||||
#else
|
||||
static int debug() { return 0; }
|
||||
#endif
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
|
||||
bool isDead(DfaVertex* vertexp) {
|
||||
// A state is dead if not accepting, and goes nowhere
|
||||
if (vertexp->accepting() || vertexp->start()) return false;
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (edgep->top() != vertexp) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void optimize_accepting_out() {
|
||||
// Delete outbound edges from accepting states
|
||||
// (As once we've accepted, we no longer care about anything else.)
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
|
||||
if (vvertexp->accepting()) {
|
||||
for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void optimize_orphans() {
|
||||
// Remove states that don't come from start
|
||||
// Presumably the previous optimization orphaned them.
|
||||
|
||||
// Vertex::m_user begin: 1 indicates on the work list, 2 processed
|
||||
// (Otherwise we might have nodes on the list twice, and reference after deleting them.)
|
||||
m_graphp->userClearVertices();
|
||||
|
||||
DfaVertex* startp = graphp()->findStart();
|
||||
std::stack<V3GraphVertex*> workps;
|
||||
workps.push(startp);
|
||||
|
||||
// Mark all nodes connected to start
|
||||
while (!workps.empty()) {
|
||||
V3GraphVertex* vertexp = workps.top();
|
||||
workps.pop();
|
||||
vertexp->user(2); // Processed
|
||||
// Add nodes from here to the work list
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
V3GraphVertex* tovertexp = edgep->top();
|
||||
if (!tovertexp->user()) {
|
||||
workps.push(tovertexp);
|
||||
tovertexp->user(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all nodes not connected
|
||||
for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
if (!vertexp->user()) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
}
|
||||
|
||||
void optimize_no_outbound() {
|
||||
// Non-accepting states with no outbound transitions may be
|
||||
// deleted. Then, any arcs feeding those states, and perhaps those
|
||||
// states...
|
||||
|
||||
// Vertex::m_user begin: 1 indicates on the work list
|
||||
// (Otherwise we might have nodes on the list twice, and reference after deleting them.)
|
||||
m_graphp->userClearVertices();
|
||||
|
||||
// Find all dead vertexes
|
||||
std::stack<DfaVertex*> workps;
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
|
||||
workps.push(vvertexp);
|
||||
vertexp->user(1);
|
||||
} else {
|
||||
// If ever remove this, need dyn cast below
|
||||
vertexp->v3fatalSrc("Non DfaVertex in dfa graph");
|
||||
}
|
||||
}
|
||||
|
||||
// While deadness... Delete and find new dead nodes.
|
||||
while (!workps.empty()) {
|
||||
DfaVertex* vertexp = workps.top();
|
||||
workps.pop();
|
||||
vertexp->user(0);
|
||||
if (isDead(vertexp)) {
|
||||
// Add nodes that go here to the work list
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
DfaVertex* fromvertexp = static_cast<DfaVertex*>(edgep->fromp());
|
||||
if (fromvertexp != vertexp && !fromvertexp->user()) {
|
||||
workps.push(fromvertexp);
|
||||
fromvertexp->user(1);
|
||||
}
|
||||
}
|
||||
// Transitions to this state removed by the unlink function
|
||||
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DfaGraphReduce(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
|
||||
: GraphAlg<>{graphp, edgeFuncp} {
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_in");
|
||||
optimize_accepting_out();
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_acc");
|
||||
optimize_orphans();
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_orph");
|
||||
optimize_no_outbound();
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_noout");
|
||||
}
|
||||
~DfaGraphReduce() = default;
|
||||
};
|
||||
|
||||
void DfaGraph::dfaReduce() { DfaGraphReduce(this, &V3GraphEdge::followAlwaysTrue); }
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
// Algorithms - complement a DFA
|
||||
//
|
||||
// The traditional algorithm is to make a rejecting state, add edges to
|
||||
// reject from all missing values, then swap accept and reject. Rather
|
||||
// than swap at the end, it's faster if we swap up front, then do the edge
|
||||
// changes.
|
||||
//
|
||||
// 1. Since we didn't log rejecting states, make a temp state (this will be
|
||||
// the old accept, and new reject).
|
||||
//
|
||||
// 2. All vertexes except start/accept get edges to NEW accept for any
|
||||
// non-existing case. Weedely we don't have a nice way of representing
|
||||
// this so we just create a edge for each case and mark it "complemented."
|
||||
//
|
||||
// 3. Delete temp vertex (old accept/new reject) and related edges.
|
||||
// The user's old accept is now the new accept. This is important as
|
||||
// we want the virtual type of it to be intact.
|
||||
|
||||
class DfaGraphComplement final : GraphAlg<> {
|
||||
private:
|
||||
// MEMBERS
|
||||
DfaVertex* m_tempNewerReject;
|
||||
|
||||
// METHODS
|
||||
static int debug() { return 9; }
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
|
||||
void add_complement_edges() {
|
||||
// Find accepting vertex
|
||||
DfaVertex* acceptp = nullptr;
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
|
||||
if (vvertexp->accepting()) {
|
||||
acceptp = vvertexp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!acceptp) v3fatalSrc("No accepting vertex in DFA");
|
||||
|
||||
// Remap edges
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
|
||||
// UINFO(9, " on vertex "<<vvertexp->name()<<endl);
|
||||
if (!vvertexp->accepting() && vvertexp != m_tempNewerReject) {
|
||||
for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
if (!edgep->user()) { // Not processed
|
||||
// Old edges to accept now go to new reject
|
||||
DfaEdge* vedgep = static_cast<DfaEdge*>(edgep);
|
||||
DfaVertex* tovertexp = static_cast<DfaVertex*>(edgep->top());
|
||||
if (tovertexp->accepting()) {
|
||||
new DfaEdge(graphp(), vvertexp, m_tempNewerReject, vedgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
|
||||
// NOT of all values goes to accept
|
||||
// We make a edge for each value to OR, IE
|
||||
// edge(complemented,a) edge(complemented,b) means !(a | b)
|
||||
if (!tovertexp->accepting()) {
|
||||
// Note we must include edges moved above to reject
|
||||
DfaEdge* newp = new DfaEdge(graphp(), vvertexp, acceptp, vedgep);
|
||||
newp->complement(!newp->complement());
|
||||
newp->user(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DfaGraphComplement(V3Graph* dfagraphp, V3EdgeFuncP edgeFuncp)
|
||||
: GraphAlg<>{dfagraphp, edgeFuncp} {
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_in");
|
||||
|
||||
// Vertex::m_user begin: 1 indicates new edge, no more processing
|
||||
m_graphp->userClearEdges();
|
||||
|
||||
m_tempNewerReject = new DfaVertex(graphp());
|
||||
add_complement_edges();
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_preswap");
|
||||
|
||||
VL_DO_CLEAR(m_tempNewerReject->unlinkDelete(graphp()), m_tempNewerReject = nullptr);
|
||||
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_out");
|
||||
}
|
||||
~DfaGraphComplement() = default;
|
||||
VL_UNCOPYABLE(DfaGraphComplement);
|
||||
};
|
||||
|
||||
void DfaGraph::dfaComplement() { DfaGraphComplement(this, &V3GraphEdge::followAlwaysTrue); }
|
||||
152
src/V3GraphDfa.h
152
src/V3GraphDfa.h
|
|
@ -1,152 +0,0 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Graph automata base class
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2021 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
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3GRAPHDFA_H_
|
||||
#define VERILATOR_V3GRAPHDFA_H_
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h" // for VNUser
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
|
||||
class DfaGraph;
|
||||
class DfaVertex;
|
||||
class DfaEdge;
|
||||
|
||||
//=============================================================================
|
||||
// NFA/DFA Graphs
|
||||
/// The NFA graph consists of:
|
||||
/// DfaVertex(START) The starting point
|
||||
/// DfaVertex() Interior states
|
||||
/// DfaVertex(ACCEPT) The completion point
|
||||
///
|
||||
/// Transitions include a list of all inputs (arbitrary user pointers),
|
||||
/// or epsilon, represented as a empty list of inputs.
|
||||
///
|
||||
/// We're only looking for matches, so the only accepting states are
|
||||
/// at the end of the transformations. (If we want the complement, we
|
||||
/// call complement and the algorithm makes a REJECT state, then flips
|
||||
/// accept and reject for you.)
|
||||
///
|
||||
/// Common transforms:
|
||||
///
|
||||
/// "*": DfaVertex(START) --> [epsilon] -->DfaVertex(ACCEPT)
|
||||
///
|
||||
/// "L": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
|
||||
///
|
||||
/// "LR": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
|
||||
/// ->[ON_R]-->DfaVtx-->[epsilon]-/
|
||||
///
|
||||
/// "L|R": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
|
||||
/// \->[epsilon]-->DfaVtx-->[ON_R]-->DfaVtx()->[epsilon]-/
|
||||
///
|
||||
/// "L*": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
|
||||
/// | ^\----[epsilon]<-------/ |
|
||||
/// \->[epsilon]-----------------------------------------/
|
||||
|
||||
class DfaGraph final : public V3Graph {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
DfaGraph() = default;
|
||||
virtual ~DfaGraph() override = default;
|
||||
// METHODS
|
||||
/// Find start node
|
||||
DfaVertex* findStart();
|
||||
/// Convert automata: NFA to DFA
|
||||
void nfaToDfa();
|
||||
/// Simplify a DFA automata
|
||||
void dfaReduce();
|
||||
/// Complement result (must already be dfa)
|
||||
void dfaComplement();
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Vertex
|
||||
|
||||
class DfaVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
// Each DFA state is captured in this vertex.
|
||||
// Start and accepting are members, rather than the more intuitive
|
||||
// subclasses, as subclassing them would make it harder to inherit from here.
|
||||
bool m_start; // Start state
|
||||
bool m_accepting; // Accepting state?
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DfaVertex(DfaGraph* graphp, bool start = false, bool accepting = false)
|
||||
: V3GraphVertex{graphp}
|
||||
, m_start{start}
|
||||
, m_accepting{accepting} {}
|
||||
using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*)
|
||||
virtual DfaVertex* clone(DfaGraph* graphp) {
|
||||
return new DfaVertex(graphp, start(), accepting());
|
||||
}
|
||||
virtual ~DfaVertex() override = default;
|
||||
// ACCESSORS
|
||||
virtual string dotShape() const override { return (accepting() ? "doublecircle" : ""); }
|
||||
virtual string dotColor() const override {
|
||||
return start() ? "blue" : (color() ? "red" : "black");
|
||||
}
|
||||
bool start() const { return m_start; }
|
||||
void start(bool flag) { m_start = flag; }
|
||||
bool accepting() const { return m_accepting; }
|
||||
void accepting(bool flag) { m_accepting = flag; }
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
/// Abstract type indicating a specific "input" to the NFA
|
||||
/// DFA assumes each .toInt() is unique
|
||||
using DfaInput = VNUser;
|
||||
|
||||
//============================================================================
|
||||
// Edge types
|
||||
|
||||
class DfaEdge final : public V3GraphEdge {
|
||||
DfaInput m_input;
|
||||
bool m_complement; // Invert value when doing compare
|
||||
public:
|
||||
static DfaInput EPSILON() { return VNUser::fromInt(0); }
|
||||
static DfaInput NA() { return VNUser::fromInt(1); } // as in not-applicable
|
||||
// CONSTRUCTORS
|
||||
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaInput& input)
|
||||
: V3GraphEdge{graphp, fromp, top, 1}
|
||||
, m_input{input}
|
||||
, m_complement{false} {}
|
||||
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaEdge* copyfrom)
|
||||
: V3GraphEdge{graphp, fromp, top, copyfrom->weight()}
|
||||
, m_input{copyfrom->input()}
|
||||
, m_complement{copyfrom->complement()} {}
|
||||
virtual ~DfaEdge() override = default;
|
||||
// METHODS
|
||||
virtual string dotColor() const override {
|
||||
return (na() ? "yellow" : epsilon() ? "green" : "black");
|
||||
}
|
||||
virtual string dotLabel() const override {
|
||||
return (na() ? ""
|
||||
: epsilon() ? "e"
|
||||
: complement() ? ("not " + cvtToStr(input().toInt()))
|
||||
: cvtToStr(input().toInt()));
|
||||
}
|
||||
virtual string dotStyle() const override { return (na() || cutable()) ? "dashed" : ""; }
|
||||
bool epsilon() const { return input().toInt() == EPSILON().toInt(); }
|
||||
bool na() const { return input().toInt() == NA().toInt(); }
|
||||
bool complement() const { return m_complement; }
|
||||
void complement(bool value) { m_complement = value; }
|
||||
DfaInput input() const { return m_input; }
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
#endif // Guard
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue