Merge from master for release.

This commit is contained in:
Wilson Snyder 2022-10-01 08:33:50 -04:00
commit 04fff7ebd8
283 changed files with 17784 additions and 15562 deletions

View File

@ -11,7 +11,7 @@ on:
jobs: jobs:
Test: Test:
name: "'docs/CONTRIBUTORS' was signed" name: "'docs/CONTRIBUTORS' was signed"
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: test_regress/t/t_dist_contributors.pl - run: test_regress/t/t_dist_contributors.pl

View File

@ -10,11 +10,11 @@ on:
jobs: jobs:
format: format:
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
name: Ubuntu 20.04 | format name: Ubuntu 22.04 | format
env: env:
CI_OS_NAME: linux CI_OS_NAME: linux
CI_RUNS_ON: ubuntu-20.04 CI_RUNS_ON: ubuntu-22.04
CI_COMMIT: ${{ github.sha }} CI_COMMIT: ${{ github.sha }}
CI_M32: 0 CI_M32: 0
steps: steps:
@ -27,14 +27,14 @@ jobs:
CI_BUILD_STAGE_NAME: build CI_BUILD_STAGE_NAME: build
run: | run: |
bash ci/ci-install.bash && bash ci/ci-install.bash &&
sudo apt-get install clang-format-11 yapf3 && sudo apt-get install clang-format-14 yapf3 &&
git config --global user.email "action@example.com" && git config --global user.email "action@example.com" &&
git config --global user.name "github action" git config --global user.name "github action"
- name: Format code - name: Format code
run: | run: |
autoconf && autoconf &&
./configure && ./configure &&
make -j 2 format CLANGFORMAT=clang-format-11 && make -j 2 format CLANGFORMAT=clang-format-14 &&
git status git status
- name: Push - name: Push
run: | run: |

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
\#* \#*
.#* .#*
.gdb_history
.nfs* .nfs*
*~ *~
*.tidy *.tidy

30
Changes
View File

@ -8,6 +8,31 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks! contributors that suggested a given feature are shown in []. Thanks!
Verilator 4.228 2022-10-01
==========================
**Announcement:**
* The next release is anticipated primere Verilator Version 5. Please
consider beta-testing the github 'develop-v5' branch, which will soon
merge into the github 'master' branch (#3383).
**Minor:**
* Support some IEEE signal strengths (#3601) (#3629). [Ryszard Rozak/Antmicro]
* Add --main to generate main() C++ (previously was experimental only).
* Add --build-jobs, and rework arguments for -j (#3623). [Kamil Rakoczy]
* Rename --bin to --build-dep-bin.
* Rename debug flags --dumpi-tree, --dumpi-graph, etc. [Geza Lore]
* Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic]
* Fix crash in gate optimization of circular logic (#3543). [Bill Flynn]
* Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk]
* Fix default --mod-prefix when --prefix is repeated (#3603). [Geza Lore]
* Fix calling trace() after open() segfault (#3610) (#3627). [Yu-Sheng Lin]
* Fix typedef'ed class conversion to boolean (#3616). [Aleksander Kiryk]
* Fix Verilation speed when disabled warnings (#3632). [Kamil Rakoczy/Antmicro]
Verilator 4.226 2022-08-31 Verilator 4.226 2022-08-31
========================== ==========================
@ -20,12 +45,13 @@ Verilator 4.226 2022-08-31
* Support $test$plusargs(expr) (#3489). * Support $test$plusargs(expr) (#3489).
* Rename trace rolloverSize() (#3570). * Rename trace rolloverSize() (#3570).
* Improve Verilation speed with --threads on large designs. [Geza Lore] * Improve Verilation speed with --threads on large designs. [Geza Lore]
* Improve Verilation memory by reducing V3Number (#3521). [Mariusz Glebocki/Antmicro]
* Fix struct pattern assignment (#2328) (#3517). [Mostafa Gamal] * Fix struct pattern assignment (#2328) (#3517). [Mostafa Gamal]
* Fix public combo propagation issues (#2905). [Todd Strader] * Fix public combo propagation issues (#2905). [Todd Strader]
* Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer] * Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer]
* Fix incorrect bit op tree optimization (#3470). [algrobman] * Fix incorrect bit op tree optimization (#3470). [algrobman]
* Fix bisonpre for MSYS2 (#3471). * Fix bisonpre for MSYS2 (#3471).
* Fix max memory usage (#3483). [Kamil Rakoczy] * Fix max memory usage (#3483). [Kamil Rakoczy/Antmicro]
* Fix empty string arguments to display (#3484). [Grulfen] * Fix empty string arguments to display (#3484). [Grulfen]
* Fix table misoptimizing away display (#3488). [Stefan Post] * Fix table misoptimizing away display (#3488). [Stefan Post]
* Fix unique_ptr memory header for MinGW64 (#3493). * Fix unique_ptr memory header for MinGW64 (#3493).
@ -36,7 +62,7 @@ Verilator 4.226 2022-08-31
* Fix segfault exporting non-existant package (#3535). * Fix segfault exporting non-existant package (#3535).
* Fix void-cast queue pop_front or pop_back (#3542) (#3364). [Drew Ranck] * Fix void-cast queue pop_front or pop_back (#3542) (#3364). [Drew Ranck]
* Fix case statement comparing string literal (#3544). [Gustav Svensk] * Fix case statement comparing string literal (#3544). [Gustav Svensk]
* Fix === with some tristate constants (#3551). [Ryszard Rozak] * Fix === with some tristate constants (#3551). [Ryszard Rozak/Antmicro]
* Fix converting subclasses to string (#3552). [Arkadiusz Kozdra/Antmicro] * Fix converting subclasses to string (#3552). [Arkadiusz Kozdra/Antmicro]
* Fix --hierarchical with order-based pin connections (#3583) (#3585). [Kelin9298] * Fix --hierarchical with order-based pin connections (#3583) (#3585). [Kelin9298]

View File

@ -346,13 +346,13 @@ analyzer-include:
format: clang-format yapf format-pl-exec format: clang-format yapf format-pl-exec
CLANGFORMAT = clang-format-11 CLANGFORMAT = clang-format-14
CLANGFORMAT_FLAGS = -i CLANGFORMAT_FLAGS = -i
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h
clang-format: clang-format:
@$(CLANGFORMAT) --version | egrep 11.0 > /dev/null \ @$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \
|| echo "*** You are not using clang-format 11.0, indents may differ from master's ***" || echo "*** You are not using clang-format-14, indents may differ from master's ***"
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES) $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
PY_PROGRAMS = \ PY_PROGRAMS = \
@ -391,10 +391,10 @@ yapf:
FLAKE8 = flake8 FLAKE8 = flake8
FLAKE8_FLAGS = \ FLAKE8_FLAGS = \
--extend-exclude=fastcov.py \ --extend-exclude=fastcov.py \
--ignore=E123,E129,E251,E501,W503,W504,E701 --ignore=E123,E129,E251,E402,E501,W503,W504,E701
PYLINT = pylint PYLINT = pylint
PYLINT_FLAGS = --disable=R0801 PYLINT_FLAGS = --score=n --disable=R0801
lint-py: lint-py:
-$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS) -$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS)

View File

@ -28,7 +28,7 @@ Welcome to Verilator
- |Logo| - |Logo|
* - |verilator multithreaded performance| * - |verilator multithreaded performance|
- **Fast** - **Fast**
* Outperforms many commercial simulators * Outperforms many closed-source commercial simulators
* Single- and multi-threaded output models * Single- and multi-threaded output models
* - **Widely Used** * - **Widely Used**
* Wide industry and academic deployment * Wide industry and academic deployment
@ -55,20 +55,19 @@ performing lint checks, and optionally inserting assertion checks and
coverage-analysis points. It outputs single- or multi-threaded .cpp and .h coverage-analysis points. It outputs single- or multi-threaded .cpp and .h
files, the "Verilated" code. files, the "Verilated" code.
The user writes a little C++/SystemC wrapper file, which instantiates the These Verilated C++/SystemC files are then compiled by a C++ compiler
"Verilated" model of the user's top level module. These C++/SystemC files (gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper
are then compiled by a C++ compiler (gcc/clang/MSVC++). Executing the file to instantiate the Verilated model. Executing the resulting executable
resulting executable performs the design simulation. Verilator also performs the design simulation. Verilator also supports linking Verilated
supports linking Verilated generated libraries, optionally encrypted, into generated libraries, optionally encrypted, into other simulators.
other simulators.
Verilator may not be the best choice if you are expecting a full featured Verilator may not be the best choice if you are expecting a full featured
replacement for Incisive, ModelSim/Questa, VCS or another commercial replacement for a closed-source Verilog simulator, need SDF annotation,
Verilog simulator, or if you are looking for a behavioral Verilog simulator mixed-signal simulation, or are doing a quick class project (we recommend
e.g. for a quick class project (we recommend `Icarus Verilog`_ for this.) `Icarus Verilog`_ for classwork.) However, if you are looking for a path
However, if you are looking for a path to migrate SystemVerilog to C++ or to migrate SystemVerilog to C++/SystemC, or want high speed simulation of
SystemC, or your team is comfortable writing just a touch of C++ code, synthesizable designs containing limited verification constructs, Verilator
Verilator is the tool for you. is the tool for you.
Performance Performance
@ -85,9 +84,11 @@ multithreading (yielding 200-1000x total over interpreted simulators).
Verilator has typically similar or better performance versus the Verilator has typically similar or better performance versus the
closed-source Verilog simulators (Carbon Design Systems Carbonator, closed-source Verilog simulators (Carbon Design Systems Carbonator,
Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
CVer/CVC). But, Verilator is open-sourced, so you can spend on computes Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
rather than licenses. Thus Verilator gives you the best cycles/dollar. computes rather than licenses. Thus Verilator gives you the best
cycles/dollar.
Installation & Documentation Installation & Documentation
============================ ============================

View File

@ -282,8 +282,9 @@ detailed descriptions of these arguments.
--autoflush Flush streams after all $displays --autoflush Flush streams after all $displays
--bbox-sys Blackbox unknown $system calls --bbox-sys Blackbox unknown $system calls
--bbox-unsup Blackbox unsupported language features --bbox-unsup Blackbox unsupported language features
--bin <filename> Override Verilator binary
--build Build model executable/library after Verilation --build Build model executable/library after Verilation
--build-dep-bin <filename> Override build dependency Verilator binary
--build-jobs <jobs> Parallelism for --build
--cc Create C++ output --cc Create C++ output
--cdc Clock domain crossing analysis --cdc Clock domain crossing analysis
-CFLAGS <flags> C++ compiler arguments for makefile -CFLAGS <flags> C++ compiler arguments for makefile
@ -308,10 +309,13 @@ detailed descriptions of these arguments.
+define+<var>=<value> Set preprocessor define +define+<var>=<value> Set preprocessor define
--dpi-hdr-only Only produce the DPI header file --dpi-hdr-only Only produce the DPI header file
--dump-defines Show preprocessor defines with -E --dump-defines Show preprocessor defines with -E
--dump-tree Enable dumping .tree files --dump-graph Enable dumping V3Graphs to .dot
--dump-tree Enable dumping Ast .tree files
--dump-tree-addrids Use short identifiers instead of addresses --dump-tree-addrids Use short identifiers instead of addresses
--dump-treei <level> Enable dumping .tree files at a level --dump-<srcfile> Enable dumping everything in source file
--dump-treei-<srcfile> <level> Enable dumping .tree file at a source file at a level --dumpi-graph <level> Enable dumping V3Graphs to .dot files at level
--dumpi-tree <level> Enable dumping Ast .tree files at level
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
-E Preprocess, but do not compile -E Preprocess, but do not compile
--error-limit <value> Abort after this number of errors --error-limit <value> Abort after this number of errors
--exe Link to create executable --exe Link to create executable
@ -334,7 +338,7 @@ detailed descriptions of these arguments.
+incdir+<dir> Directory to search for includes +incdir+<dir> Directory to search for includes
--inline-mult <value> Tune module inlining --inline-mult <value> Tune module inlining
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports --instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
-j <jobs> Parallelism for --build -j <jobs> Parallelism for --build (alias to --build-jobs)
--l2-name <value> Verilog scope name of the top module --l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse --language <lang> Default language standard to parse
-LDFLAGS <flags> Linker pre-object arguments for makefile -LDFLAGS <flags> Linker pre-object arguments for makefile
@ -343,6 +347,7 @@ detailed descriptions of these arguments.
--lint-only Lint, but do not make output --lint-only Lint, but do not make output
--make <build-tool> Generate scripts for specified build tool --make <build-tool> Generate scripts for specified build tool
-MAKEFLAGS <flags> Arguments to pass to make during --build -MAKEFLAGS <flags> Arguments to pass to make during --build
--main Generate C++ main() file
--max-num-width <value> Maximum number width (default: 64K) --max-num-width <value> Maximum number width (default: 64K)
--Mdir <directory> Name of output object directory --Mdir <directory> Name of output object directory
--MMD Create .d dependency files --MMD Create .d dependency files
@ -354,6 +359,7 @@ detailed descriptions of these arguments.
-O<optimization-letter> Selectable optimizations -O<optimization-letter> Selectable optimizations
-o <executable> Name of final executable -o <executable> Name of final executable
--no-order-clock-delay Disable ordering clock enable assignments --no-order-clock-delay Disable ordering clock enable assignments
--no-verilate Skip Verilation, only compile previously Verilated code
--output-split <statements> Split .cpp files into pieces --output-split <statements> Split .cpp files into pieces
--output-split-cfuncs <statements> Split model functions --output-split-cfuncs <statements> Split model functions
--output-split-ctrace <statements> Split tracing functions --output-split-ctrace <statements> Split tracing functions

View File

@ -38,7 +38,7 @@ def diff_dir(a, b):
anyfile = False anyfile = False
for base in sorted(files.keys()): for base in sorted(files.keys()):
if (not 'a' in files[base]) or (not 'b' in files[base]): if ('a' not in files[base]) or ('b' not in files[base]):
continue continue
a = files[base]['a'] a = files[base]['a']
b = files[base]['b'] b = files[base]['b']

View File

@ -149,7 +149,8 @@ def report():
for thread in Threads: for thread in Threads:
# Make potentially multiple characters per column # Make potentially multiple characters per column
for start in Threads[thread]: for start in Threads[thread]:
if not Threads[thread][start]: continue if not Threads[thread][start]:
continue
cpu = Threads[thread][start]['cpu'] cpu = Threads[thread][start]['cpu']
elapsed = Threads[thread][start]['end'] - start elapsed = Threads[thread][start]['end'] - start
if cpu not in Global['cpus']: if cpu not in Global['cpus']:

View File

@ -19,6 +19,10 @@ set -x
cd $(dirname "$0")/.. cd $(dirname "$0")/..
# Avoid occasional cpan failures "Issued certificate has expired."
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
echo "check_certificate = off" >> ~/.wgetrc
fatal() { fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1; echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
} }

View File

@ -6,7 +6,7 @@
# Version 2.0. # Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:20.04 FROM ubuntu:22.04
RUN apt-get update \ RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \ && DEBIAN_FRONTEND=noninteractive \

View File

@ -8,7 +8,7 @@ Verilator build. It uses the following parameters:
- Source revision (default: master) - Source revision (default: master)
- Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0) - Compiler (GCC 10.3.0, clang 10.0.0, default: 10.3.0)
The container is published as ``verilator/verilator-buildenv`` on `docker The container is published as ``verilator/verilator-buildenv`` on `docker
hub hub

View File

@ -6,7 +6,7 @@
# Version 2.0. # Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:20.04 FROM ubuntu:22.04
RUN apt-get update \ RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \ && DEBIAN_FRONTEND=noninteractive \

View File

@ -10,7 +10,7 @@
# Then 'make maintainer-dist' # Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel]) #AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.226 2022-08-31], AC_INIT([Verilator],[4.228 2022-10-01],
[https://verilator.org], [https://verilator.org],
[verilator],[https://verilator.org]) [verilator],[https://verilator.org])

View File

@ -44,6 +44,7 @@ HyungKi Jeong
Iru Cai Iru Cai
Ivan Vnučec Ivan Vnučec
Iztok Jeras Iztok Jeras
Jake Merdich
James Hanlon James Hanlon
James Hutchinson James Hutchinson
James Pallister James Pallister
@ -82,6 +83,7 @@ Michael Killough
Michaël Lefebvre Michaël Lefebvre
Mike Popoloski Mike Popoloski
Miodrag Milanović Miodrag Milanović
Mladen Slijepcevic
Morten Borup Petersen Morten Borup Petersen
Mostafa Gamal Mostafa Gamal
Nandu Raj Nandu Raj
@ -89,6 +91,7 @@ Nathan Kohagen
Nathan Myers Nathan Myers
Patrick Stewart Patrick Stewart
Paul Wright Paul Wright
Pawel Sagan
Peter Horvath Peter Horvath
Peter Monsson Peter Monsson
Philipp Wagner Philipp Wagner
@ -128,5 +131,6 @@ Yoda Lee
Yossi Nivin Yossi Nivin
Yuri Victorovich Yuri Victorovich
Yutetsu TAKATSUKASA Yutetsu TAKATSUKASA
Yu-Sheng Lin
Yves Mathieu Yves Mathieu
Zhanglei Wang Zhanglei Wang

View File

@ -13,6 +13,7 @@ from datetime import datetime
import os import os
import re import re
import sys import sys
sys.path.insert(0, os.path.abspath('./_ext')) sys.path.insert(0, os.path.abspath('./_ext'))
import sphinx_rtd_theme # pylint: disable=wrong-import-position, import sphinx_rtd_theme # pylint: disable=wrong-import-position,

View File

@ -115,13 +115,6 @@ Summary:
Using this argument will likely cause incorrect simulation. Using this argument will likely cause incorrect simulation.
.. option:: --bin <filename>
Rarely needed. Override the default filename for Verilator itself.
When a dependency (.d) file is created, this filename will become a
source dependency, such that a change in this binary will have make
rebuild the output files.
.. option:: --build .. option:: --build
After generating the SystemC/C++ code, Verilator will invoke the After generating the SystemC/C++ code, Verilator will invoke the
@ -129,6 +122,24 @@ Summary:
is also used). Verilator manages the build itself, and for this --build is also used). Verilator manages the build itself, and for this --build
requires GNU Make to be available on the platform. requires GNU Make to be available on the platform.
.. option:: --build-dep-bin <filename>
Rarely needed. When a dependency (.d) file is created, this filename
will become a source dependency, such that a change in this binary will
have make rebuild the output files. Defaults to the full path to the
Verilator binary.
This option was named `--bin` prior to version 4.228.
.. option:: --build-jobs [<value>]
Specify the level of parallelism for :vlopt:`--build`. If zero, uses the
number of threads in the current hardware. Otherwise, the <value> must
be a positive integer specifying the maximum number of parallel build
jobs.
See also :vlopt:`-j`.
.. option:: --cc .. option:: --cc
Specifies C++ without SystemC output mode; see also :vlopt:`--sc` Specifies C++ without SystemC output mode; see also :vlopt:`--sc`
@ -255,8 +266,8 @@ Summary:
generally is a less-optimized binary with symbols present (so GDB can be used on it). generally is a less-optimized binary with symbols present (so GDB can be used on it).
* Enable debugging messages (equivalent to :vlopt:`--debugi 3 <--debugi>`). * Enable debugging messages (equivalent to :vlopt:`--debugi 3 <--debugi>`).
* Enable internal assertions (equivalent to :vlopt:`--debug-check`). * Enable internal assertions (equivalent to :vlopt:`--debug-check`).
* Enable intermediate form dump files (equivalent to :vlopt:`--dump-treei 3 * Enable intermediate form dump files (equivalent to :vlopt:`--dumpi-tree 3
<--dump-treei>`). <--dumpi-tree>`).
* Leak to make node numbers unique (equivalent to :vlopt:`--debug-leak * Leak to make node numbers unique (equivalent to :vlopt:`--debug-leak
<--no-debug-leak>`. <--no-debug-leak>`.
* Call abort() instead of exit() if there are any errors (so GDB can see * Call abort() instead of exit() if there are any errors (so GDB can see
@ -347,26 +358,21 @@ Summary:
touch foo.v ; verilator -E --dump-defines foo.v touch foo.v ; verilator -E --dump-defines foo.v
.. option:: --dump-graph
Rarely needed. Enable dumping V3Graph .dot debug files with dumping
level 3. Before Verilator 4.228, :vlopt:`--dump-tree` used
to include this option.
.. option:: --dump-tree .. option:: --dump-tree
Rarely needed. Enable writing .tree debug files with dumping level 3, Rarely needed. Enable dumping Ast .tree debug files with dumping level 3,
which dumps the standard critical stages. For details on the format see which dumps the standard critical stages. For details on the format see
the Verilator Internals manual. :vlopt:`--dump-tree` is enabled the Verilator Internals manual. :vlopt:`--dump-tree` is enabled
automatically with :vlopt:`--debug`, so :vlopt:`--debug --no-dump-tree automatically with :vlopt:`--debug`, so :vlopt:`--debug --no-dump-tree
<--dump-tree>` may be useful if the dump files are large and not <--dump-tree>` may be useful if the dump files are large and not
desired. desired.
.. option:: --dump-treei <level>
.. option:: --dump-treei-<srcfile> <level>
Rarely needed - for developer use. Set internal tree dumping level
globally to a specific dumping level or set the specified Verilator
source file to the specified tree dumping level (e.g.
:vlopt:`--dump-treei-V3Order 9 <--dump-treei>`). Level 0 disables dumps
and is equivalent to :vlopt:`--no-dump-tree <--dump-tree>`. Level 9
enables dumping of every stage.
.. option:: --dump-tree-addrids .. option:: --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with Rarely needed - for developer use. Replace AST node addresses with
@ -376,6 +382,28 @@ Summary:
by a newly allocated node after a node with the same address has been by a newly allocated node after a node with the same address has been
dumped then freed. dumped then freed.
.. option:: --dump-<srcfile>
Rarely needed - for developer use. Enable all dumping in the given
source file at level 3.
.. option:: --dumpi-graph <level>
Rarely needed - for developer use. Set internal V3Graph dumping level
globally to the specified value.
.. option:: --dumpi-tree <level>
Rarely needed - for developer use. Set internal Ast dumping level
globally to the specified value.
.. option:: --dumpi-<srcfile> <level>
Rarely needed - for developer use. Set the dumping level in the
specified Verilator source file to the specified value (e.g.
:vlopt:`--dumpi-V3Order 9`). Level 0 disables dumps and is equivalent
to :vlopt:`--no-dump-<srcfile>`. Level 9 enables dumping of everything.
.. option:: -E .. option:: -E
Preprocess the source code, but do not compile, similar to C++ Preprocess the source code, but do not compile, similar to C++
@ -615,11 +643,10 @@ Summary:
.. option:: -j [<value>] .. option:: -j [<value>]
Specify the level of parallelism for :vlopt:`--build`. The <value> must Specify the level of parallelism for :vlopt:`--build` if
be a positive integer specifying the maximum number of parallel build :vlopt:`--build-jobs` isn't provided. If zero, uses the number of threads
jobs, or can be omitted. When <value> is omitted, the build will not try in the current hardware. Otherwise, the <value> must be a positive
to limit the number of parallel build jobs but attempt to execute all integer specifying the maximum number of parallel build jobs.
independent build steps in parallel.
.. option:: --l2-name <value> .. option:: --l2-name <value>
@ -709,6 +736,15 @@ Summary:
(e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be (e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be
required for simple builds using the host toolchain. required for simple builds using the host toolchain.
.. option:: --main
Generates a top-level C++ main() file that supports parsing arguments,
but does not drive any inputs. This is sufficient to use for top-level
SystemVerilog designs that has no inputs, and does not need the C++ to
do any time advancement.
Implies :vlopt:`--cc` if no other output mode was provided.
.. option:: --max-num-width <value> .. option:: --max-num-width <value>
Set the maximum number literal width (e.g. in 1024'd22 this it the Set the maximum number literal width (e.g. in 1024'd22 this it the

View File

@ -124,7 +124,7 @@ Those developing Verilator itself may also want these (see internals.rst):
:: ::
sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov
sudo apt-get install yapf3 sudo apt-get install yapf3
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
cpan install Pod::Perldoc cpan install Pod::Perldoc

View File

@ -7,9 +7,9 @@
Simulating (Verilated-Model Runtime) Simulating (Verilated-Model Runtime)
************************************ ************************************
This section describes items related to simulating, that using a Verilated This section describes items related to simulating, that is, the use of a
model's executable. For the runtime arguments to a simulated model, see Verilated model's executable. For the runtime arguments to a simulated
:ref:`Simulation Runtime Arguments`. model, see :ref:`Simulation Runtime Arguments`.
.. _Benchmarking & Optimization: .. _Benchmarking & Optimization:

View File

@ -96,10 +96,11 @@ this.
Each ``AstNode`` has pointers to up to four children, accessed by the Each ``AstNode`` has pointers to up to four children, accessed by the
``op1p`` through ``op4p`` methods. These methods are then abstracted in a ``op1p`` through ``op4p`` methods. These methods are then abstracted in a
specific Ast\* node class to a more specific name. For example with the specific Ast\* node class to a more specific name. For example with the
``AstIf`` node (for ``if`` statements), ``ifsp`` calls ``op2p`` to give the ``AstIf`` node (for ``if`` statements), ``thensp`` calls ``op2p`` to give the
pointer to the AST for the "then" block, while ``elsesp`` calls ``op3p`` to pointer to the AST for the "then" block, while ``elsesp`` calls ``op3p`` to
give the pointer to the AST for the "else" block, or NULL if there is not give the pointer to the AST for the "else" block, or NULL if there is not
one. one. These accessors are automatically generated by ``astgen`` after
parsing the ``@astgen`` directives in the specific ``AstNode`` subclasses.
``AstNode`` has the concept of a next and previous AST - for example the ``AstNode`` has the concept of a next and previous AST - for example the
next and previous statements in a block. Pointers to the AST for these next and previous statements in a block. Pointers to the AST for these
@ -501,22 +502,99 @@ code:
The ``astgen`` Script The ``astgen`` Script
--------------------- ---------------------
Some of the code implementing passes is extremely repetitive, and must be The ``astgen`` script is used to generate some of the repetitive C++ code
implemented for each sub-class of ``AstNode``. However, while repetitive, related to the ``AstNode`` type hierarchy. An example is the abstract ``visit``
there is more variability than can be handled in C++ macros. methods in ``VNVisitor``. There are other uses, please see the ``*__gen*``
files in the bulid directories and the ``astgen`` script itself for details. A
description of the more advanced features of ``astgen`` are provided here.
In Verilator this is implemented by using a script, ``astgen`` to
pre-process the C++ code. For example in ``V3Const.cpp`` this is used to
implement the ``visit()`` functions for each binary operation using the
``TREEOP`` macro.
The original C source code is transformed into C code in the ``obj_opt`` Generating ``AstNode`` members
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some of the member s of ``AstNode`` sub-classes are generated by ``astgen``.
These are emitted as pre-processor macro definitions, which then need to be
added to the ``AstNode`` sub-classes they correspond to. Specifically ``class
AstFoo`` should contain an instance of ``ASTGEN_MEMBERS_Foo;`` at class scope.
The ``astgen`` script checks and errors if this is not present. The method
generated depends on whether the class is a concrete final class, or an
abstract ``AstNode*`` base-class, and on ``@astgen`` directives present in
comment sections in the body of the ``AstNode`` sub-class definitions.
List of ``@astgen`` directives
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``@astgen`` directives in comments contained in the body of ``AstNode``
sub-class definitions are parsed and contribute to the code generated by
``astgen``. The general syntax is ``@astgen <keywords> := <description>``,
where ``<keywords>`` determines what is being defined, and ``<description>`` is
a ``<keywords>`` dependent description of the definition. The list of
``@astgen`` directives is as follows:
``op<N>`` operand directives
"""""""""""""""""""""""""""""
The ``op1``, ``op2``, ``op3`` and ``op4`` directives are used to describe the
name and type of the up to 4 child operands of a node. The syntax of the
``<description>`` field is ``<identifier> : <type>``, where ``<identifier>``
will be used as the base name of the generated operand accessors, and
``<type>`` is one of:
1. An ``AstNode`` sub-class, defining the operand to be of that type, always
no-null, and with an always null ``nextp()``. That is, the child node is
always present, and is a single ``AstNode`` (as opposed to a list).
2. ``Optional[<AstNode sub-class>]``. This is just like in point 1 above, but
defines the child node to be optional, meaning it may be null.
3. ``List[AstNode sub-class]`` describes a list operand, which means the child
node may have a non-null ``nextp()`` and in addition the child itself may be
null, representing an empty list.
An example of the full syntax of the directive is
``@astgen op1 := lhsp : AstNodeMath``.
``astnode`` generates accessors for the child nodes based on these directives.
For non-list children, the names of the getter and setter both are that of the
given ``<identifier>``. For list type children, the getter is ``<identifier>``,
and instead of the setter, there an ``add<Identifier>`` method is generated
that appends new nodes (or lists of nodes) to the child list.
``alias op<N>`` operand alias directives
""""""""""""""""""""""""""""""""""""""""
If a super-class already defined a name and type for a child node using the
``op<N>`` directive, but a more appropriate name exists in the context of a
sub-class, then the alias directive can be used to introduce an additional name
for the child node. The is ``alias op<N> := <identifier>`` where
``<identifier>`` is the new name. ``op<N>`` must have been defined in some
super-class of the current node.
Example: ``@astgen alias op1 := condp``
Additional features of ``astgen``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In addition to generating ``AstNode`` members as described above,
``astgen`` is also use to handle some of the repetitive implementation code
that is still variable enough not to be handled in C++ macros.
In particular, ``astgen`` is used to pre-process some of the C++ source
files. For example in ``V3Const.cpp``, it is used to implement the
``visit()`` functions for each binary operation using the ``TREEOP`` macro.
The original C++ source code is transformed into C++ code in the ``obj_opt``
and ``obj_dbg`` sub-directories (the former for the optimized version of and ``obj_dbg`` sub-directories (the former for the optimized version of
Verilator, the latter for the debug version). So for example Verilator, the latter for the debug version). So for example
``V3Const.cpp`` into ``V3Const__gen.cpp``. ``V3Const.cpp`` into ``V3Const__gen.cpp``.
Visitor Functions ----------------- Visitor Functions
-----------------
Verilator uses the "Visitor" design pattern to implement its refinement and Verilator uses the "Visitor" design pattern to implement its refinement and
optimization passes. This allows separation of the pass algorithm from the optimization passes. This allows separation of the pass algorithm from the
@ -1153,8 +1231,9 @@ Generally what would you do to add a new feature?
language and has a lot of back-and-forth with Verilator's grammar. Copy language and has a lot of back-and-forth with Verilator's grammar. Copy
the appropriate rules to src/verilog.y and modify the productions. the appropriate rules to src/verilog.y and modify the productions.
4. If a new Ast type is needed, add it to V3AstNodes.h. Follow the 4. If a new Ast type is needed, add it to the appropriate V3AstNode*.h.
convention described above about the AstNode type hierarchy. Follow the convention described above about the AstNode type hierarchy.
Ordering of definitions is enforced by ``astgen``.
5. Now you can run "test_regress/t/t_<newtestcase>.pl --debug" and it'll 5. Now you can run "test_regress/t/t_<newtestcase>.pl --debug" and it'll
probably fail but you'll see a probably fail but you'll see a

View File

@ -32,7 +32,7 @@ int main(int argc, char** argv, char** env) {
// When tracing, the contents of the secret module will not be seen // When tracing, the contents of the secret module will not be seen
VerilatedVcdC* tfp = nullptr; VerilatedVcdC* tfp = nullptr;
const char* flag = contextp->commandArgsPlusMatch("trace"); const char* flag = contextp->commandArgsPlusMatch("trace");
if (flag && 0 == strcmp(flag, "+trace")) { if (flag && 0 == std::strcmp(flag, "+trace")) {
contextp->traceEverOn(true); contextp->traceEverOn(true);
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n"); VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
tfp = new VerilatedVcdC; tfp = new VerilatedVcdC;

View File

@ -82,14 +82,14 @@ int sc_main(int argc, char* argv[]) {
// You must do one evaluation before enabling waves, in order to allow // You must do one evaluation before enabling waves, in order to allow
// SystemC to interconnect everything for testing. // SystemC to interconnect everything for testing.
sc_start(1, SC_NS); sc_start(SC_ZERO_TIME);
#if VM_TRACE #if VM_TRACE
// If verilator was invoked with --trace argument, // If verilator was invoked with --trace argument,
// and if at run time passed the +trace argument, turn on tracing // and if at run time passed the +trace argument, turn on tracing
VerilatedVcdSc* tfp = nullptr; VerilatedVcdSc* tfp = nullptr;
const char* flag = Verilated::commandArgsPlusMatch("trace"); const char* flag = Verilated::commandArgsPlusMatch("trace");
if (flag && 0 == strcmp(flag, "+trace")) { if (flag && 0 == std::strcmp(flag, "+trace")) {
cout << "Enabling waves into logs/vlt_dump.vcd...\n"; cout << "Enabling waves into logs/vlt_dump.vcd...\n";
tfp = new VerilatedVcdSc; tfp = new VerilatedVcdSc;
top->trace(tfp, 99); // Trace 99 levels of hierarchy top->trace(tfp, 99); // Trace 99 levels of hierarchy

View File

@ -16,12 +16,13 @@ from shutil import copy2
class VlFileCopy: class VlFileCopy:
def __init__( def __init__(
self, self,
verilator_args, # presently all verilator options are passed-thru verilator_args, # presently all verilator options are passed-thru
# ideally this script would check against options mentioned in help # ideally this script would check against options mentioned in help
debug=0, debug=0,
output_dir='copied'): # directory name we output file uses output_dir='copied'): # directory name we output file uses
self.debug = debug self.debug = debug

View File

@ -14,12 +14,13 @@ import xml.etree.ElementTree as ET
class VlHierGraph: class VlHierGraph:
def __init__( def __init__(
self, self,
verilator_args, # presently all verilator options are passed-thru verilator_args, # presently all verilator options are passed-thru
# ideally this script would check against options mentioned in help # ideally this script would check against options mentioned in help
debug=0, debug=0,
output_filename='graph.dot'): # output filename output_filename='graph.dot'): # output filename
self.debug = debug self.debug = debug
self.next_vertex_number = 0 self.next_vertex_number = 0
self.name_to_number = {} self.name_to_number = {}

View File

@ -1003,22 +1003,22 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
} }
} }
static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE { static bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE {
if (VL_LIKELY(fp)) { if (VL_LIKELY(fp)) {
return std::feof(fp) ? true : false; // true : false to prevent MSVC++ warning return std::feof(fp) ? true : false; // true : false to prevent MSVC++ warning
} else { } else {
return floc < 0; return floc < 0;
} }
} }
static inline void _vl_vsss_advance(FILE* fp, int& floc) VL_MT_SAFE { static void _vl_vsss_advance(FILE* fp, int& floc) VL_MT_SAFE {
if (VL_LIKELY(fp)) { if (VL_LIKELY(fp)) {
std::fgetc(fp); std::fgetc(fp);
} else { } else {
floc -= 8; floc -= 8;
} }
} }
static inline int _vl_vsss_peek(FILE* fp, int& floc, const WDataInP fromp, static int _vl_vsss_peek(FILE* fp, int& floc, const WDataInP fromp,
const std::string& fstr) VL_MT_SAFE { const std::string& fstr) VL_MT_SAFE {
// Get a character without advancing // Get a character without advancing
if (VL_LIKELY(fp)) { if (VL_LIKELY(fp)) {
const int data = std::fgetc(fp); const int data = std::fgetc(fp);
@ -1035,17 +1035,16 @@ static inline int _vl_vsss_peek(FILE* fp, int& floc, const WDataInP fromp,
} }
} }
} }
static inline void _vl_vsss_skipspace(FILE* fp, int& floc, const WDataInP fromp, static void _vl_vsss_skipspace(FILE* fp, int& floc, const WDataInP fromp,
const std::string& fstr) VL_MT_SAFE { const std::string& fstr) VL_MT_SAFE {
while (true) { while (true) {
const int c = _vl_vsss_peek(fp, floc, fromp, fstr); const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF || !std::isspace(c)) return; if (c == EOF || !std::isspace(c)) return;
_vl_vsss_advance(fp, floc); _vl_vsss_advance(fp, floc);
} }
} }
static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp, static void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp, const std::string& fstr,
const std::string& fstr, char* tmpp, char* tmpp, const char* acceptp) VL_MT_SAFE {
const char* acceptp) VL_MT_SAFE {
// Read into tmp, consisting of characters from acceptp list // Read into tmp, consisting of characters from acceptp list
char* cp = tmpp; char* cp = tmpp;
while (true) { while (true) {
@ -1059,9 +1058,8 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp,
*cp++ = '\0'; *cp++ = '\0';
// VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n"); // VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n");
} }
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp, static char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp, const std::string& fstr,
const std::string& fstr, char* beginp, std::size_t n, char* beginp, std::size_t n, const bool inhibit = false) {
const bool inhibit = false) {
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized // 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 // 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. // whitespace). In the fp case, except descriptor to have been opened in binary mode.
@ -1073,12 +1071,11 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
} }
return beginp; return beginp;
} }
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, static void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) VL_MT_SAFE {
IData ld) VL_MT_SAFE {
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) { VL_ASSIGNBIT_WI(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, static void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp,
size_t posstart, size_t posend) VL_MT_SAFE { size_t posstart, size_t posend) VL_MT_SAFE {
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits. // Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits.
int lsb = 0; int lsb = 0;
for (int i = 0, pos = static_cast<int>(posend) - 1; for (int i = 0, pos = static_cast<int>(posend) - 1;

View File

@ -274,7 +274,7 @@ protected:
public: public:
/// Returns the VerilatedContext this model is instantiated under /// Returns the VerilatedContext this model is instantiated under
/// Used to get to e.g. simulation time via contextp()->time() /// Used to get to e.g. simulation time via contextp()->time()
inline VerilatedContext* contextp() const { return &m_context; } VerilatedContext* contextp() const { return &m_context; }
/// Returns the hierarchical name of this module instance. /// Returns the hierarchical name of this module instance.
virtual const char* hierName() const = 0; virtual const char* hierName() const = 0;
/// Returns the name of this model (the name of the generated model class). /// Returns the name of this model (the name of the generated model class).
@ -457,9 +457,9 @@ public:
VerilatedCovContext* coveragep() VL_MT_SAFE; VerilatedCovContext* coveragep() VL_MT_SAFE;
/// Set debug level /// Set debug level
/// Debug is currently global, but for forward compatibility have a per-context method /// Debug is currently global, but for forward compatibility have a per-context method
static void debug(int val) VL_MT_SAFE; static inline void debug(int val) VL_MT_SAFE;
/// Return debug level /// Return debug level
static int debug() VL_MT_SAFE; static inline int debug() VL_MT_SAFE;
/// Set current number of errors/assertions /// Set current number of errors/assertions
void errorCount(int val) VL_MT_SAFE; void errorCount(int val) VL_MT_SAFE;
/// Increment current number of errors/assertions /// Increment current number of errors/assertions
@ -521,7 +521,7 @@ public:
/// ///
/// * Else, time comes from the legacy 'double sc_time_stamp()' which /// * Else, time comes from the legacy 'double sc_time_stamp()' which
/// must be a function defined by the user's wrapper. /// must be a function defined by the user's wrapper.
uint64_t time() const VL_MT_SAFE; inline uint64_t time() const VL_MT_SAFE;
/// Set current simulation time. See time() for side effect details /// Set current simulation time. See time() for side effect details
void time(uint64_t value) VL_MT_SAFE { m_s.m_time = value; } void time(uint64_t value) VL_MT_SAFE { m_s.m_time = value; }
/// Advance current simulation time. See time() for side effect details /// Advance current simulation time. See time() for side effect details
@ -652,13 +652,13 @@ public: // But internals only - called from VerilatedModule's
const char* name() const { return m_namep; } const char* name() const { return m_namep; }
const char* identifier() const { return m_identifierp; } const char* identifier() const { return m_identifierp; }
int8_t timeunit() const { return m_timeunit; } int8_t timeunit() const { return m_timeunit; }
inline VerilatedSyms* symsp() const { return m_symsp; } VerilatedSyms* symsp() const { return m_symsp; }
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT; VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; } VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
void scopeDump() const; void scopeDump() const;
void* exportFindError(int funcnum) const; void* exportFindError(int funcnum) const;
static void* exportFindNullError(int funcnum) VL_MT_SAFE; static void* exportFindNullError(int funcnum) VL_MT_SAFE;
static inline void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE { static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum); if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) { if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) {
// m_callbacksp must be declared, as Max'es are > 0 // m_callbacksp must be declared, as Max'es are > 0
@ -727,7 +727,7 @@ public:
/// Return debug level /// Return debug level
/// When multithreaded this may not immediately react to another thread /// When multithreaded this may not immediately react to another thread
/// changing the level (no mutex) /// changing the level (no mutex)
static inline int debug() VL_MT_SAFE { return s_debug; } static int debug() VL_MT_SAFE { return s_debug; }
#else #else
/// Return constant 0 debug level, so C++'s optimizer rips up /// Return constant 0 debug level, so C++'s optimizer rips up
static constexpr int debug() VL_PURE { return 0; } static constexpr int debug() VL_PURE { return 0; }
@ -933,8 +933,8 @@ private:
#endif #endif
}; };
inline void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); } void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); }
inline int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); } int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); }
//========================================================================= //=========================================================================
// Data Types // Data Types

View File

@ -181,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
//====================================================================== //======================================================================
// Open array internals // Open array internals
static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) { static const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
if (VL_UNLIKELY(!h)) { if (VL_UNLIKELY(!h)) {
VL_FATAL_MT(__FILE__, __LINE__, "", VL_FATAL_MT(__FILE__, __LINE__, "",
"%%Error: DPI svOpenArrayHandle function called with nullptr handle"); "%%Error: DPI svOpenArrayHandle function called with nullptr handle");

View File

@ -161,13 +161,13 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are // Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them. // called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval); VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits); VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits); VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits); VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits);
VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits); VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits);
VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits); VL_ATTR_ALWINLINE void emitWData(uint32_t code, const WData* newvalp, int bits);
VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval); VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
}; };
//============================================================================= //=============================================================================
@ -232,7 +232,7 @@ public:
} }
// Internal class access // Internal class access
inline VerilatedFst* spTrace() { return &m_sptrace; } VerilatedFst* spTrace() { return &m_sptrace; }
}; };
#endif // guard #endif // guard

View File

@ -52,35 +52,35 @@ public:
} }
spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
} }
virtual ~VerilatedFstSc() /*override*/ { close(); } ~VerilatedFstSc() override { close(); }
// METHODS // METHODS
/// Called by SystemC simulate() /// Called by SystemC simulate()
virtual void cycle(bool delta_cycle) { void cycle(bool delta_cycle) override {
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
} }
// Override VerilatedFstC. Must be called after starting simulation. // Override VerilatedFstC. Must be called after starting simulation.
// cppcheck-suppress missingOverride // GCC won't accept override // Note: this is not a virtual function in the base class, so no 'override'
virtual void open(const char* filename) /*override*/ VL_MT_SAFE; virtual void open(const char* filename) VL_MT_SAFE;
private: private:
/// Fake outs for linker /// Fake outs for linker
#ifdef NC_SYSTEMC #ifdef NC_SYSTEMC
// Cadence Incisive has these as abstract functions so we must create them // Cadence Incisive has these as abstract functions so we must create them
virtual void set_time_unit(int exponent10_seconds) {} // deprecated void set_time_unit(int exponent10_seconds) override {} // deprecated
#endif #endif
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
//-------------------------------------------------- //--------------------------------------------------
// SystemC 2.1.v1 // SystemC 2.1.v1
#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name); #define DECL_TRACE_METHOD_A(tp) void trace(const tp& object, const std::string& name) override;
#define DECL_TRACE_METHOD_B(tp) \ #define DECL_TRACE_METHOD_B(tp) \
virtual void trace(const tp& object, const std::string& name, int width); void trace(const tp& object, const std::string& name, int width) override;
virtual void write_comment(const std::string&); void write_comment(const std::string&) override;
virtual void trace(const unsigned int&, const std::string&, const char**); void trace(const unsigned int&, const std::string&, const char**) override;
// clang-format off // clang-format off
// Formatting matches that of sc_trace.h // Formatting matches that of sc_trace.h

View File

@ -282,7 +282,7 @@ inline uint64_t vl_time_stamp64() {
# endif # endif
#endif #endif
inline uint64_t VerilatedContext::time() const VL_MT_SAFE { uint64_t VerilatedContext::time() const VL_MT_SAFE {
// When using non-default context, fastest path is return time // When using non-default context, fastest path is return time
if (VL_LIKELY(m_s.m_time)) return m_s.m_time; if (VL_LIKELY(m_s.m_time)) return m_s.m_time;
#if defined(SYSTEMC_VERSION) || (!defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)) #if defined(SYSTEMC_VERSION) || (!defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY))
@ -448,10 +448,17 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
{ \ { \
const int words = VL_WORDS_I(obits); \ const int words = VL_WORDS_I(obits); \
sc_biguint<(obits)> _butemp = (svar).read(); \ sc_biguint<(obits)> _butemp = (svar).read(); \
for (int i = 0; i < words; ++i) { \ uint32_t* chunk = _butemp.get_raw(); \
int msb = ((i + 1) * VL_IDATASIZE) - 1; \ int32_t lsb = 0; \
msb = (msb >= (obits)) ? ((obits)-1) : msb; \ while (lsb < obits - BITS_PER_DIGIT) { \
(owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \ const uint32_t data = *chunk; \
++chunk; \
_vl_insert_WI(owp.data(), data, lsb + BITS_PER_DIGIT - 1, lsb); \
lsb += BITS_PER_DIGIT; \
} \
if (lsb < obits) { \
const uint32_t msb_data = *chunk; \
_vl_insert_WI(owp.data(), msb_data, obits - 1, lsb); \
} \ } \
(owp)[words - 1] &= VL_MASK_E(obits); \ (owp)[words - 1] &= VL_MASK_E(obits); \
} }
@ -492,13 +499,23 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
{ (svar).write(rd); } { (svar).write(rd); }
#define VL_ASSIGN_SBQ(obits, svar, rd) \ #define VL_ASSIGN_SBQ(obits, svar, rd) \
{ (svar).write(rd); } { (svar).write(rd); }
#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT
#define VL_ASSIGN_SBW(obits, svar, rwp) \ #define VL_ASSIGN_SBW(obits, svar, rwp) \
{ \ { \
sc_biguint<(obits)> _butemp; \ sc_biguint<(obits)> _butemp; \
for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ int32_t lsb = 0; \
int msb = ((i + 1) * VL_IDATASIZE) - 1; \ uint32_t* chunk = _butemp.get_raw(); \
msb = (msb >= (obits)) ? ((obits)-1) : msb; \ while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \
_butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ static_assert(std::is_same<IData, EData>::value, "IData and EData missmatch"); \
const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \
VL_SC_BITS_PER_DIGIT); \
*chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \
++chunk; \
lsb += VL_SC_BITS_PER_DIGIT; \
} \
if (lsb < (obits)) { \
const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \
*chunk = msb_data & VL_MASK_E((obits)-lsb); \
} \ } \
(svar).write(_butemp); \ (svar).write(_butemp); \
} }

View File

@ -356,7 +356,7 @@ public: // But only for verilated*.cpp
} }
} }
} }
inline FILE* fdToFp(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) { FILE* fdToFp(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
const VerilatedLockGuard lock{m_fdMutex}; const VerilatedLockGuard lock{m_fdMutex};
const VerilatedFpList fdlist = fdToFpList(fdi); const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr; if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr;
@ -466,7 +466,7 @@ public:
// There's often many more scopes than userdata's and thus having a ~48byte // There's often many more scopes than userdata's and thus having a ~48byte
// per map overhead * N scopes would take much more space and cache thrashing. // per map overhead * N scopes would take much more space and cache thrashing.
// As scopep's are pointers, this implicitly handles multiple Context's // As scopep's are pointers, this implicitly handles multiple Context's
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE { static void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
const VerilatedLockGuard lock{s().m_userMapMutex}; const VerilatedLockGuard lock{s().m_userMapMutex};
const auto it = s().m_userMap.find(std::make_pair(scopep, userKey)); const auto it = s().m_userMap.find(std::make_pair(scopep, userKey));
if (it != s().m_userMap.end()) { if (it != s().m_userMap.end()) {
@ -475,7 +475,7 @@ public:
s().m_userMap.emplace(std::make_pair(scopep, userKey), userData); s().m_userMap.emplace(std::make_pair(scopep, userKey), userData);
} }
} }
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE { static void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
const VerilatedLockGuard lock{s().m_userMapMutex}; const VerilatedLockGuard lock{s().m_userMapMutex};
const auto& it = vlstd::as_const(s().m_userMap).find(std::make_pair(scopep, userKey)); const auto& it = vlstd::as_const(s().m_userMap).find(std::make_pair(scopep, userKey));
if (VL_UNLIKELY(it == s().m_userMap.end())) return nullptr; if (VL_UNLIKELY(it == s().m_userMap.end())) return nullptr;

View File

@ -45,8 +45,7 @@ class VlThreadPool;
//============================================================================= //=============================================================================
// Return high-precision counter for profiling, or 0x0 if not available // Return high-precision counter for profiling, or 0x0 if not available
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE QData VL_CPU_TICK() {
inline QData VL_CPU_TICK() {
uint64_t val; uint64_t val;
VL_GET_CPU_TICK(val); VL_GET_CPU_TICK(val);
return val; return val;
@ -171,9 +170,9 @@ public:
// METHODS // METHODS
// Is profiling enabled // Is profiling enabled
inline bool enabled() const { return m_enabled; } bool enabled() const { return m_enabled; }
// Append a trace record to the trace buffer of the current thread // Append a trace record to the trace buffer of the current thread
static inline VlExecutionRecord& addRecord() { static VlExecutionRecord& addRecord() {
t_trace.emplace_back(); t_trace.emplace_back();
return t_trace.back(); return t_trace.back();
} }

View File

@ -103,7 +103,7 @@ public:
// Upstream mtasks must call this when they complete. // Upstream mtasks must call this when they complete.
// Returns true when the current MTaskVertex becomes ready to execute, // Returns true when the current MTaskVertex becomes ready to execute,
// false while it's still waiting on more dependencies. // false while it's still waiting on more dependencies.
inline bool signalUpstreamDone(bool evenCycle) { bool signalUpstreamDone(bool evenCycle) {
if (evenCycle) { if (evenCycle) {
const uint32_t upstreamDepsDone const uint32_t upstreamDepsDone
= 1 + m_upstreamDepsDone.fetch_add(1, std::memory_order_release); = 1 + m_upstreamDepsDone.fetch_add(1, std::memory_order_release);
@ -116,11 +116,11 @@ public:
return (upstreamDepsDone_prev == 1); return (upstreamDepsDone_prev == 1);
} }
} }
inline bool areUpstreamDepsDone(bool evenCycle) const { bool areUpstreamDepsDone(bool evenCycle) const {
const uint32_t target = evenCycle ? m_upstreamDepCount : 0; const uint32_t target = evenCycle ? m_upstreamDepCount : 0;
return m_upstreamDepsDone.load(std::memory_order_acquire) == target; return m_upstreamDepsDone.load(std::memory_order_acquire) == target;
} }
inline void waitUntilUpstreamDone(bool evenCycle) const { void waitUntilUpstreamDone(bool evenCycle) const {
unsigned ct = 0; unsigned ct = 0;
while (VL_UNLIKELY(!areUpstreamDepsDone(evenCycle))) { while (VL_UNLIKELY(!areUpstreamDepsDone(evenCycle))) {
VL_CPU_RELAX(); VL_CPU_RELAX();
@ -171,7 +171,7 @@ public:
// METHODS // METHODS
template <bool SpinWait> template <bool SpinWait>
inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) { void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
// Spin for a while, waiting for new data // Spin for a while, waiting for new data
if VL_CONSTEXPR_CXX17 (SpinWait) { if VL_CONSTEXPR_CXX17 (SpinWait) {
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) { for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
@ -191,7 +191,7 @@ public:
m_ready.erase(m_ready.begin()); m_ready.erase(m_ready.begin());
m_ready_size.fetch_sub(1, std::memory_order_relaxed); m_ready_size.fetch_sub(1, std::memory_order_relaxed);
} }
inline void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle = false) void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle = false)
VL_MT_SAFE_EXCLUDES(m_mutex) { VL_MT_SAFE_EXCLUDES(m_mutex) {
bool notify; bool notify;
{ {
@ -223,8 +223,8 @@ public:
~VlThreadPool() override; ~VlThreadPool() override;
// METHODS // METHODS
inline int numThreads() const { return m_workers.size(); } int numThreads() const { return m_workers.size(); }
inline VlWorkerThread* workerp(int index) { VlWorkerThread* workerp(int index) {
assert(index >= 0); assert(index >= 0);
assert(index < m_workers.size()); assert(index < m_workers.size());
return m_workers[index]; return m_workers[index];

View File

@ -318,8 +318,8 @@ protected:
void flushBase(); void flushBase();
#ifdef VL_THREADED #ifdef VL_THREADED
inline bool offload() const { return m_offload; } bool offload() const { return m_offload; }
inline bool parallel() const { return m_parallel; } bool parallel() const { return m_parallel; }
#else #else
static constexpr bool offload() { return false; } static constexpr bool offload() { return false; }
static constexpr bool parallel() { return false; } static constexpr bool parallel() { return false; }
@ -425,7 +425,7 @@ public:
// duck-typed void emitWData(uint32_t code, const WData* newvalp, int bits) = 0; // duck-typed void emitWData(uint32_t code, const WData* newvalp, int bits) = 0;
// duck-typed void emitDouble(uint32_t code, double newval) = 0; // duck-typed void emitDouble(uint32_t code, double newval) = 0;
VL_ATTR_ALWINLINE inline uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; } VL_ATTR_ALWINLINE uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; }
// Write to previous value buffer value and emit trace entry. // Write to previous value buffer value and emit trace entry.
void fullBit(uint32_t* oldp, CData newval); void fullBit(uint32_t* oldp, CData newval);
@ -441,27 +441,27 @@ public:
// thread and are called chg*Impl // thread and are called chg*Impl
// Check previous dumped value of signal. If changed, then emit trace entry // Check previous dumped value of signal. If changed, then emit trace entry
VL_ATTR_ALWINLINE inline void chgBit(uint32_t* oldp, CData newval) { VL_ATTR_ALWINLINE void chgBit(uint32_t* oldp, CData newval) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullBit(oldp, newval); if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
} }
VL_ATTR_ALWINLINE inline void chgCData(uint32_t* oldp, CData newval, int bits) { VL_ATTR_ALWINLINE void chgCData(uint32_t* oldp, CData newval, int bits) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE inline void chgSData(uint32_t* oldp, SData newval, int bits) { VL_ATTR_ALWINLINE void chgSData(uint32_t* oldp, SData newval, int bits) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE inline void chgIData(uint32_t* oldp, IData newval, int bits) { VL_ATTR_ALWINLINE void chgIData(uint32_t* oldp, IData newval, int bits) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE inline void chgQData(uint32_t* oldp, QData newval, int bits) { VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) {
const uint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval; const uint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval;
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE inline void chgWData(uint32_t* oldp, const WData* newvalp, int bits) { VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WData* newvalp, int bits) {
for (int i = 0; i < (bits + 31) / 32; ++i) { for (int i = 0; i < (bits + 31) / 32; ++i) {
if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) {
fullWData(oldp, newvalp, bits); fullWData(oldp, newvalp, bits);
@ -469,7 +469,7 @@ public:
} }
} }
} }
VL_ATTR_ALWINLINE inline void chgDouble(uint32_t* oldp, double newval) { VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast // cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval); if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
} }
@ -498,48 +498,48 @@ public:
// Hot path internal interface to Verilator generated code // Hot path internal interface to Verilator generated code
// Offloaded tracing. Just dump everything in the offload buffer // Offloaded tracing. Just dump everything in the offload buffer
inline void chgBit(uint32_t code, CData newval) { void chgBit(uint32_t code, CData newval) {
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval; m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_offloadBufferWritep += 2; m_offloadBufferWritep += 2;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgCData(uint32_t code, CData newval, int bits) { void chgCData(uint32_t code, CData newval, int bits) {
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_offloadBufferWritep[2] = newval; m_offloadBufferWritep[2] = newval;
m_offloadBufferWritep += 3; m_offloadBufferWritep += 3;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgSData(uint32_t code, SData newval, int bits) { void chgSData(uint32_t code, SData newval, int bits) {
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_offloadBufferWritep[2] = newval; m_offloadBufferWritep[2] = newval;
m_offloadBufferWritep += 3; m_offloadBufferWritep += 3;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgIData(uint32_t code, IData newval, int bits) { void chgIData(uint32_t code, IData newval, int bits) {
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_offloadBufferWritep[2] = newval; m_offloadBufferWritep[2] = newval;
m_offloadBufferWritep += 3; m_offloadBufferWritep += 3;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgQData(uint32_t code, QData newval, int bits) { void chgQData(uint32_t code, QData newval, int bits) {
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
*reinterpret_cast<QData*>(m_offloadBufferWritep + 2) = newval; *reinterpret_cast<QData*>(m_offloadBufferWritep + 2) = newval;
m_offloadBufferWritep += 4; m_offloadBufferWritep += 4;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgWData(uint32_t code, const WData* newvalp, int bits) { void chgWData(uint32_t code, const WData* newvalp, int bits) {
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_offloadBufferWritep += 2; m_offloadBufferWritep += 2;
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; } for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; }
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgDouble(uint32_t code, double newval) { void chgDouble(uint32_t code, double newval) {
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE; m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE;
m_offloadBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
// cppcheck-suppress invalidPointerCast // cppcheck-suppress invalidPointerCast

View File

@ -551,15 +551,15 @@ template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks( void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
const std::vector<CallbackRecord>& cbVec) { const std::vector<CallbackRecord>& cbVec) {
// Fall back on sequential execution // Fall back on sequential execution
for (const CallbackRecord& cbr : cbVec) {
#ifdef VL_THREADED #ifdef VL_THREADED
for (const CallbackRecord& cbr : cbVec) {
Buffer* traceBufferp = getTraceBuffer(); Buffer* traceBufferp = getTraceBuffer();
cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp)); cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp));
commitTraceBuffer(traceBufferp); commitTraceBuffer(traceBufferp);
#else
VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
} }
#else
if (!cbVec.empty()) VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
} }
template <> template <>
@ -586,7 +586,9 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
if (!preChangeDump()) return; if (!preChangeDump()) return;
} }
#ifdef VL_THREADED
uint32_t* bufferp = nullptr; uint32_t* bufferp = nullptr;
#endif
if (offload()) { if (offload()) {
#ifdef VL_THREADED #ifdef VL_THREADED
// Currently only incremental dumps run on the worker thread // Currently only incremental dumps run on the worker thread

View File

@ -632,10 +632,10 @@ void VerilatedVcd::commitTraceBuffer(VerilatedVcd::Buffer* bufp) {
//============================================================================= //=============================================================================
// Trace rendering primitives // Trace rendering primitives
static inline void static void VerilatedVcdCCopyAndAppendNewLine(char* writep,
VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN; const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN;
static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) { static void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) {
// Copy the whole suffix (this avoid having hard to predict branches which // Copy the whole suffix (this avoid having hard to predict branches which
// helps a lot). Note: The maximum length of the suffix is // helps a lot). Note: The maximum length of the suffix is
// VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed.

View File

@ -73,7 +73,7 @@ private:
void bufferResize(size_t minsize); void bufferResize(size_t minsize);
void bufferFlush() VL_MT_UNSAFE_ONE; void bufferFlush() VL_MT_UNSAFE_ONE;
inline void bufferCheck() { void bufferCheck() {
// Flush the write buffer if there's not enough space left for new information // Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line // We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_writep > m_wrFlushp)) bufferFlush(); if (VL_UNLIKELY(m_writep > m_wrFlushp)) bufferFlush();
@ -210,13 +210,13 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
// Implementation of VerilatedTraceBuffer interface // Implementation of VerilatedTraceBuffer interface
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are // Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them. // called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval); VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits); VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits); VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits); VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits);
VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits); VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits);
VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits); VL_ATTR_ALWINLINE void emitWData(uint32_t code, const WData* newvalp, int bits);
VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval); VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
}; };
//============================================================================= //=============================================================================
@ -313,7 +313,7 @@ public:
} }
// Internal class access // Internal class access
inline VerilatedVcd* spTrace() { return &m_sptrace; } VerilatedVcd* spTrace() { return &m_sptrace; }
}; };
#endif // guard #endif // guard

View File

@ -55,35 +55,34 @@ public:
spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
} }
/// Destruct, flush, and close the dump /// Destruct, flush, and close the dump
virtual ~VerilatedVcdSc() /*override*/ { close(); } ~VerilatedVcdSc() override { close(); }
// METHODS - for SC kernel // METHODS - for SC kernel
// Called by SystemC simulate() // Called by SystemC simulate()
virtual void cycle(bool delta_cycle) { void cycle(bool delta_cycle) override {
if (!delta_cycle) this->dump(sc_time_stamp().to_double()); if (!delta_cycle) this->dump(sc_time_stamp().to_double());
} }
// Override VerilatedVcdC. Must be called after starting simulation. // Override VerilatedVcdC. Must be called after starting simulation.
// cppcheck-suppress missingOverride // GCC won't accept override void open(const char* filename) override VL_MT_SAFE;
virtual void open(const char* filename) /*override*/ VL_MT_SAFE;
private: private:
// METHODS - Fake outs for linker // METHODS - Fake outs for linker
#ifdef NC_SYSTEMC #ifdef NC_SYSTEMC
// Cadence Incisive has these as abstract functions so we must create them // Cadence Incisive has these as abstract functions so we must create them
virtual void set_time_unit(int exponent10_seconds) {} // deprecated void set_time_unit(int exponent10_seconds) override {} // deprecated
#endif #endif
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
//-------------------------------------------------- //--------------------------------------------------
// SystemC 2.1.v1 // SystemC 2.1.v1
#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name); #define DECL_TRACE_METHOD_A(tp) void trace(const tp& object, const std::string& name) override;
#define DECL_TRACE_METHOD_B(tp) \ #define DECL_TRACE_METHOD_B(tp) \
virtual void trace(const tp& object, const std::string& name, int width); void trace(const tp& object, const std::string& name, int width) override;
virtual void write_comment(const std::string&); void write_comment(const std::string&) override;
virtual void trace(const unsigned int&, const std::string&, const char**); void trace(const unsigned int&, const std::string&, const char**) override;
// clang-format off // clang-format off
// Formatting matches that of sc_trace.h // Formatting matches that of sc_trace.h

View File

@ -96,7 +96,7 @@ public:
*(reinterpret_cast<uint32_t*>(newp)) = activeMagic(); *(reinterpret_cast<uint32_t*>(newp)) = activeMagic();
return newp + 8; return newp + 8;
} }
static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE { static void operator delete(void* obj, size_t /*size*/) VL_MT_SAFE {
uint8_t* const oldp = (static_cast<uint8_t*>(obj)) - 8; uint8_t* const oldp = (static_cast<uint8_t*>(obj)) - 8;
if (VL_UNLIKELY(*(reinterpret_cast<uint32_t*>(oldp)) != activeMagic())) { if (VL_UNLIKELY(*(reinterpret_cast<uint32_t*>(oldp)) != activeMagic())) {
VL_FATAL_MT(__FILE__, __LINE__, "", VL_FATAL_MT(__FILE__, __LINE__, "",
@ -114,7 +114,7 @@ public:
static VerilatedVpio* castp(vpiHandle h) { static VerilatedVpio* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h)); return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h));
} }
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); } vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
// ACCESSORS // ACCESSORS
virtual const char* name() const { return "<null>"; } virtual const char* name() const { return "<null>"; }
virtual const char* fullname() const { return "<null>"; } virtual const char* fullname() const { return "<null>"; }

View File

@ -39,7 +39,7 @@
#ifdef __GNUC__ #ifdef __GNUC__
# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment))) # define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment)))
# define VL_ATTR_ALWINLINE __attribute__((always_inline)) # define VL_ATTR_ALWINLINE __attribute__((always_inline)) inline
# define VL_ATTR_NOINLINE __attribute__((noinline)) # define VL_ATTR_NOINLINE __attribute__((noinline))
# define VL_ATTR_COLD __attribute__((cold)) # define VL_ATTR_COLD __attribute__((cold))
# define VL_ATTR_HOT __attribute__((hot)) # define VL_ATTR_HOT __attribute__((hot))
@ -548,8 +548,8 @@ struct reverse_wrapper {
explicit reverse_wrapper(const T& a_v) explicit reverse_wrapper(const T& a_v)
: m_v(a_v) {} : m_v(a_v) {}
inline auto begin() -> decltype(m_v.rbegin()) { return m_v.rbegin(); } auto begin() -> decltype(m_v.rbegin()) { return m_v.rbegin(); }
inline auto end() -> decltype(m_v.rend()) { return m_v.rend(); } auto end() -> decltype(m_v.rend()) { return m_v.rend(); }
}; };
// C++20's std::ranges::reverse_view // C++20's std::ranges::reverse_view
@ -563,6 +563,7 @@ template <class T>
T const& as_const(T& v) { T const& as_const(T& v) {
return v; return v;
} }
}; // namespace vlstd }; // namespace vlstd
//========================================================================= //=========================================================================

View File

@ -48,6 +48,7 @@ exclude_line_regexp(r'\bNUM_ASSERT')
exclude_line_regexp(r'\bERROR_RSVD_WORD') exclude_line_regexp(r'\bERROR_RSVD_WORD')
exclude_line_regexp(r'\bV3ERROR_NA') exclude_line_regexp(r'\bV3ERROR_NA')
exclude_line_regexp(r'\bUINFO\b') exclude_line_regexp(r'\bUINFO\b')
exclude_line_regexp(r'\bVL_DEFINE_DEBUG_FUNCTIONS\b')
# Exclude for branch coverage only # Exclude for branch coverage only
exclude_branch_regexp(r'\bdebug\(\)') exclude_branch_regexp(r'\bdebug\(\)')

View File

@ -79,7 +79,7 @@ ifeq ($(VL_NOOPT),1)
CPPFLAGS += -O0 CPPFLAGS += -O0
else ifeq ($(VL_DEBUG),) else ifeq ($(VL_DEBUG),)
# Optimize # Optimize
CPPFLAGS += -O2 CPPFLAGS += -O3
else else
# Debug # Debug
CPPFLAGS += @CFG_CXXFLAGS_DEBUG@ -DVL_DEBUG -D_GLIBCXX_DEBUG CPPFLAGS += @CFG_CXXFLAGS_DEBUG@ -DVL_DEBUG -D_GLIBCXX_DEBUG
@ -276,9 +276,16 @@ VLCOV_OBJS = \
NON_STANDALONE_HEADERS = \ NON_STANDALONE_HEADERS = \
V3AstInlines.h \ V3AstInlines.h \
V3AstNodes.h \ V3AstNodeDType.h \
V3AstNodeMath.h \
V3AstNodeOther.h \
V3WidthCommit.h \ V3WidthCommit.h \
AST_DEFS := \
V3AstNodeDType.h \
V3AstNodeMath.h \
V3AstNodeOther.h \
#### Linking #### Linking
ifeq ($(VL_VLCOV),) ifeq ($(VL_VLCOV),)
@ -301,8 +308,8 @@ V3Number_test: V3Number_test.o
#### Modules #### Modules
%__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h %__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS)
$(PYTHON3) $(ASTGEN) -I $(srcdir) $*.cpp $(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) $*.cpp
%.o: %.cpp %.o: %.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@ $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
@ -332,8 +339,8 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h
$(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir) $(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir)
touch $@ touch $@
V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h V3Ast__gen_classes.h : $(ASTGEN) $(AST_DEFS)
$(PYTHON3) $(ASTGEN) -I $(srcdir) --classes $(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) --classes
V3ParseBison.h: V3ParseBison.c V3ParseBison.h: V3ParseBison.c

View File

@ -38,6 +38,8 @@
#include <unordered_map> #include <unordered_map>
VL_DEFINE_DEBUG_FUNCTIONS;
//***** See below for main transformation engine //***** See below for main transformation engine
//###################################################################### //######################################################################
@ -66,8 +68,8 @@ public:
: V3GraphVertex{graphp} : V3GraphVertex{graphp}
, m_name{name} , m_name{name}
, m_type{type} {} , m_type{type} {}
virtual string name() const override { return m_name + " " + typestr(); } string name() const override { return m_name + " " + typestr(); }
virtual string dotColor() const override { return user() ? "green" : "black"; } string dotColor() const override { return user() ? "green" : "black"; }
virtual int type() const { return m_type; } virtual int type() const { return m_type; }
}; };
@ -79,8 +81,6 @@ protected:
LatchDetectGraphVertex* m_curVertexp = nullptr; // Current latch detection graph vertex LatchDetectGraphVertex* m_curVertexp = nullptr; // Current latch detection graph vertex
std::vector<AstVarRef*> m_outputs; // Vector of lvalues encountered on this pass std::vector<AstVarRef*> m_outputs; // Vector of lvalues encountered on this pass
VL_DEBUG_FUNC; // Declare debug()
static LatchDetectGraphVertex* castVertexp(void* vertexp) { static LatchDetectGraphVertex* castVertexp(void* vertexp) {
return reinterpret_cast<LatchDetectGraphVertex*>(vertexp); return reinterpret_cast<LatchDetectGraphVertex*>(vertexp);
} }
@ -120,7 +120,7 @@ protected:
public: public:
LatchDetectGraph() { clear(); } LatchDetectGraph() { clear(); }
virtual ~LatchDetectGraph() override { clear(); } ~LatchDetectGraph() override { clear(); }
// ACCESSORS // ACCESSORS
LatchDetectGraphVertex* currentp() { return m_curVertexp; } LatchDetectGraphVertex* currentp() { return m_curVertexp; }
void currentp(LatchDetectGraphVertex* vertex) { m_curVertexp = vertex; } void currentp(LatchDetectGraphVertex* vertex) { m_curVertexp = vertex; }
@ -183,7 +183,7 @@ public:
<< " (not all control paths of combinational always assign a value)\n" << " (not all control paths of combinational always assign a value)\n"
<< nodep->warnMore() << nodep->warnMore()
<< "... Suggest use of always_latch for intentional latches"); << "... Suggest use of always_latch for intentional latches");
if (debug() >= 9) dumpDotFilePrefixed("latch_" + vrp->name()); if (dumpGraph() >= 9) dumpDotFilePrefixed("latch_" + vrp->name());
} }
vertp->user(false); // Clear again (see above) vertp->user(false); // Clear again (see above)
vrp->varp()->isLatched(latch_detected); vrp->varp()->isLatched(latch_detected);
@ -198,12 +198,7 @@ public:
//###################################################################### //######################################################################
// Collect existing active names // Collect existing active names
class ActiveBaseVisitor VL_NOT_FINAL : public VNVisitor { class ActiveNamer final : public VNVisitor {
protected:
VL_DEBUG_FUNC; // Declare debug()
};
class ActiveNamer final : public ActiveBaseVisitor {
private: private:
// STATE // STATE
AstScope* m_scopep = nullptr; // Current scope to add statement to AstScope* m_scopep = nullptr; // Current scope to add statement to
@ -216,10 +211,10 @@ private:
// METHODS // METHODS
void addActive(AstActive* nodep) { void addActive(AstActive* nodep) {
UASSERT_OBJ(m_scopep, nodep, "nullptr scope"); UASSERT_OBJ(m_scopep, nodep, "nullptr scope");
m_scopep->addActivep(nodep); m_scopep->addBlocksp(nodep);
} }
// VISITORS // VISITORS
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
m_scopep = nodep; m_scopep = nodep;
m_iActivep = nullptr; m_iActivep = nullptr;
m_cActivep = nullptr; m_cActivep = nullptr;
@ -227,13 +222,13 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
// Don't clear scopep, the namer persists beyond this visit // Don't clear scopep, the namer persists beyond this visit
} }
virtual void visit(AstSenTree* nodep) override { void visit(AstSenTree* nodep) override {
// Simplify sensitivity list // Simplify sensitivity list
VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep); VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep);
} }
//-------------------- //--------------------
virtual void visit(AstNodeStmt*) override {} // Accelerate void visit(AstNodeStmt*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// METHODS // METHODS
@ -275,14 +270,14 @@ public:
// CONSTRUCTORS // CONSTRUCTORS
ActiveNamer() = default; ActiveNamer() = default;
virtual ~ActiveNamer() override = default; ~ActiveNamer() override = default;
void main(AstScope* nodep) { iterate(nodep); } void main(AstScope* nodep) { iterate(nodep); }
}; };
//###################################################################### //######################################################################
// Latch checking visitor // Latch checking visitor
class ActiveLatchCheckVisitor final : public ActiveBaseVisitor { class ActiveLatchCheckVisitor final : public VNVisitor {
private: private:
// NODE STATE // NODE STATE
// Input: // Input:
@ -291,25 +286,25 @@ private:
// STATE // STATE
LatchDetectGraph m_graph; // Graph used to detect latches in combo always LatchDetectGraph m_graph; // Graph used to detect latches in combo always
// VISITORS // VISITORS
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
const AstVar* const varp = nodep->varp(); const AstVar* const varp = nodep->varp();
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) { if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) {
m_graph.addAssignment(nodep); m_graph.addAssignment(nodep);
} }
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
if (!nodep->isBoundsCheck()) { if (!nodep->isBoundsCheck()) {
LatchDetectGraphVertex* const parentp = m_graph.currentp(); LatchDetectGraphVertex* const parentp = m_graph.currentp();
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true); LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
m_graph.addPathVertex(branchp, "IF"); m_graph.addPathVertex(branchp, "IF");
iterateAndNextNull(nodep->ifsp()); iterateAndNextNull(nodep->thensp());
m_graph.addPathVertex(branchp, "ELSE"); m_graph.addPathVertex(branchp, "ELSE");
iterateAndNextNull(nodep->elsesp()); iterateAndNextNull(nodep->elsesp());
m_graph.currentp(parentp); m_graph.currentp(parentp);
} }
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -324,7 +319,7 @@ public:
//###################################################################### //######################################################################
// Replace unsupported non-blocking assignments with blocking assignments // Replace unsupported non-blocking assignments with blocking assignments
class ActiveDlyVisitor final : public ActiveBaseVisitor { class ActiveDlyVisitor final : public VNVisitor {
public: public:
enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL }; enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL };
@ -333,7 +328,7 @@ private:
const CheckType m_check; // Process type we are checking const CheckType m_check; // Process type we are checking
// VISITORS // VISITORS
virtual void visit(AstAssignDly* nodep) override { void visit(AstAssignDly* nodep) override {
// Non-blocking assignments are OK in sequential processes // Non-blocking assignments are OK in sequential processes
if (m_check == CT_SEQ) return; if (m_check == CT_SEQ) return;
@ -357,7 +352,7 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
virtual void visit(AstAssign* nodep) override { void visit(AstAssign* nodep) override {
// Blocking assignments are always OK in combinational (and initial/final) processes // Blocking assignments are always OK in combinational (and initial/final) processes
if (m_check != CT_SEQ) return; if (m_check != CT_SEQ) return;
@ -380,7 +375,7 @@ private:
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -394,7 +389,7 @@ public:
//###################################################################### //######################################################################
// Active class functions // Active class functions
class ActiveVisitor final : public ActiveBaseVisitor { class ActiveVisitor final : public VNVisitor {
private: private:
// NODE STATE // NODE STATE
// Each call to V3Const::constify // Each call to V3Const::constify
@ -407,7 +402,7 @@ private:
bool m_itemSequent = false; // Found a SenItem sequential bool m_itemSequent = false; // Found a SenItem sequential
// VISITORS // VISITORS
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
// Create required actives and add to scope // Create required actives and add to scope
UINFO(4, " SCOPE " << nodep << endl); UINFO(4, " SCOPE " << nodep << endl);
// Clear last scope's names, and collect this scope's existing names // Clear last scope's names, and collect this scope's existing names
@ -415,10 +410,10 @@ private:
m_scopeFinalp = nullptr; m_scopeFinalp = nullptr;
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstActive* nodep) override { void visit(AstActive* nodep) override {
// Actives are being formed, so we can ignore any already made // Actives are being formed, so we can ignore any already made
} }
virtual void visit(AstInitialStatic* nodep) override { void visit(AstInitialStatic* nodep) override {
// Relink to IACTIVE, unless already under it // Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl); UINFO(4, " INITIAL " << nodep << endl);
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL}; const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
@ -426,7 +421,7 @@ private:
nodep->unlinkFrBack(); nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep); wantactivep->addStmtsp(nodep);
} }
virtual void visit(AstInitial* nodep) override { void visit(AstInitial* nodep) override {
// Relink to IACTIVE, unless already under it // Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl); UINFO(4, " INITIAL " << nodep << endl);
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL}; const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
@ -434,31 +429,31 @@ private:
nodep->unlinkFrBack(); nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep); wantactivep->addStmtsp(nodep);
} }
virtual void visit(AstAssignAlias* nodep) override { void visit(AstAssignAlias* nodep) override {
// Relink to CACTIVE, unless already under it // Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl); UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline()); AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack(); nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep); wantactivep->addStmtsp(nodep);
} }
virtual void visit(AstAssignW* nodep) override { void visit(AstAssignW* nodep) override {
// Relink to CACTIVE, unless already under it // Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl); UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline()); AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack(); nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep); wantactivep->addStmtsp(nodep);
} }
virtual void visit(AstCoverToggle* nodep) override { void visit(AstCoverToggle* nodep) override {
// Relink to CACTIVE, unless already under it // Relink to CACTIVE, unless already under it
UINFO(4, " COVERTOGGLE " << nodep << endl); UINFO(4, " COVERTOGGLE " << nodep << endl);
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline()); AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack(); nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep); wantactivep->addStmtsp(nodep);
} }
virtual void visit(AstFinal* nodep) override { void visit(AstFinal* nodep) override {
// Relink to CFUNC for the final // Relink to CFUNC for the final
UINFO(4, " FINAL " << nodep << endl); UINFO(4, " FINAL " << nodep << endl);
if (!nodep->bodysp()) { // Empty, Kill it. if (!nodep->stmtsp()) { // Empty, Kill it.
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return; return;
} }
@ -471,10 +466,10 @@ private:
m_scopeFinalp->isStatic(false); m_scopeFinalp->isStatic(false);
m_scopeFinalp->isLoose(true); m_scopeFinalp->isLoose(true);
m_scopeFinalp->slow(true); m_scopeFinalp->slow(true);
m_namer.scopep()->addActivep(m_scopeFinalp); m_namer.scopep()->addBlocksp(m_scopeFinalp);
} }
nodep->unlinkFrBack(); nodep->unlinkFrBack();
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext()); m_scopeFinalp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext());
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
@ -537,33 +532,33 @@ private:
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_SEQ}; ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_SEQ};
} }
} }
virtual void visit(AstAlways* nodep) override { void visit(AstAlways* nodep) override {
// Move always to appropriate ACTIVE based on its sense list // Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALW " << nodep << endl); UINFO(4, " ALW " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); // if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
if (!nodep->bodysp()) { if (!nodep->stmtsp()) {
// Empty always. Kill it. // Empty always. Kill it.
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return; return;
} }
visitAlways(nodep, nodep->sensesp(), nodep->keyword()); visitAlways(nodep, nodep->sensesp(), nodep->keyword());
} }
virtual void visit(AstAlwaysPostponed* nodep) override { void visit(AstAlwaysPostponed* nodep) override {
UINFO(4, " ALW " << nodep << endl); UINFO(4, " ALW " << nodep << endl);
if (!nodep->bodysp()) { if (!nodep->stmtsp()) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return; return;
} }
visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS); visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS);
} }
virtual void visit(AstAlwaysPublic* nodep) override { void visit(AstAlwaysPublic* nodep) override {
// Move always to appropriate ACTIVE based on its sense list // Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALWPub " << nodep << endl); UINFO(4, " ALWPub " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); // if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS); visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
} }
virtual void visit(AstSenItem* nodep) override { void visit(AstSenItem* nodep) override {
if (nodep->varrefp()) { if (nodep->varrefp()) {
if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) { if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) {
if (basicp->isEventValue()) { if (basicp->isEventValue()) {
@ -592,9 +587,9 @@ private:
} }
//-------------------- //--------------------
virtual void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstVarScope*) override {} // Accelerate void visit(AstVarScope*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -608,5 +603,5 @@ public:
void V3Active::activeAll(AstNetlist* nodep) { void V3Active::activeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveVisitor{nodep}; } // Destruct before checking { ActiveVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("active", 0, dumpTree() >= 3);
} }

View File

@ -33,6 +33,8 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3SenTree.h" #include "V3SenTree.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Active class functions // Active class functions
@ -49,16 +51,15 @@ private:
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
// Create required actives and add to module // Create required actives and add to module
// We can start ordering at a module, or a scope // We can start ordering at a module, or a scope
UINFO(4, " MOD " << nodep << endl); UINFO(4, " MOD " << nodep << endl);
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstActive* nodep) override { void visit(AstActive* nodep) override {
UINFO(4, " ACTIVE " << nodep << endl); UINFO(4, " ACTIVE " << nodep << endl);
// Remove duplicate clocks and such; sensesp() may change! // Remove duplicate clocks and such; sensesp() may change!
V3Const::constifyExpensiveEdit(nodep); V3Const::constifyExpensiveEdit(nodep);
@ -101,27 +102,27 @@ private:
// No need to do statements under it, they're already moved. // No need to do statements under it, they're already moved.
// iterateChildren(nodep); // iterateChildren(nodep);
} }
virtual void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
//-------------------- //--------------------
virtual void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstVarScope*) override {} // Accelerate void visit(AstVarScope*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); } explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ActiveTopVisitor() override = default; ~ActiveTopVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -130,5 +131,5 @@ public:
void V3ActiveTop::activeTopAll(AstNetlist* nodep) { void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveTopVisitor{nodep}; } // Destruct before checking { ActiveTopVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("activetop", 0, dumpTree() >= 3);
} }

View File

@ -23,6 +23,8 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3Stats.h" #include "V3Stats.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Assert class functions // Assert class functions
@ -70,7 +72,7 @@ private:
if (!m_monitorNumVarp) { if (!m_monitorNumVarp) {
m_monitorNumVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorNum", m_monitorNumVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorNum",
nodep->findUInt64DType()}; nodep->findUInt64DType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorNumVarp); v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorNumVarp);
} }
const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access); const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
@ -80,7 +82,7 @@ private:
if (!m_monitorOffVarp) { if (!m_monitorOffVarp) {
m_monitorOffVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorOff", m_monitorOffVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorOff",
nodep->findBitDType()}; nodep->findBitDType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorOffVarp); v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorOffVarp);
} }
const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access); const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
@ -147,7 +149,7 @@ private:
selfDestruct = true; selfDestruct = true;
} else { } else {
// V3Coverage assigned us a bucket to increment. // V3Coverage assigned us a bucket to increment.
AstCoverInc* const covincp = VN_AS(snodep->coverincp(), CoverInc); AstCoverInc* const covincp = VN_AS(snodep->coverincsp(), CoverInc);
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion"); UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
if (message != "") covincp->declp()->comment(message); if (message != "") covincp->declp()->comment(message);
@ -196,7 +198,7 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstIf* nodep) override { void visit(AstIf* nodep) override {
if (nodep->user1SetOnce()) return; if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) { if (nodep->uniquePragma() || nodep->unique0Pragma()) {
const AstNodeIf* ifp = nodep; const AstNodeIf* ifp = nodep;
@ -209,7 +211,7 @@ private:
iterateAndNextNull(ifp->condp()); iterateAndNextNull(ifp->condp());
// Recurse into the true case. // Recurse into the true case.
iterateAndNextNull(ifp->ifsp()); iterateAndNextNull(ifp->thensp());
// If the last else is not an else if, recurse into that too. // If the last else is not an else if, recurse into that too.
if (ifp->elsesp() && !nextifp) { // if (ifp->elsesp() && !nextifp) { //
@ -254,7 +256,7 @@ private:
} }
//========== Case assertions //========== Case assertions
virtual void visit(AstCase* nodep) override { void visit(AstCase* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (!nodep->user1SetOnce()) { if (!nodep->user1SetOnce()) {
bool has_default = false; bool has_default = false;
@ -323,7 +325,7 @@ private:
} }
//========== Past //========== Past
virtual void visit(AstPast* nodep) override { void visit(AstPast* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
uint32_t ticks = 1; uint32_t ticks = 1;
if (nodep->ticksp()) { if (nodep->ticksp()) {
@ -338,28 +340,28 @@ private:
sentreep->unlinkFrBack(); sentreep->unlinkFrBack();
AstAlways* const alwaysp AstAlways* const alwaysp
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr); = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
m_modp->addStmtp(alwaysp); m_modp->addStmtsp(alwaysp);
for (uint32_t i = 0; i < ticks; ++i) { for (uint32_t i = 0; i < ticks; ++i) {
AstVar* const outvarp = new AstVar( AstVar* const outvarp = new AstVar(
nodep->fileline(), VVarType::MODULETEMP, nodep->fileline(), VVarType::MODULETEMP,
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep()); "_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep());
m_modp->addStmtp(outvarp); m_modp->addStmtsp(outvarp);
AstNode* const assp = new AstAssignDly( AstNode* const assp = new AstAssignDly(
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp); nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
alwaysp->addStmtp(assp); alwaysp->addStmtsp(assp);
// if (debug() >= 9) assp->dumpTree(cout, "-ass: "); // if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
invarp = outvarp; invarp = outvarp;
inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ); inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ);
} }
nodep->replaceWith(inp); nodep->replaceWith(inp);
} }
virtual void visit(AstSampled* nodep) override { void visit(AstSampled* nodep) override {
nodep->replaceWith(nodep->exprp()->unlinkFrBack()); nodep->replaceWith(nodep->exprp()->unlinkFrBack());
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
//========== Statements //========== Statements
virtual void visit(AstDisplay* nodep) override { void visit(AstDisplay* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// Replace the special types with standard text // Replace the special types with standard text
if (nodep->displayType() == VDisplayType::DT_INFO) { if (nodep->displayType() == VDisplayType::DT_INFO) {
@ -387,7 +389,7 @@ private:
stmtsp}; stmtsp};
ifp->branchPred(VBranchPred::BP_UNLIKELY); ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* const newp = new AstAlwaysPostponed{fl, ifp}; AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
m_modp->addStmtp(newp); m_modp->addStmtsp(newp);
} else if (nodep->displayType() == VDisplayType::DT_STROBE) { } else if (nodep->displayType() == VDisplayType::DT_STROBE) {
nodep->displayType(VDisplayType::DT_DISPLAY); nodep->displayType(VDisplayType::DT_DISPLAY);
// Need one-shot // Need one-shot
@ -395,7 +397,7 @@ private:
const auto varp const auto varp
= new AstVar{fl, VVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++), = new AstVar{fl, VVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++),
nodep->findBitDType()}; nodep->findBitDType()};
m_modp->addStmtp(varp); m_modp->addStmtsp(varp);
// Where $strobe was we do "__Vstrobe = '1;" // Where $strobe was we do "__Vstrobe = '1;"
const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitTrue{}}}; new AstConst{fl, AstConst::BitTrue{}}};
@ -407,35 +409,35 @@ private:
AstNode* const newp = new AstAlwaysPostponed{fl, ifp}; AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitFalse{}}}); new AstConst{fl, AstConst::BitFalse{}}});
m_modp->addStmtp(newp); m_modp->addStmtsp(newp);
} }
} }
virtual void visit(AstMonitorOff* nodep) override { void visit(AstMonitorOff* nodep) override {
const auto newp const auto newp
= new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE), = new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off())); new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off()));
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstAssert* nodep) override { void visit(AstAssert* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
newPslAssertion(nodep, nodep->failsp()); newPslAssertion(nodep, nodep->failsp());
} }
virtual void visit(AstAssertIntrinsic* nodep) override { void visit(AstAssertIntrinsic* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
newPslAssertion(nodep, nodep->failsp()); newPslAssertion(nodep, nodep->failsp());
} }
virtual void visit(AstCover* nodep) override { void visit(AstCover* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
newPslAssertion(nodep, nullptr); newPslAssertion(nodep, nullptr);
} }
virtual void visit(AstRestrict* nodep) override { void visit(AstRestrict* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// IEEE says simulator ignores these // IEEE says simulator ignores these
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_modPastNum); VL_RESTORER(m_modPastNum);
VL_RESTORER(m_modStrobeNum); VL_RESTORER(m_modStrobeNum);
@ -446,7 +448,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// This code is needed rather than a visitor in V3Begin, // This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin // because V3Assert is called before V3Begin
VL_RESTORER(m_beginp); VL_RESTORER(m_beginp);
@ -456,12 +458,12 @@ private:
} }
} }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit AssertVisitor(AstNetlist* nodep) { iterate(nodep); } explicit AssertVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~AssertVisitor() override { ~AssertVisitor() override {
V3Stats::addStat("Assertions, assert non-immediate statements", m_statAsNotImm); V3Stats::addStat("Assertions, assert non-immediate statements", m_statAsNotImm);
V3Stats::addStat("Assertions, assert immediate statements", m_statAsImm); V3Stats::addStat("Assertions, assert immediate statements", m_statAsImm);
V3Stats::addStat("Assertions, cover statements", m_statCover); V3Stats::addStat("Assertions, cover statements", m_statCover);
@ -475,5 +477,5 @@ public:
void V3Assert::assertAll(AstNetlist* nodep) { void V3Assert::assertAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertVisitor{nodep}; } // Destruct before checking { AssertVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("assert", 0, dumpTree() >= 3);
} }

View File

@ -25,6 +25,8 @@
#include "V3Ast.h" #include "V3Ast.h"
#include "V3Global.h" #include "V3Global.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Assert class functions // Assert class functions
@ -45,7 +47,6 @@ private:
AstNode* m_disablep = nullptr; // Last disable AstNode* m_disablep = nullptr; // Last disable
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
AstSenTree* newSenTree(AstNode* nodep) { AstSenTree* newSenTree(AstNode* nodep) {
// Create sentree based on clocked or default clock // Create sentree based on clocked or default clock
@ -69,7 +70,7 @@ private:
// VISITORS // VISITORS
//========== Statements //========== Statements
virtual void visit(AstClocking* nodep) override { void visit(AstClocking* nodep) override {
UINFO(8, " CLOCKING" << nodep << endl); UINFO(8, " CLOCKING" << nodep << endl);
// Store the new default clock, reset on new module // Store the new default clock, reset on new module
m_seniDefaultp = nodep->sensesp(); m_seniDefaultp = nodep->sensesp();
@ -81,14 +82,14 @@ private:
} }
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstAlways* nodep) override { void visit(AstAlways* nodep) override {
iterateAndNextNull(nodep->sensesp()); iterateAndNextNull(nodep->sensesp());
if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp(); if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp();
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->stmtsp());
m_seniAlwaysp = nullptr; m_seniAlwaysp = nullptr;
} }
virtual void visit(AstNodeCoverOrAssert* nodep) override { void visit(AstNodeCoverOrAssert* nodep) override {
if (nodep->sentreep()) return; // Already processed if (nodep->sentreep()) return; // Already processed
clearAssertInfo(); clearAssertInfo();
// Find Clocking's buried under nodep->exprsp // Find Clocking's buried under nodep->exprsp
@ -96,7 +97,7 @@ private:
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep)); if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
clearAssertInfo(); clearAssertInfo();
} }
virtual void visit(AstFell* nodep) override { void visit(AstFell* nodep) override {
if (nodep->sentreep()) return; // Already processed if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep); iterateChildren(nodep);
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
@ -110,12 +111,12 @@ private:
nodep->sentreep(newSenTree(nodep)); nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstPast* nodep) override { void visit(AstPast* nodep) override {
if (nodep->sentreep()) return; // Already processed if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep); iterateChildren(nodep);
nodep->sentreep(newSenTree(nodep)); nodep->sentreep(newSenTree(nodep));
} }
virtual void visit(AstRose* nodep) override { void visit(AstRose* nodep) override {
if (nodep->sentreep()) return; // Already processed if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep); iterateChildren(nodep);
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
@ -129,7 +130,7 @@ private:
nodep->sentreep(newSenTree(nodep)); nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstStable* nodep) override { void visit(AstStable* nodep) override {
if (nodep->sentreep()) return; // Already processed if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep); iterateChildren(nodep);
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
@ -143,7 +144,7 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstImplication* nodep) override { void visit(AstImplication* nodep) override {
if (nodep->sentreep()) return; // Already processed if (nodep->sentreep()) return; // Already processed
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
@ -161,7 +162,7 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstPropClocked* nodep) override { void visit(AstPropClocked* nodep) override {
// No need to iterate the body, once replace will get iterated // No need to iterate the body, once replace will get iterated
iterateAndNextNull(nodep->sensesp()); iterateAndNextNull(nodep->sensesp());
if (m_senip) if (m_senip)
@ -183,12 +184,12 @@ private:
nodep->replaceWith(blockp); nodep->replaceWith(blockp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// Reset defaults // Reset defaults
m_seniDefaultp = nullptr; m_seniDefaultp = nullptr;
} }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -197,7 +198,7 @@ public:
// Process // Process
iterate(nodep); iterate(nodep);
} }
virtual ~AssertPreVisitor() override = default; ~AssertPreVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -206,5 +207,5 @@ public:
void V3AssertPre::assertPreAll(AstNetlist* nodep) { void V3AssertPre::assertPreAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertPreVisitor{nodep}; } // Destruct before checking { AssertPreVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTree() >= 3);
} }

View File

@ -28,6 +28,8 @@
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
VL_DEFINE_DEBUG_FUNCTIONS;
//====================================================================== //======================================================================
// Statics // Statics
@ -165,22 +167,22 @@ string AstNode::prettyName(const string& namein) {
continue; continue;
} }
if (pos[0] == '_' && pos[1] == '_') { // Short-circuit if (pos[0] == '_' && pos[1] == '_') { // Short-circuit
if (0 == strncmp(pos, "__BRA__", 7)) { if (0 == std::strncmp(pos, "__BRA__", 7)) {
pretty += "["; pretty += "[";
pos += 7; pos += 7;
continue; continue;
} }
if (0 == strncmp(pos, "__KET__", 7)) { if (0 == std::strncmp(pos, "__KET__", 7)) {
pretty += "]"; pretty += "]";
pos += 7; pos += 7;
continue; continue;
} }
if (0 == strncmp(pos, "__DOT__", 7)) { if (0 == std::strncmp(pos, "__DOT__", 7)) {
pretty += "."; pretty += ".";
pos += 7; pos += 7;
continue; continue;
} }
if (0 == strncmp(pos, "__PVT__", 7)) { if (0 == std::strncmp(pos, "__PVT__", 7)) {
pretty += ""; pretty += "";
pos += 7; pos += 7;
continue; continue;
@ -212,8 +214,7 @@ string AstNode::prettyTypeName() const {
//###################################################################### //######################################################################
// Insertion // Insertion
inline void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next) {
bool next){
#ifdef VL_DEBUG #ifdef VL_DEBUG
// Called on all major tree changers. // Called on all major tree changers.
// Only for use for those really nasty bugs relating to internals // Only for use for those really nasty bugs relating to internals
@ -234,7 +235,8 @@ inline void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, i
#endif #endif
} }
AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { template <>
AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp) {
// Add to m_nextp, returns this // Add to m_nextp, returns this
UDEBUGONLY(UASSERT_OBJ(newp, nodep, "Null item passed to addNext");); UDEBUGONLY(UASSERT_OBJ(newp, nodep, "Null item passed to addNext"););
debugTreeChange(nodep, "-addNextThs: ", __LINE__, false); debugTreeChange(nodep, "-addNextThs: ", __LINE__, false);
@ -272,11 +274,6 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
return nodep; return nodep;
} }
AstNode* AstNode::addNextNull(AstNode* nodep, AstNode* newp) {
if (!newp) return nodep;
return addNext(nodep, newp);
}
void AstNode::addNextHere(AstNode* newp) { void AstNode::addNextHere(AstNode* newp) {
// Add to m_nextp on exact node passed, not at the end. // Add to m_nextp on exact node passed, not at the end.
// This could be at head, tail, or both (single) // This could be at head, tail, or both (single)
@ -925,7 +922,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(VNVisitor& v) {
} else if (!nodep->backp()) { } else if (!nodep->backp()) {
// Calling on standalone tree; insert a shim node so we can keep // Calling on standalone tree; insert a shim node so we can keep
// track, then delete it on completion // track, then delete it on completion
AstBegin* const tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep); AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep};
{ {
VL_DO_DANGLING(tempp->stmtsp()->accept(v), VL_DO_DANGLING(tempp->stmtsp()->accept(v),
nodep); // nodep to null as may be replaced nodep); // nodep to null as may be replaced
@ -1004,43 +1001,12 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
//====================================================================== //======================================================================
// Debugging // Debugging
void AstNode::checkTreeIter(AstNode* backp) { void AstNode::checkTreeIter(const AstNode* backp) const {
// private: Check a tree and children // private: Check a tree and children
UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent"); UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent");
if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) { switch (this->type()) {
// Termops have a short-circuited iterateChildren, so check usage #include "V3Ast__gen_op_checks.h"
UASSERT_OBJ(!(op1p() || op2p() || op3p() || op4p()), this, default: VL_UNREACHABLE; // LCOV_EXCL_LINE
"Terminal operation with non-terminals");
}
if (m_op1p) m_op1p->checkTreeIterList(this);
if (m_op2p) m_op2p->checkTreeIterList(this);
if (m_op3p) m_op3p->checkTreeIterList(this);
if (m_op4p) m_op4p->checkTreeIterList(this);
}
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* const headp = this;
const AstNode* tailp = this;
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
nodep->checkTreeIter(backp);
UASSERT_OBJ(headp == this || !nextp(), this,
"Headtailp should be null in middle of lists");
tailp = nodep;
backp = nodep;
}
UASSERT_OBJ(headp->m_headtailp == tailp, headp, "Tail in headtailp is inconsistent");
UASSERT_OBJ(tailp->m_headtailp == headp, tailp, "Head in headtailp is inconsistent");
}
void AstNode::checkTree() {
if (!debug()) return;
if (this->backp()) {
// Linked tree- check only the passed node
this->checkTreeIter(this->backp());
} else {
this->checkTreeIterList(this->backp());
} }
} }
@ -1156,7 +1122,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
if (logsp->fail()) v3fatal("Can't write " << filename); if (logsp->fail()) v3fatal("Can't write " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast(); *logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n"; *logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) { if (editCountGbl() == editCountLast() && ::dumpTree() < 9) {
*logsp << '\n'; *logsp << '\n';
*logsp << "No changes since last dump!\n"; *logsp << "No changes since last dump!\n";
} else { } else {
@ -1166,7 +1132,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
} }
} }
if (doDump && v3Global.opt.debugEmitV()) V3EmitV::debugEmitV(filename + ".v"); if (doDump && v3Global.opt.debugEmitV()) V3EmitV::debugEmitV(filename + ".v");
if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) { if (doCheck && (v3Global.opt.debugCheck() || ::dumpTree())) {
// Error check // Error check
checkTree(); checkTree();
// Broken isn't part of check tree because it can munge iterp's // Broken isn't part of check tree because it can munge iterp's
@ -1217,7 +1183,11 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
const_cast<AstNode*>(this)->dump(nsstr); const_cast<AstNode*>(this)->dump(nsstr);
nsstr << endl; nsstr << endl;
} }
m_fileline->v3errorEnd(nsstr, instanceStr()); // Don't look for instance name when warning is disabled.
// In case of large number of warnings, this can
// take significant amount of time
m_fileline->v3errorEnd(nsstr,
m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr());
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -17,71 +17,175 @@
#ifndef VERILATOR_V3ASTINLINES_H_ #ifndef VERILATOR_V3ASTINLINES_H_
#define VERILATOR_V3ASTINLINES_H_ #define VERILATOR_V3ASTINLINES_H_
#ifndef VERILATOR_V3ASTNODES_H_ #ifndef VERILATOR_V3AST_H_
#error "Use V3Ast.h as the include" #error "Use V3Ast.h as the include"
#include "V3AstNodes.h" // This helps code analysis tools pick up symbols in V3Ast.h and V3AstNodes.h #include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h and relaed
#endif #endif
//###################################################################### //######################################################################
// Inline ACCESSORS // Inline METHODS
inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; }
inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; }
inline bool AstNode::width1() const { // V3Const uses to know it can optimize bool AstNode::width1() const { // V3Const uses to know it can optimize
return dtypep() && dtypep()->width() == 1; return dtypep() && dtypep()->width() == 1;
} }
inline int AstNode::widthInstrs() const { int AstNode::widthInstrs() const {
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
} }
inline bool AstNode::isDouble() const { bool AstNode::isDouble() const {
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble(); return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
} }
inline bool AstNode::isString() const { bool AstNode::isString() const {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
} }
inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
inline bool AstNode::isZero() const { bool AstNode::isZero() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero()); return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
} }
inline bool AstNode::isNeqZero() const { bool AstNode::isNeqZero() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNeqZero()); return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNeqZero());
} }
inline bool AstNode::isOne() const { bool AstNode::isOne() const { return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne()); }
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne()); bool AstNode::isAllOnes() const {
}
inline bool AstNode::isAllOnes() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnes()); return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnes());
} }
inline bool AstNode::isAllOnesV() const { bool AstNode::isAllOnesV() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnesV()); return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnesV());
} }
inline bool AstNode::sameTree(const AstNode* node2p) const { bool AstNode::sameTree(const AstNode* node2p) const {
return sameTreeIter(this, node2p, true, false); return sameTreeIter(this, node2p, true, false);
} }
inline bool AstNode::sameGateTree(const AstNode* node2p) const { bool AstNode::sameGateTree(const AstNode* node2p) const {
return sameTreeIter(this, node2p, true, true); return sameTreeIter(this, node2p, true, true);
} }
inline void AstNodeVarRef::varp(AstVar* varp) { int AstNodeArrayDType::left() const { return rangep()->leftConst(); }
m_varp = varp; int AstNodeArrayDType::right() const { return rangep()->rightConst(); }
int AstNodeArrayDType::hi() const { return rangep()->hiConst(); }
int AstNodeArrayDType::lo() const { return rangep()->loConst(); }
int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; }
AstRange::AstRange(FileLine* fl, int left, int right)
: ASTGEN_SUPER_Range(fl) {
leftp(new AstConst{fl, static_cast<uint32_t>(left)});
rightp(new AstConst{fl, static_cast<uint32_t>(right)});
}
AstRange::AstRange(FileLine* fl, const VNumRange& range)
: ASTGEN_SUPER_Range(fl) {
leftp(new AstConst{fl, static_cast<uint32_t>(range.left())});
rightp(new AstConst{fl, static_cast<uint32_t>(range.right())});
}
int AstRange::leftConst() const {
AstConst* const constp = VN_CAST(leftp(), Const);
return (constp ? constp->toSInt() : 0);
}
int AstRange::rightConst() const {
AstConst* const constp = VN_CAST(rightp(), Const);
return (constp ? constp->toSInt() : 0);
}
int AstQueueDType::boundConst() const {
AstConst* const constp = VN_CAST(boundp(), Const);
return (constp ? constp->toSInt() : 0);
}
AstPin::AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp)
: ASTGEN_SUPER_Pin(fl)
, m_pinNum{pinNum}
, m_name{varname->name()} {
this->exprp(exprp);
}
AstDpiExportUpdated::AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep)
: ASTGEN_SUPER_DpiExportUpdated(fl) {
this->varRefp(new AstVarRef{fl, varScopep, VAccess::WRITE});
}
AstVarScope* AstDpiExportUpdated::varScopep() const { return varRefp()->varScopep(); }
AstPackArrayDType::AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp,
AstRange* rangep)
: ASTGEN_SUPER_PackArrayDType(fl) {
childDTypep(dtp); // Only for parser
refDTypep(nullptr);
this->rangep(rangep);
dtypep(nullptr); // V3Width will resolve
const int width = subDTypep()->width() * rangep->elementsConst();
widthForce(width, width);
}
AstPackArrayDType::AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
: ASTGEN_SUPER_PackArrayDType(fl) {
refDTypep(dtp);
this->rangep(rangep);
dtypep(this);
const int width = subDTypep()->width() * rangep->elementsConst();
widthForce(width, width);
}
int AstBasicDType::hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); }
int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); }
int AstBasicDType::elements() const {
return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements());
}
bool AstBasicDType::littleEndian() const {
return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian());
}
bool AstActive::hasInitial() const { return m_sensesp->hasInitial(); }
bool AstActive::hasSettle() const { return m_sensesp->hasSettle(); }
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp)
: ASTGEN_SUPER_ElabDisplay(fl) {
addFmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp});
m_displayType = dispType;
}
AstCStmt::AstCStmt(FileLine* fl, const string& textStmt)
: ASTGEN_SUPER_CStmt(fl) {
addExprsp(new AstText{fl, textStmt, true});
}
AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut)
: ASTGEN_SUPER_CMath(fl)
, m_cleanOut{cleanOut}
, m_pure{true} {
addExprsp(new AstText{fl, textStmt, true});
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {}
// This form only allowed post-link (see above)
AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) {
varScopep(varscp);
}
bool AstVarRef::same(const AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep() && access() == samep->access());
} else {
return (selfPointer() == samep->selfPointer() && varp()->name() == samep->varp()->name()
&& access() == samep->access());
}
}
bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep());
} else {
return (selfPointer() == samep->selfPointer()
&& (!selfPointer().empty() || !samep->selfPointer().empty())
&& varp()->name() == samep->varp()->name());
}
}
AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access)
, m_dotted{dotted} {
dtypeFrom(varp); dtypeFrom(varp);
} }
inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); }
inline int AstNodeArrayDType::left() const { return rangep()->leftConst(); }
inline int AstNodeArrayDType::right() const { return rangep()->rightConst(); }
inline int AstNodeArrayDType::hi() const { return rangep()->hiConst(); }
inline int AstNodeArrayDType::lo() const { return rangep()->loConst(); }
inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; }
inline void AstIfaceRefDType::cloneRelink() {
if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep();
if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep();
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep();
}
#endif // Guard #endif // Guard

1256
src/V3AstNodeDType.h Normal file

File diff suppressed because it is too large Load Diff

4287
src/V3AstNodeMath.h Normal file

File diff suppressed because it is too large Load Diff

4133
src/V3AstNodeOther.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
#include "V3PartitionGraph.h" // Just for mtask dumping #include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3String.h" #include "V3String.h"
#include "V3AstNodes__gen_macros.h" // Generated by 'astgen' #include "V3Ast__gen_macros.h" // Generated by 'astgen'
#include <iomanip> #include <iomanip>
#include <iterator> #include <iterator>
@ -155,6 +155,51 @@ void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Numb
} }
} }
void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
AstRange* rangep) {
// wantwidth=0 means figure it out, but if a widthmin is >=0
// we allow width 0 so that {{0{x}},y} works properly
// wantwidthmin=-1: default, use wantwidth if it is non zero
m.m_keyword = kwd;
// Implicitness: // "parameter X" is implicit and sized from initial
// value, "parameter reg x" not
if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) {
if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC;
}
if (numer == VSigning::NOSIGN) {
if (keyword().isSigned()) {
numer = VSigning::SIGNED;
} else if (keyword().isUnsigned()) {
numer = VSigning::UNSIGNED;
}
}
numeric(numer);
if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width
if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false);
const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth;
widthForce(wantwidth, wmin);
} else if (!rangep) { // Set based on keyword properties
// V3Width will pull from this width
if (keyword().width() > 1 && !isOpaque()) {
m.m_nrange.init(keyword().width() - 1, 0, false);
}
widthForce(keyword().width(), keyword().width());
} else {
widthForce(rangep->elementsConst(),
rangep->elementsConst()); // Maybe unknown if parameters underneath it
}
this->rangep(rangep);
this->dtypep(this);
}
void AstBasicDType::cvtRangeConst() {
if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) {
m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()};
rangep()->unlinkFrBackWithNext()->deleteTree();
rangep(nullptr);
}
}
int AstBasicDType::widthAlignBytes() const { int AstBasicDType::widthAlignBytes() const {
if (width() <= 8) { if (width() <= 8) {
return 1; return 1;
@ -519,11 +564,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
return dpiTypesToStringConverter{}.convert(this); return dpiTypesToStringConverter{}.convert(this);
} else { } else {
class converter final : public dpiTypesToStringConverter { class converter final : public dpiTypesToStringConverter {
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override { string bitLogicVector(const AstVar* varp, bool isBit) const override {
return string(varp->isReadOnly() ? "const " : "") return string(varp->isReadOnly() ? "const " : "")
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*'; + dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
} }
virtual string primitive(const AstVar* varp) const override { string primitive(const AstVar* varp) const override {
string type = dpiTypesToStringConverter::primitive(varp); string type = dpiTypesToStringConverter::primitive(varp);
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) { if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
if (!varp->isWritable() && varp->basicp()->keyword() != VBasicDTypeKwd::STRING) if (!varp->isWritable() && varp->basicp()->keyword() != VBasicDTypeKwd::STRING)
@ -555,16 +600,16 @@ string AstVar::dpiTmpVarType(const string& varName) const {
return ""; return "";
} }
} }
virtual string openArray(const AstVar* varp) const override { string openArray(const AstVar* varp) const override {
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
+ arraySuffix(varp, 0); + arraySuffix(varp, 0);
} }
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override { string bitLogicVector(const AstVar* varp, bool isBit) const override {
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit); string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
type += ' ' + m_name + arraySuffix(varp, varp->widthWords()); type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
return type; return type;
} }
virtual string primitive(const AstVar* varp) const override { string primitive(const AstVar* varp) const override {
string type = dpiTypesToStringConverter::primitive(varp); string type = dpiTypesToStringConverter::primitive(varp);
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) { if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
if (!varp->isWritable() && varp->basicp()->keyword() == VBasicDTypeKwd::CHANDLE) if (!varp->isWritable() && varp->basicp()->keyword() == VBasicDTypeKwd::CHANDLE)
@ -615,29 +660,21 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
} else { } else {
return nullptr; return nullptr;
} }
} else if (VN_IS(nodep, VarRef)) { } else if (AstVarRef* const vrefp = VN_CAST(nodep, VarRef)) {
if (VN_AS(nodep, VarRef)->varp()->isSc()) { if (vrefp->varp()->isSc()) {
return VN_AS(nodep, VarRef)->varp(); return vrefp->varp();
} else { } else {
return nullptr; return nullptr;
} }
} else if (VN_IS(nodep, ArraySel)) { } else if (AstArraySel* const arraySelp = VN_CAST(nodep, ArraySel)) {
if (nodep->op1p()) { if (AstVar* const p = scVarRecurse(arraySelp->fromp())) return p;
if (AstVar* p = scVarRecurse(nodep->op1p())) return p; if (AstVar* const p = scVarRecurse(arraySelp->bitp())) return p;
}
if (nodep->op2p()) {
if (AstVar* p = scVarRecurse(nodep->op2p())) return p;
}
if (nodep->op3p()) {
if (AstVar* p = scVarRecurse(nodep->op3p())) return p;
}
if (nodep->op4p()) {
if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
}
} }
return nullptr; return nullptr;
} }
bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
class AstNodeDType::CTypeRecursed final { class AstNodeDType::CTypeRecursed final {
public: public:
string m_type; // The base type, e.g.: "Foo_t"s string m_type; // The base type, e.g.: "Foo_t"s
@ -1023,8 +1060,13 @@ AstConstPool::AstConstPool(FileLine* fl)
: ASTGEN_SUPER_ConstPool(fl) : ASTGEN_SUPER_ConstPool(fl)
, m_modp{new AstModule(fl, "@CONST-POOL@")} , m_modp{new AstModule(fl, "@CONST-POOL@")}
, m_scopep{new AstScope(fl, m_modp, "@CONST-POOL@", nullptr, nullptr)} { , m_scopep{new AstScope(fl, m_modp, "@CONST-POOL@", nullptr, nullptr)} {
addOp1p(m_modp); this->modulep(m_modp);
m_modp->addStmtp(m_scopep); m_modp->addStmtsp(m_scopep);
}
const char* AstConstPool::broken() const {
BROKEN_RTN(m_modp && !m_modp->brokeExists());
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
return nullptr;
} }
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) { AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
@ -1033,9 +1075,9 @@ AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
varp->isConst(true); varp->isConst(true);
varp->isStatic(true); varp->isStatic(true);
varp->valuep(initp->cloneTree(false)); varp->valuep(initp->cloneTree(false));
m_modp->addStmtp(varp); m_modp->addStmtsp(varp);
AstVarScope* const varScopep = new AstVarScope(fl, m_scopep, varp); AstVarScope* const varScopep = new AstVarScope(fl, m_scopep, varp);
m_scopep->addVarp(varScopep); m_scopep->addVarsp(varScopep);
return varScopep; return varScopep;
} }
@ -1181,7 +1223,7 @@ void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
} else if (belowp == condp()) { } else if (belowp == condp()) {
// Goes before condition, IE in preconditions // Goes before condition, IE in preconditions
addPrecondsp(newp); addPrecondsp(newp);
} else if (belowp == bodysp()) { } else if (belowp == stmtsp()) {
// Was first statement in body, so new front // Was first statement in body, so new front
belowp->addHereThisAsNext(newp); belowp->addHereThisAsNext(newp);
} else { } else {
@ -1198,12 +1240,12 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
belowp->addNextHere(newp); belowp->addNextHere(newp);
} else if (belowp == condp()) { } else if (belowp == condp()) {
// Becomes first statement in body, body may have been empty // Becomes first statement in body, body may have been empty
if (bodysp()) { if (stmtsp()) {
bodysp()->addHereThisAsNext(newp); stmtsp()->addHereThisAsNext(newp);
} else { } else {
addBodysp(newp); addStmtsp(newp);
} }
} else if (belowp == bodysp()) { } else if (belowp == stmtsp()) {
// Next statement in body // Next statement in body
belowp->addNextHere(newp); belowp->addNextHere(newp);
} else { } else {
@ -1224,10 +1266,10 @@ static std::string nodeAddr(const AstNode* nodep) {
} }
void AstNode::dump(std::ostream& str) const { void AstNode::dump(std::ostream& str) const {
str << typeName() << " " str << typeName() << " " << nodeAddr(this)
<< nodeAddr(this) #ifdef VL_DEBUG
//<< " " << nodeAddr(m_backp)
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">") << " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
#endif
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
<< fileline()->firstColumnLetters() << "}"; << fileline()->firstColumnLetters() << "}";
if (user1p()) str << " u1=" << nodeAddr(user1p()); if (user1p()) str << " u1=" << nodeAddr(user1p());
@ -1297,11 +1339,19 @@ void AstCell::dump(std::ostream& str) const {
str << " ->UNLINKED:" << modName(); str << " ->UNLINKED:" << modName();
} }
} }
const char* AstCell::broken() const {
BROKEN_RTN(m_modp && !m_modp->brokeExists());
return nullptr;
}
void AstCellInline::dump(std::ostream& str) const { void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " -> " << origModName(); str << " -> " << origModName();
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]"; str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
} }
const char* AstCellInline::broken() const {
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
return nullptr;
}
const char* AstClassPackage::broken() const { const char* AstClassPackage::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken()); BROKEN_BASE_RTN(AstNodeModule::broken());
BROKEN_RTN(m_classp && !m_classp->brokeExists()); BROKEN_RTN(m_classp && !m_classp->brokeExists());
@ -1346,6 +1396,17 @@ void AstClass::dump(std::ostream& str) const {
if (isExtended()) str << " [EXT]"; if (isExtended()) str << " [EXT]";
if (isVirtual()) str << " [VIRT]"; if (isVirtual()) str << " [VIRT]";
} }
const char* AstClass::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
void AstClass::cloneRelink() {
AstNodeModule::cloneRelink();
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
m_classOrPackagep = m_classOrPackagep->clonep();
}
}
AstClass* AstClassExtends::classp() const { AstClass* AstClassExtends::classp() const {
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.' if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
@ -1368,6 +1429,18 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str); this->AstNodeDType::dumpSmall(str);
str << "class:" << name(); str << "class:" << name();
} }
const char* AstClassRefDType::broken() const {
BROKEN_RTN(m_classp && !m_classp->brokeExists());
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
void AstClassRefDType::cloneRelink() {
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
m_classOrPackagep = m_classOrPackagep->clonep();
}
}
string AstClassRefDType::name() const { return classp() ? classp()->name() : "<unlinked>"; }
void AstNodeCoverOrAssert::dump(std::ostream& str) const { void AstNodeCoverOrAssert::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeStmt::dump(str);
if (immediate()) str << " [IMMEDIATE]"; if (immediate()) str << " [IMMEDIATE]";
@ -1385,6 +1458,11 @@ void AstEnumItemRef::dump(std::ostream& str) const {
str << "UNLINKED"; str << "UNLINKED";
} }
} }
const char* AstEnumItemRef::broken() const {
BROKEN_RTN(m_itemp && !m_itemp->brokeExists());
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
void AstIfaceRefDType::dump(std::ostream& str) const { void AstIfaceRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str); this->AstNodeDType::dump(str);
if (cellName() != "") str << " cell=" << cellName(); if (cellName() != "") str << " cell=" << cellName();
@ -1404,6 +1482,11 @@ void AstIfaceRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str); this->AstNodeDType::dumpSmall(str);
str << "iface"; str << "iface";
} }
void AstIfaceRefDType::cloneRelink() {
if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep();
if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep();
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep();
}
void AstInitArray::dump(std::ostream& str) const { void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
int n = 0; int n = 0;
@ -1416,6 +1499,42 @@ void AstInitArray::dump(std::ostream& str) const {
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second); str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
} }
} }
const char* AstInitArray::broken() const {
for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
BROKEN_RTN(!it->second);
BROKEN_RTN(!it->second->brokeExists());
}
return nullptr;
}
void AstInitArray::cloneRelink() {
for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
if (it->second->clonep()) it->second = it->second->clonep();
}
}
void AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) {
const auto it = m_map.find(index);
if (it != m_map.end()) {
it->second->valuep(newp);
} else {
AstInitItem* const itemp = new AstInitItem(fileline(), newp);
m_map.emplace(index, itemp);
addInitsp(itemp);
}
}
AstNode* AstInitArray::getIndexValuep(uint64_t index) const {
const auto it = m_map.find(index);
if (it == m_map.end()) {
return nullptr;
} else {
return it->second->valuep();
}
}
AstNode* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
AstNode* valuep = getIndexValuep(index);
if (!valuep) valuep = defaultp();
return valuep;
}
void AstJumpGo::dump(std::ostream& str) const { void AstJumpGo::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeStmt::dump(str);
str << " -> "; str << " -> ";
@ -1425,6 +1544,13 @@ void AstJumpGo::dump(std::ostream& str) const {
str << "%Error:UNLINKED"; str << "%Error:UNLINKED";
} }
} }
const char* AstJumpGo::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return nullptr;
}
void AstJumpGo::cloneRelink() {
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
}
void AstJumpLabel::dump(std::ostream& str) const { void AstJumpLabel::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeStmt::dump(str);
str << " -> "; str << " -> ";
@ -1447,6 +1573,13 @@ void AstMemberSel::dump(std::ostream& str) const {
str << "%Error:UNLINKED"; str << "%Error:UNLINKED";
} }
} }
void AstMemberSel::cloneRelink() {
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
}
const char* AstMemberSel::broken() const {
BROKEN_RTN(m_varp && !m_varp->brokeExists());
return nullptr;
}
void AstMethodCall::dump(std::ostream& str) const { void AstMethodCall::dump(std::ostream& str) const {
this->AstNodeFTaskRef::dump(str); this->AstNodeFTaskRef::dump(str);
if (isStatement()) str << " [STMT]"; if (isStatement()) str << " [STMT]";
@ -1468,6 +1601,13 @@ void AstModportFTaskRef::dump(std::ostream& str) const {
str << " -> UNLINKED"; str << " -> UNLINKED";
} }
} }
const char* AstModportFTaskRef::broken() const {
BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists());
return nullptr;
}
void AstModportFTaskRef::cloneRelink() {
if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep();
}
void AstModportVarRef::dump(std::ostream& str) const { void AstModportVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (direction().isAny()) str << " " << direction(); if (direction().isAny()) str << " " << direction();
@ -1478,6 +1618,13 @@ void AstModportVarRef::dump(std::ostream& str) const {
str << " -> UNLINKED"; str << " -> UNLINKED";
} }
} }
const char* AstModportVarRef::broken() const {
BROKEN_RTN(m_varp && !m_varp->brokeExists());
return nullptr;
}
void AstModportVarRef::cloneRelink() {
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
}
void AstPin::dump(std::ostream& str) const { void AstPin::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (modVarp()) { if (modVarp()) {
@ -1488,6 +1635,17 @@ void AstPin::dump(std::ostream& str) const {
} }
if (svImplicit()) str << " [.SV]"; if (svImplicit()) str << " [.SV]";
} }
const char* AstPin::broken() const {
BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists());
BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists());
return nullptr;
}
string AstPin::prettyOperatorName() const {
return modVarp()
? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " : "")
+ "port connection " + modVarp()->prettyNameQ())
: "port connection";
}
void AstPrintTimeScale::dump(std::ostream& str) const { void AstPrintTimeScale::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeStmt::dump(str);
str << " " << timeunit(); str << " " << timeunit();
@ -1533,6 +1691,23 @@ void AstRefDType::dump(std::ostream& str) const {
str << " -> UNLINKED"; str << " -> UNLINKED";
} }
} }
const char* AstRefDType::broken() const {
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
void AstRefDType::cloneRelink() {
if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep();
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
m_classOrPackagep = m_classOrPackagep->clonep();
}
}
AstNodeDType* AstRefDType::subDTypep() const {
if (typedefp()) return typedefp()->subDTypep();
return refDTypep(); // Maybe nullptr
}
void AstNodeUOrStructDType::dump(std::ostream& str) const { void AstNodeUOrStructDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str); this->AstNodeDType::dump(str);
if (packed()) str << " [PACKED]"; if (packed()) str << " [PACKED]";
@ -1603,6 +1778,32 @@ void AstNetlist::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " [" << timeunit() << "/" << timeprecision() << "]"; str << " [" << timeunit() << "/" << timeprecision() << "]";
} }
const char* AstNetlist::broken() const {
BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists());
BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists());
BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists());
BROKEN_RTN(m_evalp && !m_evalp->brokeExists());
BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists());
BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists());
return nullptr;
}
AstPackage* AstNetlist::dollarUnitPkgAddp() {
if (!m_dollarUnitPkgp) {
m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName());
// packages are always libraries; don't want to make them a "top"
m_dollarUnitPkgp->inLibrary(true);
m_dollarUnitPkgp->modTrace(false); // may reconsider later
m_dollarUnitPkgp->internal(true);
addModulesp(m_dollarUnitPkgp);
}
return m_dollarUnitPkgp;
}
void AstNetlist::createTopScope(AstScope* scopep) {
UASSERT(scopep, "Must not be nullptr");
UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits");
m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep};
scopep->modp()->addStmtsp(v3Global.rootp()->topScopep());
}
void AstNodeModule::dump(std::ostream& str) const { void AstNodeModule::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " L" << level(); str << " L" << level();
@ -1620,10 +1821,24 @@ void AstPackageExport::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " -> " << packagep(); str << " -> " << packagep();
} }
const char* AstPackageExport ::broken() const {
BROKEN_RTN(!m_packagep || !m_packagep->brokeExists());
return nullptr;
}
void AstPackageExport::cloneRelink() {
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
}
void AstPackageImport::dump(std::ostream& str) const { void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " -> " << packagep(); str << " -> " << packagep();
} }
const char* AstPackageImport::broken() const {
BROKEN_RTN(!m_packagep || !m_packagep->brokeExists());
return nullptr;
}
void AstPackageImport::cloneRelink() {
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
}
void AstPatMember::dump(std::ostream& str) const { void AstPatMember::dump(std::ostream& str) const {
this->AstNodeMath::dump(str); this->AstNodeMath::dump(str);
if (isDefault()) str << " [DEFAULT]"; if (isDefault()) str << " [DEFAULT]";
@ -1650,7 +1865,7 @@ void AstTypeTable::dump(std::ostream& str) const {
for (int i = 0; i < static_cast<int>(VBasicDTypeKwd::_ENUM_MAX); ++i) { for (int i = 0; i < static_cast<int>(VBasicDTypeKwd::_ENUM_MAX); ++i) {
if (AstBasicDType* const subnodep = m_basicps[i]) { if (AstBasicDType* const subnodep = m_basicps[i]) {
str << '\n'; // Newline from caller, so newline first str << '\n'; // Newline from caller, so newline first
str << "\t\t" << std::setw(8) << VBasicDTypeKwd(i).ascii(); str << "\t\t" << std::setw(8) << VBasicDTypeKwd{i}.ascii();
str << " -> "; str << " -> ";
subnodep->dump(str); subnodep->dump(str);
} }
@ -1691,10 +1906,30 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str); this->AstNodeDType::dumpSmall(str);
str << "[*]"; str << "[*]";
} }
bool AstWildcardArrayDType::same(const AstNode* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstWildcardArrayDType::similarDType(AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const { void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str); this->AstNodeDType::dumpSmall(str);
str << "[]"; str << "[]";
} }
bool AstUnsizedArrayDType::same(const AstNode* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstUnsizedArrayDType::similarDType(AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const { void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str); this->AstNodeDType::dumpSmall(str);
str << "emptyq"; str << "emptyq";
@ -1742,6 +1977,9 @@ void AstVarRef::dump(std::ostream& str) const {
str << "UNLINKED"; str << "UNLINKED";
} }
} }
bool AstVarRef::same(const AstNode* samep) const {
return same(static_cast<const AstVarRef*>(samep));
}
void AstVar::dump(std::ostream& str) const { void AstVar::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (isSc()) str << " [SC]"; if (isSc()) str << " [SC]";
@ -1786,6 +2024,10 @@ void AstSenItem::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " [" << edgeType().ascii() << "]"; str << " [" << edgeType().ascii() << "]";
} }
void AstStrengthSpec::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")";
}
void AstParseRef::dump(std::ostream& str) const { void AstParseRef::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " [" << expect().ascii() << "]"; str << " [" << expect().ascii() << "]";
@ -1800,6 +2042,13 @@ void AstClassOrPackageRef::dump(std::ostream& str) const {
str << "UNLINKED"; str << "UNLINKED";
} }
} }
AstNodeModule* AstClassOrPackageRef::classOrPackagep() const {
AstNode* foundp = m_classOrPackageNodep;
while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp();
return VN_CAST(foundp, NodeModule);
}
void AstDot::dump(std::ostream& str) const { void AstDot::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (colon()) str << " [::]"; if (colon()) str << " [::]";
@ -1813,6 +2062,16 @@ void AstActive::dump(std::ostream& str) const {
str << "UNLINKED"; str << "UNLINKED";
} }
} }
const char* AstActive::broken() const {
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
return nullptr;
}
void AstActive::cloneRelink() {
if (m_sensesp->clonep()) {
m_sensesp = m_sensesp->clonep();
UASSERT(m_sensesp, "Bad clone cross link: " << this);
}
}
void AstNodeFTaskRef::dump(std::ostream& str) const { void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeStmt::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
@ -1916,6 +2175,14 @@ void AstCFunc::dump(std::ostream& str) const {
if (isDestructor()) str << " [DTOR]"; if (isDestructor()) str << " [DTOR]";
if (isVirtual()) str << " [VIRT]"; if (isVirtual()) str << " [VIRT]";
} }
const char* AstCFunc::broken() const {
BROKEN_RTN((m_scopep && !m_scopep->brokeExists()));
return nullptr;
}
void AstCFunc::cloneRelink() {
if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep();
}
void AstCUse::dump(std::ostream& str) const { void AstCUse::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " [" << useType() << "]"; str << " [" << useType() << "]";

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,7 @@ class AstUserAllocatorBase VL_NOT_FINAL {
private: private:
std::vector<T_Data*> m_allocated; std::vector<T_Data*> m_allocated;
inline T_Data* getUserp(const T_Node* nodep) const { T_Data* getUserp(const T_Node* nodep) const {
if VL_CONSTEXPR_CXX17 (T_UserN == 1) { if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
const VNUser user = nodep->user1u(); const VNUser user = nodep->user1u();
return user.to<T_Data*>(); return user.to<T_Data*>();
@ -54,17 +54,17 @@ private:
} }
} }
inline void setUserp(T_Node* nodep, T_Data* userp) const { void setUserp(T_Node* nodep, T_Data* userp) const {
if VL_CONSTEXPR_CXX17 (T_UserN == 1) { if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
nodep->user1u(VNUser(userp)); nodep->user1u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) { } else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
nodep->user2u(VNUser(userp)); nodep->user2u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) { } else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
nodep->user3u(VNUser(userp)); nodep->user3u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) { } else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
nodep->user4u(VNUser(userp)); nodep->user4u(VNUser{userp});
} else { } else {
nodep->user5u(VNUser(userp)); nodep->user5u(VNUser{userp});
} }
} }

View File

@ -35,6 +35,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class BeginState final { class BeginState final {
@ -70,7 +72,6 @@ private:
int m_ifDepth = 0; // Current if depth int m_ifDepth = 0; // Current if depth
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
string dot(const string& a, const string& b) { string dot(const string& a, const string& b) {
if (a == "") return b; if (a == "") return b;
@ -85,7 +86,7 @@ private:
string::size_type pos; string::size_type pos;
while ((pos = dottedname.find("__DOT__")) != string::npos) { while ((pos = dottedname.find("__DOT__")) != string::npos) {
const string ident = dottedname.substr(0, pos); const string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__")); dottedname = dottedname.substr(pos + std::strlen("__DOT__"));
if (nodep->name() != "") { if (nodep->name() != "") {
m_displayScope = dot(m_displayScope, ident); m_displayScope = dot(m_displayScope, ident);
m_namedScope = dot(m_namedScope, ident); m_namedScope = dot(m_namedScope, ident);
@ -115,19 +116,19 @@ private:
} }
} else { } else {
// Move to module // Move to module
m_modp->addStmtp(nodep); m_modp->addStmtsp(nodep);
} }
} }
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
m_modp = nodep; m_modp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
UINFO(8, " " << nodep << endl); UINFO(8, " " << nodep << endl);
// Rename it // Rename it
if (m_unnamedScope != "") { if (m_unnamedScope != "") {
@ -162,7 +163,7 @@ private:
m_ftaskp = nullptr; m_ftaskp = nullptr;
} }
} }
virtual void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete // Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep << endl); UINFO(8, " " << nodep << endl);
VL_RESTORER(m_displayScope); VL_RESTORER(m_displayScope);
@ -177,11 +178,7 @@ private:
AstNode* addsp = nullptr; AstNode* addsp = nullptr;
if (AstNode* const stmtsp = nodep->stmtsp()) { if (AstNode* const stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext(); stmtsp->unlinkFrBackWithNext();
if (addsp) { addsp = AstNode::addNext(addsp, stmtsp);
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
}
} }
if (addsp) { if (addsp) {
nodep->replaceWith(addsp); nodep->replaceWith(addsp);
@ -191,7 +188,7 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
if (m_unnamedScope != "") { if (m_unnamedScope != "") {
// Rename it // Rename it
nodep->name(dot(m_unnamedScope, nodep->name())); nodep->name(dot(m_unnamedScope, nodep->name()));
@ -200,7 +197,7 @@ private:
liftNode(nodep); liftNode(nodep);
} }
} }
virtual void visit(AstTypedef* nodep) override { void visit(AstTypedef* nodep) override {
if (m_unnamedScope != "") { if (m_unnamedScope != "") {
// Rename it // Rename it
nodep->name(dot(m_unnamedScope, nodep->name())); nodep->name(dot(m_unnamedScope, nodep->name()));
@ -209,7 +206,7 @@ private:
liftNode(nodep); liftNode(nodep);
} }
} }
virtual void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
UINFO(8, " CELL " << nodep << endl); UINFO(8, " CELL " << nodep << endl);
if (m_namedScope != "") { if (m_namedScope != "") {
m_statep->userMarkChanged(nodep); m_statep->userMarkChanged(nodep);
@ -218,18 +215,18 @@ private:
UINFO(8, " rename to " << nodep->name() << endl); UINFO(8, " rename to " << nodep->name() << endl);
// Move to module // Move to module
nodep->unlinkFrBack(); nodep->unlinkFrBack();
m_modp->addStmtp(nodep); m_modp->addStmtsp(nodep);
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstVarXRef* nodep) override { void visit(AstVarXRef* nodep) override {
UINFO(9, " VARXREF " << nodep << endl); UINFO(9, " VARXREF " << nodep << endl);
if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) { if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) {
nodep->inlinedDots(m_namedScope); nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to " << nodep << endl); UINFO(9, " rescope to " << nodep << endl);
} }
} }
virtual void visit(AstScopeName* nodep) override { void visit(AstScopeName* nodep) override {
// If there's a %m in the display text, we add a special node that will contain the name() // If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline // Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's if (nodep->user1SetOnce()) return; // Don't double-add text's
@ -237,20 +234,20 @@ private:
const string scname = nodep->forFormat() ? m_displayScope : m_namedScope; const string scname = nodep->forFormat() ? m_displayScope : m_namedScope;
if (!scname.empty()) { if (!scname.empty()) {
// To keep correct visual order, must add before other Text's // To keep correct visual order, must add before other Text's
AstNode* const afterp = nodep->scopeAttrp(); AstText* const afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext(); if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname}); nodep->addScopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
if (afterp) nodep->scopeAttrp(afterp); if (afterp) nodep->addScopeAttrp(afterp);
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstCoverDecl* nodep) override { void visit(AstCoverDecl* nodep) override {
// Don't need to fix path in coverage statements, they're not under // Don't need to fix path in coverage statements, they're not under
// any BEGINs, but V3Coverage adds them all under the module itself. // any BEGINs, but V3Coverage adds them all under the module itself.
iterateChildren(nodep); iterateChildren(nodep);
} }
// VISITORS - LINT CHECK // VISITORS - LINT CHECK
virtual void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered
// Check IFDEPTH warning - could be in other transform files if desire // Check IFDEPTH warning - could be in other transform files if desire
VL_RESTORER(m_ifDepth); VL_RESTORER(m_ifDepth);
if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off
@ -264,7 +261,7 @@ private:
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -272,7 +269,7 @@ public:
: m_statep{statep} { : m_statep{statep} {
iterate(nodep); iterate(nodep);
} }
virtual ~BeginVisitor() override = default; ~BeginVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -285,21 +282,21 @@ private:
// AstNodeFTask::user1p // Node replaced, rename it // AstNodeFTask::user1p // Node replaced, rename it
// VISITORS // VISITORS
virtual void visit(AstNodeFTaskRef* nodep) override { void visit(AstNodeFTaskRef* nodep) override {
if (nodep->taskp()->user1()) { // It was converted if (nodep->taskp()->user1()) { // It was converted
UINFO(9, " relinkFTask " << nodep << endl); UINFO(9, " relinkFTask " << nodep << endl);
nodep->name(nodep->taskp()->name()); nodep->name(nodep->taskp()->name());
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
if (nodep->varp()->user1()) { // It was converted if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef " << nodep << endl); UINFO(9, " relinVarRef " << nodep << endl);
nodep->name(nodep->varp()->name()); nodep->name(nodep->varp()->name());
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstIfaceRefDType* nodep) override { void visit(AstIfaceRefDType* nodep) override {
// May have changed cell names // May have changed cell names
// TypeTable is always after all modules, so names are stable // TypeTable is always after all modules, so names are stable
UINFO(8, " IFACEREFDTYPE " << nodep << endl); UINFO(8, " IFACEREFDTYPE " << nodep << endl);
@ -308,12 +305,12 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); } BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
virtual ~BeginRelinkVisitor() override = default; ~BeginRelinkVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -326,5 +323,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
{ BeginVisitor{nodep, &state}; } { BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; } if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("begin", 0, dumpTree() >= 3);
} }

View File

@ -33,6 +33,8 @@
#include <map> #include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Branch state, as a visitor of each AstNode // Branch state, as a visitor of each AstNode
@ -49,7 +51,6 @@ private:
std::vector<AstCFunc*> m_cfuncsp; // List of all tasks std::vector<AstCFunc*> m_cfuncsp; // List of all tasks
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void reset() { void reset() {
m_likely = false; m_likely = false;
@ -63,14 +64,14 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
UINFO(4, " IF: " << nodep << endl); UINFO(4, " IF: " << nodep << endl);
VL_RESTORER(m_likely); VL_RESTORER(m_likely);
VL_RESTORER(m_unlikely); VL_RESTORER(m_unlikely);
{ {
// Do if // Do if
reset(); reset();
iterateAndNextNull(nodep->ifsp()); iterateAndNextNull(nodep->thensp());
const int ifLikely = m_likely; const int ifLikely = m_likely;
const int ifUnlikely = m_unlikely; const int ifUnlikely = m_unlikely;
// Do else // Do else
@ -87,17 +88,17 @@ private:
} // else leave unknown } // else leave unknown
} }
} }
virtual void visit(AstNodeCCall* nodep) override { void visit(AstNodeCCall* nodep) override {
checkUnlikely(nodep); checkUnlikely(nodep);
nodep->funcp()->user1Inc(); nodep->funcp()->user1Inc();
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
checkUnlikely(nodep); checkUnlikely(nodep);
m_cfuncsp.push_back(nodep); m_cfuncsp.push_back(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
checkUnlikely(nodep); checkUnlikely(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
@ -116,7 +117,7 @@ public:
iterateChildren(nodep); iterateChildren(nodep);
calc_tasks(); calc_tasks();
} }
virtual ~BranchVisitor() override = default; ~BranchVisitor() override = default;
}; };
//###################################################################### //######################################################################

View File

@ -36,6 +36,8 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Generation counter for AstNode::m_brokenState // Generation counter for AstNode::m_brokenState
@ -132,8 +134,8 @@ private:
public: public:
// METHODS // METHODS
void clear() { m_linkable.clear(); } void clear() { m_linkable.clear(); }
inline void addLinkable(const AstNode* nodep) { m_linkable.emplace(nodep); } void addLinkable(const AstNode* nodep) { m_linkable.emplace(nodep); }
inline bool isLinkable(const AstNode* nodep) const { return m_linkable.count(nodep) != 0; } bool isLinkable(const AstNode* nodep) const { return m_linkable.count(nodep) != 0; }
} s_linkableTable; } s_linkableTable;
bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinkable(nodep); } bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinkable(nodep); }
@ -214,27 +216,27 @@ private:
} }
return false; return false;
} }
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
processAndIterate(nodep); processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue() UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef) && VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()), && !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
nodep, "Assignment LHS is not an lvalue"); nodep, "Assignment LHS is not an lvalue");
} }
virtual void visit(AstRelease* nodep) override { void visit(AstRelease* nodep) override {
processAndIterate(nodep); processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && VN_IS(nodep->lhsp(), NodeVarRef) UASSERT_OBJ(!(v3Global.assertDTypesResolved() && VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()), && !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
nodep, "Release LHS is not an lvalue"); nodep, "Release LHS is not an lvalue");
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
VL_RESTORER(m_inScope); VL_RESTORER(m_inScope);
{ {
m_inScope = true; m_inScope = true;
processAndIterate(nodep); processAndIterate(nodep);
} }
} }
virtual void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
processAndIterate(nodep); processAndIterate(nodep);
// m_inScope because some Vars have initial variable references without scopes // m_inScope because some Vars have initial variable references without scopes
// This might false fire with some debug flags, as not certain we don't have temporary // This might false fire with some debug flags, as not certain we don't have temporary
@ -252,7 +254,7 @@ private:
} }
} }
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
UASSERT_OBJ(!m_cfuncp, nodep, "Nested AstCFunc"); UASSERT_OBJ(!m_cfuncp, nodep, "Nested AstCFunc");
m_cfuncp = nodep; m_cfuncp = nodep;
m_localVars.clear(); m_localVars.clear();
@ -270,14 +272,14 @@ private:
m_cfuncp = nullptr; m_cfuncp = nullptr;
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
// Each branch is a separate local variable scope // Each branch is a separate local variable scope
pushLocalScope(); pushLocalScope();
processEnter(nodep); processEnter(nodep);
processAndIterate(nodep->condp()); processAndIterate(nodep->condp());
if (AstNode* const ifsp = nodep->ifsp()) { if (AstNode* const thensp = nodep->thensp()) {
pushLocalScope(); pushLocalScope();
processAndIterateList(ifsp); processAndIterateList(thensp);
popLocalScope(); popLocalScope();
} }
if (AstNode* const elsesp = nodep->elsesp()) { if (AstNode* const elsesp = nodep->elsesp()) {
@ -288,21 +290,21 @@ private:
processExit(nodep); processExit(nodep);
popLocalScope(); popLocalScope();
} }
virtual void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
// For local variable checking act as if any statement introduces a new scope. // For local variable checking act as if any statement introduces a new scope.
// This is aggressive but conservatively correct. // This is aggressive but conservatively correct.
pushLocalScope(); pushLocalScope();
processAndIterate(nodep); processAndIterate(nodep);
popLocalScope(); popLocalScope();
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
processAndIterate(nodep); processAndIterate(nodep);
if (m_cfuncp) { if (m_cfuncp) {
m_localVars.insert(nodep); m_localVars.insert(nodep);
m_localsStack.back().insert(nodep); m_localsStack.back().insert(nodep);
} }
} }
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
// Process not just iterate // Process not just iterate
processAndIterate(nodep); processAndIterate(nodep);
} }
@ -310,7 +312,7 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); } explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenCheckVisitor() override = default; ~BrokenCheckVisitor() override = default;
}; };
//###################################################################### //######################################################################

View File

@ -35,6 +35,8 @@
#include <algorithm> #include <algorithm>
#include <list> #include <list>
VL_DEFINE_DEBUG_FUNCTIONS;
class VCtorType final { class VCtorType final {
public: public:
enum en : uint8_t { MODULE, CLASS, COVERAGE }; enum en : uint8_t { MODULE, CLASS, COVERAGE };
@ -44,7 +46,7 @@ private:
public: public:
// cppcheck-suppress noExplicitConstructor // cppcheck-suppress noExplicitConstructor
inline VCtorType(en _e) constexpr VCtorType(en _e)
: m_e{_e} {} : m_e{_e} {}
bool isClass() const { return m_e == CLASS; } bool isClass() const { return m_e == CLASS; }
bool isCoverage() const { return m_e == COVERAGE; } bool isCoverage() const { return m_e == COVERAGE; }
@ -77,7 +79,7 @@ private:
if (!preventUnusedStmt.empty()) { if (!preventUnusedStmt.empty()) {
funcp->addStmtsp(new AstCStmt{m_modp->fileline(), preventUnusedStmt}); funcp->addStmtsp(new AstCStmt{m_modp->fileline(), preventUnusedStmt});
} }
m_modp->addStmtp(funcp); m_modp->addStmtsp(funcp);
m_numStmts = 0; m_numStmts = 0;
return funcp; return funcp;
} }
@ -136,7 +138,7 @@ void V3CCtors::evalAsserts() {
funcp->isLoose(true); funcp->isLoose(true);
funcp->slow(false); funcp->slow(false);
funcp->ifdef("VL_DEBUG"); funcp->ifdef("VL_DEBUG");
modp->addStmtp(funcp); modp->addStmtsp(funcp);
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* const varp = VN_CAST(np, Var)) { if (AstVar* const varp = VN_CAST(np, Var)) {
if (varp->isPrimaryInish() && !varp->isSc()) { if (varp->isPrimaryInish() && !varp->isSc()) {
@ -209,7 +211,7 @@ void V3CCtors::cctorsAll() {
// If can be referred to by base pointer, need virtual delete // If can be referred to by base pointer, need virtual delete
funcp->isVirtual(classp->isExtended()); funcp->isVirtual(classp->isExtended());
funcp->slow(false); funcp->slow(false);
modp->addStmtp(funcp); modp->addStmtsp(funcp);
} }
} }
} }

View File

@ -32,6 +32,8 @@
#include <set> #include <set>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Visit within a module all nodes and data types they reference, finding // Visit within a module all nodes and data types they reference, finding
@ -51,13 +53,13 @@ class CUseVisitor final : public VNVisitor {
void addNewUse(AstNode* nodep, VUseType useType, const string& name) { void addNewUse(AstNode* nodep, VUseType useType, const string& name) {
if (m_didUse.emplace(useType, name).second) { if (m_didUse.emplace(useType, name).second) {
AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name}; AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name};
m_modp->addStmtp(newp); m_modp->addStmtsp(newp);
UINFO(8, "Insert " << newp << endl); UINFO(8, "Insert " << newp << endl);
} }
} }
// VISITORS // VISITORS
virtual void visit(AstClassRefDType* nodep) override { void visit(AstClassRefDType* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
// Need to include extends() when we implement, but no need for pointers to know // Need to include extends() when we implement, but no need for pointers to know
@ -67,17 +69,17 @@ class CUseVisitor final : public VNVisitor {
iterateChildren(nodep->classp()); // This also gets all extend classes iterateChildren(nodep->classp()); // This also gets all extend classes
} }
} }
virtual void visit(AstNodeDType* nodep) override { void visit(AstNodeDType* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep()); if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep());
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p()); if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
} }
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
if (nodep->dtypep() && !nodep->dtypep()->user1()) iterate(nodep->dtypep()); if (nodep->dtypep() && !nodep->dtypep()->user1()) iterate(nodep->dtypep());
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
// Currently no IMP_INCLUDE because we include __Syms which has them all // Currently no IMP_INCLUDE because we include __Syms which has them all
addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->modp()->name()); addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->modp()->name());
@ -90,7 +92,7 @@ public:
: m_modp(modp) { : m_modp(modp) {
iterate(modp); iterate(modp);
} }
virtual ~CUseVisitor() override = default; ~CUseVisitor() override = default;
VL_UNCOPYABLE(CUseVisitor); VL_UNCOPYABLE(CUseVisitor);
}; };
@ -106,5 +108,5 @@ void V3CUse::cUseAll() {
// for each output file and put under that // for each output file and put under that
CUseVisitor{modp}; CUseVisitor{modp};
} }
V3Global::dumpCheckGlobalTree("cuse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("cuse", 0, dumpTree() >= 3);
} }

View File

@ -45,6 +45,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in #define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant #define CASE_BARF 999999 // Magic width when non-constant
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree #define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
@ -57,9 +59,8 @@ private:
= nullptr; // Under a CASE value node, if so the relevant case statement = nullptr; // Under a CASE value node, if so the relevant case statement
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstNodeCase* nodep) override { void visit(AstNodeCase* nodep) override {
if (VN_IS(nodep, Case) && VN_AS(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)"); nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
} }
@ -86,7 +87,7 @@ private:
m_caseExprp = nullptr; m_caseExprp = nullptr;
} }
} }
virtual void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
// See also neverItem // See also neverItem
if (m_caseExprp && nodep->num().isFourState()) { if (m_caseExprp && nodep->num().isFourState()) {
if (VN_IS(m_caseExprp, GenCase)) { if (VN_IS(m_caseExprp, GenCase)) {
@ -107,12 +108,12 @@ private:
} }
} }
} }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); } explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
virtual ~CaseLintVisitor() override = default; ~CaseLintVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -138,7 +139,6 @@ private:
std::array<AstNode*, 1 << CASE_OVERLAP_WIDTH> m_valueItem; std::array<AstNode*, 1 << CASE_OVERLAP_WIDTH> m_valueItem;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
bool isCaseTreeFast(AstCase* nodep) { bool isCaseTreeFast(AstCase* nodep) {
int width = 0; int width = 0;
@ -245,7 +245,7 @@ private:
// Convert valueItem from AstCaseItem* to the expression // Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch // 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) { for (uint32_t i = 0; i < numCases; ++i) {
m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->bodysp(); m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->stmtsp();
} }
return true; // All is fine return true; // All is fine
} }
@ -346,7 +346,7 @@ private:
itemp = VN_AS(itemp->nextp(), CaseItem)) { itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (!itemp->condsp()) { if (!itemp->condsp()) {
// Default clause. Just make true, we'll optimize it away later // Default clause. Just make true, we'll optimize it away later
itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue())); itemp->addCondsp(new AstConst(itemp->fileline(), AstConst::BitTrue()));
hadDefault = true; hadDefault = true;
} else { } else {
// Expressioned clause // Expressioned clause
@ -397,7 +397,7 @@ private:
} }
} }
// Replace expression in tree // Replace expression in tree
itemp->condsp(ifexprp); itemp->addCondsp(ifexprp);
} }
} }
VL_DO_DANGLING(cexprp->deleteTree(), cexprp); VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
@ -420,7 +420,7 @@ private:
AstIf* itemnextp = nullptr; AstIf* itemnextp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) { itemp = VN_AS(itemp->nextp(), CaseItem)) {
AstNode* const istmtsp = itemp->bodysp(); // Maybe null -- no action. AstNode* const istmtsp = itemp->stmtsp(); // Maybe null -- no action.
if (istmtsp) istmtsp->unlinkFrBackWithNext(); if (istmtsp) istmtsp->unlinkFrBackWithNext();
// Expressioned clause // Expressioned clause
AstNode* const ifexprp = itemp->condsp()->unlinkFrBack(); AstNode* const ifexprp = itemp->condsp()->unlinkFrBack();
@ -452,7 +452,7 @@ private:
if (itemnextp) { if (itemnextp) {
itemnextp->addElsesp(newp); itemnextp->addElsesp(newp);
} else { } else {
groupnextp->addIfsp(newp); // First in a new group groupnextp->addThensp(newp); // First in a new group
} }
itemnextp = newp; itemnextp = newp;
} }
@ -493,7 +493,7 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstCase* nodep) override { void visit(AstCase* nodep) override {
V3Case::caseLint(nodep); V3Case::caseLint(nodep);
iterateChildren(nodep); iterateChildren(nodep);
if (debug() >= 9) nodep->dumpTree(cout, " case_old: "); if (debug() >= 9) nodep->dumpTree(cout, " case_old: ");
@ -510,7 +510,7 @@ private:
} }
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
if (VN_IS(nodep, Always)) m_alwaysp = nodep; if (VN_IS(nodep, Always)) m_alwaysp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
@ -521,7 +521,7 @@ public:
for (auto& itr : m_valueItem) itr = nullptr; for (auto& itr : m_valueItem) itr = nullptr;
iterate(nodep); iterate(nodep);
} }
virtual ~CaseVisitor() override { ~CaseVisitor() override {
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast); V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow); V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
} }
@ -533,7 +533,7 @@ public:
void V3Case::caseAll(AstNetlist* nodep) { void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor{nodep}; } // Destruct before checking { CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("case", 0, dumpTree() >= 3);
} }
void V3Case::caseLint(AstNodeCase* nodep) { void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl); UINFO(4, __FUNCTION__ << ": " << endl);

View File

@ -47,6 +47,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Cast state, as a visitor of each AstNode // Cast state, as a visitor of each AstNode
@ -60,7 +62,6 @@ private:
// STATE // STATE
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
UINFO(4, " NeedCast " << nodep << endl); UINFO(4, " NeedCast " << nodep << endl);
@ -111,25 +112,25 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNodeUniop* nodep) override { void visit(AstNodeUniop* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()); nodep->user1(nodep->lhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
} }
virtual void visit(AstNodeBiop* nodep) override { void visit(AstNodeBiop* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1()); nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
} }
virtual void visit(AstNodeTriop* nodep) override { void visit(AstNodeTriop* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()); nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp()); if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
} }
virtual void visit(AstNodeQuadop* nodep) override { void visit(AstNodeQuadop* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1() nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
| nodep->fhsp()->user1()); | nodep->fhsp()->user1());
@ -138,12 +139,12 @@ private:
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp()); if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp()); if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
} }
virtual void visit(AstCCast* nodep) override { void visit(AstCCast* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureLower32Cast(nodep); ensureLower32Cast(nodep);
nodep->user1(1); nodep->user1(1);
} }
virtual void visit(AstNegate* nodep) override { void visit(AstNegate* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()); nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin() == 1) { if (nodep->lhsp()->widthMin() == 1) {
@ -155,7 +156,7 @@ private:
ensureCast(nodep->lhsp()); ensureCast(nodep->lhsp());
} }
} }
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
const AstNode* const backp = nodep->backp(); const AstNode* const backp = nodep->backp();
if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath) if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath)
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) && backp->width() && !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) && backp->width()
@ -166,7 +167,7 @@ private:
} }
nodep->user1(1); nodep->user1(1);
} }
virtual void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
// Constants are of unknown size if smaller than 33 bits, because // Constants are of unknown size if smaller than 33 bits, because
// we're too lazy to wrap every constant in the universe in // we're too lazy to wrap every constant in the universe in
// ((IData)#). // ((IData)#).
@ -174,29 +175,29 @@ private:
} }
// Null dereference protection // Null dereference protection
virtual void visit(AstNullCheck* nodep) override { void visit(AstNullCheck* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()); nodep->user1(nodep->lhsp()->user1());
} }
virtual void visit(AstCMethodCall* nodep) override { void visit(AstCMethodCall* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureNullChecked(nodep->fromp()); ensureNullChecked(nodep->fromp());
} }
virtual void visit(AstMemberSel* nodep) override { void visit(AstMemberSel* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureNullChecked(nodep->fromp()); ensureNullChecked(nodep->fromp());
} }
// NOPs // NOPs
virtual void visit(AstVar*) override {} void visit(AstVar*) override {}
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); } explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CastVisitor() override = default; ~CastVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -205,5 +206,5 @@ public:
void V3Cast::castAll(AstNetlist* nodep) { void V3Cast::castAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ CastVisitor{nodep}; } // Destruct before checking { CastVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("cast", 0, dumpTree() >= 3);
} }

View File

@ -38,13 +38,14 @@
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
VL_DEFINE_DEBUG_FUNCTIONS;
constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic
//###################################################################### //######################################################################
class CdcBaseVisitor VL_NOT_FINAL : public VNVisitor { class CdcBaseVisitor VL_NOT_FINAL : public VNVisitor {
public: public:
VL_DEBUG_FUNC; // Declare debug()
}; };
//###################################################################### //######################################################################
@ -67,9 +68,9 @@ public:
, m_srcDomainSet{false} , m_srcDomainSet{false}
, m_dstDomainSet{false} , m_dstDomainSet{false}
, m_asyncPath{false} {} , m_asyncPath{false} {}
virtual ~CdcEitherVertex() override = default; ~CdcEitherVertex() override = default;
// ACCESSORS // ACCESSORS
virtual FileLine* fileline() const override { return nodep()->fileline(); } FileLine* fileline() const override { return nodep()->fileline(); }
AstScope* scopep() const { return m_scopep; } AstScope* scopep() const { return m_scopep; }
AstNode* nodep() const { return m_nodep; } AstNode* nodep() const { return m_nodep; }
AstSenTree* srcDomainp() const { return m_srcDomainp; } AstSenTree* srcDomainp() const { return m_srcDomainp; }
@ -93,11 +94,11 @@ public:
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: CdcEitherVertex{graphp, scopep, varScp} : CdcEitherVertex{graphp, scopep, varScp}
, m_varScp{varScp} {} , m_varScp{varScp} {}
virtual ~CdcVarVertex() override = default; ~CdcVarVertex() override = default;
// ACCESSORS // ACCESSORS
AstVarScope* varScp() const { return m_varScp; } AstVarScope* varScp() const { return m_varScp; }
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
virtual string dotColor() const override { string dotColor() const override {
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
} }
int cntAsyncRst() const { return m_cntAsyncRst; } int cntAsyncRst() const { return m_cntAsyncRst; }
@ -118,12 +119,10 @@ public:
srcDomainp(sensenodep); srcDomainp(sensenodep);
dstDomainp(sensenodep); dstDomainp(sensenodep);
} }
virtual ~CdcLogicVertex() override = default; ~CdcLogicVertex() override = default;
// ACCESSORS // ACCESSORS
virtual string name() const override { string name() const override { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); string dotColor() const override { return hazard() ? "black" : "yellow"; }
}
virtual string dotColor() const override { return hazard() ? "black" : "yellow"; }
bool hazard() const { return m_hazard; } bool hazard() const { return m_hazard; }
void setHazard(AstNode* nodep) { void setHazard(AstNode* nodep) {
m_hazard = true; m_hazard = true;
@ -144,7 +143,7 @@ private:
std::ofstream* const m_ofp = nullptr; // Output file std::ofstream* const m_ofp = nullptr; // Output file
string m_prefix; string m_prefix;
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
*m_ofp << m_prefix; *m_ofp << m_prefix;
if (nodep->user3()) { if (nodep->user3()) {
*m_ofp << " %%"; *m_ofp << " %%";
@ -171,7 +170,7 @@ public:
, m_prefix{prefix} { , m_prefix{prefix} {
iterate(nodep); iterate(nodep);
} }
virtual ~CdcDumpVisitor() override = default; ~CdcDumpVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -181,7 +180,7 @@ private:
int m_maxLineno = 0; int m_maxLineno = 0;
size_t m_maxFilenameLen = 0; size_t m_maxFilenameLen = 0;
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// Keeping line+filename lengths separate is much faster than calling ascii().length() // Keeping line+filename lengths separate is much faster than calling ascii().length()
if (nodep->fileline()->lineno() >= m_maxLineno) { if (nodep->fileline()->lineno() >= m_maxLineno) {
@ -195,7 +194,7 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); } explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~CdcWidthVisitor() override = default; ~CdcWidthVisitor() override = default;
// ACCESSORS // ACCESSORS
int maxWidth() const { int maxWidth() const {
size_t width = 1; size_t width = 1;
@ -325,13 +324,11 @@ private:
void analyze() { void analyze() {
UINFO(3, __FUNCTION__ << ": " << endl); UINFO(3, __FUNCTION__ << ": " << endl);
// if (debug() > 6) m_graph.dump(); if (dumpGraph() > 6) m_graph.dumpDotFilePrefixed("cdc_pre");
if (debug() > 6) m_graph.dumpDotFilePrefixed("cdc_pre"); // This will MAX across edge weights
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
// //
m_graph.removeRedundantEdges( if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("cdc_simp");
&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
//
m_graph.dumpDotFilePrefixed("cdc_simp");
// //
analyzeReset(); analyzeReset();
} }
@ -628,21 +625,21 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
m_modp = nodep; m_modp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
UINFO(4, " SCOPE " << nodep << endl); UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep; m_scopep = nodep;
m_logicVertexp = nullptr; m_logicVertexp = nullptr;
iterateChildren(nodep); iterateChildren(nodep);
m_scopep = nullptr; m_scopep = nullptr;
} }
virtual void visit(AstActive* nodep) override { void visit(AstActive* nodep) override {
// Create required blocks and add to module // Create required blocks and add to module
UINFO(4, " BLOCK " << nodep << endl); UINFO(4, " BLOCK " << nodep << endl);
AstNode::user2ClearTree(); AstNode::user2ClearTree();
@ -654,7 +651,7 @@ private:
m_domainp = nullptr; m_domainp = nullptr;
AstNode::user2ClearTree(); AstNode::user2ClearTree();
} }
virtual void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
if (m_scopep) { if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block"); UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* const varscp = nodep->varScopep(); AstVarScope* const varscp = nodep->varScopep();
@ -682,53 +679,53 @@ private:
} }
} }
} }
virtual void visit(AstAssignDly* nodep) override { void visit(AstAssignDly* nodep) override {
m_inDly = true; m_inDly = true;
iterateChildren(nodep); iterateChildren(nodep);
m_inDly = false; m_inDly = false;
} }
virtual void visit(AstSenItem* nodep) override { void visit(AstSenItem* nodep) override {
m_inSenItem = true; m_inSenItem = true;
iterateChildren(nodep); iterateChildren(nodep);
m_inSenItem = false; m_inSenItem = false;
} }
virtual void visit(AstAlways* nodep) override { iterateNewStmt(nodep); } void visit(AstAlways* nodep) override { iterateNewStmt(nodep); }
virtual void visit(AstAlwaysPublic* nodep) override { void visit(AstAlwaysPublic* nodep) override {
// CDC doesn't care about public variables // CDC doesn't care about public variables
} }
virtual void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); } void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); }
virtual void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
virtual void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); } void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); }
// Math that shouldn't cause us to clear hazard // Math that shouldn't cause us to clear hazard
virtual void visit(AstConst*) override {} void visit(AstConst*) override {}
virtual void visit(AstReplicate* nodep) override { iterateChildren(nodep); } void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
virtual void visit(AstConcat* nodep) override { iterateChildren(nodep); } void visit(AstConcat* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNot* nodep) override { iterateChildren(nodep); } void visit(AstNot* nodep) override { iterateChildren(nodep); }
virtual void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep); if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstNodeSel* nodep) override { void visit(AstNodeSel* nodep) override {
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep); if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
// Ignores // Ignores
virtual void visit(AstInitial*) override {} void visit(AstInitial*) override {}
virtual void visit(AstInitialAutomatic*) override {} void visit(AstInitialAutomatic*) override {}
virtual void visit(AstInitialStatic*) override {} void visit(AstInitialStatic*) override {}
virtual void visit(AstTraceDecl*) override {} void visit(AstTraceDecl*) override {}
virtual void visit(AstCoverToggle*) override {} void visit(AstCoverToggle*) override {}
virtual void visit(AstNodeDType*) override {} void visit(AstNodeDType*) override {}
//-------------------- //--------------------
// Default // Default
virtual void visit(AstNodeMath* nodep) override { void visit(AstNodeMath* nodep) override {
setNodeHazard(nodep); setNodeHazard(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -754,7 +751,7 @@ public:
*m_ofp << '\n'; *m_ofp << '\n';
} }
} }
virtual ~CdcVisitor() override { ~CdcVisitor() override {
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
} }
}; };

View File

@ -36,6 +36,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class ChangedState final { class ChangedState final {
@ -67,7 +69,7 @@ public:
m_tlChgFuncp->isStatic(false); m_tlChgFuncp->isStatic(false);
m_tlChgFuncp->isLoose(true); m_tlChgFuncp->isLoose(true);
m_tlChgFuncp->declPrivate(true); m_tlChgFuncp->declPrivate(true);
m_scopetopp->addActivep(m_tlChgFuncp); m_scopetopp->addBlocksp(m_tlChgFuncp);
// Each change detection function needs at least one AstChangeDet // Each change detection function needs at least one AstChangeDet
// to ensure that V3EmitC outputs the necessary code. // to ensure that V3EmitC outputs the necessary code.
maybeCreateMidChg(); maybeCreateMidChg();
@ -86,7 +88,7 @@ public:
m_chgFuncp->isStatic(false); m_chgFuncp->isStatic(false);
m_chgFuncp->isLoose(true); m_chgFuncp->isLoose(true);
m_chgFuncp->declPrivate(true); m_chgFuncp->declPrivate(true);
m_scopetopp->addActivep(m_chgFuncp); m_scopetopp->addBlocksp(m_chgFuncp);
// Add a top call to it // Add a top call to it
AstCCall* const callp = new AstCCall{m_scopetopp->fileline(), m_chgFuncp}; AstCCall* const callp = new AstCCall{m_scopetopp->fileline(), m_chgFuncp};
@ -155,13 +157,13 @@ private:
m_state.m_numStmts += initp->nodeCount() + m_varEqnp->widthWords(); m_state.m_numStmts += initp->nodeCount() + m_varEqnp->widthWords();
} }
virtual void visit(AstBasicDType*) override { // void visit(AstBasicDType*) override { //
newChangeDet(); newChangeDet();
} }
virtual void visit(AstPackArrayDType*) override { // void visit(AstPackArrayDType*) override { //
newChangeDet(); newChangeDet();
} }
virtual void visit(AstUnpackArrayDType* nodep) override { void visit(AstUnpackArrayDType* nodep) override {
for (int index = 0; index < nodep->elementsConst(); ++index) { for (int index = 0; index < nodep->elementsConst(); ++index) {
VL_RESTORER(m_varEqnp); VL_RESTORER(m_varEqnp);
VL_RESTORER(m_newLvEqnp); VL_RESTORER(m_newLvEqnp);
@ -181,7 +183,7 @@ private:
} }
} }
} }
virtual void visit(AstNodeUOrStructDType* nodep) override { void visit(AstNodeUOrStructDType* nodep) override {
if (nodep->packedUnsup()) { if (nodep->packedUnsup()) {
newChangeDet(); newChangeDet();
} else { } else {
@ -191,7 +193,7 @@ private:
<< m_vscp->varp()->prettyNameQ()); << m_vscp->varp()->prettyNameQ());
} }
} }
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-"); if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable" m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
@ -218,9 +220,9 @@ public:
// CHANGEDET(VARREF(_last), VARREF(var)) // CHANGEDET(VARREF(_last), VARREF(var))
AstVar* const newvarp AstVar* const newvarp
= new AstVar{varp->fileline(), VVarType::MODULETEMP, newvarname, varp}; = new AstVar{varp->fileline(), VVarType::MODULETEMP, newvarname, varp};
m_state.m_topModp->addStmtp(newvarp); m_state.m_topModp->addStmtsp(newvarp);
m_newvscp = new AstVarScope{m_vscp->fileline(), m_state.m_scopetopp, newvarp}; m_newvscp = new AstVarScope{m_vscp->fileline(), m_state.m_scopetopp, newvarp};
m_state.m_scopetopp->addVarp(m_newvscp); m_state.m_scopetopp->addVarsp(m_newvscp);
m_varEqnp = new AstVarRef{m_vscp->fileline(), m_vscp, VAccess::READ}; m_varEqnp = new AstVarRef{m_vscp->fileline(), m_vscp, VAccess::READ};
m_newLvEqnp = new AstVarRef{m_vscp->fileline(), m_newvscp, VAccess::WRITE}; m_newLvEqnp = new AstVarRef{m_vscp->fileline(), m_newvscp, VAccess::WRITE};
@ -231,7 +233,7 @@ public:
m_newLvEqnp->deleteTree(); m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree(); m_newRvEqnp->deleteTree();
} }
virtual ~ChangedInsertVisitor() override = default; ~ChangedInsertVisitor() override = default;
VL_UNCOPYABLE(ChangedInsertVisitor); VL_UNCOPYABLE(ChangedInsertVisitor);
}; };
@ -252,5 +254,5 @@ void V3Changed::changedAll(AstNetlist* nodep) {
} }
}); });
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("changed", 0, dumpTree() >= 3);
} }

View File

@ -28,6 +28,8 @@
#include "V3Ast.h" #include "V3Ast.h"
#include "V3Global.h" #include "V3Global.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class ClassVisitor final : public VNVisitor { class ClassVisitor final : public VNVisitor {
@ -47,14 +49,13 @@ private:
std::vector<std::pair<AstNode*, AstNodeModule*>> m_toPackageMoves; std::vector<std::pair<AstNode*, AstNodeModule*>> m_toPackageMoves;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstClass* nodep) override { void visit(AstClass* nodep) override {
if (nodep->user1SetOnce()) return; if (nodep->user1SetOnce()) return;
// Move this class // Move this class
nodep->name(m_prefix + nodep->name()); nodep->name(m_prefix + nodep->name());
nodep->unlinkFrBack(); nodep->unlinkFrBack();
v3Global.rootp()->addModulep(nodep); v3Global.rootp()->addModulesp(nodep);
// Make containing package // Make containing package
// Note origName is the same as the class origName so errors look correct // Note origName is the same as the class origName so errors look correct
AstClassPackage* const packagep AstClassPackage* const packagep
@ -62,7 +63,7 @@ private:
packagep->name(nodep->name() + "__Vclpkg"); packagep->name(nodep->name() + "__Vclpkg");
nodep->classOrPackagep(packagep); nodep->classOrPackagep(packagep);
packagep->classp(nodep); packagep->classp(nodep);
v3Global.rootp()->addModulep(packagep); v3Global.rootp()->addModulesp(packagep);
// Add package to hierarchy // Add package to hierarchy
AstCell* const cellp = new AstCell{packagep->fileline(), AstCell* const cellp = new AstCell{packagep->fileline(),
packagep->fileline(), packagep->fileline(),
@ -72,7 +73,7 @@ private:
nullptr, nullptr,
nullptr}; nullptr};
cellp->modp(packagep); cellp->modp(packagep);
v3Global.rootp()->topModulep()->addStmtp(cellp); v3Global.rootp()->topModulep()->addStmtsp(cellp);
// Find class's scope // Find class's scope
// Alternative would be to move this and related to V3Scope // Alternative would be to move this and related to V3Scope
const AstScope* classScopep = nullptr; const AstScope* classScopep = nullptr;
@ -85,7 +86,7 @@ private:
AstScope* const scopep AstScope* const scopep
= new AstScope{nodep->fileline(), packagep, classScopep->name(), = new AstScope{nodep->fileline(), packagep, classScopep->name(),
classScopep->aboveScopep(), classScopep->aboveCellp()}; classScopep->aboveScopep(), classScopep->aboveCellp()};
packagep->addStmtp(scopep); packagep->addStmtsp(scopep);
// Iterate // Iterate
VL_RESTORER(m_prefix); VL_RESTORER(m_prefix);
VL_RESTORER(m_classPackagep); VL_RESTORER(m_classPackagep);
@ -100,7 +101,7 @@ private:
} }
nodep->repairCache(); nodep->repairCache();
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
VL_RESTORER(m_prefix); VL_RESTORER(m_prefix);
{ {
@ -109,7 +110,7 @@ private:
} }
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_packageScopep) { if (m_packageScopep) {
if (m_ftaskp && m_ftaskp->lifetime().isStatic()) { if (m_ftaskp && m_ftaskp->lifetime().isStatic()) {
@ -127,12 +128,12 @@ private:
} }
} }
virtual void visit(AstVarScope* nodep) override { void visit(AstVarScope* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->varp()->user1p(nodep); nodep->varp()->user1p(nodep);
} }
virtual void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_ftaskp); VL_RESTORER(m_ftaskp);
{ {
m_ftaskp = nodep; m_ftaskp = nodep;
@ -142,7 +143,7 @@ private:
} }
} }
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class // Don't move now, or wouldn't keep interating the class
// TODO move function statics only // TODO move function statics only
@ -150,14 +151,14 @@ private:
// m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep)); // m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep));
//} //}
} }
virtual void visit(AstInitial* nodep) override { void visit(AstInitial* nodep) override {
// But not AstInitialAutomatic, which remains under the class // But not AstInitialAutomatic, which remains under the class
iterateChildren(nodep); iterateChildren(nodep);
if (m_packageScopep) { if (m_packageScopep) {
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep)); m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
} }
} }
virtual void visit(AstInitialStatic* nodep) override { void visit(AstInitialStatic* nodep) override {
// But not AstInitialAutomatic, which remains under the class // But not AstInitialAutomatic, which remains under the class
iterateChildren(nodep); iterateChildren(nodep);
if (m_packageScopep) { if (m_packageScopep) {
@ -165,28 +166,28 @@ private:
} }
} }
virtual void visit(AstNodeMath* nodep) override {} // Short circuit void visit(AstNodeMath* nodep) override {} // Short circuit
virtual void visit(AstNodeStmt* nodep) override {} // Short circuit void visit(AstNodeStmt* nodep) override {} // Short circuit
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); } explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ClassVisitor() override { ~ClassVisitor() override {
for (auto moved : m_toScopeMoves) { for (auto moved : m_toScopeMoves) {
AstNode* const nodep = moved.first; AstNode* const nodep = moved.first;
AstScope* const scopep = moved.second; AstScope* const scopep = moved.second;
UINFO(9, "moving " << nodep << " to " << scopep << endl); UINFO(9, "moving " << nodep << " to " << scopep << endl);
if (VN_IS(nodep, NodeFTask)) { if (VN_IS(nodep, NodeFTask)) {
scopep->addActivep(nodep->unlinkFrBack()); scopep->addBlocksp(nodep->unlinkFrBack());
} else if (VN_IS(nodep, Var)) { } else if (VN_IS(nodep, Var)) {
AstVarScope* const vscp = VN_AS(nodep->user1p(), VarScope); AstVarScope* const vscp = VN_AS(nodep->user1p(), VarScope);
vscp->scopep(scopep); vscp->scopep(scopep);
vscp->unlinkFrBack(); vscp->unlinkFrBack();
scopep->addVarp(vscp); scopep->addVarsp(vscp);
} else if (VN_IS(nodep, Initial) || VN_IS(nodep, InitialStatic)) { } else if (VN_IS(nodep, Initial) || VN_IS(nodep, InitialStatic)) {
nodep->unlinkFrBack(); nodep->unlinkFrBack();
scopep->addActivep(nodep); scopep->addBlocksp(nodep);
} else { } else {
nodep->v3fatalSrc("Bad case"); nodep->v3fatalSrc("Bad case");
} }
@ -196,7 +197,7 @@ public:
AstNodeModule* const modp = moved.second; AstNodeModule* const modp = moved.second;
UINFO(9, "moving " << nodep << " to " << modp << endl); UINFO(9, "moving " << nodep << " to " << modp << endl);
nodep->unlinkFrBack(); nodep->unlinkFrBack();
modp->addStmtp(nodep); modp->addStmtsp(nodep);
} }
} }
}; };
@ -207,5 +208,5 @@ public:
void V3Class::classAll(AstNetlist* nodep) { void V3Class::classAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ ClassVisitor{nodep}; } // Destruct before checking { ClassVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("class", 0, dumpTree() >= 3);
} }

View File

@ -33,6 +33,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Clean state, as a visitor of each AstNode // Clean state, as a visitor of each AstNode
@ -54,7 +56,6 @@ private:
const AstNodeModule* m_modp = nullptr; const AstNodeModule* m_modp = nullptr;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// Width resetting // Width resetting
int cppWidth(AstNode* nodep) { int cppWidth(AstNode* nodep) {
@ -173,134 +174,134 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
m_modp = nodep; m_modp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstNodeUniop* nodep) override { void visit(AstNodeUniop* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
if (nodep->cleanLhs()) ensureClean(nodep->lhsp()); if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());
} }
virtual void visit(AstNodeBiop* nodep) override { void visit(AstNodeBiop* nodep) override {
operandBiop(nodep); operandBiop(nodep);
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());
} }
virtual void visit(AstAnd* nodep) override { void visit(AstAnd* nodep) override {
operandBiop(nodep); operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp())); setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
} }
virtual void visit(AstXor* nodep) override { void visit(AstXor* nodep) override {
operandBiop(nodep); operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp())); setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
} }
virtual void visit(AstOr* nodep) override { void visit(AstOr* nodep) override {
operandBiop(nodep); operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp())); setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
} }
virtual void visit(AstNodeQuadop* nodep) override { void visit(AstNodeQuadop* nodep) override {
operandQuadop(nodep); operandQuadop(nodep);
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());
} }
virtual void visit(AstNodeMath* nodep) override { void visit(AstNodeMath* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());
} }
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
if (nodep->cleanRhs()) ensureClean(nodep->rhsp()); if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
} }
virtual void visit(AstText* nodep) override { // void visit(AstText* nodep) override { //
setClean(nodep, true); setClean(nodep, true);
} }
virtual void visit(AstScopeName* nodep) override { // void visit(AstScopeName* nodep) override { //
setClean(nodep, true); setClean(nodep, true);
} }
virtual void visit(AstCNew* nodep) override { void visit(AstCNew* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
setClean(nodep, true); setClean(nodep, true);
} }
virtual void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
operandTriop(nodep); operandTriop(nodep);
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());
} }
virtual void visit(AstUCFunc* nodep) override { void visit(AstUCFunc* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
setClean(nodep, false); setClean(nodep, false);
// We always clean, as we don't trust those pesky users. // We always clean, as we don't trust those pesky users.
if (!VN_IS(nodep->backp(), And)) insertClean(nodep); if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
ensureCleanAndNext(nodep->bodysp()); ensureCleanAndNext(nodep->exprsp());
} }
virtual void visit(AstTraceDecl* nodep) override { void visit(AstTraceDecl* nodep) override {
// No cleaning, or would loose pointer to enum // No cleaning, or would loose pointer to enum
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstTraceInc* nodep) override { void visit(AstTraceInc* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureCleanAndNext(nodep->valuep()); ensureCleanAndNext(nodep->valuep());
} }
virtual void visit(AstTypedef* nodep) override { void visit(AstTypedef* nodep) override {
// No cleaning, or would loose pointer to enum // No cleaning, or would loose pointer to enum
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstParamTypeDType* nodep) override { void visit(AstParamTypeDType* nodep) override {
// No cleaning, or would loose pointer to enum // No cleaning, or would loose pointer to enum
iterateChildren(nodep); iterateChildren(nodep);
} }
// Control flow operators // Control flow operators
virtual void visit(AstNodeCond* nodep) override { void visit(AstNodeCond* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureClean(nodep->condp()); ensureClean(nodep->condp());
setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p())); setClean(nodep, isClean(nodep->thenp()) && isClean(nodep->elsep()));
} }
virtual void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureClean(nodep->condp()); ensureClean(nodep->condp());
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureClean(nodep->condp()); ensureClean(nodep->condp());
} }
virtual void visit(AstSFormatF* nodep) override { void visit(AstSFormatF* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureCleanAndNext(nodep->exprsp()); ensureCleanAndNext(nodep->exprsp());
setClean(nodep, true); // generates a string, so not relevant setClean(nodep, true); // generates a string, so not relevant
} }
virtual void visit(AstUCStmt* nodep) override { void visit(AstUCStmt* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureCleanAndNext(nodep->bodysp()); ensureCleanAndNext(nodep->exprsp());
} }
virtual void visit(AstNodeCCall* nodep) override { void visit(AstNodeCCall* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureCleanAndNext(nodep->argsp()); ensureCleanAndNext(nodep->argsp());
setClean(nodep, true); setClean(nodep, true);
} }
virtual void visit(AstCMethodHard* nodep) override { void visit(AstCMethodHard* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureCleanAndNext(nodep->pinsp()); ensureCleanAndNext(nodep->pinsp());
setClean(nodep, true); setClean(nodep, true);
} }
virtual void visit(AstWith* nodep) override { void visit(AstWith* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
ensureCleanAndNext(nodep->exprp()); ensureCleanAndNext(nodep->exprp());
setClean(nodep, true); setClean(nodep, true);
} }
virtual void visit(AstIntfRef* nodep) override { void visit(AstIntfRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
setClean(nodep, true); // generates a string, so not relevant setClean(nodep, true); // generates a string, so not relevant
} }
//-------------------- //--------------------
// Default: Just iterate // Default: Just iterate
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
} }
@ -308,7 +309,7 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); } explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CleanVisitor() override = default; ~CleanVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -317,5 +318,5 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) { void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ CleanVisitor{nodep}; } // Destruct before checking { CleanVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("clean", 0, dumpTree() >= 3);
} }

View File

@ -37,6 +37,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Convert every WRITE AstVarRef to a READ ref // Convert every WRITE AstVarRef to a READ ref
@ -88,7 +90,6 @@ private:
AstMTaskBody* m_mtaskBodyp = nullptr; // Current mtask body AstMTaskBody* m_mtaskBodyp = nullptr; // Current mtask body
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
AstVarScope* getCreateLastClk(AstVarScope* vscp) { AstVarScope* getCreateLastClk(AstVarScope* vscp) {
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p()); if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
@ -100,12 +101,12 @@ private:
const string newvarname const string newvarname
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name()); = (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
AstVar* const newvarp = new AstVar(vscp->fileline(), VVarType::MODULETEMP, newvarname, AstVar* const newvarp = new AstVar(vscp->fileline(), VVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1); VFlagLogicPacked{}, 1);
newvarp->noReset(true); // Reset by below assign newvarp->noReset(true); // Reset by below assign
m_modp->addStmtp(newvarp); m_modp->addStmtsp(newvarp);
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp); AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
vscp->user1p(newvscp); vscp->user1p(newvscp);
m_scopep->addVarp(newvscp); m_scopep->addVarsp(newvscp);
// Add init // Add init
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ); AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp); if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
@ -202,7 +203,7 @@ private:
funcp->slow(slow); funcp->slow(slow);
funcp->isConst(false); funcp->isConst(false);
funcp->declPrivate(true); funcp->declPrivate(true);
m_topScopep->scopep()->addActivep(funcp); m_topScopep->scopep()->addBlocksp(funcp);
return funcp; return funcp;
} }
void splitCheck(AstCFunc* ofuncp) { void splitCheck(AstCFunc* ofuncp) {
@ -229,7 +230,7 @@ private:
funcp->isStatic(false); funcp->isStatic(false);
funcp->isLoose(true); funcp->isLoose(true);
funcp->slow(ofuncp->slow()); funcp->slow(ofuncp->slow());
m_topScopep->scopep()->addActivep(funcp); m_topScopep->scopep()->addBlocksp(funcp);
// //
AstCCall* const callp = new AstCCall{funcp->fileline(), funcp}; AstCCall* const callp = new AstCCall{funcp->fileline(), funcp};
ofuncp->addStmtsp(callp); ofuncp->addStmtsp(callp);
@ -242,7 +243,7 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstTopScope* nodep) override { void visit(AstTopScope* nodep) override {
UINFO(4, " TOPSCOPE " << nodep << endl); UINFO(4, " TOPSCOPE " << nodep << endl);
m_topScopep = nodep; m_topScopep = nodep;
m_scopep = nodep->scopep(); m_scopep = nodep->scopep();
@ -277,7 +278,7 @@ private:
m_topScopep = nullptr; m_topScopep = nullptr;
m_scopep = nullptr; m_scopep = nullptr;
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
// UINFO(4, " MOD " << nodep << endl); // UINFO(4, " MOD " << nodep << endl);
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
@ -285,7 +286,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
// UINFO(4, " SCOPE " << nodep << endl); // UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep; m_scopep = nodep;
iterateChildren(nodep); iterateChildren(nodep);
@ -296,14 +297,14 @@ private:
} }
m_scopep = nullptr; m_scopep = nullptr;
} }
virtual void visit(AstNodeProcedure* nodep) override { void visit(AstNodeProcedure* nodep) override {
if (AstNode* const stmtsp = nodep->bodysp()) { if (AstNode* const stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext(); stmtsp->unlinkFrBackWithNext();
nodep->addNextHere(stmtsp); nodep->addNextHere(stmtsp);
} }
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
virtual void visit(AstCoverToggle* nodep) override { void visit(AstCoverToggle* nodep) override {
// nodep->dumpTree(cout, "ct:"); // nodep->dumpTree(cout, "ct:");
// COVERTOGGLE(INC, ORIG, CHANGE) -> // COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; } // IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
@ -316,11 +317,11 @@ private:
// We could add another IF to detect posedges, and only increment if so. // We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though versus a potential memory miss. // It's another whole branch though versus a potential memory miss.
// We'll go with the miss. // We'll go with the miss.
newp->addIfsp(new AstAssign(nodep->fileline(), changeWrp, origp->cloneTree(false))); newp->addThensp(new AstAssign(nodep->fileline(), changeWrp, origp->cloneTree(false)));
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// Link to global function // Link to global function
if (nodep->isFinal()) { if (nodep->isFinal()) {
@ -329,7 +330,7 @@ private:
m_finalFuncp->addStmtsp(callp); m_finalFuncp->addStmtsp(callp);
} }
} }
virtual void visit(AstSenTree* nodep) override { void visit(AstSenTree* nodep) override {
// Delete it later; Actives still pointing to it // Delete it later; Actives still pointing to it
nodep->unlinkFrBack(); nodep->unlinkFrBack();
pushDeletep(nodep); pushDeletep(nodep);
@ -343,7 +344,7 @@ private:
void addToInitial(AstNode* stmtsp) { void addToInitial(AstNode* stmtsp) {
m_initFuncp->addStmtsp(stmtsp); // add to top level function m_initFuncp->addStmtsp(stmtsp); // add to top level function
} }
virtual void visit(AstActive* nodep) override { void visit(AstActive* nodep) override {
// Careful if adding variables here, ACTIVES can be under other ACTIVES // Careful if adding variables here, ACTIVES can be under other ACTIVES
// Need to save and restore any member state in AstUntilStable block // Need to save and restore any member state in AstUntilStable block
if (!m_topScopep || !nodep->stmtsp()) { if (!m_topScopep || !nodep->stmtsp()) {
@ -367,7 +368,7 @@ private:
m_mtaskBodyp->addStmtsp(m_lastIfp); m_mtaskBodyp->addStmtsp(m_lastIfp);
} }
// Move statements to if // Move statements to if
m_lastIfp->addIfsp(stmtsp); m_lastIfp->addThensp(stmtsp);
} else if (nodep->hasInitial() || nodep->hasSettle()) { } else if (nodep->hasInitial() || nodep->hasSettle()) {
nodep->v3fatalSrc("MTask should not include initial/settle logic."); nodep->v3fatalSrc("MTask should not include initial/settle logic.");
} else { } else {
@ -393,7 +394,7 @@ private:
addToEvalLoop(m_lastIfp); addToEvalLoop(m_lastIfp);
} }
// Move statements to if // Move statements to if
m_lastIfp->addIfsp(stmtsp); m_lastIfp->addThensp(stmtsp);
} else if (nodep->hasInitial()) { } else if (nodep->hasInitial()) {
// Don't need to: clearLastSen();, as we're adding it to different cfunc // Don't need to: clearLastSen();, as we're adding it to different cfunc
// Move statements to function // Move statements to function
@ -411,7 +412,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
} }
virtual void visit(AstExecGraph* nodep) override { void visit(AstExecGraph* nodep) override {
VL_RESTORER(m_mtaskBodyp); VL_RESTORER(m_mtaskBodyp);
for (m_mtaskBodyp = nodep->mTaskBodiesp(); m_mtaskBodyp; for (m_mtaskBodyp = nodep->mTaskBodiesp(); m_mtaskBodyp;
m_mtaskBodyp = VN_AS(m_mtaskBodyp->nextp(), MTaskBody)) { m_mtaskBodyp = VN_AS(m_mtaskBodyp->nextp(), MTaskBody)) {
@ -427,7 +428,7 @@ private:
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -437,7 +438,7 @@ public:
// easily without iterating through the tree. // easily without iterating through the tree.
nodep->evalp(m_evalFuncp); nodep->evalp(m_evalFuncp);
} }
virtual ~ClockVisitor() override = default; ~ClockVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -446,5 +447,5 @@ public:
void V3Clock::clockAll(AstNetlist* nodep) { void V3Clock::clockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ ClockVisitor{nodep}; } // Destruct before checking { ClockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("clock", 0, dumpTree() >= 3);
} }

View File

@ -33,6 +33,8 @@
#include <list> #include <list>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
class CombineVisitor final : VNVisitor { class CombineVisitor final : VNVisitor {
// NODE STATE // NODE STATE
// AstNodeModule::user1() List of AstCFuncs in this module (via m_cfuncs) // AstNodeModule::user1() List of AstCFuncs in this module (via m_cfuncs)
@ -57,7 +59,6 @@ class CombineVisitor final : VNVisitor {
VDouble0 m_cfuncsCombined; // Statistic tracking VDouble0 m_cfuncsCombined; // Statistic tracking
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void removeEmptyFunctions(std::list<AstCFunc*>& funcps) { void removeEmptyFunctions(std::list<AstCFunc*>& funcps) {
for (funcit_t it = funcps.begin(), nit; it != funcps.end(); it = nit) { for (funcit_t it = funcps.begin(), nit; it != funcps.end(); it = nit) {
@ -180,32 +181,32 @@ class CombineVisitor final : VNVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
// Gather functions and references // Gather functions and references
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
// Combine functions // Combine functions
process(nodep); process(nodep);
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
UASSERT_OBJ(!m_modp, nodep, "Should not nest"); UASSERT_OBJ(!m_modp, nodep, "Should not nest");
m_modp = nodep; m_modp = nodep;
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
m_modp = nullptr; m_modp = nullptr;
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (nodep->dontCombine()) return; if (nodep->dontCombine()) return;
auto& coll = nodep->slow() ? m_cfuncs(m_modp).m_slow : m_cfuncs(m_modp).m_fast; auto& coll = nodep->slow() ? m_cfuncs(m_modp).m_slow : m_cfuncs(m_modp).m_fast;
coll.emplace_back(nodep); coll.emplace_back(nodep);
} }
virtual void visit(AstCCall* nodep) override { void visit(AstCCall* nodep) override {
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
AstCFunc* const funcp = nodep->funcp(); AstCFunc* const funcp = nodep->funcp();
if (funcp->dontCombine()) return; if (funcp->dontCombine()) return;
m_callSites(funcp).emplace_back(nodep); m_callSites(funcp).emplace_back(nodep);
} }
virtual void visit(AstAddrOfCFunc* nodep) override { void visit(AstAddrOfCFunc* nodep) override {
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (nodep->funcp()->dontCombine()) return; if (nodep->funcp()->dontCombine()) return;
// LCOV_EXCL_START // LCOV_EXCL_START
@ -217,7 +218,7 @@ class CombineVisitor final : VNVisitor {
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
// CONSTRUCTORS // CONSTRUCTORS
explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); } explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); }
@ -235,5 +236,5 @@ public:
void V3Combine::combineAll(AstNetlist* nodep) { void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
CombineVisitor::apply(nodep); CombineVisitor::apply(nodep);
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("combine", 0, dumpTree() >= 3);
} }

View File

@ -29,6 +29,8 @@
#include "V3EmitCBase.h" #include "V3EmitCBase.h"
#include "V3Global.h" #include "V3Global.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Common component builders // Common component builders
@ -43,7 +45,7 @@ static void makeVlToString(AstClass* nodep) {
AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0}; AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0};
exprp->dtypeSetString(); exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtp(funcp); nodep->addStmtsp(funcp);
} }
static void makeToString(AstClass* nodep) { static void makeToString(AstClass* nodep) {
AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "to_string", nullptr, "std::string"}; AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "to_string", nullptr, "std::string"};
@ -54,7 +56,7 @@ static void makeToString(AstClass* nodep) {
= new AstCMath{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0}; = new AstCMath{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0};
exprp->dtypeSetString(); exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtp(funcp); nodep->addStmtsp(funcp);
} }
static void makeToStringMiddle(AstClass* nodep) { static void makeToStringMiddle(AstClass* nodep) {
AstCFunc* const funcp AstCFunc* const funcp
@ -96,7 +98,7 @@ static void makeToStringMiddle(AstClass* nodep) {
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
} }
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "return out;\n"}); funcp->addStmtsp(new AstCStmt{nodep->fileline(), "return out;\n"});
nodep->addStmtp(funcp); nodep->addStmtsp(funcp);
} }
//###################################################################### //######################################################################
@ -117,5 +119,5 @@ void V3Common::commonAll() {
makeToStringMiddle(classp); makeToStringMiddle(classp);
} }
} }
V3Global::dumpCheckGlobalTree("common", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("common", 0, dumpTree() >= 3);
} }

View File

@ -27,6 +27,8 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Resolve wildcards in files, modules, ftasks or variables // Resolve wildcards in files, modules, ftasks or variables
@ -193,11 +195,11 @@ public:
const VPragmaType type const VPragmaType type
= m_inlineValue ? VPragmaType::INLINE_MODULE : VPragmaType::NO_INLINE_MODULE; = m_inlineValue ? VPragmaType::INLINE_MODULE : VPragmaType::NO_INLINE_MODULE;
AstNode* const nodep = new AstPragma(modp->fileline(), type); AstNode* const nodep = new AstPragma(modp->fileline(), type);
modp->addStmtp(nodep); modp->addStmtsp(nodep);
} }
for (const auto& itr : m_modPragmas) { for (const auto& itr : m_modPragmas) {
AstNode* const nodep = new AstPragma{modp->fileline(), itr}; AstNode* const nodep = new AstPragma{modp->fileline(), itr};
modp->addStmtp(nodep); modp->addStmtsp(nodep);
} }
} }
@ -309,7 +311,7 @@ public:
if (lineMatch(lineno, VPragmaType::FULL_CASE)) nodep->fullPragma(true); if (lineMatch(lineno, VPragmaType::FULL_CASE)) nodep->fullPragma(true);
if (lineMatch(lineno, VPragmaType::PARALLEL_CASE)) nodep->parallelPragma(true); if (lineMatch(lineno, VPragmaType::PARALLEL_CASE)) nodep->parallelPragma(true);
} }
inline void applyIgnores(FileLine* filelinep) { void applyIgnores(FileLine* filelinep) {
// HOT routine, called each parsed token line of this filename // HOT routine, called each parsed token line of this filename
if (m_lastIgnore.lineno != filelinep->lineno()) { if (m_lastIgnore.lineno != filelinep->lineno()) {
// UINFO(9, " ApplyIgnores for " << filelinep->ascii() << endl); // UINFO(9, " ApplyIgnores for " << filelinep->ascii() << endl);

View File

@ -37,6 +37,8 @@
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Utilities // Utilities
@ -350,7 +352,6 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
std::vector<std::unique_ptr<VarInfo>> m_varInfos; // VarInfo for each variable, [0] is nullptr std::vector<std::unique_ptr<VarInfo>> m_varInfos; // VarInfo for each variable, [0] is nullptr
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
bool isAndTree() const { return VN_IS(m_rootp, And); } bool isAndTree() const { return VN_IS(m_rootp, And); }
bool isOrTree() const { return VN_IS(m_rootp, Or); } bool isOrTree() const { return VN_IS(m_rootp, Or); }
@ -417,14 +418,12 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override { CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); }
CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); void visit(AstCCast* nodep) override {
}
virtual void visit(AstCCast* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_leafp) m_leafp->updateBitRange(nodep); if (m_leafp) m_leafp->updateBitRange(nodep);
} }
virtual void visit(AstShiftR* nodep) override { void visit(AstShiftR* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep); CONST_BITOP_RETURN_IF(!m_leafp, nodep);
AstConst* const constp = VN_CAST(nodep->rhsp(), Const); AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
@ -434,7 +433,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
m_leafp->updateBitRange(nodep); m_leafp->updateBitRange(nodep);
m_lsb -= constp->toUInt(); m_lsb -= constp->toUInt();
} }
virtual void visit(AstNot* nodep) override { void visit(AstNot* nodep) override {
CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep); CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep);
AstNode* lhsp = nodep->lhsp(); AstNode* lhsp = nodep->lhsp();
AstCCast* const castp = VN_CAST(lhsp, CCast); AstCCast* const castp = VN_CAST(lhsp, CCast);
@ -449,7 +448,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
if (!isXorTree()) m_polarity = !m_polarity; if (!isXorTree()) m_polarity = !m_polarity;
if (m_leafp && castp) m_leafp->updateBitRange(castp); if (m_leafp && castp) m_leafp->updateBitRange(castp);
} }
virtual void visit(AstWordSel* nodep) override { void visit(AstWordSel* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep); CONST_BITOP_RETURN_IF(!m_leafp, nodep);
AstConst* const constp = VN_CAST(nodep->bitp(), Const); AstConst* const constp = VN_CAST(nodep->bitp(), Const);
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
@ -457,17 +456,17 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
m_leafp->wordIdx(constp->toSInt()); m_leafp->wordIdx(constp->toSInt());
iterate(nodep->fromp()); iterate(nodep->fromp());
} }
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep); CONST_BITOP_RETURN_IF(!m_leafp, nodep);
m_leafp->setLeaf(nodep); m_leafp->setLeaf(nodep);
m_leafp->polarity(m_polarity); m_leafp->polarity(m_polarity);
} }
virtual void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep); CONST_BITOP_RETURN_IF(!m_leafp, nodep);
m_leafp->setLeaf(nodep); m_leafp->setLeaf(nodep);
} }
virtual void visit(AstRedXor* nodep) override { void visit(AstRedXor* nodep) override {
Restorer restorer{*this}; Restorer restorer{*this};
CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep); CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep);
AstNode* lhsp = nodep->lhsp(); AstNode* lhsp = nodep->lhsp();
@ -514,7 +513,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
} }
} }
virtual void visit(AstNodeBiop* nodep) override { void visit(AstNodeBiop* nodep) override {
if (VN_IS(nodep, And) && isConst(nodep->lhsp(), 1)) { // 1 & _ if (VN_IS(nodep, And) && isConst(nodep->lhsp(), 1)) { // 1 & _
// Always reach past a plain making AND // Always reach past a plain making AND
Restorer restorer{*this}; Restorer restorer{*this};
@ -895,7 +894,6 @@ private:
V3UniqueNames m_concswapNames; // For generating unique temporary variable names V3UniqueNames m_concswapNames; // For generating unique temporary variable names
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
bool operandConst(AstNode* nodep) { return VN_IS(nodep, Const); } bool operandConst(AstNode* nodep) { return VN_IS(nodep, Const); }
bool operandAsvConst(const AstNode* nodep) { bool operandAsvConst(const AstNode* nodep) {
@ -1044,20 +1042,19 @@ private:
// as high as possible, which is usally the right choice, except for this. // as high as possible, which is usally the right choice, except for this.
AstNodeCond* const condp = VN_CAST(nodep->rhsp(), NodeCond); AstNodeCond* const condp = VN_CAST(nodep->rhsp(), NodeCond);
if (!condp) return false; if (!condp) return false;
if (!VN_IS(condp->expr1p(), Const) && !VN_IS(condp->expr2p(), Const)) return false; if (!VN_IS(condp->thenp(), Const) && !VN_IS(condp->elsep(), Const)) return false;
AstConst* const maskp = VN_CAST(nodep->lhsp(), Const); AstConst* const maskp = VN_CAST(nodep->lhsp(), Const);
if (!maskp) return false; if (!maskp) return false;
UINFO(4, "AND(CONSTm, CONDcond(c, i, e))->CONDcond(c, AND(m,i), AND(m, e)) " << nodep UINFO(4, "AND(CONSTm, CONDcond(c, i, e))->CONDcond(c, AND(m,i), AND(m, e)) " << nodep
<< endl); << endl);
AstNodeCond* const newp = static_cast<AstNodeCond*>( AstNodeCond* const newp = static_cast<AstNodeCond*>(condp->cloneType(
condp->cloneType(condp->condp()->unlinkFrBack(), condp->condp()->unlinkFrBack(),
new AstAnd(nodep->fileline(), maskp->cloneTree(false), new AstAnd(nodep->fileline(), maskp->cloneTree(false), condp->thenp()->unlinkFrBack()),
condp->expr1p()->unlinkFrBack()), new AstAnd(nodep->fileline(), maskp->cloneTree(false),
new AstAnd(nodep->fileline(), maskp->cloneTree(false), condp->elsep()->unlinkFrBack())));
condp->expr2p()->unlinkFrBack())));
newp->dtypeFrom(nodep); newp->dtypeFrom(nodep);
newp->expr1p()->dtypeFrom(nodep); // As And might have been to change widths newp->thenp()->dtypeFrom(nodep); // As And might have been to change widths
newp->expr2p()->dtypeFrom(nodep); newp->elsep()->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
return true; return true;
@ -1445,19 +1442,19 @@ private:
} }
} }
bool ifSameAssign(const AstNodeIf* nodep) { bool ifSameAssign(const AstNodeIf* nodep) {
const AstNodeAssign* const ifp = VN_CAST(nodep->ifsp(), NodeAssign); const AstNodeAssign* const thensp = VN_CAST(nodep->thensp(), NodeAssign);
const AstNodeAssign* const elsep = VN_CAST(nodep->elsesp(), NodeAssign); const AstNodeAssign* const elsesp = VN_CAST(nodep->elsesp(), NodeAssign);
if (!ifp || ifp->nextp()) return false; // Must be SINGLE statement if (!thensp || thensp->nextp()) return false; // Must be SINGLE statement
if (!elsep || elsep->nextp()) return false; if (!elsesp || elsesp->nextp()) return false;
if (ifp->type() != elsep->type()) return false; // Can't mix an assigndly and an assign if (thensp->type() != elsesp->type()) return false; // Can't mix an assigndly with assign
if (!ifp->lhsp()->sameGateTree(elsep->lhsp())) return false; if (!thensp->lhsp()->sameGateTree(elsesp->lhsp())) return false;
if (!ifp->rhsp()->gateTree()) return false; if (!thensp->rhsp()->gateTree()) return false;
if (!elsep->rhsp()->gateTree()) return false; if (!elsesp->rhsp()->gateTree()) return false;
return true; return true;
} }
bool operandIfIf(const AstNodeIf* nodep) { bool operandIfIf(const AstNodeIf* nodep) {
if (nodep->elsesp()) return false; if (nodep->elsesp()) return false;
const AstNodeIf* const lowerIfp = VN_CAST(nodep->ifsp(), NodeIf); const AstNodeIf* const lowerIfp = VN_CAST(nodep->thensp(), NodeIf);
if (!lowerIfp || lowerIfp->nextp()) return false; if (!lowerIfp || lowerIfp->nextp()) return false;
if (nodep->type() != lowerIfp->type()) return false; if (nodep->type() != lowerIfp->type()) return false;
if (afterComment(lowerIfp->elsesp())) return false; if (afterComment(lowerIfp->elsesp())) return false;
@ -2079,7 +2076,7 @@ private:
AstSel* const sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2 - lsb2 + 1); AstSel* const sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2 - lsb2 + 1);
// Make new assigns of same flavor as old one // Make new assigns of same flavor as old one
//*** Not cloneTree; just one node. //*** Not cloneTree; just one node.
AstNode* newp = nullptr; AstNodeAssign* newp = nullptr;
if (!need_temp) { if (!need_temp) {
AstNodeAssign* const asn1ap = VN_AS(nodep->cloneType(lc1p, sel1p), NodeAssign); AstNodeAssign* const asn1ap = VN_AS(nodep->cloneType(lc1p, sel1p), NodeAssign);
AstNodeAssign* const asn2ap = VN_AS(nodep->cloneType(lc2p, sel2p), NodeAssign); AstNodeAssign* const asn2ap = VN_AS(nodep->cloneType(lc2p, sel2p), NodeAssign);
@ -2099,8 +2096,8 @@ private:
AstVar* const temp2p AstVar* const temp2p
= new AstVar(sel2p->fileline(), VVarType::BLOCKTEMP, = new AstVar(sel2p->fileline(), VVarType::BLOCKTEMP,
m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1); m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1);
m_modp->addStmtp(temp1p); m_modp->addStmtsp(temp1p);
m_modp->addStmtp(temp2p); m_modp->addStmtsp(temp2p);
AstNodeAssign* const asn1ap AstNodeAssign* const asn1ap
= VN_AS(nodep->cloneType( = VN_AS(nodep->cloneType(
new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p), new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p),
@ -2252,11 +2249,11 @@ private:
//---------------------------------------- //----------------------------------------
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
// Iterate modules backwards, in bottom-up order. That's faster // Iterate modules backwards, in bottom-up order. That's faster
iterateChildrenBackwards(nodep); iterateChildrenBackwards(nodep);
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
m_modp = nodep; m_modp = nodep;
@ -2264,7 +2261,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
// No ASSIGNW removals under funcs, we've long eliminated INITIALs // No ASSIGNW removals under funcs, we've long eliminated INITIALs
// (We should perhaps rename the assignw's to just assigns) // (We should perhaps rename the assignw's to just assigns)
VL_RESTORER(m_wremove); VL_RESTORER(m_wremove);
@ -2273,7 +2270,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
// No ASSIGNW removals under scope, we've long eliminated INITIALs // No ASSIGNW removals under scope, we've long eliminated INITIALs
VL_RESTORER(m_wremove); VL_RESTORER(m_wremove);
VL_RESTORER(m_scopep); VL_RESTORER(m_scopep);
@ -2370,17 +2367,17 @@ private:
} }
// Special cases // Special cases
virtual void visit(AstConst*) override {} // Already constant void visit(AstConst*) override {} // Already constant
virtual void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
if (m_params) { if (m_params) {
iterateAndNextNull(nodep->paramsp()); iterateAndNextNull(nodep->paramsp());
} else { } else {
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstClassOrPackageRef* nodep) override { iterateChildren(nodep); } void visit(AstClassOrPackageRef* nodep) override { iterateChildren(nodep); }
virtual void visit(AstPin* nodep) override { iterateChildren(nodep); } void visit(AstPin* nodep) override { iterateChildren(nodep); }
void replaceLogEq(AstLogEq* nodep) { void replaceLogEq(AstLogEq* nodep) {
// LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}} // LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}}
@ -2562,7 +2559,7 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
virtual void visit(AstAttrOf* nodep) override { void visit(AstAttrOf* nodep) override {
VL_RESTORER(m_attrp); VL_RESTORER(m_attrp);
{ {
m_attrp = nodep; m_attrp = nodep;
@ -2570,7 +2567,7 @@ private:
} }
} }
virtual void visit(AstArraySel* nodep) override { void visit(AstArraySel* nodep) override {
iterateAndNextNull(nodep->bitp()); iterateAndNextNull(nodep->bitp());
if (VN_IS(nodep->bitp(), Const) if (VN_IS(nodep->bitp(), Const)
&& VN_IS(nodep->fromp(), VarRef) && VN_IS(nodep->fromp(), VarRef)
@ -2596,7 +2593,7 @@ private:
} }
m_selp = nullptr; m_selp = nullptr;
} }
virtual void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
UASSERT_OBJ(nodep->varp(), nodep, "Not linked"); UASSERT_OBJ(nodep->varp(), nodep, "Not linked");
bool did = false; bool did = false;
@ -2650,7 +2647,7 @@ private:
<< nodep->varp()->prettyNameQ()); << nodep->varp()->prettyNameQ());
} }
} }
virtual void visit(AstEnumItemRef* nodep) override { void visit(AstEnumItemRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked"); UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
bool did = false; bool did = false;
@ -2675,7 +2672,7 @@ private:
} }
} }
// virtual void visit(AstCvtPackString* nodep) override { // void visit(AstCvtPackString* nodep) override {
// Not constant propagated (for today) because AstNodeMath::isOpaque is set // Not constant propagated (for today) because AstNodeMath::isOpaque is set
// Someday if lower is constant, convert to quoted "string". // Someday if lower is constant, convert to quoted "string".
@ -2683,7 +2680,7 @@ private:
// Only one if it's not in a list // Only one if it's not in a list
return (!nodep->nextp() && nodep->backp()->nextp() != nodep); return (!nodep->nextp() && nodep->backp()->nextp() != nodep);
} }
virtual void visit(AstSenItem* nodep) override { void visit(AstSenItem* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_doNConst if (m_doNConst
&& (VN_IS(nodep->sensp(), Const) || VN_IS(nodep->sensp(), EnumItemRef) && (VN_IS(nodep->sensp(), Const) || VN_IS(nodep->sensp(), EnumItemRef)
@ -2750,7 +2747,7 @@ private:
} }
}; };
virtual void visit(AstSenTree* nodep) override { void visit(AstSenTree* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_doExpensive) { if (m_doExpensive) {
// cout<<endl; nodep->dumpTree(cout, "ssin: "); // cout<<endl; nodep->dumpTree(cout, "ssin: ");
@ -2834,17 +2831,17 @@ private:
//----- //-----
// Zero elimination // Zero elimination
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return; if (m_doNConst && replaceNodeAssign(nodep)) return;
} }
virtual void visit(AstAssignAlias* nodep) override { void visit(AstAssignAlias* nodep) override {
// Don't perform any optimizations, keep the alias around // Don't perform any optimizations, keep the alias around
} }
virtual void visit(AstAssignVarScope* nodep) override { void visit(AstAssignVarScope* nodep) override {
// Don't perform any optimizations, the node won't be linked yet // Don't perform any optimizations, the node won't be linked yet
} }
virtual void visit(AstAssignW* nodep) override { void visit(AstAssignW* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return; if (m_doNConst && replaceNodeAssign(nodep)) return;
AstNodeVarRef* const varrefp = VN_CAST( AstNodeVarRef* const varrefp = VN_CAST(
@ -2853,6 +2850,7 @@ private:
if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp()) if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp())
&& !VN_AS(nodep->rhsp(), Const)->num().isFourState() && !VN_AS(nodep->rhsp(), Const)->num().isFourState()
&& varrefp // Don't do messes with BITREFs/ARRAYREFs && varrefp // Don't do messes with BITREFs/ARRAYREFs
&& !varrefp->varp()->hasStrengthAssignment() // Strengths are resolved in V3Tristate
&& !varrefp->varp()->valuep() // Not already constified && !varrefp->varp()->valuep() // Not already constified
&& !varrefp->varScopep()) { // Not scoped (or each scope may have different initial && !varrefp->varScopep()) { // Not scoped (or each scope may have different initial
// value) // value)
@ -2863,14 +2861,14 @@ private:
varrefp->unlinkFrBack(); varrefp->unlinkFrBack();
AstInitial* const newinitp = new AstInitial( AstInitial* const newinitp = new AstInitial(
nodep->fileline(), new AstAssign(nodep->fileline(), varrefp, exprp)); nodep->fileline(), new AstAssign(nodep->fileline(), varrefp, exprp));
m_modp->addStmtp(newinitp); m_modp->addStmtsp(newinitp);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
// Set the initial value right in the variable so we can constant propagate // Set the initial value right in the variable so we can constant propagate
AstNode* const initvaluep = exprp->cloneTree(false); AstNode* const initvaluep = exprp->cloneTree(false);
varrefp->varp()->valuep(initvaluep); varrefp->varp()->valuep(initvaluep);
} }
} }
virtual void visit(AstRelease* nodep) override { void visit(AstRelease* nodep) override {
if (AstConcat* const concatp = VN_CAST(nodep->lhsp(), Concat)) { if (AstConcat* const concatp = VN_CAST(nodep->lhsp(), Concat)) {
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
AstRelease* const newLp = new AstRelease{flp, concatp->lhsp()->unlinkFrBack()}; AstRelease* const newLp = new AstRelease{flp, concatp->lhsp()->unlinkFrBack()};
@ -2883,7 +2881,7 @@ private:
} }
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_doNConst) { if (m_doNConst) {
if (const AstConst* const constp = VN_CAST(nodep->condp(), Const)) { if (const AstConst* const constp = VN_CAST(nodep->condp(), Const)) {
@ -2893,7 +2891,7 @@ private:
keepp = nodep->elsesp(); keepp = nodep->elsesp();
} else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog } else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog
UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl); UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl);
keepp = nodep->ifsp(); keepp = nodep->thensp();
} else { } else {
UINFO(4, "IF condition is X, retaining: " << nodep << endl); UINFO(4, "IF condition is X, retaining: " << nodep << endl);
return; return;
@ -2905,7 +2903,7 @@ private:
nodep->unlinkFrBack(); nodep->unlinkFrBack();
} }
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) { } else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) {
if (!isTreePureRecurse(nodep->condp())) { if (!isTreePureRecurse(nodep->condp())) {
// Condition has side effect - leave - perhaps in // Condition has side effect - leave - perhaps in
// future simplify to remove all but side effect terms // future simplify to remove all but side effect terms
@ -2913,27 +2911,27 @@ private:
// Empty block, remove it // Empty block, remove it
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
} else if (!afterComment(nodep->ifsp())) { } else if (!afterComment(nodep->thensp())) {
UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl); UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl);
AstNode* const condp = nodep->condp(); AstNode* const condp = nodep->condp();
AstNode* const elsesp = nodep->elsesp(); AstNode* const elsesp = nodep->elsesp();
condp->unlinkFrBackWithNext(); condp->unlinkFrBackWithNext();
elsesp->unlinkFrBackWithNext(); elsesp->unlinkFrBackWithNext();
if (nodep->ifsp()) { // Must have been comment if (nodep->thensp()) { // Must have been comment
nodep->ifsp()->unlinkFrBackWithNext()->deleteTree(); nodep->thensp()->unlinkFrBackWithNext()->deleteTree();
} }
nodep->condp(new AstLogNot(condp->fileline(), nodep->condp(new AstLogNot(condp->fileline(),
condp)); // LogNot, as C++ optimization also possible condp)); // LogNot, as C++ optimization also possible
nodep->addIfsp(elsesp); nodep->addThensp(elsesp);
} else if (((VN_IS(nodep->condp(), Not) && nodep->condp()->width() == 1) } else if (((VN_IS(nodep->condp(), Not) && nodep->condp()->width() == 1)
|| VN_IS(nodep->condp(), LogNot)) || VN_IS(nodep->condp(), LogNot))
&& nodep->ifsp() && nodep->elsesp()) { && nodep->thensp() && nodep->elsesp()) {
UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep << endl); UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep << endl);
AstNode* const condp AstNode* const condp
= VN_AS(nodep->condp(), NodeUniop)->lhsp()->unlinkFrBackWithNext(); = VN_AS(nodep->condp(), NodeUniop)->lhsp()->unlinkFrBackWithNext();
AstNode* const ifsp = nodep->ifsp()->unlinkFrBackWithNext(); AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext();
AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext(); AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext();
AstIf* const ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp); AstIf* const ifp = new AstIf(nodep->fileline(), condp, elsesp, thensp);
ifp->branchPred(nodep->branchPred().invert()); ifp->branchPred(nodep->branchPred().invert());
nodep->replaceWith(ifp); nodep->replaceWith(ifp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
@ -2941,25 +2939,25 @@ private:
UINFO( UINFO(
4, 4,
"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})\n"); "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})\n");
AstNodeAssign* const ifp = VN_AS(nodep->ifsp(), NodeAssign); AstNodeAssign* const thensp = VN_AS(nodep->thensp(), NodeAssign);
AstNodeAssign* const elsep = VN_AS(nodep->elsesp(), NodeAssign); AstNodeAssign* const elsesp = VN_AS(nodep->elsesp(), NodeAssign);
ifp->unlinkFrBack(); thensp->unlinkFrBack();
AstNode* const condp = nodep->condp()->unlinkFrBack(); AstNode* const condp = nodep->condp()->unlinkFrBack();
AstNode* const truep = ifp->rhsp()->unlinkFrBack(); AstNode* const truep = thensp->rhsp()->unlinkFrBack();
AstNode* const falsep = elsep->rhsp()->unlinkFrBack(); AstNode* const falsep = elsesp->rhsp()->unlinkFrBack();
ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep)); thensp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep));
nodep->replaceWith(ifp); nodep->replaceWith(thensp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (false // Disabled, as vpm assertions are faster } else if (false // Disabled, as vpm assertions are faster
// without due to short-circuiting // without due to short-circuiting
&& operandIfIf(nodep)) { && operandIfIf(nodep)) {
UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl); UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl);
AstNodeIf* const lowerIfp = VN_AS(nodep->ifsp(), NodeIf); AstNodeIf* const lowerIfp = VN_AS(nodep->thensp(), NodeIf);
AstNode* const condp = nodep->condp()->unlinkFrBack(); AstNode* const condp = nodep->condp()->unlinkFrBack();
AstNode* const lowerIfsp = lowerIfp->ifsp()->unlinkFrBackWithNext(); AstNode* const lowerThensp = lowerIfp->thensp()->unlinkFrBackWithNext();
AstNode* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext(); AstNode* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext();
nodep->condp(new AstLogAnd(lowerIfp->fileline(), condp, lowerCondp)); nodep->condp(new AstLogAnd(lowerIfp->fileline(), condp, lowerCondp));
lowerIfp->replaceWith(lowerIfsp); lowerIfp->replaceWith(lowerThensp);
VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp); VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp);
} else if (operandBoolShift(nodep->condp())) { } else if (operandBoolShift(nodep->condp())) {
replaceBoolShift(nodep->condp()); replaceBoolShift(nodep->condp());
@ -2967,7 +2965,7 @@ private:
} }
} }
virtual void visit(AstDisplay* nodep) override { void visit(AstDisplay* nodep) override {
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2)) // DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
iterateChildren(nodep); iterateChildren(nodep);
if (stmtDisplayDisplay(nodep)) return; if (stmtDisplayDisplay(nodep)) return;
@ -3016,12 +3014,14 @@ private:
pformatp->text(pformatp->text() + nformatp->text()); pformatp->text(pformatp->text() + nformatp->text());
if (!prevp->addNewline() && nodep->addNewline()) pformatp->text(pformatp->text() + "\n"); if (!prevp->addNewline() && nodep->addNewline()) pformatp->text(pformatp->text() + "\n");
if (nformatp->exprsp()) pformatp->addExprsp(nformatp->exprsp()->unlinkFrBackWithNext()); if (nformatp->exprsp()) pformatp->addExprsp(nformatp->exprsp()->unlinkFrBackWithNext());
if (nformatp->scopeNamep()) if (AstScopeName* const scopeNamep = nformatp->scopeNamep()) {
pformatp->scopeNamep(nformatp->scopeNamep()->unlinkFrBackWithNext()); scopeNamep->unlinkFrBackWithNext();
pformatp->scopeNamep(scopeNamep);
}
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return true; return true;
} }
virtual void visit(AstSFormatF* nodep) override { void visit(AstSFormatF* nodep) override {
// Substitute constants into displays. The main point of this is to // Substitute constants into displays. The main point of this is to
// simplify assertion methodologies which call functions with display's. // simplify assertion methodologies which call functions with display's.
// This eliminates a pile of wide temps, and makes the C a whole lot more readable. // This eliminates a pile of wide temps, and makes the C a whole lot more readable.
@ -3088,17 +3088,17 @@ private:
} }
} }
virtual void visit(AstFuncRef* nodep) override { void visit(AstFuncRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_params) { // Only parameters force us to do constant function call propagation if (m_params) { // Only parameters force us to do constant function call propagation
replaceWithSimulation(nodep); replaceWithSimulation(nodep);
} }
} }
virtual void visit(AstArg* nodep) override { void visit(AstArg* nodep) override {
// replaceWithSimulation on the Arg's parent FuncRef replaces these // replaceWithSimulation on the Arg's parent FuncRef replaces these
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
const bool oldHasJumpDelay = m_hasJumpDelay; const bool oldHasJumpDelay = m_hasJumpDelay;
m_hasJumpDelay = false; m_hasJumpDelay = false;
{ iterateChildren(nodep); } { iterateChildren(nodep); }
@ -3124,22 +3124,22 @@ private:
} }
} }
} }
virtual void visit(AstInitArray* nodep) override { iterateChildren(nodep); } void visit(AstInitArray* nodep) override { iterateChildren(nodep); }
virtual void visit(AstInitItem* nodep) override { iterateChildren(nodep); } void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
virtual void visit(AstUnbounded* nodep) override { iterateChildren(nodep); } void visit(AstUnbounded* nodep) override { iterateChildren(nodep); }
// These are converted by V3Param. Don't constify as we don't want the // These are converted by V3Param. Don't constify as we don't want the
// from() VARREF to disappear, if any. // from() VARREF to disappear, if any.
// If output of a presel didn't get consted, chances are V3Param didn't visit properly // If output of a presel didn't get consted, chances are V3Param didn't visit properly
virtual void visit(AstNodePreSel*) override {} void visit(AstNodePreSel*) override {}
// Ignored, can eliminate early // Ignored, can eliminate early
virtual void visit(AstSysIgnore* nodep) override { void visit(AstSysIgnore* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
// Simplify // Simplify
virtual void visit(AstBasicDType* nodep) override { void visit(AstBasicDType* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
nodep->cvtRangeConst(); nodep->cvtRangeConst();
} }
@ -3147,11 +3147,11 @@ private:
//----- //-----
// Jump elimination // Jump elimination
virtual void visit(AstDelay* nodep) override { void visit(AstDelay* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
m_hasJumpDelay = true; m_hasJumpDelay = true;
} }
virtual void visit(AstJumpGo* nodep) override { void visit(AstJumpGo* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
// Jump to label where label immediately follows label is not useful // Jump to label where label immediately follows label is not useful
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) { if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
@ -3182,7 +3182,7 @@ private:
m_hasJumpDelay = true; m_hasJumpDelay = true;
} }
virtual void visit(AstJumpBlock* nodep) override { void visit(AstJumpBlock* nodep) override {
// Because JumpLabels disable many optimizations, // Because JumpLabels disable many optimizations,
// remove JumpLabels that are not pointed to by any AstJumpGos // remove JumpLabels that are not pointed to by any AstJumpGos
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this // Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
@ -3301,19 +3301,19 @@ private:
TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b) TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b)
// Trinary ops // Trinary ops
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump! // Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)"); TREEOP ("AstNodeCond{$condp.isZero, $thenp, $elsep}", "replaceWChild(nodep,$elsep)");
TREEOP ("AstNodeCond{$condp.isNeqZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr1p)"); TREEOP ("AstNodeCond{$condp.isNeqZero, $thenp, $elsep}", "replaceWChild(nodep,$thenp)");
TREEOPA("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)"); TREEOPA("AstNodeCond{$condp.isZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$elsep)");
TREEOPA("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)"); TREEOPA("AstNodeCond{$condp.isNeqZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$thenp)");
TREEOP ("AstNodeCond{$condp, operandsSame($expr1p,,$expr2p)}","replaceWChild(nodep,$expr1p)"); TREEOP ("AstNodeCond{$condp, operandsSame($thenp,,$elsep)}","replaceWChild(nodep,$thenp)");
// This visit function here must allow for short-circuiting. // This visit function here must allow for short-circuiting.
TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)"); TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)");
TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)"); TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)");
TREEOP ("AstCond{$condp.castNot, $expr1p, $expr2p}", "AstCond{$condp->op1p(), $expr2p, $expr1p}"); TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->op1p(), $elsep, $thenp}");
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isAllOnes, $expr2p}", "AstLogOr {$condp, $expr2p}"); // a?1:b == a||b TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isZero}", "AstLogAnd{$condp, $expr1p}"); // a?b:0 == a&&b TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isAllOnes}", "AstLogOr {AstNot{$condp}, $expr1p}"); // a?b:1 == ~a||b TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isZero, $expr2p}", "AstLogAnd{AstNot{$condp}, $expr2p}"); // a?0:b == ~a&&b TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b
TREEOP ("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())"); TREEOP ("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())");
// Prefer constants on left, since that often needs a shift, it lets // Prefer constants on left, since that often needs a shift, it lets
// constant red remove the shift // constant red remove the shift
@ -3536,7 +3536,7 @@ private:
// Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101 // Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101
//----- //-----
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
// Default: Just iterate // Default: Just iterate
if (m_required) { if (m_required) {
if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range) || VN_IS(nodep, SliceSel)) { if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range) || VN_IS(nodep, SliceSel)) {
@ -3583,7 +3583,7 @@ public:
} }
// clang-format on // clang-format on
} }
virtual ~ConstVisitor() override { ~ConstVisitor() override {
if (m_doCpp) { if (m_doCpp) {
if (m_globalPass) { if (m_globalPass) {
V3Stats::addStat("Optimizations, Const bit op reduction", m_statBitOpReduction); V3Stats::addStat("Optimizations, Const bit op reduction", m_statBitOpReduction);
@ -3664,7 +3664,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true}; ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3);
} }
void V3Const::constifyCpp(AstNetlist* nodep) { void V3Const::constifyCpp(AstNetlist* nodep) {
@ -3673,7 +3673,7 @@ void V3Const::constifyCpp(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true}; ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const_cpp", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTree() >= 3);
} }
AstNode* V3Const::constifyEdit(AstNode* nodep) { AstNode* V3Const::constifyEdit(AstNode* nodep) {
@ -3697,7 +3697,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true}; ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3);
} }
void V3Const::constifyAll(AstNetlist* nodep) { void V3Const::constifyAll(AstNetlist* nodep) {
@ -3707,7 +3707,7 @@ void V3Const::constifyAll(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true}; ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3);
} }
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {

View File

@ -35,6 +35,8 @@
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Coverage state, as a visitor of each AstNode // Coverage state, as a visitor of each AstNode
@ -86,7 +88,6 @@ private:
m_handleLines; // All line numbers for a given m_stateHandle m_handleLines; // All line numbers for a given m_stateHandle
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
const char* varIgnoreToggle(AstVar* nodep) { const char* varIgnoreToggle(AstVar* nodep) {
// Return true if this shouldn't be traced // Return true if this shouldn't be traced
@ -119,7 +120,7 @@ private:
AstCoverDecl* const declp = new AstCoverDecl(fl, page, comment, linescov, offset); AstCoverDecl* const declp = new AstCoverDecl(fl, page, comment, linescov, offset);
declp->hier(hier); declp->hier(hier);
m_modp->addStmtp(declp); m_modp->addStmtsp(declp);
UINFO(9, "new " << declp << endl); UINFO(9, "new " << declp << endl);
AstCoverInc* const incp = new AstCoverInc(fl, declp); AstCoverInc* const incp = new AstCoverInc(fl, declp);
@ -128,13 +129,13 @@ private:
incp->findUInt32DType()); incp->findUInt32DType());
varp->trace(true); varp->trace(true);
varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
m_modp->addStmtp(varp); m_modp->addStmtsp(varp);
UINFO(5, "New coverage trace: " << varp << endl); UINFO(5, "New coverage trace: " << varp << endl);
AstAssign* const assp = new AstAssign( AstAssign* const assp = new AstAssign(
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE), incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ), new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1))); new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
incp->addNext(assp); AstNode::addNext<AstNode, AstNode>(incp, assp);
} }
return incp; return incp;
} }
@ -209,7 +210,7 @@ private:
} }
// VISITORS - BOTH // VISITORS - BOTH
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
const AstNodeModule* const origModp = m_modp; const AstNodeModule* const origModp = m_modp;
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_state); VL_RESTORER(m_state);
@ -227,9 +228,9 @@ private:
} }
} }
virtual void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); } void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
virtual void visit(AstWhile* nodep) override { iterateProcedure(nodep); } void visit(AstWhile* nodep) override { iterateProcedure(nodep); }
virtual void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
if (!nodep->dpiImport()) iterateProcedure(nodep); if (!nodep->dpiImport()) iterateProcedure(nodep);
} }
void iterateProcedure(AstNode* nodep) { void iterateProcedure(AstNode* nodep) {
@ -245,11 +246,11 @@ private:
= newCoverInc(nodep->fileline(), "", "v_line", "block", = newCoverInc(nodep->fileline(), "", "v_line", "block",
linesCov(m_state, nodep), 0, traceNameForLine(nodep, "block")); linesCov(m_state, nodep), 0, traceNameForLine(nodep, "block"));
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) { if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
itemp->addStmtp(newp); itemp->addStmtsp(newp);
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) { } else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
itemp->addStmtsp(newp); itemp->addStmtsp(newp);
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) { } else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
itemp->addBodysp(newp); itemp->addStmtsp(newp);
} else { } else {
nodep->v3fatalSrc("Bad node type"); nodep->v3fatalSrc("Bad node type");
} }
@ -258,7 +259,7 @@ private:
} }
// VISITORS - TOGGLE COVERAGE // VISITORS - TOGGLE COVERAGE
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn() if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn()
&& v3Global.opt.coverageToggle()) { && v3Global.opt.coverageToggle()) {
@ -283,7 +284,7 @@ private:
AstVar* const chgVarp AstVar* const chgVarp
= new AstVar(nodep->fileline(), VVarType::MODULETEMP, newvarname, nodep); = new AstVar(nodep->fileline(), VVarType::MODULETEMP, newvarname, nodep);
chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
m_modp->addStmtp(chgVarp); m_modp->addStmtsp(chgVarp);
// Create bucket for each dimension * bit. // Create bucket for each dimension * bit.
// This is necessarily an O(n^2) expansion, which is why // This is necessarily an O(n^2) expansion, which is why
@ -304,7 +305,7 @@ private:
newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, "", 0, newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, "", 0,
""), ""),
above.m_varRefp->cloneTree(true), above.m_chgRefp->cloneTree(true)); above.m_varRefp->cloneTree(true), above.m_chgRefp->cloneTree(true));
m_modp->addStmtp(newp); m_modp->addStmtsp(newp);
} }
void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration
@ -383,12 +384,12 @@ private:
// VISITORS - LINE COVERAGE // VISITORS - LINE COVERAGE
// Note not AstNodeIf; other types don't get covered // Note not AstNodeIf; other types don't get covered
virtual void visit(AstIf* nodep) override { void visit(AstIf* nodep) override {
UINFO(4, " IF: " << nodep << endl); UINFO(4, " IF: " << nodep << endl);
if (m_state.m_on) { if (m_state.m_on) {
// An else-if. When we iterate the if, use "elsif" marking // An else-if. When we iterate the if, use "elsif" marking
const bool elsif const bool elsif
= nodep->ifsp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp(); = nodep->thensp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp();
if (elsif) VN_AS(nodep->elsesp(), If)->user1(true); if (elsif) VN_AS(nodep->elsesp(), If)->user1(true);
const bool first_elsif = !nodep->user1() && elsif; const bool first_elsif = !nodep->user1() && elsif;
const bool cont_elsif = nodep->user1() && elsif; const bool cont_elsif = nodep->user1() && elsif;
@ -403,7 +404,7 @@ private:
CheckState elseState; CheckState elseState;
{ {
createHandle(nodep); createHandle(nodep);
iterateAndNextNull(nodep->ifsp()); iterateAndNextNull(nodep->thensp());
lineTrack(nodep); lineTrack(nodep);
ifState = m_state; ifState = m_state;
} }
@ -422,9 +423,9 @@ private:
// Normal if. Linecov shows what's inside the if (not condition that is // Normal if. Linecov shows what's inside the if (not condition that is
// always executed) // always executed)
UINFO(4, " COVER-branch: " << nodep << endl); UINFO(4, " COVER-branch: " << nodep << endl);
nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_branch", "if", nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_branch", "if",
linesCov(ifState, nodep), 0, linesCov(ifState, nodep), 0,
traceNameForLine(nodep, "if"))); traceNameForLine(nodep, "if")));
// The else has a column offset of 1 to uniquify it relative to the if // The else has a column offset of 1 to uniquify it relative to the if
// As "if" and "else" are more than one character wide, this won't overlap // As "if" and "else" are more than one character wide, this won't overlap
// another token // another token
@ -436,18 +437,18 @@ private:
else if (first_elsif || cont_elsif) { else if (first_elsif || cont_elsif) {
UINFO(4, " COVER-elsif: " << nodep << endl); UINFO(4, " COVER-elsif: " << nodep << endl);
if (ifState.lineCoverageOn(nodep)) { if (ifState.lineCoverageOn(nodep)) {
nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "elsif", nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_line", "elsif",
linesCov(ifState, nodep), 0, linesCov(ifState, nodep), 0,
traceNameForLine(nodep, "elsif"))); traceNameForLine(nodep, "elsif")));
} }
// and we don't insert the else as the child if-else will do so // and we don't insert the else as the child if-else will do so
} else { } else {
// Cover as separate blocks (not a branch as is not two-legged) // Cover as separate blocks (not a branch as is not two-legged)
if (ifState.lineCoverageOn(nodep)) { if (ifState.lineCoverageOn(nodep)) {
UINFO(4, " COVER-half-if: " << nodep << endl); UINFO(4, " COVER-half-if: " << nodep << endl);
nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "if", nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_line", "if",
linesCov(ifState, nodep), 0, linesCov(ifState, nodep), 0,
traceNameForLine(nodep, "if"))); traceNameForLine(nodep, "if")));
} }
if (elseState.lineCoverageOn(nodep)) { if (elseState.lineCoverageOn(nodep)) {
UINFO(4, " COVER-half-el: " << nodep << endl); UINFO(4, " COVER-half-el: " << nodep << endl);
@ -460,7 +461,7 @@ private:
} }
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl); UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
} }
virtual void visit(AstCaseItem* nodep) override { void visit(AstCaseItem* nodep) override {
// We don't add an explicit "default" coverage if not provided, // We don't add an explicit "default" coverage if not provided,
// as we already have a warning when there is no default. // as we already have a warning when there is no default.
UINFO(4, " CASEI: " << nodep << endl); UINFO(4, " CASEI: " << nodep << endl);
@ -468,38 +469,38 @@ private:
VL_RESTORER(m_state); VL_RESTORER(m_state);
{ {
createHandle(nodep); createHandle(nodep);
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->stmtsp());
if (m_state.lineCoverageOn(nodep)) { // if the case body didn't disable it if (m_state.lineCoverageOn(nodep)) { // if the case body didn't disable it
lineTrack(nodep); lineTrack(nodep);
UINFO(4, " COVER: " << nodep << endl); UINFO(4, " COVER: " << nodep << endl);
nodep->addBodysp(newCoverInc(nodep->fileline(), "", "v_line", "case", nodep->addStmtsp(newCoverInc(nodep->fileline(), "", "v_line", "case",
linesCov(m_state, nodep), 0, linesCov(m_state, nodep), 0,
traceNameForLine(nodep, "case"))); traceNameForLine(nodep, "case")));
} }
} }
} }
} }
virtual void visit(AstCover* nodep) override { void visit(AstCover* nodep) override {
UINFO(4, " COVER: " << nodep << endl); UINFO(4, " COVER: " << nodep << endl);
VL_RESTORER(m_state); VL_RESTORER(m_state);
{ {
m_state.m_on = true; // Always do cover blocks, even if there's a $stop m_state.m_on = true; // Always do cover blocks, even if there's a $stop
createHandle(nodep); createHandle(nodep);
iterateChildren(nodep); iterateChildren(nodep);
if (!nodep->coverincp() && v3Global.opt.coverageUser()) { if (!nodep->coverincsp() && v3Global.opt.coverageUser()) {
// Note the name may be overridden by V3Assert processing // Note the name may be overridden by V3Assert processing
lineTrack(nodep); lineTrack(nodep);
nodep->coverincp(newCoverInc(nodep->fileline(), m_beginHier, "v_user", "cover", nodep->addCoverincsp(newCoverInc(nodep->fileline(), m_beginHier, "v_user", "cover",
linesCov(m_state, nodep), 0, linesCov(m_state, nodep), 0,
m_beginHier + "_vlCoverageUserTrace")); m_beginHier + "_vlCoverageUserTrace"));
} }
} }
} }
virtual void visit(AstStop* nodep) override { void visit(AstStop* nodep) override {
UINFO(4, " STOP: " << nodep << endl); UINFO(4, " STOP: " << nodep << endl);
m_state.m_on = false; m_state.m_on = false;
} }
virtual void visit(AstPragma* nodep) override { void visit(AstPragma* nodep) override {
if (nodep->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) { if (nodep->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) {
// Skip all NEXT nodes under this block, and skip this if/case branch // Skip all NEXT nodes under this block, and skip this if/case branch
UINFO(4, " OFF: h" << m_state.m_handle << " " << nodep << endl); UINFO(4, " OFF: h" << m_state.m_handle << " " << nodep << endl);
@ -510,7 +511,7 @@ private:
lineTrack(nodep); lineTrack(nodep);
} }
} }
virtual void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// Record the hierarchy of any named begins, so we can apply to user // Record the hierarchy of any named begins, so we can apply to user
// coverage points. This is because there may be cov points inside // coverage points. This is because there may be cov points inside
// generate blocks; each point should get separate consideration. // generate blocks; each point should get separate consideration.
@ -529,7 +530,7 @@ private:
} }
// VISITORS - BOTH // VISITORS - BOTH
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
lineTrack(nodep); lineTrack(nodep);
} }
@ -537,7 +538,7 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); } explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }
virtual ~CoverageVisitor() override = default; ~CoverageVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -546,5 +547,5 @@ public:
void V3Coverage::coverage(AstNetlist* rootp) { void V3Coverage::coverage(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageVisitor{rootp}; } // Destruct before checking { CoverageVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coverage", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("coverage", 0, dumpTree() >= 3);
} }

View File

@ -28,6 +28,8 @@
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// CoverageJoin state, as a visitor of each AstNode // CoverageJoin state, as a visitor of each AstNode
@ -42,7 +44,6 @@ private:
VDouble0 m_statToggleJoins; // Statistic tracking VDouble0 m_statToggleJoins; // Statistic tracking
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void detectDuplicates() { void detectDuplicates() {
UINFO(9, "Finding duplicates\n"); UINFO(9, "Finding duplicates\n");
@ -88,24 +89,24 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
// Find all Coverage's // Find all Coverage's
iterateChildren(nodep); iterateChildren(nodep);
// Simplify // Simplify
detectDuplicates(); detectDuplicates();
} }
virtual void visit(AstCoverToggle* nodep) override { void visit(AstCoverToggle* nodep) override {
m_toggleps.push_back(nodep); m_toggleps.push_back(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
//-------------------- //--------------------
virtual void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); } explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CoverageJoinVisitor() override { ~CoverageJoinVisitor() override {
V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins); V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins);
} }
}; };
@ -116,5 +117,5 @@ public:
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) { void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageJoinVisitor{rootp}; } // Destruct before checking { CoverageJoinVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coveragejoin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTree() >= 3);
} }

View File

@ -44,6 +44,8 @@
#include <map> #include <map>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Dead state, as a visitor of each AstNode // Dead state, as a visitor of each AstNode
@ -78,7 +80,6 @@ private:
bool m_sideEffect = false; // Side effects discovered in assign RHS bool m_sideEffect = false; // Side effects discovered in assign RHS
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void checkAll(AstNode* nodep) { void checkAll(AstNode* nodep) {
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
@ -102,7 +103,7 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
if (m_modp) m_modp->user1Inc(); // e.g. Class under Package if (m_modp) m_modp->user1Inc(); // e.g. Class under Package
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
@ -120,12 +121,12 @@ private:
} }
} }
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc(); if (nodep->scopep()) nodep->scopep()->user1Inc();
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc(); if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc();
@ -136,14 +137,14 @@ private:
m_scopesp.push_back(nodep); m_scopesp.push_back(nodep);
} }
} }
virtual void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
m_cellsp.push_back(nodep); m_cellsp.push_back(nodep);
nodep->modp()->user1Inc(); nodep->modp()->user1Inc();
} }
virtual void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
// Note NodeAssign skips calling this in some cases // Note NodeAssign skips calling this in some cases
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
@ -155,7 +156,7 @@ private:
if (nodep->varp()) nodep->varp()->user1Inc(); if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(); if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc();
} }
virtual void visit(AstNodeFTaskRef* nodep) override { void visit(AstNodeFTaskRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
if (nodep->classOrPackagep()) { if (nodep->classOrPackagep()) {
@ -166,11 +167,11 @@ private:
} }
} }
} }
virtual void visit(AstMethodCall* nodep) override { void visit(AstMethodCall* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
} }
virtual void visit(AstRefDType* nodep) override { void visit(AstRefDType* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkDType(nodep); checkDType(nodep);
checkAll(nodep); checkAll(nodep);
@ -184,7 +185,7 @@ private:
} }
} }
} }
virtual void visit(AstClassRefDType* nodep) override { void visit(AstClassRefDType* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkDType(nodep); checkDType(nodep);
checkAll(nodep); checkAll(nodep);
@ -197,12 +198,12 @@ private:
} }
if (nodep->classp()) nodep->classp()->user1Inc(); if (nodep->classp()) nodep->classp()->user1Inc();
} }
virtual void visit(AstNodeDType* nodep) override { void visit(AstNodeDType* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkDType(nodep); checkDType(nodep);
checkAll(nodep); checkAll(nodep);
} }
virtual void visit(AstEnumItemRef* nodep) override { void visit(AstEnumItemRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
if (nodep->classOrPackagep()) { if (nodep->classOrPackagep()) {
@ -214,13 +215,13 @@ private:
} }
checkAll(nodep); checkAll(nodep);
} }
virtual void visit(AstMemberSel* nodep) override { void visit(AstMemberSel* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (nodep->varp()) nodep->varp()->user1Inc(); if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref
checkAll(nodep); checkAll(nodep);
} }
virtual void visit(AstModport* nodep) override { void visit(AstModport* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_elimCells) { if (m_elimCells) {
if (!nodep->varsp()) { if (!nodep->varsp()) {
@ -230,14 +231,14 @@ private:
} }
checkAll(nodep); checkAll(nodep);
} }
virtual void visit(AstSelLoopVars* nodep) override { void visit(AstSelLoopVars* nodep) override {
// Var under a SelLoopVars means we haven't called V3Width to remove them yet // Var under a SelLoopVars means we haven't called V3Width to remove them yet
VL_RESTORER(m_selloopvarsp); VL_RESTORER(m_selloopvarsp);
m_selloopvarsp = nodep; m_selloopvarsp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
} }
virtual void visit(AstTypedef* nodep) override { void visit(AstTypedef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_elimCells && !nodep->attrPublic()) { if (m_elimCells && !nodep->attrPublic()) {
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
@ -248,20 +249,20 @@ private:
// Normal modules may disappear, e.g. if they are parameterized then removed // Normal modules may disappear, e.g. if they are parameterized then removed
if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc(); if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
} }
virtual void visit(AstVarScope* nodep) override { void visit(AstVarScope* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc(); if (nodep->scopep()) nodep->scopep()->user1Inc();
if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep); if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep);
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc(); if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
if (m_selloopvarsp) nodep->user1Inc(); if (m_selloopvarsp) nodep->user1Inc();
if (mightElimVar(nodep)) m_varsp.push_back(nodep); if (mightElimVar(nodep)) m_varsp.push_back(nodep);
} }
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
// See if simple assignments to variables may be eliminated because // See if simple assignments to variables may be eliminated because
// that variable is never used. // that variable is never used.
// Similar code in V3Life // Similar code in V3Life
@ -284,7 +285,7 @@ private:
} }
//----- //-----
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
if (nodep->isOutputter()) m_sideEffect = true; if (nodep->isOutputter()) m_sideEffect = true;
iterateChildren(nodep); iterateChildren(nodep);
checkAll(nodep); checkAll(nodep);
@ -446,7 +447,7 @@ public:
// We may have removed some datatypes, cleanup // We may have removed some datatypes, cleanup
nodep->typeTablep()->repairCache(); nodep->typeTablep()->repairCache();
} }
virtual ~DeadVisitor() override = default; ~DeadVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -455,30 +456,29 @@ public:
void V3Dead::deadifyModules(AstNetlist* nodep) { void V3Dead::deadifyModules(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{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); V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTree() >= 6);
} }
void V3Dead::deadifyDTypes(AstNetlist* nodep) { void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{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); V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTree() >= 3);
} }
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking { DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTree() >= 3);
v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
} }
void V3Dead::deadifyAll(AstNetlist* nodep) { void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{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); V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTree() >= 3);
} }
void V3Dead::deadifyAllScoped(AstNetlist* nodep) { void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{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); V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTree() >= 3);
} }

View File

@ -61,6 +61,8 @@
#include <deque> #include <deque>
#include <map> #include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Delayed state, as a visitor of each AstNode // Delayed state, as a visitor of each AstNode
@ -102,7 +104,6 @@ private:
std::unordered_map<const AstVarScope*, int> m_scopeVecMap; // Next var number for each scope std::unordered_map<const AstVarScope*, int> m_scopeVecMap; // Next var number for each scope
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void markVarUsage(AstNodeVarRef* nodep, bool blocking) { void markVarUsage(AstNodeVarRef* nodep, bool blocking) {
// Ignore if warning is disabled on this reference (used by V3Force). // Ignore if warning is disabled on this reference (used by V3Force).
@ -153,13 +154,13 @@ private:
varp = new AstVar(oldvarscp->fileline(), VVarType::BLOCKTEMP, name, varp = new AstVar(oldvarscp->fileline(), VVarType::BLOCKTEMP, name,
VFlagBitPacked(), width); VFlagBitPacked(), width);
} }
addmodp->addStmtp(varp); addmodp->addStmtsp(varp);
m_modVarMap.emplace(std::make_pair(addmodp, name), varp); m_modVarMap.emplace(std::make_pair(addmodp, name), varp);
} }
AstVarScope* const varscp AstVarScope* const varscp
= new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp); = new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
oldvarscp->scopep()->addVarp(varscp); oldvarscp->scopep()->addVarsp(varscp);
return varscp; return varscp;
} }
@ -356,33 +357,33 @@ private:
postLogicp = new AstIf(nodep->fileline(), postLogicp = new AstIf(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, VAccess::READ)); new AstVarRef(nodep->fileline(), setvscp, VAccess::READ));
UINFO(9, " Created " << postLogicp << endl); UINFO(9, " Created " << postLogicp << endl);
finalp->addStmtp(postLogicp); finalp->addStmtsp(postLogicp);
finalp->user3p(setvscp); // Remember IF's vset variable finalp->user3p(setvscp); // Remember IF's vset variable
finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it
} }
postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp)); postLogicp->addThensp(new AstAssign(nodep->fileline(), selectsp, valreadp));
return newlhsp; return newlhsp;
} }
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
// VV***** We reset all userp() on the netlist // VV***** We reset all userp() on the netlist
m_modVarMap.clear(); m_modVarMap.clear();
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
UINFO(4, " MOD " << nodep << endl); UINFO(4, " MOD " << nodep << endl);
AstNode::user3ClearTree(); AstNode::user3ClearTree();
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
{ {
m_cfuncp = nodep; m_cfuncp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstActive* nodep) override { void visit(AstActive* nodep) override {
m_activep = nodep; m_activep = nodep;
VL_RESTORER(m_inInitial); VL_RESTORER(m_inInitial);
{ {
@ -392,7 +393,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstAssignDly* nodep) override { void visit(AstAssignDly* nodep) override {
m_inDly = true; m_inDly = true;
m_nextDlyp m_nextDlyp
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe nullptr. = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe nullptr.
@ -426,7 +427,7 @@ private:
m_nextDlyp = nullptr; m_nextDlyp = nullptr;
} }
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
if (!nodep->user2Inc()) { // Not done yet if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->access().isWriteOrRW()) { if (m_inDly && nodep->access().isWriteOrRW()) {
UINFO(4, "AssignDlyVar: " << nodep << endl); UINFO(4, "AssignDlyVar: " << nodep << endl);
@ -488,18 +489,18 @@ private:
} }
} }
virtual void visit(AstNodeReadWriteMem* nodep) override { void visit(AstNodeReadWriteMem* nodep) override {
VL_RESTORER(m_ignoreBlkAndNBlk); VL_RESTORER(m_ignoreBlkAndNBlk);
m_ignoreBlkAndNBlk = true; // $readmem/$writemem often used in mem models m_ignoreBlkAndNBlk = true; // $readmem/$writemem often used in mem models
// so we will suppress BLKANDNBLK warnings // so we will suppress BLKANDNBLK warnings
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc( nodep->v3fatalSrc(
"For statements should have been converted to while statements in V3Begin"); "For statements should have been converted to while statements in V3Begin");
} }
virtual void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
VL_RESTORER(m_inLoop); VL_RESTORER(m_inLoop);
{ {
m_inLoop = true; m_inLoop = true;
@ -508,12 +509,12 @@ private:
} }
//-------------------- //--------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit DelayedVisitor(AstNetlist* nodep) { iterate(nodep); } explicit DelayedVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DelayedVisitor() override { ~DelayedVisitor() override {
V3Stats::addStat("Optimizations, Delayed shared-sets", m_statSharedSet); V3Stats::addStat("Optimizations, Delayed shared-sets", m_statSharedSet);
} }
}; };
@ -524,5 +525,5 @@ public:
void V3Delayed::delayedAll(AstNetlist* nodep) { void V3Delayed::delayedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DelayedVisitor{nodep}; } // Destruct before checking { DelayedVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("delayed", 0, dumpTree() >= 3);
} }

View File

@ -34,6 +34,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class DepthVisitor final : public VNVisitor { class DepthVisitor final : public VNVisitor {
@ -49,7 +51,6 @@ private:
V3UniqueNames m_tempNames; // For generating unique temporary variable names V3UniqueNames m_tempNames; // For generating unique temporary variable names
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void createDeepTemp(AstNode* nodep) { void createDeepTemp(AstNode* nodep) {
UINFO(6, " Deep " << nodep << endl); UINFO(6, " Deep " << nodep << endl);
@ -73,7 +74,7 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
VL_RESTORER(m_mtaskbodyp); VL_RESTORER(m_mtaskbodyp);
{ {
@ -85,7 +86,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstMTaskBody* nodep) override { void visit(AstMTaskBody* nodep) override {
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
VL_RESTORER(m_mtaskbodyp); VL_RESTORER(m_mtaskbodyp);
{ {
@ -106,7 +107,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) { if (!nodep->isStatement()) {
iterateChildren(nodep); iterateChildren(nodep);
} else { } else {
@ -114,8 +115,8 @@ private:
} }
} }
// Operators // Operators
virtual void visit(AstNodeTermop* nodep) override {} void visit(AstNodeTermop* nodep) override {}
virtual void visit(AstNodeMath* nodep) override { void visit(AstNodeMath* nodep) override {
// We have some operator defines that use 2 parens, so += 2. // We have some operator defines that use 2 parens, so += 2.
{ {
VL_RESTORER(m_depth); VL_RESTORER(m_depth);
@ -142,19 +143,19 @@ private:
m_cfuncp->isStatic(false); m_cfuncp->isStatic(false);
} }
} }
virtual void visit(AstUCFunc* nodep) override { void visit(AstUCFunc* nodep) override {
needNonStaticFunc(nodep); needNonStaticFunc(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstUCStmt* nodep) override { void visit(AstUCStmt* nodep) override {
needNonStaticFunc(nodep); needNonStaticFunc(nodep);
visitStmt(nodep); visitStmt(nodep);
} }
//-------------------- //--------------------
// Default: Just iterate // Default: Just iterate
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars void visit(AstVar*) override {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -162,7 +163,7 @@ public:
: m_tempNames{"__Vdeeptemp"} { : m_tempNames{"__Vdeeptemp"} {
iterate(nodep); iterate(nodep);
} }
virtual ~DepthVisitor() override = default; ~DepthVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -171,5 +172,5 @@ public:
void V3Depth::depthAll(AstNetlist* nodep) { void V3Depth::depthAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthVisitor{nodep}; } // Destruct before checking { DepthVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("depth", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); V3Global::dumpCheckGlobalTree("depth", 0, dumpTree() >= 6);
} }

View File

@ -31,6 +31,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class DepthBlockVisitor final : public VNVisitor { class DepthBlockVisitor final : public VNVisitor {
@ -44,7 +46,6 @@ private:
int m_deepNum = 0; // How many functions made int m_deepNum = 0; // How many functions made
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
AstCFunc* createDeepFunc(AstNode* nodep) { AstCFunc* createDeepFunc(AstNode* nodep) {
VNRelinker relinkHandle; VNRelinker relinkHandle;
@ -57,7 +58,7 @@ private:
funcp->isStatic(m_cfuncp->isStatic()); funcp->isStatic(m_cfuncp->isStatic());
funcp->isLoose(m_cfuncp->isLoose()); funcp->isLoose(m_cfuncp->isLoose());
funcp->addStmtsp(nodep); funcp->addStmtsp(nodep);
scopep->addActivep(funcp); scopep->addBlocksp(funcp);
// Call sub function at the point where the body was removed from // Call sub function at the point where the body was removed from
AstCCall* const callp = new AstCCall(nodep->fileline(), funcp); AstCCall* const callp = new AstCCall(nodep->fileline(), funcp);
if (VN_IS(m_modp, Class)) { if (VN_IS(m_modp, Class)) {
@ -71,7 +72,7 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl); UINFO(4, " MOD " << nodep << endl);
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
@ -80,7 +81,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
// We recurse into this. // We recurse into this.
VL_RESTORER(m_depth); VL_RESTORER(m_depth);
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
@ -106,7 +107,7 @@ private:
} }
m_depth--; m_depth--;
} }
virtual void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) { if (!nodep->isStatement()) {
iterateChildren(nodep); iterateChildren(nodep);
} else { } else {
@ -114,15 +115,15 @@ private:
} }
} }
virtual void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeMath*) override {} // Accelerate
//-------------------- //--------------------
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars void visit(AstVar*) override {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); } explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DepthBlockVisitor() override = default; ~DepthBlockVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -131,5 +132,5 @@ public:
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) { void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthBlockVisitor{nodep}; } // Destruct before checking { DepthBlockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deepblock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTree() >= 3);
} }

View File

@ -33,6 +33,8 @@
#include <map> #include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class DescopeVisitor final : public VNVisitor { class DescopeVisitor final : public VNVisitor {
@ -53,7 +55,6 @@ private:
FuncMmap m_modFuncs; // Name of public functions added FuncMmap m_modFuncs; // Name of public functions added
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
static bool modIsSingleton(AstNodeModule* modp) { static bool modIsSingleton(AstNodeModule* modp) {
// True iff there's exactly one instance of this module in the design (including top). // True iff there's exactly one instance of this module in the design (including top).
@ -139,14 +140,14 @@ private:
UINFO(6, UINFO(6,
" at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl); " at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl);
funcp->declPrivate(true); funcp->declPrivate(true);
AstNode* argsp = nullptr; AstVarRef* argsp = nullptr;
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* const portp = VN_CAST(stmtp, Var)) { if (AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) { if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* const newp = new AstVarRef( AstVarRef* const newp = new AstVarRef(
portp->fileline(), portp, portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE : VAccess::READ); portp->isWritable() ? VAccess::WRITE : VAccess::READ);
argsp = argsp ? argsp->addNextNull(newp) : newp; argsp = AstNode::addNext(argsp, newp);
} }
} }
} }
@ -185,11 +186,11 @@ private:
} }
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
nodep->dpiExportTriggerp(nullptr); nodep->dpiExportTriggerp(nullptr);
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
m_modp = nodep; m_modp = nodep;
@ -199,17 +200,17 @@ private:
makePublicFuncWrappers(); makePublicFuncWrappers();
} }
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
m_scopep = nodep; m_scopep = nodep;
iterateChildren(nodep); iterateChildren(nodep);
m_scopep = nullptr; m_scopep = nullptr;
} }
virtual void visit(AstVarScope* nodep) override { void visit(AstVarScope* nodep) override {
// Delete the varscope when we're finished // Delete the varscope when we're finished
nodep->unlinkFrBack(); nodep->unlinkFrBack();
pushDeletep(nodep); pushDeletep(nodep);
} }
virtual void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (!nodep->varScopep()) { if (!nodep->varScopep()) {
UASSERT_OBJ(nodep->varp()->isFuncLocal(), nodep, UASSERT_OBJ(nodep->varp()->isFuncLocal(), nodep,
@ -233,7 +234,7 @@ private:
nodep->varScopep(nullptr); nodep->varScopep(nullptr);
UINFO(9, " refout " << nodep << " selfPtr=" << nodep->selfPointer() << endl); UINFO(9, " refout " << nodep << " selfPtr=" << nodep->selfPointer() << endl);
} }
virtual void visit(AstCCall* nodep) override { void visit(AstCCall* nodep) override {
// UINFO(9, " " << nodep << endl); // UINFO(9, " " << nodep << endl);
iterateChildren(nodep); iterateChildren(nodep);
// Convert the hierch name // Convert the hierch name
@ -243,9 +244,9 @@ private:
// Can't do this, as we may have more calls later // Can't do this, as we may have more calls later
// nodep->funcp()->scopep(nullptr); // nodep->funcp()->scopep(nullptr);
} }
virtual void visit(AstCMethodCall* nodep) override { iterateChildren(nodep); } void visit(AstCMethodCall* nodep) override { iterateChildren(nodep); }
virtual void visit(AstCNew* nodep) override { iterateChildren(nodep); } void visit(AstCNew* nodep) override { iterateChildren(nodep); }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
VL_RESTORER(m_funcp); VL_RESTORER(m_funcp);
if (!nodep->user1()) { if (!nodep->user1()) {
// Static functions should have been moved under the corresponding AstClassPackage // Static functions should have been moved under the corresponding AstClassPackage
@ -257,7 +258,7 @@ private:
// If it's under a scope, move it up to the top // If it's under a scope, move it up to the top
if (m_scopep) { if (m_scopep) {
nodep->unlinkFrBack(); nodep->unlinkFrBack();
m_modp->addStmtp(nodep); m_modp->addStmtsp(nodep);
if (nodep->funcPublic()) { if (nodep->funcPublic()) {
// There may be multiple public functions by the same name; // There may be multiple public functions by the same name;
@ -268,13 +269,13 @@ private:
} }
} }
} }
virtual void visit(AstVar*) override {} void visit(AstVar*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); } explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DescopeVisitor() override = default; ~DescopeVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -283,5 +284,5 @@ public:
void V3Descope::descopeAll(AstNetlist* nodep) { void V3Descope::descopeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ DescopeVisitor{nodep}; } // Destruct before checking { DescopeVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("descope", 0, dumpTree() >= 3);
} }

View File

@ -28,6 +28,8 @@
#include <map> #include <map>
#include <memory> #include <memory>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// V3DupFinder class functions // V3DupFinder class functions
@ -98,7 +100,5 @@ void V3DupFinder::dumpFile(const string& filename, bool tree) {
} }
void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) { void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) {
if (v3Global.opt.dumpTree()) { // if (dump()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
}
} }

View File

@ -59,7 +59,6 @@ public:
} }
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// Expose minimal set of superclass interface // Expose minimal set of superclass interface
using Super::begin; using Super::begin;

View File

@ -57,11 +57,11 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
return name; return name;
} }
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) { AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) {
AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename); AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
cfilep->slow(slow); cfilep->slow(slow);
cfilep->source(source); cfilep->source(source);
v3Global.rootp()->addFilesp(cfilep); if (add) v3Global.rootp()->addFilesp(cfilep);
return cfilep; return cfilep;
} }

View File

@ -100,7 +100,7 @@ public:
&& (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon && (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon
} }
static AstCFile* newCFile(const string& filename, bool slow, bool source); static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true);
string cFuncArgs(const AstCFunc* nodep); string cFuncArgs(const AstCFunc* nodep);
void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope);
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
@ -110,7 +110,7 @@ public:
// CONSTRUCTORS // CONSTRUCTORS
EmitCBaseVisitor() = default; EmitCBaseVisitor() = default;
virtual ~EmitCBaseVisitor() override = default; ~EmitCBaseVisitor() override = default;
}; };
#endif // guard #endif // guard

View File

@ -32,7 +32,6 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor {
uint32_t m_unpackedWord = 0; uint32_t m_unpackedWord = 0;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
uint32_t tabModulus(AstNodeDType* dtypep) { uint32_t tabModulus(AstNodeDType* dtypep) {
const uint32_t elemBytes = dtypep->widthTotalBytes(); const uint32_t elemBytes = dtypep->widthTotalBytes();
@ -45,7 +44,7 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor {
protected: protected:
// VISITORS // VISITORS
virtual void visit(AstInitArray* nodep) override { void visit(AstInitArray* nodep) override {
VL_RESTORER(m_inUnpacked); VL_RESTORER(m_inUnpacked);
VL_RESTORER(m_unpackedWord); VL_RESTORER(m_unpackedWord);
m_inUnpacked = true; m_inUnpacked = true;
@ -94,11 +93,11 @@ protected:
} }
} }
virtual void visit(AstInitItem* nodep) override { // LCOV_EXCL_START void visit(AstInitItem* nodep) override { // LCOV_EXCL_START
nodep->v3fatal("Handled by AstInitArray"); nodep->v3fatal("Handled by AstInitArray");
} // LCOV_EXCL_STOP } // LCOV_EXCL_STOP
virtual void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
const V3Number& num = nodep->num(); const V3Number& num = nodep->num();
UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool"); UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool");
const AstNodeDType* const dtypep = nodep->dtypep(); const AstNodeDType* const dtypep = nodep->dtypep();
@ -145,7 +144,7 @@ protected:
} }
// Default // Default
virtual void visit(AstNode* nodep) override { // LCOV_EXCL_START void visit(AstNode* nodep) override { // LCOV_EXCL_START
nodep->v3fatalSrc("Unknown node type reached EmitCConstInit: " << nodep->prettyTypeName()); nodep->v3fatalSrc("Unknown node type reached EmitCConstInit: " << nodep->prettyTypeName());
} // LCOV_EXCL_STOP } // LCOV_EXCL_STOP
}; };

View File

@ -27,6 +27,8 @@
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Const pool emitter // Const pool emitter
@ -38,7 +40,6 @@ class EmitCConstPool final : public EmitCConstInit {
VDouble0 m_constsEmitted; VDouble0 m_constsEmitted;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
V3OutCFile* newOutCFile() const { V3OutCFile* newOutCFile() const {
const string fileName = v3Global.opt.makeDir() + "/" + topClassName() + "__ConstPool_" const string fileName = v3Global.opt.makeDir() + "/" + topClassName() + "__ConstPool_"
@ -100,7 +101,7 @@ class EmitCConstPool final : public EmitCConstInit {
} }
// VISITORS // VISITORS
virtual void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
m_outFileSize += nodep->num().isString() ? 10 : nodep->isWide() ? nodep->widthWords() : 1; m_outFileSize += nodep->num().isString() ? 10 : nodep->isWide() ? nodep->widthWords() : 1;
EmitCConstInit::visit(nodep); EmitCConstInit::visit(nodep);
} }

View File

@ -36,18 +36,20 @@ constexpr int EMITC_NUM_CONSTW = 8;
class EmitCLazyDecls final : public VNVisitor { class EmitCLazyDecls final : public VNVisitor {
// NODE STATE/TYPES // NODE STATE/TYPES
// AstNode::user2() -> bool. Already emitted decl for symbols. // None allowed to support threaded emitting
const VNUser2InUse m_inuser2;
// MEMBERS // MEMBERS
std::unordered_set<string> m_emittedManually; // Set of names already declared manually. std::unordered_set<string> m_emittedManually; // Set of names already declared manually.
EmitCBaseVisitor& m_emitter; // For access to file output EmitCBaseVisitor& m_emitter; // For access to file output
bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic) bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic)
std::set<AstNode*> m_emitted; // -> in set. Already emitted decl for symbols.
// METHODS // METHODS
bool declaredOnce(AstNode* nodep) { return m_emitted.insert(nodep).second; }
void lazyDeclare(AstCFunc* funcp) { void lazyDeclare(AstCFunc* funcp) {
// Already declared in this compilation unit // Already declared in this compilation unit
if (funcp->user2SetOnce()) return; if (!declaredOnce(funcp)) return;
// Check if this kind of function is lazily declared // Check if this kind of function is lazily declared
if (!(funcp->isMethod() && funcp->isLoose()) && !funcp->dpiImportPrototype()) return; if (!(funcp->isMethod() && funcp->isLoose()) && !funcp->dpiImportPrototype()) return;
// Already declared manually // Already declared manually
@ -58,7 +60,7 @@ class EmitCLazyDecls final : public VNVisitor {
} }
void lazyDeclareConstPoolVar(AstVar* varp) { void lazyDeclareConstPoolVar(AstVar* varp) {
if (varp->user2SetOnce()) return; // Already declared if (!declaredOnce(varp)) return; // Already declared
const string nameProtect const string nameProtect
= m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect(); = m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect();
m_emitter.puts("extern const "); m_emitter.puts("extern const ");
@ -68,17 +70,17 @@ class EmitCLazyDecls final : public VNVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstNodeCCall* nodep) override { void visit(AstNodeCCall* nodep) override {
lazyDeclare(nodep->funcp()); lazyDeclare(nodep->funcp());
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstAddrOfCFunc* nodep) override { void visit(AstAddrOfCFunc* nodep) override {
lazyDeclare(nodep->funcp()); lazyDeclare(nodep->funcp());
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
AstVar* const varp = nodep->varp(); AstVar* const varp = nodep->varp();
// Only constant pool symbols are lazy declared for now ... // Only constant pool symbols are lazy declared for now ...
if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) { if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) {
@ -86,9 +88,7 @@ class EmitCLazyDecls final : public VNVisitor {
} }
} }
virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
VL_DEBUG_FUNC;
public: public:
explicit EmitCLazyDecls(EmitCBaseVisitor& emitter) explicit EmitCLazyDecls(EmitCBaseVisitor& emitter)
@ -106,8 +106,8 @@ public:
m_emitter.puts(suffix); m_emitter.puts(suffix);
m_emitter.ensureNewLine(); m_emitter.ensureNewLine();
} }
void declared(AstCFunc* nodep) { nodep->user2SetOnce(); } void declared(AstCFunc* nodep) { m_emitted.insert(nodep); }
void reset() { AstNode::user2ClearTree(); } void reset() { m_emitted.clear(); }
}; };
//###################################################################### //######################################################################
@ -152,7 +152,6 @@ protected:
public: public:
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// ACCESSORS // ACCESSORS
void splitSizeInc(int count) { m_splitSize += count; } void splitSizeInc(int count) { m_splitSize += count; }
@ -211,7 +210,7 @@ public:
// VISITORS // VISITORS
using EmitCConstInit::visit; using EmitCConstInit::visit;
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
VL_RESTORER(m_useSelfForThis); VL_RESTORER(m_useSelfForThis);
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
m_cfuncp = nodep; m_cfuncp = nodep;
@ -279,12 +278,12 @@ public:
if (nodep->ifdef() != "") puts("#endif // " + nodep->ifdef() + "\n"); if (nodep->ifdef() != "") puts("#endif // " + nodep->ifdef() + "\n");
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
UASSERT_OBJ(m_cfuncp, nodep, "Cannot emit non-local variable"); UASSERT_OBJ(m_cfuncp, nodep, "Cannot emit non-local variable");
emitVarDecl(nodep); emitVarDecl(nodep);
} }
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
bool paren = true; bool paren = true;
bool decind = false; bool decind = false;
bool rhs = true; bool rhs = true;
@ -366,8 +365,8 @@ public:
if (decind) ofp()->blockDec(); if (decind) ofp()->blockDec();
puts(";\n"); puts(";\n");
} }
virtual void visit(AstAlwaysPublic*) override {} void visit(AstAlwaysPublic*) override {}
virtual void visit(AstAssocSel* nodep) override { void visit(AstAssocSel* nodep) override {
iterateAndNextNull(nodep->fromp()); iterateAndNextNull(nodep->fromp());
putbs(".at("); putbs(".at(");
AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType); AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType);
@ -379,7 +378,7 @@ public:
} }
puts(")"); puts(")");
} }
virtual void visit(AstWildcardSel* nodep) override { void visit(AstWildcardSel* nodep) override {
iterateAndNextNull(nodep->fromp()); iterateAndNextNull(nodep->fromp());
putbs(".at("); putbs(".at(");
AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType); AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType);
@ -387,7 +386,7 @@ public:
iterateAndNextNull(nodep->bitp()); iterateAndNextNull(nodep->bitp());
puts(")"); puts(")");
} }
virtual void visit(AstCCall* nodep) override { void visit(AstCCall* nodep) override {
const AstCFunc* const funcp = nodep->funcp(); const AstCFunc* const funcp = nodep->funcp();
const AstNodeModule* const funcModp = EmitCParentModule::get(funcp); const AstNodeModule* const funcModp = EmitCParentModule::get(funcp);
if (funcp->dpiImportPrototype()) { if (funcp->dpiImportPrototype()) {
@ -413,7 +412,7 @@ public:
} }
emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis)); emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis));
} }
virtual void visit(AstCMethodCall* nodep) override { void visit(AstCMethodCall* nodep) override {
const AstCFunc* const funcp = nodep->funcp(); const AstCFunc* const funcp = nodep->funcp();
UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall"); UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall");
iterate(nodep->fromp()); iterate(nodep->fromp());
@ -421,7 +420,7 @@ public:
puts(funcp->nameProtect()); puts(funcp->nameProtect());
emitCCallArgs(nodep, ""); emitCCallArgs(nodep, "");
} }
virtual void visit(AstCNew* nodep) override { void visit(AstCNew* nodep) override {
bool comma = false; bool comma = false;
puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">(");
puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary
@ -433,7 +432,7 @@ public:
} }
puts(")"); puts(")");
} }
virtual void visit(AstCMethodHard* nodep) override { void visit(AstCMethodHard* nodep) override {
iterate(nodep->fromp()); iterate(nodep->fromp());
puts("."); puts(".");
puts(nodep->name()); puts(nodep->name());
@ -455,8 +454,8 @@ public:
UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep, UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep,
"Statement of non-void data type"); "Statement of non-void data type");
} }
virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
virtual void visit(AstWith* nodep) override { void visit(AstWith* nodep) override {
// With uses a C++11 lambda // With uses a C++11 lambda
putbs("[=]("); putbs("[=](");
if (auto* const argrefp = nodep->indexArgRefp()) { if (auto* const argrefp = nodep->indexArgRefp()) {
@ -471,11 +470,11 @@ public:
iterateAndNextNull(nodep->exprp()); iterateAndNextNull(nodep->exprp());
puts("; }\n"); puts("; }\n");
} }
virtual void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE
// In V3Case... // In V3Case...
nodep->v3fatalSrc("Case statements should have been reduced out"); nodep->v3fatalSrc("Case statements should have been reduced out");
} }
virtual void visit(AstComment* nodep) override { void visit(AstComment* nodep) override {
string at; string at;
if (nodep->showAt()) { if (nodep->showAt()) {
at = " at " + nodep->fileline()->ascii(); at = " at " + nodep->fileline()->ascii();
@ -487,7 +486,7 @@ public:
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstCoverDecl* nodep) override { void visit(AstCoverDecl* nodep) override {
puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
puts("&(vlSymsp->__Vcoverage["); puts("&(vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts(cvtToStr(nodep->dataDeclThisp()->binNum()));
@ -515,7 +514,7 @@ public:
putsQuoted(nodep->linescov()); putsQuoted(nodep->linescov());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstCoverInc* nodep) override { void visit(AstCoverInc* nodep) override {
if (v3Global.opt.threads()) { if (v3Global.opt.threads()) {
puts("vlSymsp->__Vcoverage["); puts("vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum())); puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
@ -526,17 +525,17 @@ public:
puts("]);\n"); puts("]);\n");
} }
} }
virtual void visit(AstCReturn* nodep) override { void visit(AstCReturn* nodep) override {
puts("return ("); puts("return (");
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstDisplay* nodep) override { void visit(AstDisplay* nodep) override {
string text = nodep->fmtp()->text(); string text = nodep->fmtp()->text();
if (nodep->addNewline()) text += "\n"; if (nodep->addNewline()) text += "\n";
displayNode(nodep, nodep->fmtp()->scopeNamep(), text, nodep->fmtp()->exprsp(), false); displayNode(nodep, nodep->fmtp()->scopeNamep(), text, nodep->fmtp()->exprsp(), false);
} }
virtual void visit(AstDumpCtl* nodep) override { void visit(AstDumpCtl* nodep) override {
switch (nodep->ctlType()) { switch (nodep->ctlType()) {
case VDumpCtlType::FILE: case VDumpCtlType::FILE:
puts("vlSymsp->_vm_contextp__->dumpfile("); puts("vlSymsp->_vm_contextp__->dumpfile(");
@ -575,7 +574,7 @@ public:
default: nodep->v3fatalSrc("Bad case, unexpected " << nodep->ctlType().ascii()); default: nodep->v3fatalSrc("Bad case, unexpected " << nodep->ctlType().ascii());
} }
} }
virtual void visit(AstScopeName* nodep) override { void visit(AstScopeName* nodep) override {
// For use under AstCCalls for dpiImports. ScopeNames under // For use under AstCCalls for dpiImports. ScopeNames under
// displays are handled in AstDisplay // displays are handled in AstDisplay
if (!nodep->dpiExport()) { if (!nodep->dpiExport()) {
@ -584,20 +583,20 @@ public:
putbs("(&(vlSymsp->" + protect("__Vscope_" + scope) + "))"); putbs("(&(vlSymsp->" + protect("__Vscope_" + scope) + "))");
} }
} }
virtual void visit(AstSFormat* nodep) override { void visit(AstSFormat* nodep) override {
displayNode(nodep, nodep->fmtp()->scopeNamep(), nodep->fmtp()->text(), displayNode(nodep, nodep->fmtp()->scopeNamep(), nodep->fmtp()->text(),
nodep->fmtp()->exprsp(), false); nodep->fmtp()->exprsp(), false);
} }
virtual void visit(AstSFormatF* nodep) override { void visit(AstSFormatF* nodep) override {
displayNode(nodep, nodep->scopeNamep(), nodep->text(), nodep->exprsp(), false); displayNode(nodep, nodep->scopeNamep(), nodep->text(), nodep->exprsp(), false);
} }
virtual void visit(AstFScanF* nodep) override { void visit(AstFScanF* nodep) override {
displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true); displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true);
} }
virtual void visit(AstSScanF* nodep) override { void visit(AstSScanF* nodep) override {
displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true); displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true);
} }
virtual void visit(AstValuePlusArgs* nodep) override { void visit(AstValuePlusArgs* nodep) override {
puts("VL_VALUEPLUSARGS_IN"); puts("VL_VALUEPLUSARGS_IN");
emitIQW(nodep->outp()); emitIQW(nodep->outp());
puts("("); puts("(");
@ -609,19 +608,19 @@ public:
iterateAndNextNull(nodep->outp()); iterateAndNextNull(nodep->outp());
puts(")"); puts(")");
} }
virtual void visit(AstTestPlusArgs* nodep) override { void visit(AstTestPlusArgs* nodep) override {
puts("VL_TESTPLUSARGS_I("); puts("VL_TESTPLUSARGS_I(");
emitCvtPackStr(nodep->searchp()); emitCvtPackStr(nodep->searchp());
puts(")"); puts(")");
} }
virtual void visit(AstFError* nodep) override { void visit(AstFError* nodep) override {
puts("VL_FERROR_IN("); puts("VL_FERROR_IN(");
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
putbs(", "); putbs(", ");
iterateAndNextNull(nodep->strp()); iterateAndNextNull(nodep->strp());
puts(")"); puts(")");
} }
virtual void visit(AstFGetS* nodep) override { void visit(AstFGetS* nodep) override {
checkMaxWords(nodep); checkMaxWords(nodep);
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
} }
@ -634,7 +633,7 @@ public:
<< " bits exceeds hardcoded limit VL_VALUE_STRING_MAX_WORDS in verilatedos.h"); << " bits exceeds hardcoded limit VL_VALUE_STRING_MAX_WORDS in verilatedos.h");
} }
} }
virtual void visit(AstFOpen* nodep) override { void visit(AstFOpen* nodep) override {
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
puts(" = VL_FOPEN_NN("); puts(" = VL_FOPEN_NN(");
emitCvtPackStr(nodep->filenamep()); emitCvtPackStr(nodep->filenamep());
@ -644,13 +643,13 @@ public:
emitCvtPackStr(nodep->modep()); emitCvtPackStr(nodep->modep());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFOpenMcd* nodep) override { void visit(AstFOpenMcd* nodep) override {
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
puts(" = VL_FOPEN_MCD_N("); puts(" = VL_FOPEN_MCD_N(");
emitCvtPackStr(nodep->filenamep()); emitCvtPackStr(nodep->filenamep());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstNodeReadWriteMem* nodep) override { void visit(AstNodeReadWriteMem* nodep) override {
puts(nodep->cFuncPrefixp()); puts(nodep->cFuncPrefixp());
puts("N("); puts("N(");
puts(nodep->isHex() ? "true" : "false"); puts(nodep->isHex() ? "true" : "false");
@ -699,14 +698,14 @@ public:
} }
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFClose* nodep) override { void visit(AstFClose* nodep) override {
puts("VL_FCLOSE_I("); puts("VL_FCLOSE_I(");
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
puts("); "); puts("); ");
iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it. iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it.
puts(" = 0;\n"); puts(" = 0;\n");
} }
virtual void visit(AstFFlush* nodep) override { void visit(AstFFlush* nodep) override {
if (!nodep->filep()) { if (!nodep->filep()) {
puts("Verilated::runFlushCallbacks();\n"); puts("Verilated::runFlushCallbacks();\n");
} else { } else {
@ -717,7 +716,7 @@ public:
puts("); }\n"); puts("); }\n");
} }
} }
virtual void visit(AstFSeek* nodep) override { void visit(AstFSeek* nodep) override {
puts("(VL_FSEEK_I("); puts("(VL_FSEEK_I(");
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
puts(","); puts(",");
@ -726,17 +725,17 @@ public:
iterateAndNextNull(nodep->operation()); iterateAndNextNull(nodep->operation());
puts(") == -1 ? -1 : 0)"); puts(") == -1 ? -1 : 0)");
} }
virtual void visit(AstFTell* nodep) override { void visit(AstFTell* nodep) override {
puts("VL_FTELL_I("); puts("VL_FTELL_I(");
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
puts(")"); puts(")");
} }
virtual void visit(AstFRewind* nodep) override { void visit(AstFRewind* nodep) override {
puts("(VL_FSEEK_I("); puts("(VL_FSEEK_I(");
iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->filep());
puts(", 0, 0) == -1 ? -1 : 0)"); puts(", 0, 0) == -1 ? -1 : 0)");
} }
virtual void visit(AstFRead* nodep) override { void visit(AstFRead* nodep) override {
puts("VL_FREAD_I("); puts("VL_FREAD_I(");
puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width
putbs(","); putbs(",");
@ -779,12 +778,12 @@ public:
} }
puts(")"); puts(")");
} }
virtual void visit(AstSysFuncAsTask* nodep) override { void visit(AstSysFuncAsTask* nodep) override {
if (!nodep->lhsp()->isWide()) puts("(void)"); if (!nodep->lhsp()->isWide()) puts("(void)");
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
if (!nodep->lhsp()->isWide()) puts(";"); if (!nodep->lhsp()->isWide()) puts(";");
} }
virtual void visit(AstSystemT* nodep) override { void visit(AstSystemT* nodep) override {
puts("(void)VL_SYSTEM_I"); puts("(void)VL_SYSTEM_I");
emitIQW(nodep->lhsp()); emitIQW(nodep->lhsp());
puts("("); puts("(");
@ -796,7 +795,7 @@ public:
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstSystemF* nodep) override { void visit(AstSystemF* nodep) override {
puts("VL_SYSTEM_I"); puts("VL_SYSTEM_I");
emitIQW(nodep->lhsp()); emitIQW(nodep->lhsp());
puts("("); puts("(");
@ -808,30 +807,30 @@ public:
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(")"); puts(")");
} }
virtual void visit(AstJumpBlock* nodep) override { void visit(AstJumpBlock* nodep) override {
nodep->labelNum(++m_labelNum); nodep->labelNum(++m_labelNum);
puts("{\n"); // Make it visually obvious label jumps outside these puts("{\n"); // Make it visually obvious label jumps outside these
iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->endStmtsp()); iterateAndNextNull(nodep->endStmtsp());
puts("}\n"); puts("}\n");
} }
virtual void visit(AstJumpGo* nodep) override { void visit(AstJumpGo* nodep) override {
puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
} }
virtual void visit(AstJumpLabel* nodep) override { void visit(AstJumpLabel* nodep) override {
puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n"); puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
} }
virtual void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
iterateAndNextNull(nodep->precondsp()); iterateAndNextNull(nodep->precondsp());
puts("while ("); puts("while (");
iterateAndNextNull(nodep->condp()); iterateAndNextNull(nodep->condp());
puts(") {\n"); puts(") {\n");
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->incsp()); iterateAndNextNull(nodep->incsp());
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
puts("}\n"); puts("}\n");
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
puts("if ("); puts("if (");
if (!nodep->branchPred().unknown()) { if (!nodep->branchPred().unknown()) {
puts(nodep->branchPred().ascii()); puts(nodep->branchPred().ascii());
@ -840,7 +839,7 @@ public:
iterateAndNextNull(nodep->condp()); iterateAndNextNull(nodep->condp());
if (!nodep->branchPred().unknown()) puts(")"); if (!nodep->branchPred().unknown()) puts(")");
puts(") {\n"); puts(") {\n");
iterateAndNextNull(nodep->ifsp()); iterateAndNextNull(nodep->thensp());
puts("}"); puts("}");
if (!nodep->elsesp()) { if (!nodep->elsesp()) {
puts("\n"); puts("\n");
@ -855,7 +854,7 @@ public:
} }
} }
} }
virtual void visit(AstExprStmt* nodep) override { void visit(AstExprStmt* nodep) override {
// GCC allows compound statements in expressions, but this is not standard. // GCC allows compound statements in expressions, but this is not standard.
// So we use an immediate-evaluation lambda and comma operator // So we use an immediate-evaluation lambda and comma operator
putbs("([&]() {\n"); putbs("([&]() {\n");
@ -864,7 +863,7 @@ public:
iterateAndNextNull(nodep->resultp()); iterateAndNextNull(nodep->resultp());
puts(")"); puts(")");
} }
virtual void visit(AstStop* nodep) override { void visit(AstStop* nodep) override {
puts("VL_STOP_MT("); puts("VL_STOP_MT(");
putsQuoted(protect(nodep->fileline()->filename())); putsQuoted(protect(nodep->fileline()->filename()));
puts(", "); puts(", ");
@ -872,38 +871,38 @@ public:
puts(", \"\""); puts(", \"\"");
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFinish* nodep) override { void visit(AstFinish* nodep) override {
puts("VL_FINISH_MT("); puts("VL_FINISH_MT(");
putsQuoted(protect(nodep->fileline()->filename())); putsQuoted(protect(nodep->fileline()->filename()));
puts(", "); puts(", ");
puts(cvtToStr(nodep->fileline()->lineno())); puts(cvtToStr(nodep->fileline()->lineno()));
puts(", \"\");\n"); puts(", \"\");\n");
} }
virtual void visit(AstPrintTimeScale* nodep) override { void visit(AstPrintTimeScale* nodep) override {
puts("VL_PRINTTIMESCALE("); puts("VL_PRINTTIMESCALE(");
putsQuoted(protect(nodep->name())); putsQuoted(protect(nodep->name()));
puts(", "); puts(", ");
putsQuoted(nodep->timeunit().ascii()); putsQuoted(nodep->timeunit().ascii());
puts(", vlSymsp->_vm_contextp__);\n"); puts(", vlSymsp->_vm_contextp__);\n");
} }
virtual void visit(AstRand* nodep) override { void visit(AstRand* nodep) override {
emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr); emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr);
} }
virtual void visit(AstTime* nodep) override { void visit(AstTime* nodep) override {
puts("VL_TIME_UNITED_Q("); puts("VL_TIME_UNITED_Q(");
if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units"); if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units");
puts(cvtToStr(nodep->timeunit().multiplier() puts(cvtToStr(nodep->timeunit().multiplier()
/ v3Global.rootp()->timeprecision().multiplier())); / v3Global.rootp()->timeprecision().multiplier()));
puts(")"); puts(")");
} }
virtual void visit(AstTimeD* nodep) override { void visit(AstTimeD* nodep) override {
puts("VL_TIME_UNITED_D("); puts("VL_TIME_UNITED_D(");
if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$realtime has no units"); if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$realtime has no units");
puts(cvtToStr(nodep->timeunit().multiplier() puts(cvtToStr(nodep->timeunit().multiplier()
/ v3Global.rootp()->timeprecision().multiplier())); / v3Global.rootp()->timeprecision().multiplier()));
puts(")"); puts(")");
} }
virtual void visit(AstTimeFormat* nodep) override { void visit(AstTimeFormat* nodep) override {
puts("VL_TIMEFORMAT_IINI("); puts("VL_TIMEFORMAT_IINI(");
iterateAndNextNull(nodep->unitsp()); iterateAndNextNull(nodep->unitsp());
puts(", "); puts(", ");
@ -914,7 +913,7 @@ public:
iterateAndNextNull(nodep->widthp()); iterateAndNextNull(nodep->widthp());
puts(", vlSymsp->_vm_contextp__);\n"); puts(", vlSymsp->_vm_contextp__);\n");
} }
virtual void visit(AstNodeSimpleText* nodep) override { void visit(AstNodeSimpleText* nodep) override {
const string text = m_inUC && m_useSelfForThis const string text = m_inUC && m_useSelfForThis
? VString::replaceWord(nodep->text(), "this", "vlSelf") ? VString::replaceWord(nodep->text(), "this", "vlSelf")
: nodep->text(); : nodep->text();
@ -924,42 +923,42 @@ public:
ofp()->putsNoTracking(text); ofp()->putsNoTracking(text);
} }
} }
virtual void visit(AstTextBlock* nodep) override { void visit(AstTextBlock* nodep) override {
visit(static_cast<AstNodeSimpleText*>(nodep)); visit(static_cast<AstNodeSimpleText*>(nodep));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) { for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp); iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", "); if (nodep->commas() && childp->nextp()) puts(", ");
} }
} }
virtual void visit(AstCStmt* nodep) override { void visit(AstCStmt* nodep) override {
putbs(""); putbs("");
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->exprsp());
} }
virtual void visit(AstCMath* nodep) override { void visit(AstCMath* nodep) override {
putbs(""); putbs("");
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->exprsp());
} }
virtual void visit(AstUCStmt* nodep) override { void visit(AstUCStmt* nodep) override {
VL_RESTORER(m_inUC); VL_RESTORER(m_inUC);
m_inUC = true; m_inUC = true;
putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n")); putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n"));
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->exprsp());
puts("\n"); puts("\n");
} }
virtual void visit(AstUCFunc* nodep) override { void visit(AstUCFunc* nodep) override {
VL_RESTORER(m_inUC); VL_RESTORER(m_inUC);
m_inUC = true; m_inUC = true;
puts("\n"); puts("\n");
putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n")); putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n"));
iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->exprsp());
puts("\n"); puts("\n");
} }
// Operators // Operators
virtual void visit(AstNodeTermop* nodep) override { void visit(AstNodeTermop* nodep) override {
emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr); emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr);
} }
virtual void visit(AstNodeUniop* nodep) override { void visit(AstNodeUniop* nodep) override {
if (nodep->emitCheckMaxWords() if (nodep->emitCheckMaxWords()
&& (nodep->widthWords() > VL_MULS_MAX_WORDS && (nodep->widthWords() > VL_MULS_MAX_WORDS
|| nodep->lhsp()->widthWords() > VL_MULS_MAX_WORDS)) { || nodep->lhsp()->widthWords() > VL_MULS_MAX_WORDS)) {
@ -979,7 +978,7 @@ public:
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr);
} }
} }
virtual void visit(AstNodeBiop* nodep) override { void visit(AstNodeBiop* nodep) override {
if (nodep->emitCheckMaxWords() && nodep->widthWords() > VL_MULS_MAX_WORDS) { if (nodep->emitCheckMaxWords() && nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3warn( nodep->v3warn(
E_UNSUPPORTED, E_UNSUPPORTED,
@ -999,11 +998,11 @@ public:
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
} }
} }
virtual void visit(AstNodeTriop* nodep) override { void visit(AstNodeTriop* nodep) override {
UASSERT_OBJ(!emitSimpleOk(nodep), nodep, "Triop cannot be described in a simple way"); UASSERT_OBJ(!emitSimpleOk(nodep), nodep, "Triop cannot be described in a simple way");
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nodep->thsp()); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
} }
virtual void visit(AstRedXor* nodep) override { void visit(AstRedXor* nodep) override {
if (nodep->lhsp()->isWide()) { if (nodep->lhsp()->isWide()) {
visit(static_cast<AstNodeUniop*>(nodep)); visit(static_cast<AstNodeUniop*>(nodep));
} else { } else {
@ -1019,7 +1018,7 @@ public:
puts(")"); puts(")");
} }
} }
virtual void visit(AstCCast* nodep) override { void visit(AstCCast* nodep) override {
// Extending a value of the same word width is just a NOP. // Extending a value of the same word width is just a NOP.
if (nodep->size() <= VL_IDATASIZE) { if (nodep->size() <= VL_IDATASIZE) {
puts("(IData)("); puts("(IData)(");
@ -1029,26 +1028,26 @@ public:
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(")"); puts(")");
} }
virtual void visit(AstNodeCond* nodep) override { void visit(AstNodeCond* nodep) override {
// Widths match up already, so we'll just use C++'s operator w/o any temps. // Widths match up already, so we'll just use C++'s operator w/o any temps.
if (nodep->expr1p()->isWide()) { if (nodep->thenp()->isWide()) {
emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->expr1p(), nodep->expr2p()); emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep());
} else { } else {
putbs("("); putbs("(");
iterateAndNextNull(nodep->condp()); iterateAndNextNull(nodep->condp());
putbs(" ? "); putbs(" ? ");
iterateAndNextNull(nodep->expr1p()); iterateAndNextNull(nodep->thenp());
putbs(" : "); putbs(" : ");
iterateAndNextNull(nodep->expr2p()); iterateAndNextNull(nodep->elsep());
puts(")"); puts(")");
} }
} }
virtual void visit(AstMemberSel* nodep) override { void visit(AstMemberSel* nodep) override {
iterateAndNextNull(nodep->fromp()); iterateAndNextNull(nodep->fromp());
putbs("->"); putbs("->");
puts(nodep->varp()->nameProtect()); puts(nodep->varp()->nameProtect());
} }
virtual void visit(AstNullCheck* nodep) override { void visit(AstNullCheck* nodep) override {
puts("VL_NULL_CHECK("); puts("VL_NULL_CHECK(");
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(", "); puts(", ");
@ -1057,17 +1056,17 @@ public:
puts(cvtToStr(nodep->fileline()->lineno())); puts(cvtToStr(nodep->fileline()->lineno()));
puts(")"); puts(")");
} }
virtual void visit(AstNewCopy* nodep) override { void visit(AstNewCopy* nodep) override {
puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">(");
puts("*"); // i.e. make into a reference puts("*"); // i.e. make into a reference
iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->rhsp());
puts(")"); puts(")");
} }
virtual void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
// Note ASSIGN checks for this on a LHS // Note ASSIGN checks for this on a LHS
emitOpName(nodep, nodep->emitC(), nodep->fromp(), nodep->lsbp(), nodep->thsp()); emitOpName(nodep, nodep->emitC(), nodep->fromp(), nodep->lsbp(), nodep->thsp());
} }
virtual void visit(AstReplicate* nodep) override { void visit(AstReplicate* nodep) override {
if (nodep->lhsp()->widthMin() == 1 && !nodep->isWide()) { if (nodep->lhsp()->widthMin() == 1 && !nodep->isWide()) {
UASSERT_OBJ((static_cast<int>(VN_AS(nodep->rhsp(), Const)->toUInt()) UASSERT_OBJ((static_cast<int>(VN_AS(nodep->rhsp(), Const)->toUInt())
* nodep->lhsp()->widthMin()) * nodep->lhsp()->widthMin())
@ -1086,7 +1085,7 @@ public:
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
} }
} }
virtual void visit(AstStreamL* nodep) override { void visit(AstStreamL* nodep) override {
// Attempt to use a "fast" stream function for slice size = power of 2 // Attempt to use a "fast" stream function for slice size = power of 2
if (!nodep->isWide()) { if (!nodep->isWide()) {
const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1; const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1;
@ -1108,14 +1107,14 @@ public:
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(), emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(),
nullptr); nullptr);
} }
virtual void visit(AstCastDynamic* nodep) override { void visit(AstCastDynamic* nodep) override {
putbs("VL_CAST_DYNAMIC("); putbs("VL_CAST_DYNAMIC(");
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(", "); puts(", ");
iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->rhsp());
puts(")"); puts(")");
} }
virtual void visit(AstCountBits* nodep) override { void visit(AstCountBits* nodep) override {
putbs("VL_COUNTBITS_"); putbs("VL_COUNTBITS_");
emitIQW(nodep->lhsp()); emitIQW(nodep->lhsp());
puts("("); puts("(");
@ -1135,9 +1134,9 @@ public:
iterateAndNextNull(nodep->fhsp()); iterateAndNextNull(nodep->fhsp());
puts(")"); puts(")");
} }
virtual void visit(AstInitItem* nodep) override { iterateChildren(nodep); } void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
// Terminals // Terminals
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
const AstVar* const varp = nodep->varp(); const AstVar* const varp = nodep->varp();
const AstNodeModule* const varModp = EmitCParentModule::get(varp); const AstNodeModule* const varModp = EmitCParentModule::get(varp);
if (isConstPoolMod(varModp)) { if (isConstPoolMod(varModp)) {
@ -1154,14 +1153,14 @@ public:
} }
puts(nodep->varp()->nameProtect()); puts(nodep->varp()->nameProtect());
} }
virtual void visit(AstAddrOfCFunc* nodep) override { void visit(AstAddrOfCFunc* nodep) override {
// Note: Can be thought to handle more, but this is all that is needed right now // Note: Can be thought to handle more, but this is all that is needed right now
const AstCFunc* const funcp = nodep->funcp(); const AstCFunc* const funcp = nodep->funcp();
UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method"); UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method");
puts("&"); puts("&");
puts(funcNameProtect(funcp)); puts(funcNameProtect(funcp));
} }
virtual void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
if (m_emitConstInit) { if (m_emitConstInit) {
EmitCConstInit::visit(nodep); EmitCConstInit::visit(nodep);
} else if (nodep->isWide()) { } else if (nodep->isWide()) {
@ -1174,12 +1173,12 @@ public:
} }
// //
virtual void visit(AstMTaskBody* nodep) override { void visit(AstMTaskBody* nodep) override {
VL_RESTORER(m_useSelfForThis); VL_RESTORER(m_useSelfForThis);
m_useSelfForThis = true; m_useSelfForThis = true;
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstConsAssoc* nodep) override { void visit(AstConsAssoc* nodep) override {
putbs(nodep->dtypep()->cType("", false, false)); putbs(nodep->dtypep()->cType("", false, false));
puts("()"); puts("()");
if (nodep->defaultp()) { if (nodep->defaultp()) {
@ -1188,7 +1187,7 @@ public:
puts(")"); puts(")");
} }
} }
virtual void visit(AstSetAssoc* nodep) override { void visit(AstSetAssoc* nodep) override {
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
putbs(".set("); putbs(".set(");
iterateAndNextNull(nodep->keyp()); iterateAndNextNull(nodep->keyp());
@ -1197,7 +1196,7 @@ public:
iterateAndNextNull(nodep->valuep()); iterateAndNextNull(nodep->valuep());
puts(")"); puts(")");
} }
virtual void visit(AstConsWildcard* nodep) override { void visit(AstConsWildcard* nodep) override {
putbs(nodep->dtypep()->cType("", false, false)); putbs(nodep->dtypep()->cType("", false, false));
puts("()"); puts("()");
if (nodep->defaultp()) { if (nodep->defaultp()) {
@ -1206,7 +1205,7 @@ public:
puts(")"); puts(")");
} }
} }
virtual void visit(AstSetWildcard* nodep) override { void visit(AstSetWildcard* nodep) override {
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
putbs(".set("); putbs(".set(");
iterateAndNextNull(nodep->keyp()); iterateAndNextNull(nodep->keyp());
@ -1215,7 +1214,7 @@ public:
iterateAndNextNull(nodep->valuep()); iterateAndNextNull(nodep->valuep());
puts(")"); puts(")");
} }
virtual void visit(AstConsDynArray* nodep) override { void visit(AstConsDynArray* nodep) override {
putbs(nodep->dtypep()->cType("", false, false)); putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) { if (!nodep->lhsp()) {
puts("()"); puts("()");
@ -1230,7 +1229,7 @@ public:
puts(")"); puts(")");
} }
} }
virtual void visit(AstConsQueue* nodep) override { void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false)); putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) { if (!nodep->lhsp()) {
puts("()"); puts("()");
@ -1245,22 +1244,22 @@ public:
puts(")"); puts(")");
} }
} }
virtual void visit(AstCReset* nodep) override { void visit(AstCReset* nodep) override {
AstVar* const varp = nodep->varrefp()->varp(); AstVar* const varp = nodep->varrefp()->varp();
emitVarReset(varp); emitVarReset(varp);
} }
virtual void visit(AstExecGraph* nodep) override { void visit(AstExecGraph* nodep) override {
// The location of the AstExecGraph within the containing AstCFunc is where we want to // The location of the AstExecGraph within the containing AstCFunc is where we want to
// invoke the graph and wait for it to complete. Emitting the children does just that. // invoke the graph and wait for it to complete. Emitting the children does just that.
UASSERT_OBJ(!nodep->mTaskBodiesp(), nodep, "These should have been lowered"); UASSERT_OBJ(!nodep->mTaskBodiesp(), nodep, "These should have been lowered");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstChangeDet* nodep) override { // void visit(AstChangeDet* nodep) override { //
m_blkChangeDetVec.push_back(nodep); m_blkChangeDetVec.push_back(nodep);
} }
// Default // Default
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
iterateChildren(nodep); iterateChildren(nodep);
// LCOV_EXCL_START // LCOV_EXCL_START
@ -1278,7 +1277,7 @@ public:
m_trackText = trackText; m_trackText = trackText;
iterate(nodep); iterate(nodep);
} }
virtual ~EmitCFunc() override = default; ~EmitCFunc() override = default;
}; };
#endif // guard #endif // guard

View File

@ -24,12 +24,13 @@
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Internal EmitC implementation // Internal EmitC implementation
class EmitCHeader final : public EmitCConstInit { class EmitCHeader final : public EmitCConstInit {
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void decorateFirst(bool& first, const string& str) { void decorateFirst(bool& first, const string& str) {
if (first) { if (first) {
@ -326,7 +327,7 @@ class EmitCHeader final : public EmitCConstInit {
// Close output file // Close output file
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
} }
virtual ~EmitCHeader() override = default; ~EmitCHeader() override = default;
public: public:
static void main(const AstNodeModule* modp) { EmitCHeader emitCHeader(modp); } static void main(const AstNodeModule* modp) { EmitCHeader emitCHeader(modp); }

View File

@ -28,6 +28,8 @@
#include <set> #include <set>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Visitor that gathers the headers required by an AstCFunc // Visitor that gathers the headers required by an AstCFunc
@ -68,59 +70,59 @@ class EmitCGatherDependencies final : VNVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstCCall* nodep) override { void visit(AstCCall* nodep) override {
addSelfDependency(nodep->selfPointer(), nodep->funcp()); addSelfDependency(nodep->selfPointer(), nodep->funcp());
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstCNew* nodep) override { void visit(AstCNew* nodep) override {
addDTypeDependency(nodep->dtypep()); addDTypeDependency(nodep->dtypep());
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstCMethodCall* nodep) override { void visit(AstCMethodCall* nodep) override {
addDTypeDependency(nodep->fromp()->dtypep()); addDTypeDependency(nodep->fromp()->dtypep());
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstNewCopy* nodep) override { void visit(AstNewCopy* nodep) override {
addDTypeDependency(nodep->dtypep()); addDTypeDependency(nodep->dtypep());
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstMemberSel* nodep) override { void visit(AstMemberSel* nodep) override {
addDTypeDependency(nodep->fromp()->dtypep()); addDTypeDependency(nodep->fromp()->dtypep());
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
addSelfDependency(nodep->selfPointer(), nodep->varp()); addSelfDependency(nodep->selfPointer(), nodep->varp());
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstCoverDecl* nodep) override { void visit(AstCoverDecl* nodep) override {
addSymsDependency(); addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstCoverInc* nodep) override { void visit(AstCoverInc* nodep) override {
addSymsDependency(); addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstDumpCtl* nodep) override { void visit(AstDumpCtl* nodep) override {
addSymsDependency(); addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstScopeName* nodep) override { void visit(AstScopeName* nodep) override {
addSymsDependency(); addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstPrintTimeScale* nodep) override { void visit(AstPrintTimeScale* nodep) override {
addSymsDependency(); addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstTimeFormat* nodep) override { void visit(AstTimeFormat* nodep) override {
addSymsDependency(); addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstNodeSimpleText* nodep) override { void visit(AstNodeSimpleText* nodep) override {
if (nodep->text().find("vlSymsp") != string::npos) addSymsDependency(); if (nodep->text().find("vlSymsp") != string::npos) addSymsDependency();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
// CONSTRUCTOR // CONSTRUCTOR
explicit EmitCGatherDependencies(AstCFunc* cfuncp) { explicit EmitCGatherDependencies(AstCFunc* cfuncp) {
@ -148,6 +150,7 @@ class EmitCImp final : EmitCFunc {
const std::set<string>* m_requiredHeadersp; // Header files required by output file const std::set<string>* m_requiredHeadersp; // Header files required by output file
std::string m_subFileName; // substring added to output filenames std::string m_subFileName; // substring added to output filenames
V3UniqueNames m_uniqueNames; // For generating unique file names V3UniqueNames m_uniqueNames; // For generating unique file names
std::deque<AstCFile*>& m_cfilesr; // cfiles generated by this emit
// METHODS // METHODS
void openNextOutputFile(const std::set<string>& headers, const string& subFileName) { void openNextOutputFile(const std::set<string>& headers, const string& subFileName) {
@ -160,7 +163,8 @@ class EmitCImp final : EmitCFunc {
// Unfortunately we have some lint checks here, so we can't just skip processing. // Unfortunately we have some lint checks here, so we can't just skip processing.
// We should move them to a different stage. // We should move them to a different stage.
const string filename = VL_DEV_NULL; const string filename = VL_DEV_NULL;
newCFile(filename, /* slow: */ m_slow, /* source: */ true); m_cfilesr.push_back(
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
m_ofp = new V3OutCFile(filename); m_ofp = new V3OutCFile(filename);
} else { } else {
string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp);
@ -170,7 +174,8 @@ class EmitCImp final : EmitCFunc {
} }
if (m_slow) filename += "__Slow"; if (m_slow) filename += "__Slow";
filename += ".cpp"; filename += ".cpp";
newCFile(filename, /* slow: */ m_slow, /* source: */ true); m_cfilesr.push_back(
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename); m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename);
} }
@ -509,7 +514,7 @@ class EmitCImp final : EmitCFunc {
} }
// VISITORS // VISITORS
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
if (splitNeeded()) { if (splitNeeded()) {
// Splitting file, so using parallel build. // Splitting file, so using parallel build.
v3Global.useParallelBuild(true); v3Global.useParallelBuild(true);
@ -522,9 +527,10 @@ class EmitCImp final : EmitCFunc {
EmitCFunc::visit(nodep); EmitCFunc::visit(nodep);
} }
explicit EmitCImp(const AstNodeModule* modp, bool slow) explicit EmitCImp(const AstNodeModule* modp, bool slow, std::deque<AstCFile*>& cfilesr)
: m_fileModp{modp} : m_fileModp{modp}
, m_slow{slow} { , m_slow{slow}
, m_cfilesr{cfilesr} {
UINFO(5, " Emitting implementation of " << prefixNameProtect(modp) << endl); UINFO(5, " Emitting implementation of " << prefixNameProtect(modp) << endl);
m_modp = modp; m_modp = modp;
@ -540,10 +546,12 @@ class EmitCImp final : EmitCFunc {
// Emit implementations of all AstCFunc // Emit implementations of all AstCFunc
emitCFuncImp(modp); emitCFuncImp(modp);
} }
virtual ~EmitCImp() override = default; ~EmitCImp() override = default;
public: public:
static void main(const AstNodeModule* modp, bool slow) { EmitCImp{modp, slow}; } static void main(const AstNodeModule* modp, bool slow, std::deque<AstCFile*>& cfilesr) {
EmitCImp{modp, slow, cfilesr};
}
}; };
//###################################################################### //######################################################################
@ -551,14 +559,14 @@ public:
class EmitCTrace final : EmitCFunc { class EmitCTrace final : EmitCFunc {
// NODE STATE/TYPES // NODE STATE/TYPES
// Cleared on netlist // None allowed to support threaded emitting
// AstNode::user1() -> int. Enum number
const VNUser1InUse m_inuser1;
// MEMBERS // MEMBERS
const bool m_slow; // Making slow file const bool m_slow; // Making slow file
int m_enumNum = 0; // Enumeration number (whole netlist) int m_enumNum = 0; // Enumeration number (whole netlist)
V3UniqueNames m_uniqueNames; // For generating unique file names V3UniqueNames m_uniqueNames; // For generating unique file names
std::unordered_map<AstNode*, int> m_enumNumMap; // EnumDType to enumeration number
std::deque<AstCFile*>& m_cfilesr; // cfiles generated by this emit
// METHODS // METHODS
void openNextOutputFile() { void openNextOutputFile() {
@ -573,8 +581,9 @@ class EmitCTrace final : EmitCFunc {
if (m_slow) filename += "__Slow"; if (m_slow) filename += "__Slow";
filename += ".cpp"; filename += ".cpp";
AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/); AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/);
cfilep->support(true); cfilep->support(true);
m_cfilesr.push_back(cfilep);
if (optSystemC()) { if (optSystemC()) {
m_ofp = new V3OutScFile(filename); m_ofp = new V3OutScFile(filename);
@ -710,10 +719,10 @@ class EmitCTrace final : EmitCFunc {
// Skip over refs-to-refs, but stop before final ref so can get data type name // 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 // Alternatively back in V3Width we could push enum names from upper typedefs
if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
int enumNum = enump->user1(); int enumNum = m_enumNumMap[enump];
if (!enumNum) { if (!enumNum) {
enumNum = ++m_enumNum; enumNum = ++m_enumNum;
enump->user1(enumNum); m_enumNumMap[enump] = enumNum;
int nvals = 0; int nvals = 0;
puts("{\n"); puts("{\n");
puts("const char* " + protect("__VenumItemNames") + "[]\n"); puts("const char* " + protect("__VenumItemNames") + "[]\n");
@ -816,7 +825,7 @@ class EmitCTrace final : EmitCFunc {
// VISITORS // VISITORS
using EmitCFunc::visit; // Suppress hidden overloaded virtual function warning using EmitCFunc::visit; // Suppress hidden overloaded virtual function warning
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
if (!nodep->isTrace()) return; if (!nodep->isTrace()) return;
if (nodep->slow() != m_slow) return; if (nodep->slow() != m_slow) return;
@ -831,17 +840,17 @@ class EmitCTrace final : EmitCFunc {
EmitCFunc::visit(nodep); EmitCFunc::visit(nodep);
} }
virtual void visit(AstTracePushNamePrefix* nodep) override { void visit(AstTracePushNamePrefix* nodep) override {
puts("tracep->pushNamePrefix("); puts("tracep->pushNamePrefix(");
putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect())); putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect()));
puts(");\n"); puts(");\n");
} }
virtual void visit(AstTracePopNamePrefix* nodep) override { // void visit(AstTracePopNamePrefix* nodep) override { //
puts("tracep->popNamePrefix("); puts("tracep->popNamePrefix(");
puts(cvtToStr(nodep->count())); puts(cvtToStr(nodep->count()));
puts(");\n"); puts(");\n");
} }
virtual void visit(AstTraceDecl* nodep) override { void visit(AstTraceDecl* nodep) override {
const int enumNum = emitTraceDeclDType(nodep->dtypep()); const int enumNum = emitTraceDeclDType(nodep->dtypep());
if (nodep->arrayRange().ranged()) { if (nodep->arrayRange().ranged()) {
puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n"); puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n");
@ -852,7 +861,7 @@ class EmitCTrace final : EmitCFunc {
puts("\n"); puts("\n");
} }
} }
virtual void visit(AstTraceInc* nodep) override { void visit(AstTraceInc* nodep) override {
if (nodep->declp()->arrayRange().ranged()) { if (nodep->declp()->arrayRange().ranged()) {
// It traces faster if we unroll the loop // It traces faster if we unroll the loop
for (int i = 0; i < nodep->declp()->arrayRange().elements(); i++) { for (int i = 0; i < nodep->declp()->arrayRange().elements(); i++) {
@ -863,8 +872,9 @@ class EmitCTrace final : EmitCFunc {
} }
} }
explicit EmitCTrace(AstNodeModule* modp, bool slow) explicit EmitCTrace(AstNodeModule* modp, bool slow, std::deque<AstCFile*>& cfilesr)
: m_slow{slow} { : m_slow{slow}
, m_cfilesr{cfilesr} {
m_modp = modp; m_modp = modp;
// Open output file // Open output file
openNextOutputFile(); openNextOutputFile();
@ -875,10 +885,12 @@ class EmitCTrace final : EmitCFunc {
// Close output file // Close output file
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
} }
virtual ~EmitCTrace() override = default; ~EmitCTrace() override = default;
public: public:
static void main(AstNodeModule* modp, bool slow) { EmitCTrace{modp, slow}; } static void main(AstNodeModule* modp, bool slow, std::deque<AstCFile*>& cfilesr) {
EmitCTrace{modp, slow, cfilesr};
}
}; };
//###################################################################### //######################################################################
@ -888,19 +900,27 @@ void V3EmitC::emitcImp() {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
// Make parent module pointers available. // Make parent module pointers available.
const EmitCParentModule emitCParentModule; const EmitCParentModule emitCParentModule;
std::list<std::deque<AstCFile*>> cfiles;
// Process each module in turn // Process each module in turn
for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) {
if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage
const AstNodeModule* const modp = VN_AS(nodep, NodeModule); const AstNodeModule* const modp = VN_AS(nodep, NodeModule);
EmitCImp::main(modp, /* slow: */ true); cfiles.emplace_back();
EmitCImp::main(modp, /* slow: */ false); EmitCImp::main(modp, /* slow: */ true, cfiles.back());
cfiles.emplace_back();
EmitCImp::main(modp, /* slow: */ false, cfiles.back());
} }
// Emit trace routines (currently they can only exist in the top module) // Emit trace routines (currently they can only exist in the top module)
if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) {
EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true); cfiles.emplace_back();
EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false); EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, cfiles.back());
cfiles.emplace_back();
EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, cfiles.back());
}
for (const auto& collr : cfiles) {
for (const auto cfilep : collr) v3Global.rootp()->addFilesp(cfilep);
} }
} }

View File

@ -24,6 +24,8 @@
#include <map> #include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class EmitCInlines final : EmitCBaseVisitor { class EmitCInlines final : EmitCBaseVisitor {
@ -32,18 +34,18 @@ class EmitCInlines final : EmitCBaseVisitor {
// METHODS // METHODS
// VISITORS // VISITORS
virtual void visit(AstCNew* nodep) override { void visit(AstCNew* nodep) override {
if (v3Global.opt.savable()) if (v3Global.opt.savable())
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new"); v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstDumpCtl* nodep) override { void visit(AstDumpCtl* nodep) override {
if (v3Global.opt.trace()) v3Global.needTraceDumper(true); if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
iterateChildren(nodep); iterateChildren(nodep);
} }
//--------------------------------------- //---------------------------------------
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); } explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); }

View File

@ -25,6 +25,8 @@
#include <map> #include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class EmitCMain final : EmitCBaseVisitor { class EmitCMain final : EmitCBaseVisitor {
@ -32,7 +34,7 @@ class EmitCMain final : EmitCBaseVisitor {
// VISITORS // VISITORS
// This visitor doesn't really iterate, but exist to appease base class // This visitor doesn't really iterate, but exist to appease base class
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE
public: public:
// CONSTRUCTORS // CONSTRUCTORS

View File

@ -26,13 +26,14 @@
#include <memory> #include <memory>
//###################################################################### VL_DEFINE_DEBUG_FUNCTIONS;
// Emit statements
// ######################################################################
// Emit statements
class CMakeEmitter final { class CMakeEmitter final {
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// STATIC FUNCTIONS // STATIC FUNCTIONS

View File

@ -26,6 +26,8 @@
#include <functional> #include <functional>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
class EmitCModel final : public EmitCFunc { class EmitCModel final : public EmitCFunc {
// TYPES // TYPES
using CFuncVector = std::vector<const AstCFunc*>; using CFuncVector = std::vector<const AstCFunc*>;
@ -34,8 +36,6 @@ class EmitCModel final : public EmitCFunc {
V3UniqueNames m_uniqueNames; // For generating unique file names V3UniqueNames m_uniqueNames; // For generating unique file names
// METHODS // METHODS
VL_DEBUG_FUNC;
CFuncVector findFuncps(std::function<bool(const AstCFunc*)> cb) { CFuncVector findFuncps(std::function<bool(const AstCFunc*)> cb) {
CFuncVector funcps; CFuncVector funcps;
for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) {
@ -190,7 +190,7 @@ class EmitCModel final : public EmitCFunc {
+ "C* tfp, int levels, int options = 0);\n"); + "C* tfp, int levels, int options = 0);\n");
if (optSystemC()) { if (optSystemC()) {
puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); puts("/// SC tracing; avoid overloaded virtual function lint warning\n");
puts("virtual void trace(sc_trace_file* tfp) const override { " puts("void trace(sc_trace_file* tfp) const override { "
"::sc_core::sc_module::trace(tfp); }\n"); "::sc_core::sc_module::trace(tfp); }\n");
} }
} }
@ -552,6 +552,11 @@ class EmitCModel final : public EmitCFunc {
"elaboration.\");\n"); "elaboration.\");\n");
puts(/**/ "}"); puts(/**/ "}");
} }
puts(/**/ "if (tfp->isOpen()) {\n");
puts(/****/ "vl_fatal(__FILE__, __LINE__, __FILE__,\"'" + topClassName()
+ +"::trace()' shall not be called after '" + v3Global.opt.traceClassBase()
+ "C::open()'.\");\n");
puts(/**/ "}\n");
puts(/**/ "if (false && levels && options) {} // Prevent unused\n"); puts(/**/ "if (false && levels && options) {} // Prevent unused\n");
puts(/**/ "tfp->spTrace()->addModel(this);\n"); puts(/**/ "tfp->spTrace()->addModel(this);\n");
puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n"); puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
@ -565,7 +570,7 @@ class EmitCModel final : public EmitCFunc {
// Some hackery to locate handle__V for trace_init_task // 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 // Considered a pragma on the handle, but that still doesn't help us attach it here
string handle = funcp->name(); string handle = funcp->name();
const size_t wr_len = strlen("__Vdpiimwrap_"); const size_t wr_len = std::strlen("__Vdpiimwrap_");
UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp, UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp,
"Strange trace_init_task function name"); "Strange trace_init_task function name");
handle = "vlSymsp->TOP." + handle.substr(wr_len); handle = "vlSymsp->TOP." + handle.substr(wr_len);

View File

@ -27,6 +27,8 @@
#include <map> #include <map>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Symbol table emitting // Symbol table emitting
@ -211,7 +213,7 @@ class EmitCSyms final : EmitCBaseVisitor {
const string::size_type dpos = whole.rfind("__DOT__"); const string::size_type dpos = whole.rfind("__DOT__");
if (dpos != string::npos) { if (dpos != string::npos) {
scpName = whole.substr(0, dpos); scpName = whole.substr(0, dpos);
varBase = whole.substr(dpos + strlen("__DOT__")); varBase = whole.substr(dpos + std::strlen("__DOT__"));
} else { } else {
varBase = whole; varBase = whole;
} }
@ -258,7 +260,7 @@ class EmitCSyms final : EmitCBaseVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
// Collect list of scopes // Collect list of scopes
iterateChildren(nodep); iterateChildren(nodep);
varsExpand(); varsExpand();
@ -280,8 +282,8 @@ class EmitCSyms final : EmitCBaseVisitor {
if (!m_dpiHdrOnly) emitDpiImp(); if (!m_dpiHdrOnly) emitDpiImp();
} }
} }
virtual void visit(AstConstPool* nodep) override {} // Ignore void visit(AstConstPool* nodep) override {} // Ignore
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
nameCheck(nodep); nameCheck(nodep);
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
@ -289,7 +291,7 @@ class EmitCSyms final : EmitCBaseVisitor {
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
virtual void visit(AstCellInline* nodep) override { void visit(AstCellInline* nodep) override {
if (v3Global.opt.vpi()) { if (v3Global.opt.vpi()) {
const string type const string type
= (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE"; = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE";
@ -300,7 +302,7 @@ class EmitCSyms final : EmitCBaseVisitor {
std::make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type))); std::make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type)));
} }
} }
virtual void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
nameCheck(nodep); nameCheck(nodep);
@ -315,7 +317,7 @@ class EmitCSyms final : EmitCBaseVisitor {
timeunit, type))); timeunit, type)));
} }
} }
virtual void visit(AstScopeName* nodep) override { void visit(AstScopeName* nodep) override {
const string name = nodep->scopeSymName(); const string name = nodep->scopeSymName();
// UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName() // UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()
// <<" ss"<<name<<endl); // <<" ss"<<name<<endl);
@ -337,19 +339,19 @@ class EmitCSyms final : EmitCBaseVisitor {
} }
} }
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
nameCheck(nodep); nameCheck(nodep);
iterateChildren(nodep); iterateChildren(nodep);
if (nodep->isSigUserRdPublic() && !m_cfuncp) if (nodep->isSigUserRdPublic() && !m_cfuncp)
m_modVars.emplace_back(std::make_pair(m_modp, nodep)); m_modVars.emplace_back(std::make_pair(m_modp, nodep));
} }
virtual void visit(AstCoverDecl* nodep) override { void visit(AstCoverDecl* nodep) override {
// Assign numbers to all bins, so we know how big of an array to use // Assign numbers to all bins, so we know how big of an array to use
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
nodep->binNum(m_coverBins++); nodep->binNum(m_coverBins++);
} }
} }
virtual void visit(AstCFunc* nodep) override { void visit(AstCFunc* nodep) override {
nameCheck(nodep); nameCheck(nodep);
if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) m_dpis.push_back(nodep); if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) m_dpis.push_back(nodep);
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
@ -360,8 +362,8 @@ class EmitCSyms final : EmitCBaseVisitor {
} }
//--------------------------------------- //---------------------------------------
virtual void visit(AstConst*) override {} void visit(AstConst*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly) explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly)

View File

@ -24,13 +24,14 @@
#include "V3HierBlock.h" #include "V3HierBlock.h"
#include "V3Os.h" #include "V3Os.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Emit statements and math operators // Emit statements and math operators
class EmitMk final { class EmitMk final {
public: public:
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
void putMakeClassEntry(V3OutMkFile& of, const string& name) { void putMakeClassEntry(V3OutMkFile& of, const string& name) {
of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n"); of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n");
@ -292,7 +293,7 @@ class EmitMkHierVerilation final {
of.puts("# Verilation of hierarchical blocks are executed in this directory\n"); of.puts("# Verilation of hierarchical blocks are executed in this directory\n");
of.puts("VM_HIER_RUN_DIR := " + cwd + "\n"); of.puts("VM_HIER_RUN_DIR := " + cwd + "\n");
of.puts("# Common options for hierarchical blocks\n"); of.puts("# Common options for hierarchical blocks\n");
const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.bin()); const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.buildDepBin());
const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator"; const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n"); of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n");
of.puts("VM_HIER_INPUT_FILES := \\\n"); of.puts("VM_HIER_INPUT_FILES := \\\n");
@ -399,7 +400,6 @@ public:
V3OutMkFile of(m_makefile); V3OutMkFile of(m_makefile);
emit(of); emit(of);
} }
VL_DEBUG_FUNC; // Declare debug()
}; };
//###################################################################### //######################################################################

View File

@ -26,6 +26,8 @@
#include <map> #include <map>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Emit statements and math operators // Emit statements and math operators
@ -36,7 +38,6 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void puts(const string& str) = 0; virtual void puts(const string& str) = 0;
virtual void putbs(const string& str) = 0; virtual void putbs(const string& str) = 0;
@ -53,14 +54,14 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); } void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n"); putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
putqs(nodep, "end" + nodep->verilogKwd() + "\n"); putqs(nodep, "end" + nodep->verilogKwd() + "\n");
} }
virtual void visit(AstPort* nodep) override {} void visit(AstPort* nodep) override {}
virtual void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
putfs(nodep, nodep->isFunction() ? "function" : "task"); putfs(nodep, nodep->isFunction() ? "function" : "task");
puts(" "); puts(" ");
puts(nodep->prettyName()); puts(nodep->prettyName());
@ -70,7 +71,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
putfs(nodep, nodep->isFunction() ? "endfunction\n" : "endtask\n"); putfs(nodep, nodep->isFunction() ? "endfunction\n" : "endtask\n");
} }
virtual void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
if (nodep->name() == "") { if (nodep->name() == "") {
putbs("begin\n"); putbs("begin\n");
} else { } else {
@ -79,7 +80,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
puts("end\n"); puts("end\n");
} }
virtual void visit(AstFork* nodep) override { void visit(AstFork* nodep) override {
if (nodep->name() == "") { if (nodep->name() == "") {
putbs("fork\n"); putbs("fork\n");
} else { } else {
@ -89,19 +90,19 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
puts(nodep->joinType().verilogKwd()); puts(nodep->joinType().verilogKwd());
puts("\n"); puts("\n");
} }
virtual void visit(AstFinal* nodep) override { void visit(AstFinal* nodep) override {
putfs(nodep, "final begin\n"); putfs(nodep, "final begin\n");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
putqs(nodep, "end\n"); putqs(nodep, "end\n");
} }
virtual void visit(AstInitial* nodep) override { void visit(AstInitial* nodep) override {
putfs(nodep, "initial begin\n"); putfs(nodep, "initial begin\n");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
putqs(nodep, "end\n"); putqs(nodep, "end\n");
} }
virtual void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); } void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); }
virtual void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); } void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); }
virtual void visit(AstAlways* nodep) override { void visit(AstAlways* nodep) override {
putfs(nodep, "always "); putfs(nodep, "always ");
if (m_sensesp) { if (m_sensesp) {
iterateAndNextConstNull(m_sensesp); iterateAndNextConstNull(m_sensesp);
@ -110,10 +111,10 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->sensesp()); iterateAndNextConstNull(nodep->sensesp());
} }
putbs(" begin\n"); putbs(" begin\n");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->stmtsp());
putqs(nodep, "end\n"); putqs(nodep, "end\n");
} }
virtual void visit(AstAlwaysPublic* nodep) override { void visit(AstAlwaysPublic* nodep) override {
putfs(nodep, "/*verilator public_flat_rw "); putfs(nodep, "/*verilator public_flat_rw ");
if (m_sensesp) { if (m_sensesp) {
iterateAndNextConstNull(m_sensesp); iterateAndNextConstNull(m_sensesp);
@ -122,46 +123,46 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->sensesp()); iterateAndNextConstNull(nodep->sensesp());
} }
putqs(nodep, " "); putqs(nodep, " ");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->stmtsp());
putqs(nodep, "*/\n"); putqs(nodep, "*/\n");
} }
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
if (VN_IS(nodep, AssignForce)) puts("force "); if (VN_IS(nodep, AssignForce)) puts("force ");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
putfs(nodep, " " + nodep->verilogKwd() + " "); putfs(nodep, " " + nodep->verilogKwd() + " ");
iterateAndNextConstNull(nodep->rhsp()); iterateAndNextConstNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstAssignDly* nodep) override { void visit(AstAssignDly* nodep) override {
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
putfs(nodep, " <= "); putfs(nodep, " <= ");
iterateAndNextConstNull(nodep->rhsp()); iterateAndNextConstNull(nodep->rhsp());
puts(";\n"); puts(";\n");
} }
virtual void visit(AstAssignAlias* nodep) override { void visit(AstAssignAlias* nodep) override {
putbs("alias "); putbs("alias ");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
putfs(nodep, " = "); putfs(nodep, " = ");
iterateAndNextConstNull(nodep->rhsp()); iterateAndNextConstNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstAssignW* nodep) override { void visit(AstAssignW* nodep) override {
putfs(nodep, "assign "); putfs(nodep, "assign ");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
putbs(" = "); putbs(" = ");
iterateAndNextConstNull(nodep->rhsp()); iterateAndNextConstNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstRelease* nodep) override { void visit(AstRelease* nodep) override {
puts("release "); puts("release ");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstBreak*) override { void visit(AstBreak*) override {
putbs("break"); putbs("break");
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstSenTree* nodep) override { void visit(AstSenTree* nodep) override {
// AstSenItem is called for dumping in isolation by V3Order // AstSenItem is called for dumping in isolation by V3Order
putfs(nodep, "@("); putfs(nodep, "@(");
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) { for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
@ -170,13 +171,13 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts(")"); puts(")");
} }
virtual void visit(AstSenItem* nodep) override { void visit(AstSenItem* nodep) override {
putfs(nodep, ""); putfs(nodep, "");
puts(nodep->edgeType().verilogKwd()); puts(nodep->edgeType().verilogKwd());
if (nodep->sensp()) puts(" "); if (nodep->sensp()) puts(" ");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstNodeCase* nodep) override { void visit(AstNodeCase* nodep) override {
putfs(nodep, ""); putfs(nodep, "");
if (const AstCase* const casep = VN_CAST(nodep, Case)) { if (const AstCase* const casep = VN_CAST(nodep, Case)) {
if (casep->priorityPragma()) puts("priority "); if (casep->priorityPragma()) puts("priority ");
@ -197,27 +198,27 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->itemsp()); iterateAndNextConstNull(nodep->itemsp());
putqs(nodep, "endcase\n"); putqs(nodep, "endcase\n");
} }
virtual void visit(AstCaseItem* nodep) override { void visit(AstCaseItem* nodep) override {
if (nodep->condsp()) { if (nodep->condsp()) {
iterateAndNextConstNull(nodep->condsp()); iterateAndNextConstNull(nodep->condsp());
} else { } else {
putbs("default"); putbs("default");
} }
putfs(nodep, ": begin "); putfs(nodep, ": begin ");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->stmtsp());
putqs(nodep, "end\n"); putqs(nodep, "end\n");
} }
virtual void visit(AstComment* nodep) override { void visit(AstComment* nodep) override {
puts(std::string{"// "} + nodep->name() + "\n"); puts(std::string{"// "} + nodep->name() + "\n");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
virtual void visit(AstContinue*) override { void visit(AstContinue*) override {
putbs("continue"); putbs("continue");
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstCoverDecl*) override {} // N/A void visit(AstCoverDecl*) override {} // N/A
virtual void visit(AstCoverInc*) override {} // N/A void visit(AstCoverInc*) override {} // N/A
virtual void visit(AstCoverToggle*) override {} // N/A void visit(AstCoverToggle*) override {} // N/A
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text, void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
AstNode* exprsp) { AstNode* exprsp) {
@ -234,26 +235,26 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts(");\n"); puts(");\n");
} }
virtual void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); } void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); }
virtual void visit(AstDisplay* nodep) override { void visit(AstDisplay* nodep) override {
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp()); visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
} }
virtual void visit(AstElabDisplay* nodep) override { void visit(AstElabDisplay* nodep) override {
visitNodeDisplay(nodep, nullptr, nodep->fmtp()->text(), nodep->fmtp()->exprsp()); visitNodeDisplay(nodep, nullptr, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
} }
virtual void visit(AstFScanF* nodep) override { void visit(AstFScanF* nodep) override {
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp()); visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
} }
virtual void visit(AstSScanF* nodep) override { void visit(AstSScanF* nodep) override {
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp()); visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
} }
virtual void visit(AstSFormat* nodep) override { void visit(AstSFormat* nodep) override {
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp()); visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
} }
virtual void visit(AstSFormatF* nodep) override { void visit(AstSFormatF* nodep) override {
visitNodeDisplay(nodep, nullptr, nodep->text(), nodep->exprsp()); visitNodeDisplay(nodep, nullptr, nodep->text(), nodep->exprsp());
} }
virtual void visit(AstFOpen* nodep) override { void visit(AstFOpen* nodep) override {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
putbs("("); putbs("(");
iterateAndNextConstNull(nodep->filenamep()); iterateAndNextConstNull(nodep->filenamep());
@ -261,36 +262,34 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->modep()); iterateAndNextConstNull(nodep->modep());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFOpenMcd* nodep) override { void visit(AstFOpenMcd* nodep) override {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
putbs("("); putbs("(");
iterateAndNextConstNull(nodep->filenamep()); iterateAndNextConstNull(nodep->filenamep());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFClose* nodep) override { void visit(AstFClose* nodep) override {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
putbs("("); putbs("(");
if (nodep->filep()) iterateAndNextConstNull(nodep->filep()); if (nodep->filep()) iterateAndNextConstNull(nodep->filep());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFFlush* nodep) override { void visit(AstFFlush* nodep) override {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
putbs("("); putbs("(");
if (nodep->filep()) iterateAndNextConstNull(nodep->filep()); if (nodep->filep()) iterateAndNextConstNull(nodep->filep());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstJumpBlock* nodep) override { void visit(AstJumpBlock* nodep) override {
putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n"); putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n");
if (nodep->stmtsp()) iterateAndNextConstNull(nodep->stmtsp()); if (nodep->stmtsp()) iterateAndNextConstNull(nodep->stmtsp());
puts("end\n"); puts("end\n");
} }
virtual void visit(AstJumpGo* nodep) override { void visit(AstJumpGo* nodep) override {
putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
} }
virtual void visit(AstJumpLabel* nodep) override { void visit(AstJumpLabel* nodep) override { putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); }
putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); void visit(AstNodeReadWriteMem* nodep) override {
}
virtual void visit(AstNodeReadWriteMem* nodep) override {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
putbs("("); putbs("(");
if (nodep->filenamep()) iterateAndNextConstNull(nodep->filenamep()); if (nodep->filenamep()) iterateAndNextConstNull(nodep->filenamep());
@ -306,17 +305,17 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts(");\n"); puts(");\n");
} }
virtual void visit(AstSysFuncAsTask* nodep) override { void visit(AstSysFuncAsTask* nodep) override {
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
puts(";\n"); puts(";\n");
} }
virtual void visit(AstSysIgnore* nodep) override { void visit(AstSysIgnore* nodep) override {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
putbs("("); putbs("(");
iterateAndNextConstNull(nodep->exprsp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstNodeFor* nodep) override { void visit(AstNodeFor* nodep) override {
putfs(nodep, "for ("); putfs(nodep, "for (");
{ {
VL_RESTORER(m_suppressSemi); VL_RESTORER(m_suppressSemi);
@ -328,27 +327,27 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->incsp()); iterateAndNextConstNull(nodep->incsp());
} }
puts(") begin\n"); puts(") begin\n");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->stmtsp());
putqs(nodep, "end\n"); putqs(nodep, "end\n");
} }
virtual void visit(AstRepeat* nodep) override { void visit(AstRepeat* nodep) override {
putfs(nodep, "repeat ("); putfs(nodep, "repeat (");
iterateAndNextConstNull(nodep->countp()); iterateAndNextConstNull(nodep->countp());
puts(") begin\n"); puts(") begin\n");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->stmtsp());
putfs(nodep, "end\n"); putfs(nodep, "end\n");
} }
virtual void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
iterateAndNextConstNull(nodep->precondsp()); iterateAndNextConstNull(nodep->precondsp());
putfs(nodep, "while ("); putfs(nodep, "while (");
iterateAndNextConstNull(nodep->condp()); iterateAndNextConstNull(nodep->condp());
puts(") begin\n"); puts(") begin\n");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->incsp()); iterateAndNextConstNull(nodep->incsp());
iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop
putfs(nodep, "end\n"); putfs(nodep, "end\n");
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
putfs(nodep, ""); putfs(nodep, "");
if (const AstIf* const ifp = VN_CAST(nodep, If)) { if (const AstIf* const ifp = VN_CAST(nodep, If)) {
if (ifp->priorityPragma()) puts("priority "); if (ifp->priorityPragma()) puts("priority ");
@ -358,7 +357,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
puts("if ("); puts("if (");
iterateAndNextConstNull(nodep->condp()); iterateAndNextConstNull(nodep->condp());
puts(") begin\n"); puts(") begin\n");
iterateAndNextConstNull(nodep->ifsp()); iterateAndNextConstNull(nodep->thensp());
if (nodep->elsesp()) { if (nodep->elsesp()) {
putqs(nodep, "end\n"); putqs(nodep, "end\n");
putqs(nodep, "else begin\n"); putqs(nodep, "else begin\n");
@ -366,7 +365,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
putqs(nodep, "end\n"); putqs(nodep, "end\n");
} }
virtual void visit(AstPast* nodep) override { void visit(AstPast* nodep) override {
putfs(nodep, "$past("); putfs(nodep, "$past(");
iterateAndNextConstNull(nodep->exprp()); iterateAndNextConstNull(nodep->exprp());
if (nodep->ticksp()) { if (nodep->ticksp()) {
@ -375,21 +374,21 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts(")"); puts(")");
} }
virtual void visit(AstReturn* nodep) override { void visit(AstReturn* nodep) override {
putfs(nodep, "return "); putfs(nodep, "return ");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
puts(";\n"); puts(";\n");
} }
virtual void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); } void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); }
virtual void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); } void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); }
virtual void visit(AstNodeSimpleText* nodep) override { void visit(AstNodeSimpleText* nodep) override {
if (nodep->tracking() || m_trackText) { if (nodep->tracking() || m_trackText) {
puts(nodep->text()); puts(nodep->text());
} else { } else {
putsNoTracking(nodep->text()); putsNoTracking(nodep->text());
} }
} }
virtual void visit(AstTextBlock* nodep) override { void visit(AstTextBlock* nodep) override {
visit(static_cast<AstNodeSimpleText*>(nodep)); visit(static_cast<AstNodeSimpleText*>(nodep));
{ {
VL_RESTORER(m_suppressSemi); VL_RESTORER(m_suppressSemi);
@ -400,25 +399,25 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
} }
} }
virtual void visit(AstScopeName* nodep) override {} void visit(AstScopeName* nodep) override {}
virtual void visit(AstCStmt* nodep) override { void visit(AstCStmt* nodep) override {
putfs(nodep, "$_CSTMT("); putfs(nodep, "$_CSTMT(");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstCMath* nodep) override { void visit(AstCMath* nodep) override {
putfs(nodep, "$_CMATH("); putfs(nodep, "$_CMATH(");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstUCStmt* nodep) override { void visit(AstUCStmt* nodep) override {
putfs(nodep, "$c("); putfs(nodep, "$c(");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }
virtual void visit(AstUCFunc* nodep) override { void visit(AstUCFunc* nodep) override {
putfs(nodep, "$c("); putfs(nodep, "$c(");
iterateAndNextConstNull(nodep->bodysp()); iterateAndNextConstNull(nodep->exprsp());
puts(")"); puts(")");
} }
@ -481,25 +480,23 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
} }
virtual void visit(AstNodeTermop* nodep) override { void visit(AstNodeTermop* nodep) override { emitVerilogFormat(nodep, nodep->emitVerilog()); }
emitVerilogFormat(nodep, nodep->emitVerilog()); void visit(AstNodeUniop* nodep) override {
}
virtual void visit(AstNodeUniop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp()); emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
} }
virtual void visit(AstNodeBiop* nodep) override { void visit(AstNodeBiop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp()); emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
} }
virtual void visit(AstNodeTriop* nodep) override { void visit(AstNodeTriop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(),
nodep->thsp()); nodep->thsp());
} }
virtual void visit(AstMemberSel* nodep) override { void visit(AstMemberSel* nodep) override {
iterate(nodep->fromp()); iterate(nodep->fromp());
puts("."); puts(".");
puts(nodep->prettyName()); puts(nodep->prettyName());
} }
virtual void visit(AstAttrOf* nodep) override { void visit(AstAttrOf* nodep) override {
putfs(nodep, "$_ATTROF("); putfs(nodep, "$_ATTROF(");
iterateAndNextConstNull(nodep->fromp()); iterateAndNextConstNull(nodep->fromp());
if (nodep->dimp()) { if (nodep->dimp()) {
@ -508,7 +505,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts(")"); puts(")");
} }
virtual void visit(AstInitArray* nodep) override { void visit(AstInitArray* nodep) override {
putfs(nodep, "'{"); putfs(nodep, "'{");
int comma = 0; int comma = 0;
const auto& mapr = nodep->map(); const auto& mapr = nodep->map();
@ -521,16 +518,16 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts("}"); puts("}");
} }
virtual void visit(AstNodeCond* nodep) override { void visit(AstNodeCond* nodep) override {
putbs("("); putbs("(");
iterateAndNextConstNull(nodep->condp()); iterateAndNextConstNull(nodep->condp());
putfs(nodep, " ? "); putfs(nodep, " ? ");
iterateAndNextConstNull(nodep->expr1p()); iterateAndNextConstNull(nodep->thenp());
putbs(" : "); putbs(" : ");
iterateAndNextConstNull(nodep->expr2p()); iterateAndNextConstNull(nodep->elsep());
puts(")"); puts(")");
} }
virtual void visit(AstRange* nodep) override { void visit(AstRange* nodep) override {
puts("["); puts("[");
if (VN_IS(nodep->leftp(), Const) && VN_IS(nodep->rightp(), Const)) { if (VN_IS(nodep->leftp(), Const) && VN_IS(nodep->rightp(), Const)) {
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0] // Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
@ -545,7 +542,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
puts("]"); puts("]");
} }
} }
virtual void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
iterateAndNextConstNull(nodep->fromp()); iterateAndNextConstNull(nodep->fromp());
puts("["); puts("[");
if (VN_IS(nodep->lsbp(), Const)) { if (VN_IS(nodep->lsbp(), Const)) {
@ -569,18 +566,18 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts("]"); puts("]");
} }
virtual void visit(AstSliceSel* nodep) override { void visit(AstSliceSel* nodep) override {
iterateAndNextConstNull(nodep->fromp()); iterateAndNextConstNull(nodep->fromp());
puts(cvtToStr(nodep->declRange())); puts(cvtToStr(nodep->declRange()));
} }
virtual void visit(AstTypedef* nodep) override { void visit(AstTypedef* nodep) override {
putfs(nodep, "typedef "); putfs(nodep, "typedef ");
iterateAndNextConstNull(nodep->dtypep()); iterateAndNextConstNull(nodep->dtypep());
puts(" "); puts(" ");
puts(nodep->prettyName()); puts(nodep->prettyName());
puts(";\n"); puts(";\n");
} }
virtual void visit(AstBasicDType* nodep) override { void visit(AstBasicDType* nodep) override {
if (nodep->isSigned()) putfs(nodep, "signed "); if (nodep->isSigned()) putfs(nodep, "signed ");
putfs(nodep, nodep->prettyName()); putfs(nodep, nodep->prettyName());
if (nodep->rangep()) { if (nodep->rangep()) {
@ -593,15 +590,15 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
puts(":0] "); puts(":0] ");
} }
} }
virtual void visit(AstConstDType* nodep) override { void visit(AstConstDType* nodep) override {
putfs(nodep, "const "); putfs(nodep, "const ");
iterate(nodep->subDTypep()); iterate(nodep->subDTypep());
} }
virtual void visit(AstNodeArrayDType* nodep) override { void visit(AstNodeArrayDType* nodep) override {
iterate(nodep->subDTypep()); iterate(nodep->subDTypep());
iterateAndNextConstNull(nodep->rangep()); iterateAndNextConstNull(nodep->rangep());
} }
virtual void visit(AstNodeUOrStructDType* nodep) override { void visit(AstNodeUOrStructDType* nodep) override {
puts(nodep->verilogKwd() + " "); puts(nodep->verilogKwd() + " ");
if (nodep->packed()) puts("packed "); if (nodep->packed()) puts("packed ");
puts("\n"); puts("\n");
@ -609,12 +606,12 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->membersp()); iterateAndNextConstNull(nodep->membersp());
puts("}"); puts("}");
} }
virtual void visit(AstMemberDType* nodep) override { void visit(AstMemberDType* nodep) override {
iterate(nodep->subDTypep()); iterate(nodep->subDTypep());
puts(" "); puts(" ");
puts(nodep->name()); puts(nodep->name());
} }
virtual void visit(AstNodeFTaskRef* nodep) override { void visit(AstNodeFTaskRef* nodep) override {
if (nodep->dotted() != "") { if (nodep->dotted() != "") {
putfs(nodep, nodep->dotted()); putfs(nodep, nodep->dotted());
puts("."); puts(".");
@ -626,14 +623,14 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->pinsp()); iterateAndNextConstNull(nodep->pinsp());
puts(")"); puts(")");
} }
virtual void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); } void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); }
virtual void visit(AstPrintTimeScale* nodep) override { void visit(AstPrintTimeScale* nodep) override {
puts(nodep->verilogKwd()); puts(nodep->verilogKwd());
puts(";\n"); puts(";\n");
} }
// Terminals // Terminals
virtual void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
if (nodep->varScopep()) { if (nodep->varScopep()) {
putfs(nodep, nodep->varScopep()->prettyName()); putfs(nodep, nodep->varScopep()->prettyName());
} else { } else {
@ -649,7 +646,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
} }
} }
virtual void visit(AstVarXRef* nodep) override { void visit(AstVarXRef* nodep) override {
putfs(nodep, nodep->dotted()); putfs(nodep, nodep->dotted());
puts("."); puts(".");
if (nodep->varp()) { if (nodep->varp()) {
@ -658,12 +655,12 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
puts(nodep->prettyName()); puts(nodep->prettyName());
} }
} }
virtual void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); } void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); }
// Just iterate // Just iterate
virtual void visit(AstTopScope* nodep) override { iterateChildrenConst(nodep); } void visit(AstTopScope* nodep) override { iterateChildrenConst(nodep); }
virtual void visit(AstScope* nodep) override { iterateChildrenConst(nodep); } void visit(AstScope* nodep) override { iterateChildrenConst(nodep); }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
if (nodep->isIO()) { if (nodep->isIO()) {
putfs(nodep, nodep->verilogKwd()); putfs(nodep, nodep->verilogKwd());
puts(" "); puts(" ");
@ -691,21 +688,21 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
puts(m_suppressVarSemi ? "\n" : ";\n"); puts(m_suppressVarSemi ? "\n" : ";\n");
} }
virtual void visit(AstActive* nodep) override { void visit(AstActive* nodep) override {
m_sensesp = nodep->sensesp(); m_sensesp = nodep->sensesp();
iterateAndNextConstNull(nodep->stmtsp()); iterateAndNextConstNull(nodep->stmtsp());
m_sensesp = nullptr; m_sensesp = nullptr;
} }
virtual void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); } void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); }
virtual void visit(AstVarScope*) override {} void visit(AstVarScope*) override {}
virtual void visit(AstNodeText*) override {} void visit(AstNodeText*) override {}
virtual void visit(AstTraceDecl*) override {} void visit(AstTraceDecl*) override {}
virtual void visit(AstTraceInc*) override {} void visit(AstTraceInc*) override {}
// NOPs // NOPs
virtual void visit(AstPragma*) override {} void visit(AstPragma*) override {}
virtual void visit(AstCell*) override {} // Handled outside the Visit class void visit(AstCell*) override {} // Handled outside the Visit class
// Default // Default
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
puts(std::string{"\n???? // "} + nodep->prettyTypeName() + "\n"); puts(std::string{"\n???? // "} + nodep->prettyTypeName() + "\n");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
// Not v3fatalSrc so we keep processing // Not v3fatalSrc so we keep processing
@ -720,7 +717,7 @@ public:
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp) explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
: m_suppressUnknown{suppressUnknown} : m_suppressUnknown{suppressUnknown}
, m_sensesp{domainp} {} , m_sensesp{domainp} {}
virtual ~EmitVBaseVisitor() override = default; ~EmitVBaseVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -731,11 +728,11 @@ class EmitVFileVisitor final : public EmitVBaseVisitor {
V3OutFile* m_ofp; V3OutFile* m_ofp;
// METHODS // METHODS
V3OutFile* ofp() const { return m_ofp; } V3OutFile* ofp() const { return m_ofp; }
virtual void puts(const string& str) override { ofp()->puts(str); } void puts(const string& str) override { ofp()->puts(str); }
virtual void putbs(const string& str) override { ofp()->putbs(str); } void putbs(const string& str) override { ofp()->putbs(str); }
virtual void putfs(AstNode*, const string& str) override { putbs(str); } void putfs(AstNode*, const string& str) override { putbs(str); }
virtual void putqs(AstNode*, const string& str) override { putbs(str); } void putqs(AstNode*, const string& str) override { putbs(str); }
virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); } void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
public: public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressUnknown) EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressUnknown)
@ -744,7 +741,7 @@ public:
m_trackText = trackText; m_trackText = trackText;
iterate(nodep); iterate(nodep);
} }
virtual ~EmitVFileVisitor() override = default; ~EmitVFileVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -754,11 +751,11 @@ class EmitVStreamVisitor final : public EmitVBaseVisitor {
// MEMBERS // MEMBERS
std::ostream& m_os; std::ostream& m_os;
// METHODS // METHODS
virtual void putsNoTracking(const string& str) override { m_os << str; } void putsNoTracking(const string& str) override { m_os << str; }
virtual void puts(const string& str) override { putsNoTracking(str); } void puts(const string& str) override { putsNoTracking(str); }
virtual void putbs(const string& str) override { puts(str); } void putbs(const string& str) override { puts(str); }
virtual void putfs(AstNode*, const string& str) override { putbs(str); } void putfs(AstNode*, const string& str) override { putbs(str); }
virtual void putqs(AstNode*, const string& str) override { putbs(str); } void putqs(AstNode*, const string& str) override { putbs(str); }
public: public:
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os) EmitVStreamVisitor(const AstNode* nodep, std::ostream& os)
@ -766,7 +763,7 @@ public:
, m_os(os) { // Need () or GCC 4.8 false warning , m_os(os) { // Need () or GCC 4.8 false warning
iterate(const_cast<AstNode*>(nodep)); iterate(const_cast<AstNode*>(nodep));
} }
virtual ~EmitVStreamVisitor() override = default; ~EmitVStreamVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -779,7 +776,7 @@ class EmitVPrefixedFormatter final : public V3OutFormatter {
int m_column = 0; // Rough location; need just zero or non-zero int m_column = 0; // Rough location; need just zero or non-zero
FileLine* m_prefixFl; FileLine* m_prefixFl;
// METHODS // METHODS
virtual void putcOutput(char chr) override { void putcOutput(char chr) override {
if (chr == '\n') { if (chr == '\n') {
m_column = 0; m_column = 0;
m_os << chr; m_os << chr;
@ -796,7 +793,7 @@ class EmitVPrefixedFormatter final : public V3OutFormatter {
} }
} }
virtual void putsOutput(const char* strg) override { void putsOutput(const char* strg) override {
for (const char* cp = strg; *cp; cp++) putcOutput(*cp); for (const char* cp = strg; *cp; cp++) putcOutput(*cp);
} }
@ -812,7 +809,7 @@ public:
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
// avoid nullptr checks // avoid nullptr checks
} }
virtual ~EmitVPrefixedFormatter() override { ~EmitVPrefixedFormatter() override {
if (m_column) puts("\n"); if (m_column) puts("\n");
} }
}; };
@ -822,13 +819,13 @@ class EmitVPrefixedVisitor final : public EmitVBaseVisitor {
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the
// inheritance is another unused V3OutFormatter) // inheritance is another unused V3OutFormatter)
// METHODS // METHODS
virtual void putsNoTracking(const string& str) override { m_formatter.putsNoTracking(str); } void putsNoTracking(const string& str) override { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) override { m_formatter.puts(str); } void puts(const string& str) override { m_formatter.puts(str); }
// We don't use m_formatter's putbs because the tokens will change filelines // We don't use m_formatter's putbs because the tokens will change filelines
// and insert returns at the proper locations // and insert returns at the proper locations
virtual void putbs(const string& str) override { m_formatter.puts(str); } void putbs(const string& str) override { m_formatter.puts(str); }
virtual void putfs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, false); } void putfs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, false); }
virtual void putqs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, true); } void putqs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, true); }
void putfsqs(AstNode* nodep, const string& str, bool quiet) { void putfsqs(AstNode* nodep, const string& str, bool quiet) {
if (m_formatter.prefixFl() != nodep->fileline()) { if (m_formatter.prefixFl() != nodep->fileline()) {
m_formatter.prefixFl(nodep->fileline()); m_formatter.prefixFl(nodep->fileline());
@ -846,7 +843,7 @@ public:
if (user3mark) VNUser3InUse::check(); if (user3mark) VNUser3InUse::check();
iterate(const_cast<AstNode*>(nodep)); iterate(const_cast<AstNode*>(nodep));
} }
virtual ~EmitVPrefixedVisitor() override = default; ~EmitVPrefixedVisitor() override = default;
}; };
//###################################################################### //######################################################################

View File

@ -26,6 +26,8 @@
#include <map> #include <map>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Emit statements and math operators // Emit statements and math operators
@ -39,7 +41,6 @@ class EmitXmlFileVisitor final : public VNVisitor {
uint64_t m_id = 0; uint64_t m_id = 0;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// Outfile methods // Outfile methods
V3OutFile* ofp() const { return m_ofp; } V3OutFile* ofp() const { return m_ofp; }
@ -101,11 +102,11 @@ class EmitXmlFileVisitor final : public VNVisitor {
} }
// VISITORS // VISITORS
virtual void visit(AstAssignW* nodep) override { void visit(AstAssignW* nodep) override {
outputTag(nodep, "contassign"); // IEEE: vpiContAssign outputTag(nodep, "contassign"); // IEEE: vpiContAssign
outputChildrenEnd(nodep, "contassign"); outputChildrenEnd(nodep, "contassign");
} }
virtual void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
outputTag(nodep, "instance"); // IEEE: vpiInstance outputTag(nodep, "instance"); // IEEE: vpiInstance
puts(" defName="); puts(" defName=");
putsQuoted(nodep->modName()); // IEEE vpiDefName putsQuoted(nodep->modName()); // IEEE vpiDefName
@ -113,7 +114,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
putsQuoted(nodep->origName()); putsQuoted(nodep->origName());
outputChildrenEnd(nodep, "instance"); outputChildrenEnd(nodep, "instance");
} }
virtual void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
outputTag(nodep, "if"); outputTag(nodep, "if");
puts(">\n"); puts(">\n");
iterateAndNextNull(nodep->op1p()); iterateAndNextNull(nodep->op1p());
@ -127,7 +128,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
} }
puts("</if>\n"); puts("</if>\n");
} }
virtual void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
outputTag(nodep, "while"); outputTag(nodep, "while");
puts(">\n"); puts(">\n");
puts("<begin>\n"); puts("<begin>\n");
@ -150,19 +151,19 @@ class EmitXmlFileVisitor final : public VNVisitor {
} }
puts("</while>\n"); puts("</while>\n");
} }
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
puts("<netlist>\n"); puts("<netlist>\n");
iterateChildren(nodep); iterateChildren(nodep);
puts("</netlist>\n"); puts("</netlist>\n");
} }
virtual void visit(AstConstPool* nodep) override { void visit(AstConstPool* nodep) override {
if (!v3Global.opt.xmlOnly()) { if (!v3Global.opt.xmlOnly()) {
puts("<constpool>\n"); puts("<constpool>\n");
iterateChildren(nodep); iterateChildren(nodep);
puts("</constpool>\n"); puts("</constpool>\n");
} }
} }
virtual void visit(AstInitArray* nodep) override { void visit(AstInitArray* nodep) override {
puts("<initarray>\n"); puts("<initarray>\n");
const auto& mapr = nodep->map(); const auto& mapr = nodep->map();
for (const auto& itr : mapr) { for (const auto& itr : mapr) {
@ -174,7 +175,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
} }
puts("</initarray>\n"); puts("</initarray>\n");
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" origName="); puts(" origName=");
putsQuoted(nodep->origName()); putsQuoted(nodep->origName());
@ -184,7 +185,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
if (nodep->modPublic()) puts(" public=\"true\""); if (nodep->modPublic()) puts(" public=\"true\"");
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
const VVarType typ = nodep->varType(); const VVarType typ = nodep->varType();
const string kw = nodep->verilogKwd(); const string kw = nodep->verilogKwd();
const string vt = nodep->dtypep()->name(); const string vt = nodep->dtypep()->name();
@ -222,7 +223,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
if (nodep->attrSFormat()) puts(" sformat=\"true\""); if (nodep->attrSFormat()) puts(" sformat=\"true\"");
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstPin* nodep) override { void visit(AstPin* nodep) override {
// What we call a pin in verilator is a port in the IEEE spec. // What we call a pin in verilator is a port in the IEEE spec.
outputTag(nodep, "port"); // IEEE: vpiPort outputTag(nodep, "port"); // IEEE: vpiPort
if (nodep->modVarp()->isIO()) { if (nodep->modVarp()->isIO()) {
@ -232,12 +233,12 @@ class EmitXmlFileVisitor final : public VNVisitor {
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?) // Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
outputChildrenEnd(nodep, "port"); outputChildrenEnd(nodep, "port");
} }
virtual void visit(AstSenItem* nodep) override { void visit(AstSenItem* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstModportVarRef* nodep) override { void visit(AstModportVarRef* nodep) override {
// Dump direction for Modport references // Dump direction for Modport references
const string kw = nodep->direction().xmlKwd(); const string kw = nodep->direction().xmlKwd();
outputTag(nodep, ""); outputTag(nodep, "");
@ -245,13 +246,13 @@ class EmitXmlFileVisitor final : public VNVisitor {
putsQuoted(kw); putsQuoted(kw);
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstVarXRef* nodep) override { void visit(AstVarXRef* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" dotted="); puts(" dotted=");
putsQuoted(nodep->dotted()); putsQuoted(nodep->dotted());
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstNodeCCall* nodep) override { void visit(AstNodeCCall* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" func="); puts(" func=");
putsQuoted(nodep->funcp()->name()); putsQuoted(nodep->funcp()->name());
@ -259,7 +260,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
} }
// Data types // Data types
virtual void visit(AstBasicDType* nodep) override { void visit(AstBasicDType* nodep) override {
outputTag(nodep, "basicdtype"); outputTag(nodep, "basicdtype");
if (nodep->isRanged()) { if (nodep->isRanged()) {
puts(" left=\"" + cvtToStr(nodep->left()) + "\""); puts(" left=\"" + cvtToStr(nodep->left()) + "\"");
@ -268,7 +269,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
if (nodep->isSigned()) { puts(" signed=\"true\""); } if (nodep->isSigned()) { puts(" signed=\"true\""); }
puts("/>\n"); puts("/>\n");
} }
virtual void visit(AstIfaceRefDType* nodep) override { void visit(AstIfaceRefDType* nodep) override {
string mpn; string mpn;
outputTag(nodep, ""); outputTag(nodep, "");
if (nodep->isModport()) mpn = nodep->modportName(); if (nodep->isModport()) mpn = nodep->modportName();
@ -276,19 +277,19 @@ class EmitXmlFileVisitor final : public VNVisitor {
putsQuoted(mpn); putsQuoted(mpn);
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstDisplay* nodep) override { void visit(AstDisplay* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" displaytype="); puts(" displaytype=");
putsQuoted(nodep->verilogKwd()); putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstElabDisplay* nodep) override { void visit(AstElabDisplay* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" displaytype="); puts(" displaytype=");
putsQuoted(nodep->verilogKwd()); putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstExtend* nodep) override { void visit(AstExtend* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" width="); puts(" width=");
putsQuoted(cvtToStr(nodep->width())); putsQuoted(cvtToStr(nodep->width()));
@ -296,7 +297,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV())); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstExtendS* nodep) override { void visit(AstExtendS* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
puts(" width="); puts(" width=");
putsQuoted(cvtToStr(nodep->width())); putsQuoted(cvtToStr(nodep->width()));
@ -306,7 +307,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
} }
// Default // Default
virtual void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
outputTag(nodep, ""); outputTag(nodep, "");
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
@ -316,7 +317,7 @@ public:
: m_ofp{ofp} { : m_ofp{ofp} {
iterate(nodep); iterate(nodep);
} }
virtual ~EmitXmlFileVisitor() override = default; ~EmitXmlFileVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -330,14 +331,13 @@ private:
std::deque<FileLine*> m_nodeModules; std::deque<FileLine*> m_nodeModules;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) override { void visit(AstNetlist* nodep) override {
// Children are iterated backwards to ensure correct compilation order // Children are iterated backwards to ensure correct compilation order
iterateChildrenBackwards(nodep); iterateChildrenBackwards(nodep);
} }
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
// Only list modules and interfaces // Only list modules and interfaces
// Assumes modules and interfaces list is already sorted level wise // Assumes modules and interfaces list is already sorted level wise
if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface)) if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
@ -346,7 +346,7 @@ private:
} }
} }
//----- //-----
virtual void visit(AstNode*) override { void visit(AstNode*) override {
// All modules are present at root so no need to iterate on children // All modules are present at root so no need to iterate on children
} }
@ -364,7 +364,7 @@ public:
} }
m_os << "</module_files>\n"; m_os << "</module_files>\n";
} }
virtual ~ModuleFilesXmlVisitor() override = default; ~ModuleFilesXmlVisitor() override = default;
}; };
//###################################################################### //######################################################################
@ -378,12 +378,11 @@ private:
bool m_hasChildren = false; bool m_hasChildren = false;
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS // VISITORS
virtual void visit(AstConstPool*) override {} void visit(AstConstPool*) override {}
virtual void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
if (nodep->level() >= 0 if (nodep->level() >= 0
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode && nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
m_os << "<cells>\n"; m_os << "<cells>\n";
@ -402,7 +401,7 @@ private:
m_os << "</cells>\n"; m_os << "</cells>\n";
} }
} }
virtual void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
if (nodep->modp()->dead()) return; if (nodep->modp()->dead()) return;
if (!m_hasChildren) m_os << ">\n"; if (!m_hasChildren) m_os << ">\n";
m_os << "<cell " << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() m_os << "<cell " << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name()
@ -422,7 +421,7 @@ private:
m_hasChildren = true; m_hasChildren = true;
} }
//----- //-----
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
@ -431,7 +430,7 @@ public:
// Operate on whole netlist // Operate on whole netlist
nodep->accept(*this); nodep->accept(*this);
} }
virtual ~HierCellsXmlVisitor() override = default; ~HierCellsXmlVisitor() override = default;
}; };
//###################################################################### //######################################################################

View File

@ -20,6 +20,7 @@
# include "V3Ast.h" # include "V3Ast.h"
# include "V3Global.h" # include "V3Global.h"
# include "V3Stats.h" # include "V3Stats.h"
VL_DEFINE_DEBUG_FUNCTIONS;
#endif #endif
// clang-format on // clang-format on
@ -54,7 +55,7 @@ v3errorIniter v3errorInit;
V3ErrorCode::V3ErrorCode(const char* msgp) { V3ErrorCode::V3ErrorCode(const char* msgp) {
// Return error encoding for given string, or ERROR, which is a bad code // Return error encoding for given string, or ERROR, which is a bad code
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
const V3ErrorCode code = V3ErrorCode(codei); const V3ErrorCode code{codei};
if (0 == VL_STRCASECMP(msgp, code.ascii())) { if (0 == VL_STRCASECMP(msgp, code.ascii())) {
m_e = code; m_e = code;
return; return;
@ -69,9 +70,9 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
void V3Error::init() { void V3Error::init() {
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) { for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
s_describedEachWarn[i] = false; s_describedEachWarn[i] = false;
s_pretendError[i] = V3ErrorCode(i).pretendError(); s_pretendError[i] = V3ErrorCode{i}.pretendError();
} }
if (VL_UNCOVERABLE(string(V3ErrorCode(V3ErrorCode::_ENUM_MAX).ascii()) != " MAX")) { if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) {
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged"); v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
} }
} }
@ -275,8 +276,10 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
s_tellManual = 2; s_tellManual = 2;
} }
#ifndef V3ERROR_NO_GLOBAL_ #ifndef V3ERROR_NO_GLOBAL_
if (debug()) { if (dumpTree()) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990)); v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990));
}
if (debug()) {
if (s_errorExitCb) s_errorExitCb(); if (s_errorExitCb) s_errorExitCb();
V3Stats::statsFinalAll(v3Global.rootp()); V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport(); V3Stats::statsReport();

View File

@ -26,6 +26,7 @@
#include <array> #include <array>
#include <bitset> #include <bitset>
#include <cassert> #include <cassert>
#include <cctype>
#include <deque> #include <deque>
#include <map> #include <map>
#include <set> #include <set>
@ -142,15 +143,15 @@ public:
}; };
// clang-format on // clang-format on
enum en m_e; enum en m_e;
inline V3ErrorCode() V3ErrorCode()
: m_e{EC_MIN} {} : m_e{EC_MIN} {}
// cppcheck-suppress noExplicitConstructor // cppcheck-suppress noExplicitConstructor
inline V3ErrorCode(en _e) constexpr V3ErrorCode(en _e)
: m_e{_e} {} : m_e{_e} {}
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
explicit inline V3ErrorCode(int _e) explicit V3ErrorCode(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning : m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; } constexpr operator en() const { return m_e; }
const char* ascii() const { const char* ascii() const {
// clang-format off // clang-format off
static const char* const names[] = { static const char* const names[] = {
@ -220,16 +221,16 @@ public:
|| m_e == VARHIDDEN); || m_e == VARHIDDEN);
} }
}; };
inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) { constexpr bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) {
return lhs.m_e == rhs.m_e; return lhs.m_e == rhs.m_e;
} }
inline bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; } constexpr bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; } constexpr bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) { inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
return os << rhs.ascii(); return os << rhs.ascii();
} }
//###################################################################### // ######################################################################
class V3Error final { class V3Error final {
// Base class for any object that wants debugging and error reporting // Base class for any object that wants debugging and error reporting
@ -317,7 +318,6 @@ public:
}; };
// Global versions, so that if the class doesn't define a operator, we get the functions anyways. // Global versions, so that if the class doesn't define a operator, we get the functions anyways.
inline int debug() { return V3Error::debugDefault(); }
inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); } inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
inline void v3errorEndFatal(std::ostringstream& sstr) { inline void v3errorEndFatal(std::ostringstream& sstr) {
V3Error::v3errorEnd(sstr); V3Error::v3errorEnd(sstr);
@ -412,19 +412,47 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
V3ERROR_NA; \ V3ERROR_NA; \
return value return value
/// Declare a convenience debug() routine that may be added to any class in // Helper macros for VL_DEFINE_DEBUG_FUNCTIONS
/// Verilator so that --debugi-<srcfile> will work to control UINFOs in #define VL_DEFINE_DEBUG(name) \
/// that class: VL_ATTR_UNUSED static int debug##name() { \
#define VL_DEBUG_FUNC \
static int debug() { \
static int level = -1; \ static int level = -1; \
if (VL_UNLIKELY(level < 0)) { \ if (VL_UNLIKELY(level < 0)) { \
const int debugSrcLevel = v3Global.opt.debugSrcLevel(__FILE__); \ std::string tag{VL_STRINGIFY(name)}; \
if (!v3Global.opt.available()) return debugSrcLevel; \ tag[0] = std::tolower(tag[0]); \
level = debugSrcLevel; \ const unsigned debugTag = v3Global.opt.debugLevel(tag); \
const unsigned debugSrc = v3Global.opt.debugSrcLevel(__FILE__); \
const unsigned debugLevel = debugTag >= debugSrc ? debugTag : debugSrc; \
if (!v3Global.opt.available()) return static_cast<int>(debugLevel); \
level = static_cast<int>(debugLevel); \
} \ } \
return level; \ return level; \
} } \
static_assert(true, "")
#define VL_DEFINE_DUMP(name) \
VL_ATTR_UNUSED static int dump##name() { \
static int level = -1; \
if (VL_UNLIKELY(level < 0)) { \
std::string tag{VL_STRINGIFY(name)}; \
tag[0] = std::tolower(tag[0]); \
const unsigned dumpTag = v3Global.opt.dumpLevel(tag); \
const unsigned dumpSrc = v3Global.opt.dumpSrcLevel(__FILE__); \
const unsigned dumpLevel = dumpTag >= dumpSrc ? dumpTag : dumpSrc; \
if (!v3Global.opt.available()) return static_cast<int>(dumpLevel); \
level = static_cast<int>(dumpLevel); \
} \
return level; \
} \
static_assert(true, "")
// Define debug*() and dump*() routines. This needs to be added to every compilation unit so that
// --debugi-<tag/srcfile> and --dumpi-<tag/srcfile> can be used to control debug prints and dumping
#define VL_DEFINE_DEBUG_FUNCTIONS \
VL_DEFINE_DEBUG(); /* Define 'int debug()' */ \
VL_DEFINE_DUMP(); /* Define 'int dump()' */ \
VL_DEFINE_DUMP(Graph); /* Define 'int dumpGraph()' */ \
VL_DEFINE_DUMP(Tree); /* Define 'int dumpTree()' */ \
static_assert(true, "")
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@ -37,6 +37,8 @@
#include <algorithm> #include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
// Expand state, as a visitor of each AstNode // Expand state, as a visitor of each AstNode
@ -53,7 +55,6 @@ private:
VDouble0 m_statWideLimited; // Statistic tracking VDouble0 m_statWideLimited; // Statistic tracking
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
bool doExpand(AstNode* nodep) { bool doExpand(AstNode* nodep) {
++m_statWides; ++m_statWides;
@ -306,14 +307,14 @@ private:
for (int w = 0; w < nodep->widthWords(); ++w) { for (int w = 0; w < nodep->widthWords(); ++w) {
addWordAssign(nodep, w, addWordAssign(nodep, w,
new AstCond{fl, rhsp->condp()->cloneTree(true), new AstCond{fl, rhsp->condp()->cloneTree(true),
newAstWordSelClone(rhsp->expr1p(), w), newAstWordSelClone(rhsp->thenp(), w),
newAstWordSelClone(rhsp->expr2p(), w)}); newAstWordSelClone(rhsp->elsep(), w)});
} }
return true; return true;
} }
// VISITORS // VISITORS
virtual void visit(AstExtend* nodep) override { void visit(AstExtend* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
if (nodep->isWide()) { if (nodep->isWide()) {
@ -339,7 +340,7 @@ private:
} }
} }
virtual void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
// Remember, Sel's may have non-integer rhs, so need to optimize for that! // Remember, Sel's may have non-integer rhs, so need to optimize for that!
@ -628,7 +629,7 @@ private:
} }
} }
virtual void visit(AstConcat* nodep) override { void visit(AstConcat* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
if (nodep->isWide()) { if (nodep->isWide()) {
@ -665,7 +666,7 @@ private:
return true; return true;
} }
virtual void visit(AstReplicate* nodep) override { void visit(AstReplicate* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
if (nodep->isWide()) { if (nodep->isWide()) {
@ -750,10 +751,10 @@ private:
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} }
} }
virtual void visit(AstEq* nodep) override { visitEqNeq(nodep); } void visit(AstEq* nodep) override { visitEqNeq(nodep); }
virtual void visit(AstNeq* nodep) override { visitEqNeq(nodep); } void visit(AstNeq* nodep) override { visitEqNeq(nodep); }
virtual void visit(AstRedOr* nodep) override { void visit(AstRedOr* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
@ -775,7 +776,7 @@ private:
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} }
} }
virtual void visit(AstRedAnd* nodep) override { void visit(AstRedAnd* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
@ -805,7 +806,7 @@ private:
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} }
} }
virtual void visit(AstRedXor* nodep) override { void visit(AstRedXor* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep); iterateChildren(nodep);
if (nodep->lhsp()->isWide()) { if (nodep->lhsp()->isWide()) {
@ -825,7 +826,7 @@ private:
// which the inlined function does nicely. // which the inlined function does nicely.
} }
virtual void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
if (!nodep->isStatement()) { if (!nodep->isStatement()) {
iterateChildren(nodep); iterateChildren(nodep);
@ -835,7 +836,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
m_stmtp = nullptr; m_stmtp = nullptr;
} }
virtual void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
m_stmtp = nodep; m_stmtp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
@ -876,13 +877,13 @@ private:
} }
//-------------------- //--------------------
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars void visit(AstVar*) override {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); } explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ExpandVisitor() override { ~ExpandVisitor() override {
V3Stats::addStat("Optimizations, expand wides", m_statWides); V3Stats::addStat("Optimizations, expand wides", m_statWides);
V3Stats::addStat("Optimizations, expand wide words", m_statWideWords); V3Stats::addStat("Optimizations, expand wide words", m_statWideWords);
V3Stats::addStat("Optimizations, expand limited", m_statWideLimited); V3Stats::addStat("Optimizations, expand limited", m_statWideLimited);
@ -898,5 +899,5 @@ public:
void V3Expand::expandAll(AstNetlist* nodep) { void V3Expand::expandAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ ExpandVisitor{nodep}; } // Destruct before checking { ExpandVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("expand", 0, dumpTree() >= 3);
} }

View File

@ -56,6 +56,8 @@
#endif #endif
// clang-format on // clang-format on
VL_DEFINE_DEBUG_FUNCTIONS;
// If change this code, run a test with the below size set very small // If change this code, run a test with the below size set very small
// #define INFILTER_IPC_BUFSIZ 16 // #define INFILTER_IPC_BUFSIZ 16
constexpr int INFILTER_IPC_BUFSIZ = (64 * 1024); // For debug, try this as a small number constexpr int INFILTER_IPC_BUFSIZ = (64 * 1024); // For debug, try this as a small number
@ -94,7 +96,7 @@ class V3FileDependImp final {
const string fn = filename(); const string fn = filename();
const int err = stat(fn.c_str(), &m_stat); const int err = stat(fn.c_str(), &m_stat);
if (err != 0) { if (err != 0) {
memset(&m_stat, 0, sizeof(m_stat)); std::memset(&m_stat, 0, sizeof(m_stat));
m_stat.st_mtime = 1; m_stat.st_mtime = 1;
m_exists = false; m_exists = false;
// Not an error... This can occur due to `line directives in the .vpp files // Not an error... This can occur due to `line directives in the .vpp files
@ -146,7 +148,7 @@ V3FileDependImp dependImp; // Depend implementation class
//###################################################################### //######################################################################
// V3FileDependImp // V3FileDependImp
inline void V3FileDependImp::writeDepend(const string& filename) { void V3FileDependImp::writeDepend(const string& filename) {
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)}; const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
if (ofp->fail()) v3fatal("Can't write " << filename); if (ofp->fail()) v3fatal("Can't write " << filename);
@ -154,7 +156,7 @@ inline void V3FileDependImp::writeDepend(const string& filename) {
if (i.target()) *ofp << i.filename() << " "; if (i.target()) *ofp << i.filename() << " ";
} }
*ofp << " : "; *ofp << " : ";
*ofp << v3Global.opt.bin(); *ofp << v3Global.opt.buildDepBin();
*ofp << " "; *ofp << " ";
for (const DependFile& i : m_filenameList) { for (const DependFile& i : m_filenameList) {
@ -171,7 +173,7 @@ inline void V3FileDependImp::writeDepend(const string& filename) {
} }
} }
inline std::vector<string> V3FileDependImp::getAllDeps() const { std::vector<string> V3FileDependImp::getAllDeps() const {
std::vector<string> r; std::vector<string> r;
for (const auto& itr : m_filenameList) { for (const auto& itr : m_filenameList) {
if (!itr.target() && itr.exists()) r.push_back(itr.filename()); if (!itr.target() && itr.exists()) r.push_back(itr.filename());
@ -179,7 +181,7 @@ inline std::vector<string> V3FileDependImp::getAllDeps() const {
return r; return r;
} }
inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) { void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) {
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)}; const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
if (ofp->fail()) v3fatal("Can't write " << filename); if (ofp->fail()) v3fatal("Can't write " << filename);
@ -214,7 +216,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
} }
} }
inline bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) { bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) {
const std::unique_ptr<std::ifstream> ifp{V3File::new_ifstream_nodepend(filename)}; const std::unique_ptr<std::ifstream> ifp{V3File::new_ifstream_nodepend(filename)};
if (ifp->fail()) { if (ifp->fail()) {
UINFO(2, " --check-times failed: no input " << filename << endl); UINFO(2, " --check-times failed: no input " << filename << endl);
@ -346,7 +348,6 @@ class VInFilterImp final {
private: private:
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug()
bool readContents(const string& filename, StrList& outl) { bool readContents(const string& filename, StrList& outl) {
if (m_pid) { if (m_pid) {
@ -389,7 +390,7 @@ private:
if (!m_pidExited && waitpid(m_pid, &m_pidStatus, hang ? 0 : WNOHANG)) { if (!m_pidExited && waitpid(m_pid, &m_pidStatus, hang ? 0 : WNOHANG)) {
UINFO(1, "--pipe-filter: Exited, status " UINFO(1, "--pipe-filter: Exited, status "
<< m_pidStatus << " exit=" << WEXITSTATUS(m_pidStatus) << " err" << m_pidStatus << " exit=" << WEXITSTATUS(m_pidStatus) << " err"
<< strerror(errno) << endl); << std::strerror(errno) << endl);
m_readEof = true; m_readEof = true;
m_pidExited = true; m_pidExited = true;
} }
@ -495,7 +496,7 @@ private:
constexpr int P_WR = 1; constexpr int P_WR = 1;
if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
v3fatal("--pipe-filter: Can't pipe: " << strerror(errno)); v3fatal("--pipe-filter: Can't pipe: " << std::strerror(errno));
} }
if (fd_stdin[P_RD] <= 2 || fd_stdin[P_WR] <= 2 || fd_stdout[P_RD] <= 2 if (fd_stdin[P_RD] <= 2 || fd_stdin[P_WR] <= 2 || fd_stdout[P_RD] <= 2
|| fd_stdout[P_WR] <= 2) { || fd_stdout[P_WR] <= 2) {
@ -507,7 +508,7 @@ private:
UINFO(1, "--pipe-filter: /bin/sh -c " << command << endl); UINFO(1, "--pipe-filter: /bin/sh -c " << command << endl);
const pid_t pid = fork(); const pid_t pid = fork();
if (pid < 0) v3fatal("--pipe-filter: fork failed: " << strerror(errno)); if (pid < 0) v3fatal("--pipe-filter: fork failed: " << std::strerror(errno));
if (pid == 0) { // Child if (pid == 0) { // Child
UINFO(6, "In child\n"); UINFO(6, "In child\n");
close(fd_stdin[P_WR]); close(fd_stdin[P_WR]);
@ -518,7 +519,7 @@ private:
execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char*>(nullptr)); execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char*>(nullptr));
// Don't use v3fatal, we don't share the common structures any more // Don't use v3fatal, we don't share the common structures any more
fprintf(stderr, "--pipe-filter: exec failed: %s\n", strerror(errno)); fprintf(stderr, "--pipe-filter: exec failed: %s\n", std::strerror(errno));
_exit(1); _exit(1);
} else { // Parent } else { // Parent
UINFO(6, "In parent, child pid " << pid << " stdin " << fd_stdin[P_WR] << "->" UINFO(6, "In parent, child pid " << pid << " stdin " << fd_stdin[P_WR] << "->"

View File

@ -206,7 +206,7 @@ public:
V3OutFile(V3OutFile&&) = delete; V3OutFile(V3OutFile&&) = delete;
V3OutFile& operator=(V3OutFile&&) = delete; V3OutFile& operator=(V3OutFile&&) = delete;
virtual ~V3OutFile() override; ~V3OutFile() override;
void putsForceIncs(); void putsForceIncs();
private: private:
@ -216,15 +216,15 @@ private:
} }
// CALLBACKS // CALLBACKS
virtual void putcOutput(char chr) override { void putcOutput(char chr) override {
m_bufferp->at(m_usedBytes++) = chr; m_bufferp->at(m_usedBytes++) = chr;
if (VL_UNLIKELY(m_usedBytes >= WRITE_BUFFER_SIZE_BYTES)) writeBlock(); if (VL_UNLIKELY(m_usedBytes >= WRITE_BUFFER_SIZE_BYTES)) writeBlock();
} }
virtual void putsOutput(const char* str) override { void putsOutput(const char* str) override {
std::size_t len = strlen(str); std::size_t len = strlen(str);
std::size_t availableBytes = WRITE_BUFFER_SIZE_BYTES - m_usedBytes; std::size_t availableBytes = WRITE_BUFFER_SIZE_BYTES - m_usedBytes;
while (VL_UNLIKELY(len >= availableBytes)) { while (VL_UNLIKELY(len >= availableBytes)) {
memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); std::memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes);
m_usedBytes = WRITE_BUFFER_SIZE_BYTES; m_usedBytes = WRITE_BUFFER_SIZE_BYTES;
writeBlock(); writeBlock();
str += availableBytes; str += availableBytes;
@ -232,7 +232,7 @@ private:
availableBytes = WRITE_BUFFER_SIZE_BYTES; availableBytes = WRITE_BUFFER_SIZE_BYTES;
} }
if (len > 0) { if (len > 0) {
memcpy(m_bufferp->data() + m_usedBytes, str, len); std::memcpy(m_bufferp->data() + m_usedBytes, str, len);
m_usedBytes += len; m_usedBytes += len;
} }
} }
@ -246,7 +246,7 @@ public:
: V3OutFile{filename, V3OutFormatter::LA_C} { : V3OutFile{filename, V3OutFormatter::LA_C} {
resetPrivate(); resetPrivate();
} }
virtual ~V3OutCFile() override = default; ~V3OutCFile() override = default;
virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); } virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); }
virtual void putsIntTopInclude() { putsForceIncs(); } virtual void putsIntTopInclude() { putsForceIncs(); }
virtual void putsGuard(); virtual void putsGuard();
@ -270,9 +270,9 @@ class V3OutScFile final : public V3OutCFile {
public: public:
explicit V3OutScFile(const string& filename) explicit V3OutScFile(const string& filename)
: V3OutCFile{filename} {} : V3OutCFile{filename} {}
virtual ~V3OutScFile() override = default; ~V3OutScFile() override = default;
virtual void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); } void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() override { void putsIntTopInclude() override {
putsForceIncs(); putsForceIncs();
puts("#include \"systemc.h\"\n"); puts("#include \"systemc.h\"\n");
puts("#include \"verilated_sc.h\"\n"); puts("#include \"verilated_sc.h\"\n");
@ -283,7 +283,7 @@ class V3OutVFile final : public V3OutFile {
public: public:
explicit V3OutVFile(const string& filename) explicit V3OutVFile(const string& filename)
: V3OutFile{filename, V3OutFormatter::LA_VERILOG} {} : V3OutFile{filename, V3OutFormatter::LA_VERILOG} {}
virtual ~V3OutVFile() override = default; ~V3OutVFile() override = default;
virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); } virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); }
}; };
@ -293,7 +293,7 @@ public:
: V3OutFile{filename, V3OutFormatter::LA_XML} { : V3OutFile{filename, V3OutFormatter::LA_XML} {
blockIndent(2); blockIndent(2);
} }
virtual ~V3OutXmlFile() override = default; ~V3OutXmlFile() override = default;
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); } virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
}; };
@ -301,7 +301,7 @@ class V3OutMkFile final : public V3OutFile {
public: public:
explicit V3OutMkFile(const string& filename) explicit V3OutMkFile(const string& filename)
: V3OutFile{filename, V3OutFormatter::LA_MK} {} : V3OutFile{filename, V3OutFormatter::LA_MK} {}
virtual ~V3OutMkFile() override = default; ~V3OutMkFile() override = default;
virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); } virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); }
// No automatic indentation yet. // No automatic indentation yet.
void puts(const char* strg) { putsNoTracking(strg); } void puts(const char* strg) { putsNoTracking(strg); }

Some files were not shown because too many files have changed in this diff Show More