Merge from master for release.

This commit is contained in:
Wilson Snyder
2024-02-24 07:48:43 -05:00
679 changed files with 37887 additions and 4813 deletions
+18 -45
View File
@@ -37,43 +37,29 @@ jobs:
compiler:
- { cc: clang, cxx: clang++ }
- { cc: gcc, cxx: g++ }
# m32 1 is deprecated, not here to speed up regressions
m32: [0]
exclude:
# Build pull requests only with ubuntu-22.04 and without m32
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
# - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04 clang++
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
- compiler: { cc: gcc, cxx: g++ }
m32: 1
include:
# Build GCC 10 on ubuntu-20.04
- os: ubuntu-20.04
compiler: { cc: gcc-10, cxx: g++-10 }
m32: 0
runs-on: ${{ matrix.os }}
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }} ${{ matrix.m32 && '| -m32' || '' }}
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }}
env:
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ${{ matrix.os }}
CI_M32: ${{ matrix.m32 }}
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
path: repo
- name: Cache $CCACHE_DIR
uses: actions/cache@v3
uses: actions/cache@v4
env:
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
with:
@@ -93,7 +79,7 @@ jobs:
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
- name: Upload tar archive
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
name: ${{ env.VERILATOR_ARCHIVE }}
@@ -108,40 +94,28 @@ jobs:
compiler:
- { cc: clang, cxx: clang++ }
- { cc: gcc, cxx: g++ }
m32: [0]
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1]
exclude:
# Build pull requests only with ubuntu-22.04 and without m32
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
# - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
- compiler: { cc: gcc, cxx: g++ }
m32: 1
include:
# Test with GCC 10 on ubuntu-20.04 without m32
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-1}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-2}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-0}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-1}
# Test with GCC 10 on ubuntu-20.04
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-0}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-1}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-2}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-0}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-1}
runs-on: ${{ matrix.os }}
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }} ${{ matrix.m32 && '| -m32' || '' }}
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }}
env:
CI_BUILD_STAGE_NAME: test
CI_RUNS_ON: ${{ matrix.os }}
CI_M32: ${{ matrix.m32 }}
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${{ matrix.suite }}
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.suite }}
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
steps:
- name: Download tar archive
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ${{ env.VERILATOR_ARCHIVE }}
path: ${{ github.workspace }}
@@ -151,7 +125,7 @@ jobs:
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
- name: Cache $CCACHE_DIR
uses: actions/cache@v3
uses: actions/cache@v4
env:
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
with:
@@ -174,10 +148,9 @@ jobs:
env:
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ubuntu-22.04
CI_M32: 0
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
path: repo
+1 -1
View File
@@ -13,5 +13,5 @@ jobs:
name: "'docs/CONTRIBUTORS' was signed"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- run: test_regress/t/t_dist_contributors.pl
+3 -4
View File
@@ -11,7 +11,6 @@ on:
env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
CI_M32: 0
COVERAGE: 1
VERILATOR_ARCHIVE: verilator-coverage-${{ github.sha }}.tar.gz
@@ -31,7 +30,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
path: repo
@@ -46,7 +45,7 @@ jobs:
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
- name: Upload tar archive
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
name: ${{ env.VERILATOR_ARCHIVE }}
@@ -81,7 +80,7 @@ jobs:
steps:
- name: Download tar archive
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ${{ env.VERILATOR_ARCHIVE }}
path: ${{ github.workspace }}
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Extract context variables
run: |
+1 -2
View File
@@ -16,10 +16,9 @@ jobs:
CI_OS_NAME: linux
CI_RUNS_ON: ubuntu-22.04
CI_COMMIT: ${{ github.sha }}
CI_M32: 0
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install packages for build
+3 -3
View File
@@ -32,11 +32,11 @@ jobs:
name: run on windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
path: repo
- name: Cache $CCACHE_DIR
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: msbuild-msvc-cmake
@@ -49,7 +49,7 @@ jobs:
- name: Zip up repository
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
- name: Upload zip archive
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ github.workspace }}/repo/verilator.zip
name: verilator-win.zip
+1 -1
View File
@@ -15,7 +15,7 @@
cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
project(Verilator
VERSION 5.020
VERSION 5.022
HOMEPAGE_URL https://verilator.org
LANGUAGES CXX
)
+58 -2
View File
@@ -8,12 +8,68 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 5.022 2024-04-24
==========================
**Minor:**
* Add predicted stack overflow warning (#4799).
* Add `+verilator+coverage+file` runtime option.
* Add `--assert-case` option (#4919). [Yutetsu TAKATSUKASA]
* Add `--decorations node` for inserting debug comments into emitted code.
* Add `--json-only` and related JSON dumping (#4715) (#4831). [Szymon Gizler, Antmicro Ltd.]
* Add `--[no]-stop-fail` option for continuing after assertions (#4904). [Yutetsu TAKATSUKASA]
* Add `--runtime-debug` for Verilated executable runtime debugging.
* Add `--valgrind` switch (#4828). [Szymon Gizler]
* Add `unroll_disable` and `unroll_full` loop control metacomments (#3260). [Jiaxun Yang]
* Remove deprecated 32-bit pointer mode (`gcc -m32`).
* Deprecate --xml-only and XML dumping (#4715) (#4831).
* Change zero replication width error to ZEROREPL warning (#4753) (#4762). [Pengcheng Xu]
* Improve message for priority case assertion failure (#4905). [Yutetsu TAKATSUKASA]
* Support dumping coverage with `--main`.
* Support dumping DFG patterns with `--stats` (#4889). [Geza Lore]
* Support `vpiConstType` in `vpi_get_str()` (#4797). [Marlon James]
* Support SystemC 3.0.0 public review version (#4805) (#4807). [Anthony Donlon]
* Support parsing anonymous primitive instantiations (#4809). [Anthony Donlon]
* Fix to not emit already waived warnings in waiver output (#4574) (#4818). [Jonathan Schröter]
* Fix `this` in member initialization (#4710). [eliasphanna]
* Fix localparam elaboration (#3858) (#4794). [Andrew Nolte]
* Fix lint_off disables on preprocessor warnings (#4703). [Srinivasan Venkataramanan]
* Fix $time not rounding up (#4790) (#4792). [Paul Wright]
* Fix `vpi_get()` and `vpi_get64()` to return vpiUndefined on errors (#4795). [Marlon James]
* Fix VPI parameter iteration (#4798). [Marlon James]
* Fix delays using wrong timeunit when modules inlined (#4806). [Paul Wright]
* Fix warnings in verilated_sc_trace.h for Clang. (#4807) (#4827). [Anthony Donlon]
* Fix null pointer dereference (#4810) (#4825). [Adrian Sampson]
* Fix compilation error on multi-inherited interface class usage (#4819).
* Fix maybe-uninitialized compiler warning (#4820) (#4822). [Larry Doolittle]
* Fix mis-splitting of dump control functions (#4821). [Fan Shupei]
* Fix wrong utimes() parameter (#4829). [Szymon Gizler]
* Fix incorrect bit-op-tree NOT optimization (#4832) (#4847). [Yutetsu TAKATSUKASA]
* Fix width calculation in replaceShiftOp (#4837) (#4841) (#4849). [Yutetsu TAKATSUKASA]
* Fix unsafe write in wide array insertion (#4850) (#4855). [Paul Swirhun]
* Fix NOT when checking EQ/NEQ under AND/OR tree (#4857) (#4863). [Yutetsu TAKATSUKASA]
* Fix tracing chandles (#4860). [Nathan Graybeal]
* Fix $fwrite of null (#4862). [Jose Tejada]
* Fix -fno-const-bit-op-tree wrong runtime result (#4864) (#4867). [Yutetsu TAKATSUKASA]
* Fix SystemC biguint sign desynchronization (#4870). [Bartłomiej Chmiel]
* Fix incorrect temporary insertion in loop conditions with statements (#4873). [Geza Lore]
* Fix timing with expr on assign LHS (#4880). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix assertion for unique case (#4892). [Yutetsu TAKATSUKASA]
* Fix GCC tautological-compare warnings.
* Fix compile error on structs with queues (and ignore toggle coverage on queues).
* Fix toggle coverage error on multi-edge driven signals.
* Fix whitespace in `pragma protect version` (#4902) (#4914). [Paul Swirhun]
* Fix incorrect code generation for change expression on typedefed unpacked array (#4915). [Geza Lore]
* Fix inconsistent driver resolution with typedefs (#4917). [Geza Lore]
Verilator 5.020 2024-01-01
==========================
**Major:**
* Support compilation with precompiled headers with Make and GCC or CLang.
* Support compilation with precompiled headers with Make, and GCC or CLang.
* Change include to systemc instead of systemc.h (#4622) (#4623). [Chih-Mao Chen]
This may require that SystemC programs add 'using namespace sc_core', 'using namespace sc_dt'.
@@ -271,7 +327,7 @@ Verilator 5.012 2023-06-13
* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk]
* Configure for faster C++ linking using 'mold', if it is installed.
* Fix crash on duplicate imported modules (#3231). [Robert Balas]
* Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO]
* Fix false WIDTHEXPAND on array declarations (#3959). [Jose Tejada]
* Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd]
* Fix SystemC signal copy macro use (#4135). [Josep Sans]
* Fix duplicate static names in blocks in functions (#4144) (#4160). [Stefan Wallentowitz]
+6 -6
View File
@@ -112,7 +112,7 @@ SUBDIRS = docs src test_regress \
examples/make_tracing_c \
examples/make_tracing_sc \
examples/make_protect_lib \
examples/xml_py \
examples/json_py \
INFOS = verilator.html verilator.pdf
@@ -269,7 +269,7 @@ installdata:
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/xml_py
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/json_py
cd $(srcdir) \
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
@@ -305,7 +305,7 @@ uninstall:
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
-rmdir $(DESTDIR)$(pkgdatadir)/examples/xml_py
-rmdir $(DESTDIR)$(pkgdatadir)/examples/json_py
-rmdir $(DESTDIR)$(pkgdatadir)/examples
-rmdir $(DESTDIR)$(pkgdatadir)
-rmdir $(DESTDIR)$(pkgconfigdir)
@@ -340,7 +340,7 @@ CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=useStlAlgorithm
CPPCHECK_FLAGS += --xml
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CHECK_CPP))
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/include/gtkwave -I$(srcdir)/include/vltstd -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
cppcheck: cppcheck-1 cppcheck-2 cppcheck-3 cppcheck-4 cppcheck-5 cppcheck-6 cppcheck-7 cppcheck-8
cppcheck-1:
@@ -399,8 +399,8 @@ PY_PROGRAMS = \
bin/verilator_gantt \
bin/verilator_includer \
bin/verilator_profcfunc \
examples/xml_py/vl_file_copy \
examples/xml_py/vl_hier_graph \
examples/json_py/vl_file_copy \
examples/json_py/vl_hier_graph \
docs/guide/conf.py \
docs/bin/vl_sphinx_extract \
docs/bin/vl_sphinx_fix \
+4 -4
View File
@@ -66,9 +66,9 @@ executable performs the design simulation. Verilator also supports linking
Verilated generated libraries, optionally encrypted, into other simulators.
Verilator may not be the best choice if you are expecting a full-featured
replacement for a closed-source Verilog simulator, needs SDF annotation,
replacement for a closed-source Verilog simulator, need SDF annotation,
mixed-signal simulation, or are doing a quick class project (we recommend
`Icarus Verilog`_ for classwork.) However, if you are looking for a path
`Icarus Verilog`_ for classwork). However, if you are looking for a path
to migrate SystemVerilog to C++/SystemC, or want high-speed simulation of
designs, Verilator is the tool for you.
@@ -80,12 +80,12 @@ Verilator does not directly translate Verilog HDL to C++ or SystemC. Rather,
Verilator compiles your code into a much faster optimized and optionally
thread-partitioned model, which is in turn wrapped inside a C++/SystemC
module. The results are a compiled Verilog model that executes even on a
single-thread over 10x faster than standalone SystemC, and on a single
single thread over 10x faster than standalone SystemC, and on a single
thread is about 100 times faster than interpreted Verilog simulators such
as `Icarus Verilog`_. Another 2-10x speedup might be gained from
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
closed-source Verilog simulators (e.g., Carbon Design Systems Carbonator,
Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
+31 -4
View File
@@ -32,6 +32,7 @@ my $opt_rr;
my $opt_gdbbt;
my $opt_quiet_exit;
my $opt_unlimited_stack = 1;
my $opt_valgrind;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
@@ -59,6 +60,7 @@ if (! GetOptions(
"quiet-exit!" => \$opt_quiet_exit,
"rr!" => \$opt_rr,
"unlimited-stack!" => \$opt_unlimited_stack,
"valgrind!" => \$opt_valgrind,
# Additional parameters
"<>" => sub {}, # Ignored
)) {
@@ -109,6 +111,18 @@ if ($opt_gdb) {
. " -ex \"run " . join(' ', @quoted_sw)."\""
. " -ex 'set width 0'"
. " -ex 'bt' -ex 'quit'");
} elsif ($opt_valgrind) {
# Run under valgrind
my $valgrind_bin = ($ENV{VERILATOR_VALGRIND} || "valgrind --error-exitcode=1 --max-stackframe=2815880"
# Magic number sugested by valgrind, may need to be increased in future
# if you get warnings. See: https://valgrind.org/docs/manual/manual-core.html#opt.max-stackframe
);
run (ulimit_stack_unlimited()
. aslr_off()
. $valgrind_bin
. " " . verilator_bin()
. " " . join(' ', @quoted_sw));
} elsif ($Debug) {
# Debug
run(ulimit_stack_unlimited()
@@ -299,6 +313,7 @@ detailed descriptions of these arguments.
+1800-2012ext+<ext> Use SystemVerilog 2012 with file extension <ext>
+1800-2017ext+<ext> Use SystemVerilog 2017 with file extension <ext>
--assert Enable all assertions
--assert-case Enable unique/unique0/priority case related checks
--autoflush Flush streams after all $displays
--bbox-sys Blackbox unknown $system calls
--bbox-unsup Blackbox unsupported language features
@@ -307,7 +322,6 @@ detailed descriptions of these arguments.
--build-dep-bin <filename> Override build dependency Verilator binary
--build-jobs <jobs> Parallelism for --build
--cc Create C++ output
--cdc Clock domain crossing analysis
-CFLAGS <flags> C++ compiler arguments for makefile
--clk <signal-name> Mark specified signal as clock
--no-clk <signal-name> Prevent marking specified signal as clock
@@ -325,7 +339,8 @@ detailed descriptions of these arguments.
--no-debug-leak Disable leaking memory in --debug mode
--debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a level
--no-decoration Disable comments and symbol decorations
--decorations <level> Set output comment and spacing level
--no-decoration Disable comments and lower spacing level
--default-language <lang> Default language to parse
+define+<var>=<value> Set preprocessor define
--dpi-hdr-only Only produce the DPI header file
@@ -334,6 +349,7 @@ detailed descriptions of these arguments.
--dump-graph Enable dumping V3Graphs to .dot files
--dump-tree Enable dumping Ast .tree files
--dump-tree-addrids Use short identifiers instead of addresses
--dump-tree-dot Enable dumping Ast .tree.dot debug files
--dump-<srcfile> Enable dumping everything in source file
--dumpi-dfg <level> Enable dumping DfgGraphs to .dot files at level
--dumpi-graph <level> Enable dumping V3Graphs to .dot files at level
@@ -347,6 +363,8 @@ detailed descriptions of these arguments.
-f <file> Parse arguments from a file
-FI <file> Force include of a file
--flatten Force inlining of all modules, tasks and functions
--future0 <option> Ignore an option for compatibility
--future1 <option> Ignore an option with argument for compatibility
-fno-<optimization> Disable internal optimization stage
-G<name>=<value> Overwrite top-level parameter
--gate-stmts <value> Tune gate optimizer depth
@@ -383,7 +401,6 @@ detailed descriptions of these arguments.
-O3 High-performance optimizations
-O<optimization-letter> Selectable optimizations
-o <executable> Name of final executable
--no-order-clock-delay Disable ordering clock enable assignments
--output-split <statements> Split .cpp files into pieces
--output-split-cfuncs <statements> Split model functions
--output-split-ctrace <statements> Split tracing functions
@@ -404,7 +421,8 @@ detailed descriptions of these arguments.
--protect-ids Hash identifier names for obscurity
--protect-key <key> Key for symbol protection
--protect-lib <name> Create a DPI protected library
--public Debugging; see docs
--public Mark signals as public; see docs
--public-depth <level> Mark public to specified module depth
--public-params Mark all parameters as public_flat
--public-flat-rw Mark all variables, etc as public_flat_rw
-pvalue+<name>=<value> Overwrite toplevel parameter
@@ -413,12 +431,14 @@ detailed descriptions of these arguments.
--reloop-limit Minimum iterations for forming loops
--report-unoptflat Extra diagnostics for UNOPTFLAT
--rr Run Verilator and record with rr
--runtime-debug Enable model runtime debugging
--savable Enable model save-restore
--sc Create SystemC output
--no-skip-identical Disable skipping identical output
--stats Create statistics file
--stats-vars Provide statistics on variables
--no-std Prevent parsing standard library
--no-stop-fail Do not call $stop when assertion fails
--structs-packed Convert all unpacked structures to packed structures
-sv Enable SystemVerilog parsing
+systemverilogext+<ext> Synonym for +1800-2017ext+<ext>
@@ -449,6 +469,7 @@ detailed descriptions of these arguments.
--unused-regexp <regexp> Tune UNUSED lint signals
-V Verbose version and config
-v <filename> Verilog library
--valgrind Run Verilator under valgrind
--verilate-jobs Job threads for Verilation stage
--no-verilate Skip Verilation and just compile previously Verilated code
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
@@ -471,6 +492,11 @@ detailed descriptions of these arguments.
--x-assign <mode> Assign non-initial Xs to this value
--x-initial <mode> Assign initial Xs to this value
--x-initial-edge Enable initial X->0 and X->1 edge triggers
--no-json-edit-nums Don't dump editNum in .tree.json files
--no-json-ids Don't use short identifiers instead of adresses/paths in .tree.json
--json-only Create JSON parser output (.tree.json and .meta.json)
--json-only-output .tree.json output filename
--json-only-meta-output .tree.meta.json output filename
--xml-only Create XML parser output
--xml-output XML output filename
-y <dir> Directory to search for modules
@@ -484,6 +510,7 @@ description of these arguments.
+verilator+debug Enable debugging
+verilator+debugi+<value> Enable debugging at a level
+verilator+coverage+file+<filename> Set coverage output filename
+verilator+error+limit+<value> Set error limit
+verilator+help Display help
+verilator+noassert Disable assert checking
+6 -6
View File
@@ -177,12 +177,12 @@ L<https://verilator.org/guide/latest/exe_verilator_coverage.html>.
--write <filename> Write aggregate coverage results.
--write-info <filename.info> Write lcov .info.
+libext+I<ext>+I<ext>... Extensions for Verilog files.
+define+I<var>+I<value> Defines the given variable.
-DI<var>=I<value> Defines the given variable.
+incdir+I<dir> Add directory for finding include files.
-II<dir> Add directory for finding include files.
-y I<dir> Specifies module search directory.
+libext+<ext>+<ext>... Extensions for Verilog files.
+define+<var>+<value> Defines the given variable.
-D<var>=<value> Defines the given variable.
+incdir+<dir> Add directory for finding include files.
-I<dir> Add directory for finding include files.
-y <dir> Specifies module search directory.
=head1 DISTRIBUTION
-14
View File
@@ -27,12 +27,6 @@ fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$CI_M32" = "0" ]; then
unset CI_M32
elif [ "$CI_M32" != "1" ]; then
fatal "\$CI_M32 must be '0' or '1'";
fi
if [ "$CI_OS_NAME" = "linux" ]; then
MAKE=make
elif [ "$CI_OS_NAME" = "osx" ]; then
@@ -77,10 +71,6 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Parallel::Forker
fi
if [ "$CI_M32" = 1 ]; then
sudo apt-get install gcc-multilib g++-multilib ||
sudo apt-get install gcc-multilib g++-multilib
fi
elif [ "$CI_OS_NAME" = "osx" ]; then
brew update
brew install ccache perl gperftools
@@ -114,10 +104,6 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
sudo apt-get install libsystemc-dev ||
sudo apt-get install libsystemc-dev
fi
if [ "$CI_M32" = 1 ]; then
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib ||
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib
fi
elif [ "$CI_OS_NAME" = "osx" ]; then
brew update
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
+2 -8
View File
@@ -21,12 +21,6 @@ fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$CI_M32" = "0" ]; then
unset CI_M32
elif [ "$CI_M32" != "1" ]; then
fatal "\$CI_M32 must be '0' or '1'";
fi
if [ "$CI_OS_NAME" = "linux" ]; then
export MAKE=make
NPROC=$(nproc)
@@ -46,7 +40,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn ${CI_M32:+--enable-m32}
./configure --enable-longtests --enable-ccwarn
ccache -z
"$MAKE" -j "$NPROC" -k
# 22.04: ccache -s -v
@@ -91,7 +85,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
fi
# Run sanitize on Ubuntu 22.04 only
[ "$CI_RUNS_ON" = 'ubuntu-22.04' ] && [ "$CI_M32" = "" ] && sanitize='--sanitize' || sanitize=''
[ "$CI_RUNS_ON" = 'ubuntu-22.04' ] && sanitize='--sanitize' || sanitize=''
# Run the specified test
ccache -z
+4 -25
View File
@@ -10,7 +10,7 @@
# Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[5.020 2024-01-01],
AC_INIT([Verilator],[5.022 2024-02-24],
[https://verilator.org],
[verilator],[https://verilator.org])
@@ -67,20 +67,6 @@ AC_ARG_ENABLE([tcmalloc],
[CFG_WITH_TCMALLOC=check;])
AC_MSG_RESULT($CFG_WITH_TCMALLOC)
# Flag to enable -m32 build
AC_MSG_CHECKING(whether to use -m32)
AC_ARG_ENABLE([m32],
[AS_HELP_STRING([--enable-m32],
[Use -m32 for all compilation and link,
including Verilator and generated models.])],
[case "${enableval}" in
yes) CFG_ENABLE_M32=yes ;;
no) CFG_ENABLE_M32=no ;;
*) AC_MSG_ERROR([bad value '${enableval}' for --enable-m32]) ;;
esac],
CFG_ENABLE_M32=no)
AC_MSG_RESULT($CFG_ENABLE_M32)
# Flag to enable coverage build
AC_MSG_CHECKING(whether to build for coverage collection)
AC_ARG_ENABLE([coverage],
@@ -319,15 +305,7 @@ AC_DEFUN([_MY_LDLIBS_CHECK_OPT],
_MY_LDLIBS_CHECK_IFELSE($2, $1="$$1 $2")
])
# When using -m32. Check this first as later checks may fail with the -m32 flag.
if test "$CFG_ENABLE_M32" = "yes"; then
_MY_CXX_CHECK_IFELSE(
-m32,
[CXX="$CXX -m32"],
[AC_MSG_ERROR([--enable-m32 was given but compiler does not support -m32])])
fi
# Similarly, add the coverage flags early as they influence later checks.
# Add the coverage flags early as they influence later checks.
if test "$CFG_ENABLE_COVERAGE" = "yes"; then
_MY_CXX_CHECK_OPT(CXX,--coverage)
# Otherwise inline may not show as uncovered
@@ -446,11 +424,11 @@ m4_foreach([cflag],[
[-Wno-c++11-narrowing],
[-Wno-constant-logical-operand],
[-Wno-non-pod-varargs],
[-Wno-overloaded-virtual],
[-Wno-parentheses-equality],
[-Wno-shadow],
[-Wno-sign-compare],
[-Wno-tautological-bitwise-compare],
[-Wno-tautological-compare],
[-Wno-uninitialized],
[-Wno-unused-but-set-parameter],
[-Wno-unused-but-set-variable],
@@ -497,6 +475,7 @@ AC_SUBST(CFG_LDFLAGS_VERILATED)
# pthreads is harmless otherwise.
CFG_LIBS="$LIBS $CFG_LIBS"
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread)
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -latomic)
# Check libraries for MingW
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt)
+8
View File
@@ -4,6 +4,7 @@ under the Developer Certificate of Origin (https://developercertificate.org/).
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
Adam Bagley
Adrian Sampson
Adrien Le Masle
Ahmed El-Mahmoudy
Aleksander Kiryk
@@ -18,10 +19,12 @@ Andrew Nolte
Anthony Donlon
Arkadiusz Kozdra
Aylon Chaim Porat
Bartłomiej Chmiel
Cameron Kirk
Chih-Mao Chen
Chris Randall
Chuxuan Wang
Chykon
Conor McCullough
Dan Petrisko
Daniel Bates
@@ -73,6 +76,7 @@ James Shi
Jamey Hicks
Jamie Iles
Jan Van Winkel
Jiangjie Weng
Jean Berniolles
Jeremy Bennett
Jesse Taube
@@ -86,6 +90,7 @@ John Coiner
John Demme
John Wehle
Jonathan Drolet
Jonathan Schröter
Jordan McConnon
Jose Loyola
Josep Sans
@@ -132,8 +137,10 @@ Nathan Kohagen
Nathan Myers
Oleh Maksymenko
Patrick Stewart
Paul Swirhun
Paul Wright
Pawel Sagan
Pengcheng Xu
Peter Debacker
Peter Horvath
Peter Monsson
@@ -159,6 +166,7 @@ Srinivasan Venkataramanan
Stefan Wallentowitz
Stephen Henry
Steven Hugg
Szymon Gizler
Sören Tempel
Teng Huang
Tim Hutt
+1 -1
View File
@@ -45,7 +45,7 @@ def setup(app):
# -- Project information
project = 'Verilator'
copyright = '2022 by Wilson Snyder, under LGPL-3.0 or Artistic-2.0'
copyright = '2024 by Wilson Snyder, under LGPL-3.0 or Artistic-2.0'
author = 'Wilson Snyder'
# The master toctree document.
+1 -1
View File
@@ -500,7 +500,7 @@ the user should call:
any delayed events pending,
* :code:`designp->nextTimeSlot()`, which returns the simulation time of the
next delayed event. This method can only be called if
:code:`designp->nextTimeSlot()` returned :code:`true`.
:code:`designp->eventsPending()` returned :code:`true`.
Call :code:`eventsPending()` to check if you should continue with the
simulation, and then :code:`nextTimeSlot()` to move simulation time forward.
+4 -5
View File
@@ -6,7 +6,7 @@ Deprecations
The following deprecated items are scheduled for future removal:
C++11 compiler support
C++14 compiler support
Verilator currently requires a C++20 or newer compiler for timing, and a
C++14 or newer compiler for both compiling Verilator and compiling
Verilated models with --no-timing.
@@ -14,7 +14,6 @@ C++11 compiler support
Verilator will require C++20 or newer compilers for both compiling
Verilator and compiling all Verilated models no sooner than January 2025.
32-bit compiler support
Verilator currently regresses both 64-bit and 32-bit pointer modes (GCC's
`-m64` and `-m32`). Support for 32-bit `-m32` mode will be deprecated no
sooner than January 2024.
XML output
Verilator currently supports XML parser output (enabled with `--xml-only`).
Support for `--xml-*` options will be deprecated no sooner than January 2025.
+5
View File
@@ -118,6 +118,11 @@ associated programs.
See :ref:`Installation` for more details.
.. option:: VERILATOR_VALGRIND
If set, the command to run when using the :vlopt:`--valgrind` option, such as
"valgrind --tool=callgrind". If not specified, it will use "valgrind".
Make Variables
==============
+1
View File
@@ -9,6 +9,7 @@ Examples
This section covers the following examples:
* :ref:`Example Create-Binary Execution`
* :ref:`Example C++ Execution`
* :ref:`Example SystemC Execution`
* :ref:`Examples in the Distribution`
+9
View File
@@ -19,11 +19,20 @@ Summary:
.. include:: ../_build/gen/args_verilated.rst
.. option:: +verilator+coverage+file+<filename>
When a model was Verilated using :vlopt:`--coverage`, sets the filename
to write coverage data into. Defaults to :file:`coverage.dat`.
.. option:: +verilator+debug
Enable simulation runtime debugging. Equivalent to
:vlopt:`+verilator+debugi+4 <+verilator+debugi+\<value\>>`.
To be useful, the model typically must first be compiled with debug
capabilities by Verilating with :vlopt:`--runtime-debug` or `-CFLAGS
-DVL_DEBUG=1`.
.. option:: +verilator+debugi+<value>
Enable simulation runtime debugging at the provided level.
+129 -10
View File
@@ -85,7 +85,11 @@ Summary:
.. option:: --assert
Enable all assertions.
Enable all assertions. Implies :vlopt:`--assert-case`.
.. option:: --assert-case
Enable unique/unique0/priority case related checks.
.. option:: --autoflush
@@ -304,12 +308,40 @@ Summary:
detailed messages. See :vlopt:`--debug` for other implications of
enabling debug.
.. option:: --decorations none
.. option:: --decorations medium
.. option:: --decorations node
When creating output Verilated code, set level of comment and whitespace
decoration.
With "--decorations none",
Minimize comments, white space, symbol names, and other decorative
items, at the cost of reduced readability. This may assist C++ compile
times. This will not typically change the ultimate model's
performance, but may in some cases. See also :vlopt:`--no-decoration`
option.
With "--decorations medium",
The default, put a small amount of comments and white space, for
typical level of readability.
With "--decorations node",
Include comments indicating what caused generation of the following
text, including what node pointer (corresponding to
:vlopt:`--dump-tree` .tree printed data), and the source Verilog
filename and line number. If subsequent following statements etc have
the same filename/line number these comments are omitted. This
enables easy debug when looking at the C++ code to determine what
Verilog source may be related. As node pointers are not stable
between different Verilator runs, this may harm compile caching and
should only be used for debug.
.. option:: --no-decoration
When creating output Verilated code, minimize comments, white space,
symbol names, and other decorative items, at the cost of reduced
readability. This may assist C++ compile times. This will not typically
change the ultimate model's performance, but may in some cases.
Alias for ``--decorations none``.
.. option:: --default-language <value>
@@ -1183,6 +1215,40 @@ Summary:
Run Verilator and record with the :command:`rr` command. See
`https://rr-project.org <https://rr-project.org>`_.
.. option:: --runtime-debug
Enable including debug assertions in the generated model. This may
significantly decrease model performance. This option will only work
with gcc/clang.
This option has the same effect as the following flags:
:vlopt:`--decorations node <--decorations>`
Instructs Verilator to add comments to the Verilated C++ code to
assist determining what Verilog code was responsible for each C++
statement.
``-CFLAGS -ggdb -LDFLAGS -ggdb``
Instructs the compiler and linker to enable debugger symbols.
``-CFLAGS -fsanitize=address,undefined -LDFLAGS -fsanitize=address,undefined``
Instructs the compiler and linker to enable the address sanitizer, and
undefined behavior sanitizer.
``-CFLAGS -D_GLIBCXX_DEBUG``
Instructs the compiler to enable C++ library (glibc) internal
assertions to find library-misuse issues.
``-CFLAGS -DVL_DEBUG=1``
Instructs the compiler to enable Verilator's runtime assertions and
debug capabilities. To enable debug print messages at runtime, see
:vlopt:`+verilator+debug`.
The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options used here pass the
following argument into the generated Makefile for use as compiler or
linker options respectively. If you are using your own Makefiles, adapt
appropriately to pass the suggested flags to the compiler and linker.
.. option:: --savable
Enable including save and restore functions in the generated model. See
@@ -1205,6 +1271,8 @@ Summary:
Creates a dump file with statistics on the design in
:file:`<prefix>__stats.txt`.
Also dumps DFG patterns to
:file:`<prefix>__stats_dfg_patterns__*.txt`.
.. option:: --stats-vars
@@ -1216,6 +1284,10 @@ Summary:
Prevents parsing standard library.
.. option:: --no-stop-fail
Don't call $stop when assertion fails. Simulation will continue.
.. option:: --structs-packed
Converts all unpacked structures to packed structures, and issues an
@@ -1424,13 +1496,17 @@ Summary:
.. option:: --unroll-count <loops>
Rarely needed. Specifies the maximum number of loop iterations that may be
unrolled. See also :option:`BLKLOOPINIT` warning.
Rarely needed. Specifies the maximum number of loop iterations that may
be unrolled. See also :option:`BLKLOOPINIT` warning, and
:option:`/*verilator&32;unroll_disable*/` and
:option:`/*verilator&32;unroll_full*/` metacomments.
.. option:: --unroll-stmts <statements>
Rarely needed. Specifies the maximum number of statements in a loop for
that loop to be unrolled. See also :option:`BLKLOOPINIT` warning.
that loop to be unrolled. See also :option:`BLKLOOPINIT` warning, and
:option:`/*verilator&32;unroll_disable*/` and
:option:`/*verilator&32;unroll_full*/` metacomments.
.. option:: --unused-regexp <regexp>
@@ -1450,6 +1526,11 @@ Summary:
used to resolve instances in the top-level module, otherwise, they are
ignored. Note "-v" is relatively standard across Verilog tools.
.. option:: --valgrind
Run Verilator under `Valgrind <https://valgrind.org/>`_. The command may be
changed with :option:`VERILATOR_VALGRIND`.
.. option:: --no-verilate
When using :vlopt:`--build`, disable the generation of C++/SystemC code, and
@@ -1695,19 +1776,57 @@ Summary:
iterations. This may be another indication of problems with the
modeled design that should be addressed.
.. option:: --json-only
Create JSON output only, do not create any other output.
The JSON format is intended to be used to leverage Verilator's parser and
elaboration to feed to other downstream tools. For details on the format, see
the Verilator Internals manual. Be aware that the JSON
format is still evolving; there will be some changes in future versions.
This option disables some more aggressive transformations and dumps only
the final state of the AST.
.. option:: --json-only-meta-output <filename>
Specifies the filename for the metadata output file (`.tree.meta.json`) of --json-only.
Using this option automatically sets :vlopt:`--json-only`.
.. option:: --json-only-output <filename>
Specifies the filename for the main output file (`.tree.json`) of --json-only.
Using this option automatically sets :vlopt:`--json-only`.
.. option:: --no-json-edit-nums
Don't dump edit number in .tree.json files. This may make the file more
run-to-run stable for easier comparison.
.. option:: --no-json-ids
Don't use short identifiers instead of addresses/paths in .tree.json.
.. option:: --xml-only
Create XML output only, do not create any other output.
The XML format is intended to be used to leverage Verilator's parser and
elaboration to feed to other downstream tools. Be aware that the XML
format is still evolving; there will be some changes in future versions.
elaboration to feed to other downstream tools.
.. note::
This feature is deprecated in favor of :vlopt:`--json-only`.
.. option:: --xml-output <filename>
Specifies the filename for the XML output file. Using this option
automatically sets :vlopt:`--xml-only`.
.. note::
This feature is deprecated in favor of :vlopt:`--json-only`.
.. option:: -y <dir>
Add the directory to the list of directories that should be searched to find
+17
View File
@@ -594,6 +594,23 @@ or "`ifdef`"'s may break other tools.
Re-enable waveform tracing for all future signals or instances that are
declared.
.. option:: /*verilator&32;unroll_disable*/
Used in a statement position to indicate the immediately following loop
at the same statement level should not be unrolled by Verilator,
ignoring :vlopt:`--unroll-count`. This is similar to clang's ``#pragma
clang loop unroll(disable)``.
This option does not currently disable the C++ compiler's unrolling (or
not) of any loops that make it through to the Verilated C++ code.
.. option:: /*verilator&32;unroll_full*/
Rarely needed. Used in a statement position to indicate the immediately
following loop at the same statement level should always be fully
unrolled by Verilator, ignoring :vlopt:`--unroll-count`. This is
similar to clang's ``#pragma clang loop unroll(full)``.
.. option:: $stacktrace
Called as a task, print a stack trace. Called as a function, return a
+8 -6
View File
@@ -226,12 +226,14 @@ How do I generate FST waveforms (traces) in C++ or SystemC?
FST is a trace file format developed by GTKWave. Verilator provides basic
FST support. To dump traces in FST format, add the :vlopt:`--trace-fst`
option to Verilator and either A. use :code:`$dumpfile & $dumpvars` in
Verilog as described in the VCD example above,
option to Verilator and either:
Use :code:`$dumpfile & $dumpvars` in Verilog as described in the VCD
example above,
Or, in C++ change the include described in the VCD example above:
.. code-block:: C++
.. code-block:: C++
#include "verilated_fst_c.h"
VerilatedFstC* tfp = new VerilatedFstC;
@@ -239,14 +241,14 @@ Or, in C++ change the include described in the VCD example above:
Or, in SystemC, change the include described in the VCD example above:
.. code-block:: C++
.. code-block:: C++
#include "verilated_fst_sc.h"
VerilatedFstC* tfp = new VerilatedFstSc;
Currently, supporting FST and VCD in a single simulation is impossible, but
such requirement should be rare. You can however ifdef around the trace
Currently, supporting FST and VCD in a single simulation is not supported,
but such usage should be unlikely. You can however ifdef around the trace
format in your C++ main loop, and select VCD or FST at compile time.
+4
View File
@@ -112,6 +112,10 @@ In specific debug and other modes, it also creates:
* - *{prefix}*\ .xml
- XML tree information (from --xml)
* - *{prefix}*\ .tree.json
- JSON tree information (from --json-only)
* - *{prefix}*\ .tree.meta.json
- JSON tree metadata (from --json-only)
* - *{prefix}*\ __cdc.txt
- Clock Domain Crossing checks (from --cdc)
* - *{prefix}*\ __stats.txt
+2 -2
View File
@@ -23,12 +23,12 @@ resulting model's C++ or SystemC code is output as .cpp and .h files. This
is referred to as "Verilating", and the process is "to Verilate"; the
output is a "Verilated" model.
2. For simulation, a small-user written C++ wrapper file is required, the
2. For simulation, a small user-written C++ wrapper file is required, the
"wrapper". This wrapper defines the C++ standard function "main()", which
instantiates the Verilated model as a C++/SystemC object.
3. The user C++ wrapper, the files created by Verilator, a "runtime
library" provided by Verilator, and, if applicable SystemC libraries are
library" provided by Verilator, and, if applicable, SystemC libraries are
then compiled using a C++ compiler to create a simulation executable.
4. The resulting executable will perform the actual simulation during
+47 -20
View File
@@ -230,14 +230,20 @@ Coverage Collection
When any coverage flag is used to Verilate, Verilator will add appropriate
coverage point insertions into the model and collect the coverage data.
To get the coverage data from the model, in the user wrapper code,
typically at the end once a test passes, call
:code:`Verilated::threadContextp()->coveragep()->write` with an argument of the filename for
the coverage data file to write coverage data to (typically
"logs/coverage.dat").
To get the coverage data from the model, write the coverage with either:
1. Using :vlopt:`--binary` or :vlopt:`--main`, and Verilator will dump
coverage when the test completes to the filename specified with
:vlopt:`+verilator+coverage+file+\<filename\>`.
2. In the user wrapper code, typically at the end once a test passes, call
:code:`Verilated::threadContextp()->coveragep()->write` with an argument
of the filename for the coverage data file to write coverage data to
(typically "logs/coverage.dat").
Run each of your tests in different directories, potentially in parallel.
Each test will create a :file:`logs/coverage.dat` file.
Each test will create the file specified above,
e.g. :file:`logs/coverage.dat`.
After running all of the tests, execute the :command:`verilator_coverage`
command, passing arguments pointing to the filenames of all the
@@ -273,13 +279,17 @@ profiled C++ code functions.
To use profiling:
#. Use Verilator's :vlopt:`--prof-cfuncs`.
#. Make sure the Verilog code will call `$finish` at the end of simulation
(otherwise the C library may not correctly create the `gmon.out` file in
the later steps below).
#. Run Verilator, adding the :vlopt:`--prof-cfuncs` option.
#. Build and run the simulation model.
#. The model will create gmon.out.
#. Run :command:`gprof` to see where in the C++ code the time is spent.
#. Run the gprof output through the :command:`verilator_profcfunc` program,
and it will tell you what Verilog line numbers on which most of the time
is being spent.
#. The model will create `gmon.out`.
#. Run :command:`gprof gmon.out > gprof.log` to see where in the C++ code
the time is spent.
#. Run :command:`verilator_profcfunc gprof.log > profcfunc.log` to take the
gprof output and translate into output showing the Verilog line numbers
on which most of the time is being spent.
.. _Execution Profiling:
@@ -505,13 +515,30 @@ documentation.
Runtime Debugging
=================
To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a
similar tool. Typically you will want to have debugger symbols inserted by
the compiler, assertions enabled in the C library, and assertions enabled
in the Verilated library. (These options slow down the executable, so do
this only when debugging.) To enable this, Verilate with:
To debug a Verilated executable, Verilate with :vlopt:`--runtime-debug`.
This will instruct the compiler to insert debugger, and enable various
library assertions. These options slow down the executable, so do this
only when debugging.
-CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG
If you are using your own Makefiles, adapt appropriately to pass the
options documented under :vlopt:`--runtime-debug` to the compiler and
linker.
The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options pass arguments
directly to the compiler or linker.
Once you have a debugging-enabled executable, run it using the the standard
GNU debugger ``gdb`` or a similar tool, and create a backtrace; e.g.:
.. code-block:: bash
gdb obj_dir/Vtop
run {Vtop_command_arguments}
{Vtop prints output, perhaps a segmentation faults}
bt
Rarely the bug may disappear with :vlopt:`--runtime-debug`; if so, try
instead using the sub-options that :vlopt:`--runtime-debug` documents, to
find the maximum subset that still shows the issue. E.g. it is likely that
using `-CFLAGS -D_GLIBCXX_DEBUG` will not hide any bug, so may be used.
Using :vlopt:`--runtime-debug` or `-CFLAGS -DVL_DEBUG=1` will only print a
message if something goes wrong. To enable debug print messages at
runtime, additionally use the :vlopt:`+verilator+debug` runtime option.
+43
View File
@@ -2131,3 +2131,46 @@ List Of Warnings
Inactive region. Such processes do get resumed in the same time slot
somewhere in the Active region. Issued only if Verilator is run with the
:vlopt:`--timing` option.
.. option:: ZEROREPL
Warns that zero is used as the replication value in the replication
operator. This is specified as an error by IEEE 1800-2017 11.4.12.1.
Faulty example:
.. code-block:: sv
:linenos:
:emphasize-lines: 5
module dut
#(parameter int MY_PARAM = 0);
reg [7:0] data;
always @* begin
data = {MY_PARAM{1'b1}}; //<--- WARNING
end
endmodule
Results in the following error:
.. code-block::
%Error-ZEROREPL: test.v:5:22: Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1)
Note that in some cases, this warning may be false, when a condition
upstream or downstream of the access means the zero replication will
never execute or be used.
Repaired example:
.. code-block:: sv
:linenos:
:emphasize-lines: 2
module dut
#(parameter int MY_PARAM = 1); //<--- REPAIRED
reg [7:0] data;
always @* begin
data = {MY_PARAM{1'b1}};
end
endmodule
+84
View File
@@ -1696,6 +1696,84 @@ Similarly, the ``NETLIST`` has a list of modules referred to by its
``op1p()`` pointer.
.tree.json Output
-----------------
``.tree.json``` is an alternative dump format to ``.tree`` that is meant for
programmatic processing (e.g. with `astsee <https://github.com/antmicro/astsee>`_).
To enable this dump format, use :vlopt:`--json-only`.
Structure:
::
{
/* Attributes that are common to all types of nodes */
"type": "VAR",
"name": "cyc",
/* By default addresses and filenames use short/stable ids rather than real value */
"addr": "(H)",
"loc": "a,25:12,26:15", /* "fileid,firstLine:firstCol,lastLine:endCol" (endCol is right exclusive) */
"editNum": 602,
/* Fields that are specific to AstVar nodes: */
"origName": "cyc",
"isSc": false,
"ioDirection": "NONE",
"isConst": false,
"isPullup": false,
"isPulldown": false,
"isUsedClock": false,
"isSigPublic": false,
"isLatched": false,
"isUsedLoopIdx": false,
"noReset": false,
"attrIsolateAssign": false,
"attrFileDescr": false,
"isDpiOpenArray": false,
"isFuncReturn": false,
"isFuncLocal": false,
"attrClocker": "UNKNOWN",
"lifetime": "NONE",
"varType": "VAR",
/* Lists of child nodes (which use similar structure as their parent): */
"childDTypep": [ /* ... */ ],
"delayp": [ /* ... */ ],
"valuep": [ /* ... */ ],
"attrsp": [ /* ... */ ]
}
.tree.meta.json Output
----------------
.tree.meta.json contains metadata that is common across the whole AST tree.
Besides de-duplication of data shared between multiple stages, .meta.json enables offloading
unstable data (that can vary from machine-to-machine or run-to-run) from main .tree.json.
This offloading allows, for example, to use byte-to-byte comparisons of AST dumps in tests.
::
{"files": {
/* Map id to filename, and other metadata */
"d": {"filename":"/home/ant/tmp/verilator/include/verilated_std.sv", "realpath":"/home/ant/tmp/verilator/include/verilated_std.sv", "language":"1800-2017"},
"a": {"filename":"<built-in>", "realpath":"<built-in>", "language":"1800-2017"},
"b": {"filename":"<command-line>", "realpath":"<command-line>", "language":"1800-2017"},
"c": {"filename":"input.vc", "realpath":"/home/ant/tmp/verilator/test_regress/input.vc", "language":"1800-2017"},
"e": {"filename":"t/t_EXAMPLE.v", "realpath":"/home/ant/tmp/verilator/test_regress/t/t_EXAMPLE.v", "language":"1800-2017"}
},"pointers": {
/* Map id to real address */
"(AG)": "0x562997289180",
"(YF)": "0x5629971c50b0",
"(WF)": "0x5629971e7ae0",
/* ... /*
},"ptrFieldNames": [
/* List of fields that are used for storing pointers */
"aboveScopep",
"voidp",
"addr",
/* ... */
]}
.tree.dot Output
----------------
@@ -1937,6 +2015,9 @@ driver.pl Non-Scenario Arguments
--trace
Set the simulator specific flags to request waveform tracing.
--valgrind
Same as ``verilator --valgrind``: Run Verilator under `Valgrind <https://valgrind.org/>`_.
--verbose
Compile and run the test in verbose mode. This means ``TEST_VERBOSE``
will be defined for the test (Verilog and any C++/SystemC wrapper).
@@ -1980,6 +2061,9 @@ simultaneously.
--vltmt
Run Verilator tests in multithreaded mode.
--xrun
Run Cadence Xcelium simulator tests.
--xsim
Run Xilinx XSim simulator tests.
+11
View File
@@ -180,6 +180,7 @@ Jannis
Jasen
Jens
Jeras
Jiaxun
Jiuyang
Joannou
Joly
@@ -519,6 +520,7 @@ buildenv
bv
bvs
callValueCbs
callgrind
casex
casez
casted
@@ -583,6 +585,7 @@ der
dereference
desassign
destructor
desynchronization
detections
dev
devcontainer
@@ -613,6 +616,7 @@ dut
dx
dynarray
elab
eliasphanna
elike
elsif
endcase
@@ -688,6 +692,7 @@ genvars
getenv
getline
ggdb
glibc
gmake
gmon
gotFinish
@@ -732,6 +737,7 @@ ish
isunbounded
isunknown
jobserver
json
jwoutersymatra
killua
lang
@@ -902,6 +908,7 @@ recrem
redeclaring
regs
reloop
replaceShiftOp
resetall
respecified
rodata
@@ -940,6 +947,7 @@ stdin
stdout
stime
stmts
str
strcasecmp
stringification
stringified
@@ -1014,8 +1022,10 @@ unsup
untyped
urandom
uselib
utimes
uwire
uwires
valgrind
vc
vcd
vcddiff
@@ -1047,6 +1057,7 @@ vpiSize
vpiSuppressVal
vpiTimeUnit
vpiType
vpiUndefined
vpm
vpp
warmup
@@ -1,15 +1,15 @@
#!/usr/bin/env python3
# -*- Python -*- See copyright, etc below
# pylint: disable=C0114,C0115,C0209,R0903
# pylint: disable=C0103,C0114,C0115,C0209,R0903
######################################################################
import argparse
import json
import os
import re
import subprocess
import tempfile
import xml.etree.ElementTree as ET
from shutil import copy2
from tempfile import NamedTemporaryFile
# from pprint import pprint, pformat
#######################################################################
@@ -25,29 +25,30 @@ class VlFileCopy:
self.debug = debug
with tempfile.NamedTemporaryFile() as xml_temp:
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
) as meta_temp:
vargs = [
'--xml-output',
xml_temp.name,
'--json-only-output',
tree_temp.name,
'--json-only-meta-output',
meta_temp.name,
'--bbox-sys', # Parse some stuff can't translate
'--bbox-unsup',
'--prefix vlxml'
] # So we know name of .xml output
'--prefix vljson'
]
vargs += verilator_args
self.run_verilator(vargs)
self.tree = ET.parse(xml_temp.name)
self.tree = json.load(tree_temp)
self.meta = json.load(meta_temp)
os.makedirs(output_dir, 0o777, True)
# Find and copy the files
root = self.tree.getroot()
xfiles = root.find('files')
for xfile in xfiles.findall('file'):
filename = xfile.get('filename')
if not re.match('^<', filename): # e.g. <built-in>
for file_id in self.meta['files']:
path = self.meta['files'][file_id]['realpath']
if not re.match('^<', path): # e.g. <built-in>
if self.debug:
print("\tcp %s %s" % (filename, output_dir))
copy2(filename, output_dir)
print("\tcp %s %s" % (path, output_dir))
copy2(path, output_dir)
def run_verilator(self, vargs):
"""Run Verilator command, check errors"""
@@ -71,7 +72,7 @@ if __name__ == '__main__':
allow_abbrev=False,
formatter_class=argparse.RawTextHelpFormatter,
description=
"""Example of using Verilator XML output to copy a list of files to an
"""Example of using Verilator JSON output to copy a list of files to an
output directory (-odir, defaults to 'copied'), e.g. to easily create a
tarball of the design to pass to others.
@@ -4,10 +4,10 @@
######################################################################
import argparse
import json
import os
import subprocess
import tempfile
import xml.etree.ElementTree as ET
from tempfile import NamedTemporaryFile
# from pprint import pprint, pformat
#######################################################################
@@ -22,19 +22,23 @@ class VlHierGraph:
output_filename='graph.dot'): # output filename
self.debug = debug
self.next_vertex_number = 0
self.name_to_number = {}
self.addr_to_number = {}
with tempfile.NamedTemporaryFile() as xml_temp:
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
) as meta_temp:
vargs = [
'--xml-output',
xml_temp.name,
'--json-only-output',
tree_temp.name,
'--json-only-meta-output',
meta_temp.name,
'--bbox-sys', # Parse some stuff can't translate
'--bbox-unsup',
'--prefix vlxml'
] # So we know name of .xml output
'--prefix vljson'
]
vargs += verilator_args
self.run_verilator(vargs)
self.tree = ET.parse(xml_temp.name)
self.tree = json.load(tree_temp)
self.meta = json.load(meta_temp)
with open(output_filename, "w", encoding="utf8") as fh:
# For more serious purposes, use the python graphviz package instead
@@ -46,31 +50,45 @@ class VlHierGraph:
)
fh.write(" edge [fontsize=6]")
# Find cells
root = self.tree.getroot()
netlist = root.find('netlist')
for module in netlist.findall('module'):
modules = self.flatten(self.tree, lambda n: n['type'] == "MODULE")
top_module = True
for mod in modules:
# origNames are before parameterization, name if after
mod_name = module.get('name')
mod_number = self.name_to_vertex_number(mod_name)
fh.write(" n%d [label=\"%s\"" % (mod_number, mod_name))
if module.get('topModule'):
mod_number = self.addr_to_vertex_number(mod['addr'])
fh.write(" n%d [label=\"%s\"" % (mod_number, mod['name']))
if top_module:
fh.write(" color=\"red\" rank=1")
top_module = False
fh.write("];\n")
for instance in module.findall('instance'):
inst_name = instance.get('name')
def_name = instance.get('defName')
def_number = self.name_to_vertex_number(def_name)
cells = self.flatten(mod, lambda n: n['type'] == "CELL")
for cell in cells:
def_number = self.addr_to_vertex_number(cell['modp'])
fh.write(" n%d->n%d [label=\"%s\"];\n" %
(mod_number, def_number, inst_name))
(mod_number, def_number, cell['name']))
fh.write("}\n")
def name_to_vertex_number(self, name):
if name not in self.name_to_number:
def flatten(self, node, accept_cb=lambda n: True):
"""Flatten tree to list using DFS.
accept_cb(node) should return True for nodes you want to save"""
arr = []
self.dfs(node, lambda n: accept_cb(n) and arr.append(n))
return arr
def dfs(self, node, node_cb):
"""Traverse given tree using DFS and apply node_cb(node) on each one"""
node_cb(node)
for _, v in node.items():
if isinstance(v, list): # childlist
for child in v:
self.dfs(child, node_cb)
def addr_to_vertex_number(self, name):
if name not in self.addr_to_number:
self.next_vertex_number += 1
self.name_to_number[name] = self.next_vertex_number
return self.name_to_number[name]
self.addr_to_number[name] = self.next_vertex_number
return self.addr_to_number[name]
def run_verilator(self, vargs):
"""Run Verilator command, check errors"""
@@ -94,7 +112,7 @@ if __name__ == '__main__':
allow_abbrev=False,
formatter_class=argparse.RawTextHelpFormatter,
description=
"""Example of using Verilator XML output to create a .dot file showing the
"""Example of using Verilator JSON output to create a .dot file showing the
design module hierarchy.
Example usage:
+2 -2
View File
@@ -19,14 +19,14 @@ int main(int argc, char** argv) {
// e.g. examples/c_tracing.
// Construct a VerilatedContext to hold simulation time, etc.
VerilatedContext* contextp = new VerilatedContext;
VerilatedContext* const contextp = new VerilatedContext;
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
contextp->commandArgs(argc, argv);
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop{contextp};
Vtop* const top = new Vtop{contextp};
// Simulate until $finish
while (!contextp->gotFinish()) {
+1 -1
View File
@@ -25,7 +25,7 @@ int sc_main(int argc, char* argv[]) {
// e.g. examples/c_tracing.
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop{"top"};
Vtop* const top = new Vtop{"top"};
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
+2 -8
View File
@@ -20,13 +20,13 @@ int main(int argc, char** argv) {
if (false && argc && argv) {}
// Construct context to hold simulation time, etc
VerilatedContext* contextp = new VerilatedContext;
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
contextp->debug(0);
contextp->randReset(2);
contextp->commandArgs(argc, argv);
// Construct the Verilated model, including the secret module
Vtop* top = new Vtop{contextp};
const std::unique_ptr<Vtop> top{new Vtop{contextp.get(), "TOP"}};
#if VM_TRACE
// When tracing, the contents of the secret module will not be seen
@@ -65,12 +65,6 @@ int main(int argc, char** argv) {
}
#endif
// Destroy model
delete top;
top = nullptr;
delete contextp;
contextp = nullptr;
// Return good completion status
// Don't use exit() or destructor won't get called
return 0;
-3
View File
@@ -20,9 +20,6 @@ double sc_time_stamp() { return 0; }
int main(int argc, char** argv) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (false && argc && argv) {}
// Create logs/ directory in case we have traces to put under it
Verilated::mkdir("logs");
-3
View File
@@ -29,9 +29,6 @@ using namespace sc_dt;
int sc_main(int argc, char* argv[]) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (false && argc && argv) {}
// Create logs/ directory in case we have traces to put under it
Verilated::mkdir("logs");
+181 -35
View File
@@ -34,7 +34,6 @@
* FST_DEBUG : not for production use, only enable for development
* FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact)
* HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code
* FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores
* _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable)
*
*/
@@ -132,10 +131,6 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
#define FST_GZIO_LEN (32768)
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) || defined(__aarch64__)
#define FST_DO_MISALIGNED_OPS
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define FST_MACOSX
#include <sys/sysctl.h>
@@ -192,6 +187,16 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
/* 01234567 */
/*
* report abort messages
*/
static void chk_report_abort(const char *s)
{
fprintf(stderr,"Triggered %s security check, exiting.\n", s);
abort();
}
/*
* prevent old file overwrite when currently being read
*/
@@ -367,22 +372,15 @@ return ptr;
/*
* regular and variable-length integer access functions
*/
#ifdef FST_DO_MISALIGNED_OPS
#define fstGetUint32(x) (*(uint32_t *)(x))
#else
static uint32_t fstGetUint32(unsigned char *mem)
{
uint32_t u32;
unsigned char *buf = (unsigned char *)(&u32);
buf[0] = mem[0];
buf[1] = mem[1];
buf[2] = mem[2];
buf[3] = mem[3];
memcpy(buf, mem, sizeof(uint32_t));
return(*(uint32_t *)buf);
}
#endif
static int fstWriterUint64(FILE *handle, uint64_t v)
@@ -550,7 +548,8 @@ return(rc);
static uint32_t fstReaderVarint32(FILE *f)
{
unsigned char buf[5];
int chk_len = 5; /* TALOS-2023-1783 */
unsigned char buf[chk_len];
unsigned char *mem = buf;
uint32_t rc = 0;
int ch;
@@ -559,7 +558,9 @@ do
{
ch = fgetc(f);
*(mem++) = ch;
} while(ch & 0x80);
} while((ch & 0x80) && (--chk_len));
if(ch & 0x80) chk_report_abort("TALOS-2023-1783");
mem--;
for(;;)
@@ -579,7 +580,8 @@ return(rc);
static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
{
unsigned char buf[5];
int chk_len = 5; /* TALOS-2023-1783 */
unsigned char buf[chk_len];
unsigned char *mem = buf;
uint32_t rc = 0;
int ch;
@@ -588,7 +590,9 @@ do
{
ch = fgetc(f);
*(mem++) = ch;
} while(ch & 0x80);
} while((ch & 0x80) && (--chk_len));
if(ch & 0x80) chk_report_abort("TALOS-2023-1783");
*skiplen = mem - buf;
mem--;
@@ -609,7 +613,8 @@ return(rc);
static uint64_t fstReaderVarint64(FILE *f)
{
unsigned char buf[16];
int chk_len = 16; /* TALOS-2023-1783 */
unsigned char buf[chk_len];
unsigned char *mem = buf;
uint64_t rc = 0;
int ch;
@@ -618,9 +623,12 @@ do
{
ch = fgetc(f);
*(mem++) = ch;
} while(ch & 0x80);
} while((ch & 0x80) && (--chk_len));
if(ch & 0x80) chk_report_abort("TALOS-2023-1783");
mem--;
for(;;)
{
rc <<= 7;
@@ -851,11 +859,7 @@ unsigned char *pnt = buf;
uint32_t nxt;
uint32_t len;
#ifdef FST_DO_MISALIGNED_OPS
(*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
#else
memcpy(pnt, u, sizeof(uint32_t));
#endif
pnt += 4;
while((nxt = v>>7))
@@ -878,11 +882,7 @@ unsigned char *pnt = buf;
uint32_t nxt;
uint32_t len;
#ifdef FST_DO_MISALIGNED_OPS
(*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
#else
memcpy(pnt, u, sizeof(uint32_t));
#endif
pnt += 4;
while((nxt = v>>7))
@@ -1542,7 +1542,7 @@ for(i=0;i<xc->maxhandle;i++)
dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2);
}
rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem);
rc = (xc->fourpack) ? LZ4_compress_default((char *)scratchpnt, (char *)dmem, wrlen, packmemlen) : fastlz_compress(scratchpnt, wrlen, dmem);
if(rc < destlen)
{
#ifndef FST_DYNAMIC_ALIAS_DISABLE
@@ -1838,6 +1838,14 @@ if(xc->parallel_enabled)
xc->xc_parent = xc;
memcpy(xc2, xc, sizeof(struct fstWriterContext));
if(sizeof(size_t) < sizeof(uint64_t))
{
/* TALOS-2023-1777 for 32b overflow */
uint64_t chk_64 = xc->maxhandle * 4 * sizeof(uint32_t);
size_t chk_32 = xc->maxhandle * 4 * sizeof(uint32_t);
if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1777");
}
xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t));
memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
@@ -2101,7 +2109,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
{
fstWriterMmapSanity(hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0), __FILE__, __LINE__, "hmem");
}
packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len);
packed_len = LZ4_compress_default((char *)hmem, (char *)mem, xc->hier_file_len, lz4_maxlen);
fstMunmap(hmem, xc->hier_file_len);
fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */
@@ -2114,7 +2122,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
lz4_maxlen_duo = LZ4_compressBound(packed_len);
mem_duo = (unsigned char *)malloc(lz4_maxlen_duo);
packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len);
packed_len_duo = LZ4_compress_default((char *)mem, (char *)mem_duo, packed_len, lz4_maxlen_duo);
fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */
fstFwrite(mem_duo, packed_len_duo, 1, xc->handle);
@@ -3434,7 +3442,7 @@ return(rc);
#ifndef FST_WRITEX_DISABLE
static void fstWritex(struct fstReaderContext *xc, void *v, int len)
static void fstWritex(struct fstReaderContext *xc, void *v, uint32_t len) /* TALOS-2023-1793: change len to unsigned */
{
unsigned char *s = (unsigned char *)v;
@@ -5060,6 +5068,7 @@ if(fv)
for(;;)
{
uint32_t *tc_head = NULL;
uint32_t tc_head_items = 0;
traversal_mem_offs = 0;
fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
@@ -5103,12 +5112,12 @@ for(;;)
}
mem_required_for_traversal = fstReaderUint64(xc->f);
mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */
mem_required_for_traversal = fstReaderUint64(xc->f) + 66; /* add in potential fastlz overhead */
mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal);
#ifdef FST_DEBUG
fprintf(stderr, FST_APIMESS "sec: %u seclen: %d begtim: %d endtim: %d\n",
secnum, (int)seclen, (int)beg_tim, (int)end_tim);
fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal-66);
#endif
/* process time block */
{
@@ -5158,6 +5167,22 @@ for(;;)
}
free(time_table);
if(sizeof(size_t) < sizeof(uint64_t))
{
/* TALOS-2023-1792 for 32b overflow */
uint64_t chk_64 = tsec_nitems * sizeof(uint64_t);
size_t chk_32 = ((size_t)tsec_nitems) * sizeof(uint64_t);
if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1792");
}
else
{
uint64_t chk_64 = tsec_nitems * sizeof(uint64_t);
if((chk_64/sizeof(uint64_t)) != tsec_nitems)
{
chk_report_abort("TALOS-2023-1792");
}
}
time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
tpnt = ucdata;
tpval = 0;
@@ -5169,7 +5194,23 @@ for(;;)
tpnt += skiplen;
}
tc_head = (uint32_t *)calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t));
tc_head_items = tsec_nitems /* scan-build */ ? tsec_nitems : 1;
if(sizeof(size_t) < sizeof(uint64_t))
{
/* TALOS-2023-1792 for 32b overflow */
uint64_t chk_64 = tc_head_items * sizeof(uint32_t);
size_t chk_32 = ((size_t)tc_head_items) * sizeof(uint32_t);
if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1792");
}
else
{
uint64_t chk_64 = tc_head_items * sizeof(uint32_t);
if((chk_64/sizeof(uint32_t)) != tc_head_items)
{
chk_report_abort("TALOS-2023-1792");
}
}
tc_head = (uint32_t *)calloc(tc_head_items, sizeof(uint32_t));
free(ucdata);
}
@@ -5273,6 +5314,10 @@ for(;;)
{
if(value_change_callback)
{
if(xc->signal_lens[idx] > xc->longest_signal_value_len)
{
chk_report_abort("TALOS-2023-1797");
}
memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]);
xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0;
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
@@ -5286,6 +5331,10 @@ for(;;)
vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
fstWritex(xc, vcd_id, 1);
if((sig_offs + xc->signal_lens[idx]) > frame_uclen)
{
chk_report_abort("TALOS-2023-1793");
}
fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]);
vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */
@@ -5410,7 +5459,44 @@ for(;;)
free(chain_table_lengths);
vc_maxhandle_largest = vc_maxhandle;
if(!(vc_maxhandle+1))
{
chk_report_abort("TALOS-2023-1798");
}
if(sizeof(size_t) < sizeof(uint64_t))
{
/* TALOS-2023-1798 for 32b overflow */
uint64_t chk_64 = (vc_maxhandle+1) * sizeof(fst_off_t);
size_t chk_32 = ((size_t)(vc_maxhandle+1)) * sizeof(fst_off_t);
if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1798");
}
else
{
uint64_t chk_64 = (vc_maxhandle+1) * sizeof(fst_off_t);
if((chk_64/sizeof(fst_off_t)) != (vc_maxhandle+1))
{
chk_report_abort("TALOS-2023-1798");
}
}
chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t));
if(sizeof(size_t) < sizeof(uint64_t))
{
/* TALOS-2023-1798 for 32b overflow */
uint64_t chk_64 = (vc_maxhandle+1) * sizeof(uint32_t);
size_t chk_32 = ((size_t)(vc_maxhandle+1)) * sizeof(uint32_t);
if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1798");
}
else
{
uint64_t chk_64 = (vc_maxhandle+1) * sizeof(uint32_t);
if((chk_64/sizeof(uint32_t)) != (vc_maxhandle+1))
{
chk_report_abort("TALOS-2023-1798");
}
}
chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t));
}
@@ -5454,6 +5540,11 @@ for(;;)
uint64_t val = fstGetVarint32(pnt, &skiplen);
fstHandle loopcnt = val >> 1;
if((idx+loopcnt-1) > vc_maxhandle) /* TALOS-2023-1789 */
{
chk_report_abort("TALOS-2023-1789");
}
for(i=0;i<loopcnt;i++)
{
chain_table[idx++] = 0;
@@ -5487,6 +5578,12 @@ for(;;)
else
{
fstHandle loopcnt = val >> 1;
if((idx+loopcnt-1) > vc_maxhandle) /* TALOS-2023-1789 */
{
chk_report_abort("TALOS-2023-1789");
}
for(i=0;i<loopcnt;i++)
{
chain_table[idx++] = 0;
@@ -5547,6 +5644,11 @@ for(;;)
unsigned long destlen = val;
unsigned long sourcelen = chain_table_lengths[i];
if(traversal_mem_offs >= mem_required_for_traversal)
{
chk_report_abort("TALOS-2023-1785");
}
if(mc_mem_len < chain_table_lengths[i])
{
free(mc_mem);
@@ -5575,6 +5677,12 @@ for(;;)
{
int destlen = chain_table_lengths[i] - skiplen;
unsigned char *mu = mem_for_traversal + traversal_mem_offs;
if(traversal_mem_offs >= mem_required_for_traversal)
{
chk_report_abort("TALOS-2023-1785");
}
fstFread(mu, destlen, 1, xc->f);
/* data to process is for(j=0;j<destlen;j++) in mu[j] */
headptr[i] = traversal_mem_offs;
@@ -5600,6 +5708,11 @@ for(;;)
tdelta = vli >> 1;
}
if(tdelta >= tc_head_items)
{
chk_report_abort("TALOS-2023-1791");
}
scatterptr[i] = tc_head[tdelta];
tc_head[tdelta] = i+1;
}
@@ -5698,6 +5811,11 @@ for(;;)
shamt = 2 << (vli & 1);
tdelta = vli >> shamt;
if((tdelta+i) >= tc_head_items)
{
chk_report_abort("TALOS-2023-1791");
}
scatterptr[idx] = tc_head[i+tdelta];
tc_head[i+tdelta] = idx+1;
}
@@ -5731,6 +5849,14 @@ for(;;)
vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
{
if(sizeof(size_t) < sizeof(uint64_t))
{
/* TALOS-2023-1790 for 32b overflow */
uint64_t chk_64 = len*4 + 1;
size_t chk_32 = len*4 + 1;
if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1790");
}
unsigned char *vesc = (unsigned char *)malloc(len*4 + 1);
int vlen = fstUtilityBinToEsc(vesc, vdata, len);
fstWritex(xc, vesc, vlen);
@@ -5756,6 +5882,11 @@ for(;;)
vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
tdelta = vli >> 1;
if((tdelta+i) >= tc_head_items)
{
chk_report_abort("TALOS-2023-1791");
}
scatterptr[idx] = tc_head[i+tdelta];
tc_head[i+tdelta] = idx+1;
}
@@ -5772,6 +5903,11 @@ for(;;)
if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
{
if(len > xc->longest_signal_value_len)
{
chk_report_abort("TALOS-2023-1797");
}
if(!(vli & 1))
{
int byte = 0;
@@ -5817,8 +5953,13 @@ for(;;)
if(fv)
{
unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
uint64_t mem_required_for_traversal_chk = vdata - mem_for_traversal + len;
fstWritex(xc, &ch_bp, 1);
if(mem_required_for_traversal_chk > mem_required_for_traversal)
{
chk_report_abort("TALOS-2023-1793");
}
fstWritex(xc, vdata, len);
}
}
@@ -5941,6 +6082,11 @@ for(;;)
vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
tdelta = vli >> 1;
if((tdelta+i) >= tc_head_items)
{
chk_report_abort("TALOS-2023-1791");
}
scatterptr[idx] = tc_head[i+tdelta];
tc_head[i+tdelta] = idx+1;
}
+2240 -972
View File
File diff suppressed because it is too large Load Diff
+771 -265
View File
File diff suppressed because it is too large Load Diff
+129 -87
View File
@@ -71,6 +71,11 @@
# include <execinfo.h>
# define _VL_HAVE_STACKTRACE
#endif
#if defined(__linux) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/time.h>
# include <sys/resource.h>
# define _VL_HAVE_GETRLIMIT
#endif
#include "verilated_threads.h"
// clang-format on
@@ -107,7 +112,8 @@ thread_local Verilated::ThreadLocal Verilated::t_s;
#ifndef VL_USER_FINISH ///< Define this to override the vl_finish function
void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
if (false && hier) {} // Unused argument
// hier is unused in the default implementation.
(void)hier;
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
"- %s:%d: Verilog $finish\n", filename, linenum);
Verilated::threadContextp()->gotFinish(true);
@@ -135,7 +141,8 @@ void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
#ifndef VL_USER_FATAL ///< Define this to override the vl_fatal function
void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE {
if (false && hier) {}
// hier is unused in the default implementation.
(void)hier;
Verilated::threadContextp()->gotError(true);
Verilated::threadContextp()->gotFinish(true);
if (filename && filename[0]) {
@@ -173,7 +180,8 @@ void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool may
#ifndef VL_USER_WARN ///< Define this to override the vl_warn function
void vl_warn(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE {
if (false && hier) {}
// hier is unused in the default implementation.
(void)hier;
if (filename && filename[0]) {
// Not VL_PRINTF_MT, already on main thread
VL_PRINTF("%%Warning: %s:%d: %s\n", filename, linenum, msg);
@@ -783,7 +791,7 @@ std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t w
}
}
const int needmore = width - digits;
const int needmore = static_cast<int>(width) - digits;
std::string padding;
if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces
return left ? (tmp + padding) : (padding + tmp);
@@ -792,7 +800,7 @@ std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t w
// Do a va_arg returning a quad, assuming input argument is anything less than wide
#define VL_VA_ARG_Q_(ap, bits) (((bits) <= VL_IDATASIZE) ? va_arg(ap, IData) : va_arg(ap, QData))
void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SAFE {
void _vl_vsformat(std::string& output, const std::string& format, va_list ap) VL_MT_SAFE {
// Format a Verilog $write style format into the output list
// The format must be pre-processed (and lower cased) by Verilator
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
@@ -801,24 +809,24 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
// Note also assumes variables < 64 are not wide, this assumption is
// sometimes not true in low-level routines written here in verilated.cpp
static thread_local char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
const char* pctp = nullptr; // Most recent %##.##g format
std::string::const_iterator pctit = format.end(); // Most recent %##.##g format
bool inPct = false;
bool widthSet = false;
bool left = false;
size_t width = 0;
for (const char* pos = formatp; *pos; ++pos) {
for (std::string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
if (!inPct && pos[0] == '%') {
pctp = pos;
pctit = pos;
inPct = true;
widthSet = false;
width = 0;
} else if (!inPct) { // Normal text
// Fast-forward to next escape and add to output
const char* ep = pos;
while (ep[0] && ep[0] != '%') ++ep;
std::string::const_iterator ep = pos;
while (ep != format.end() && ep[0] != '%') ++ep;
if (ep != pos) {
output.append(pos, ep - pos);
pos += ep - pos - 1;
output.append(pos, ep);
pos = ep - 1;
}
} else { // Format character
inPct = false;
@@ -881,8 +889,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const int timeunit = va_arg(ap, int);
output += _vl_vsformat_time(t_tmp, d, timeunit, left, width);
} else {
const size_t len = pos - pctp + 1;
const std::string fmts{pctp, len};
const std::string fmts{pctit, pos + 1};
VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d);
output += t_tmp;
}
@@ -936,20 +943,20 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
if (VL_SIGN_E(lbits, lwp[VL_WORDS_I(lbits) - 1])) {
VlWide<VL_VALUE_STRING_MAX_WIDTH / 4 + 2> neg;
VL_NEGATE_W(VL_WORDS_I(lbits), neg, lwp);
append = std::string{"-"} + VL_DECIMAL_NW(lbits, neg);
append = "-"s + VL_DECIMAL_NW(lbits, neg);
} else {
append = VL_DECIMAL_NW(lbits, lwp);
}
digits = append.length();
digits = static_cast<int>(append.length());
}
const int needmore = width - digits;
const int needmore = static_cast<int>(width) - digits;
if (needmore > 0) {
std::string padding;
if (left) {
padding.append(needmore, ' '); // Pre-pad spaces
output += append + padding;
} else {
if (pctp && pctp[0] && pctp[1] == '0') { // %0
if (pctit != format.end() && pctit[0] && pctit[1] == '0') { // %0
padding.append(needmore, '0'); // Pre-pad zero
} else {
padding.append(needmore, ' '); // Pre-pad spaces
@@ -969,16 +976,16 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
append = t_tmp;
} else {
append = VL_DECIMAL_NW(lbits, lwp);
digits = append.length();
digits = static_cast<int>(append.length());
}
const int needmore = width - digits;
const int needmore = static_cast<int>(width) - digits;
if (needmore > 0) {
std::string padding;
if (left) {
padding.append(needmore, ' '); // Pre-pad spaces
output += append + padding;
} else {
if (pctp && pctp[0] && pctp[1] == '0') { // %0
if (pctit != format.end() && pctit[0] && pctit[1] == '0') { // %0
padding.append(needmore, '0'); // Pre-pad zero
} else {
padding.append(needmore, ' '); // Pre-pad spaces
@@ -1037,7 +1044,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
} // switch
const int needmore = width - digits;
const int needmore = static_cast<int>(width) - digits;
if (needmore > 0) {
std::string padding;
if (left) {
@@ -1078,7 +1085,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
break;
default: { // LCOV_EXCL_START
const std::string msg = std::string{"Unknown _vl_vsformat code: "} + pos[0];
const std::string msg = "Unknown _vl_vsformat code: "s + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // LCOV_EXCL_STOP
@@ -1196,7 +1203,7 @@ static void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* s
IData _vl_vsscanf(FILE* fp, // If a fscanf
int fbits, const WDataInP fromp, // Else if a sscanf
const std::string& fstr, // if a sscanf to string
const char* formatp, va_list ap) VL_MT_SAFE {
const std::string& format, va_list ap) VL_MT_SAFE {
// Read a Verilog $sscanf/$fscanf style format into the output list
// The format must be pre-processed (and lower cased) by Verilator
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
@@ -1205,8 +1212,8 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
IData got = 0;
bool inPct = false;
bool inIgnore = false;
const char* pos = formatp;
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
std::string::const_iterator pos = format.begin();
for (; pos != format.end() && !_vl_vsss_eof(fp, floc); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
// fromp, fstr)<<"'\n");
if (!inPct && pos[0] == '%') {
@@ -1360,7 +1367,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
break;
}
default: { // LCOV_EXCL_START
const std::string msg = std::string{"Unknown _vl_vsscanf code: "} + pos[0];
const std::string msg = "Unknown _vl_vsscanf code: "s + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // LCOV_EXCL_STOP
@@ -1500,149 +1507,152 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
Verilated::threadContextp()->impp()->fdClose(fdi);
}
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE {
void VL_SFORMAT_NX(int obits, CData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE {
void VL_SFORMAT_NX(int obits, SData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE {
void VL_SFORMAT_NX(int obits, IData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE {
void VL_SFORMAT_NX(int obits, QData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE {
void VL_SFORMAT_NX(int obits, void* destp, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
_vl_string_to_vint(obits, destp, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE {
if (obits_ignored) {}
void VL_SFORMAT_NX(int obits_ignored, std::string& output, const std::string& format, int argc,
...) VL_MT_SAFE {
(void)obits_ignored; // So VL_SFORMAT_NNX function signatures all match
std::string temp_output;
va_list ap;
va_start(ap, formatp);
_vl_vsformat(temp_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(temp_output, format, ap);
va_end(ap);
output = temp_output;
}
std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE {
std::string VL_SFORMATF_N_NX(const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
return t_output;
}
void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE {
void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
VL_PRINTF_MT("%s", t_output.c_str());
}
void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(t_output, formatp, ap);
va_start(ap, argc);
_vl_vsformat(t_output, format, ap);
va_end(ap);
Verilated::threadContextp()->impp()->fdWrite(fpi, t_output);
}
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
IData VL_FSCANF_INX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* const fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return ~0U; // -1
va_list ap;
va_start(ap, formatp);
const IData got = _vl_vsscanf(fp, 0, nullptr, "", formatp, ap);
va_start(ap, argc);
const IData got = _vl_vsscanf(fp, 0, nullptr, "", format, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE {
IData VL_SSCANF_IINX(int lbits, IData ld, const std::string& format, int argc, ...) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> fnw;
VL_SET_WI(fnw, ld);
va_list ap;
va_start(ap, formatp);
const IData got = _vl_vsscanf(nullptr, lbits, fnw, "", formatp, ap);
va_start(ap, argc);
const IData got = _vl_vsscanf(nullptr, lbits, fnw, "", format, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE {
IData VL_SSCANF_IQNX(int lbits, QData ld, const std::string& format, int argc, ...) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> fnw;
VL_SET_WQ(fnw, ld);
va_list ap;
va_start(ap, formatp);
const IData got = _vl_vsscanf(nullptr, lbits, fnw, "", formatp, ap);
va_start(ap, argc);
const IData got = _vl_vsscanf(nullptr, lbits, fnw, "", format, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IWX(int lbits, const WDataInP lwp, const char* formatp, ...) VL_MT_SAFE {
IData VL_SSCANF_IWNX(int lbits, const WDataInP lwp, const std::string& format, int argc,
...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
const IData got = _vl_vsscanf(nullptr, lbits, lwp, "", formatp, ap);
va_start(ap, argc);
const IData got = _vl_vsscanf(nullptr, lbits, lwp, "", format, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_SAFE {
IData VL_SSCANF_INNX(int, const std::string& ld, const std::string& format, int argc,
...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
const IData got = _vl_vsscanf(nullptr, ld.length() * 8, nullptr, ld, formatp, ap);
va_start(ap, argc);
const IData got = _vl_vsscanf(nullptr, ld.length() * 8, nullptr, ld, format, ap);
va_end(ap);
return got;
}
@@ -1717,7 +1727,7 @@ std::string VL_STACKTRACE_N() VL_MT_SAFE {
if (!strings) return "Unable to backtrace\n";
std::string result = "Backtrace:\n";
for (int j = 0; j < nptrs; j++) result += std::string{strings[j]} + std::string{"\n"};
for (int j = 0; j < nptrs; j++) result += std::string{strings[j]} + "\n"s;
free(strings);
return result;
}
@@ -1860,13 +1870,13 @@ const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE {
//===========================================================================
// Heavy string functions
std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_NX("'h%0x", 8, lhs); }
std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_NX("'h%0x", 16, lhs); }
std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_NX("'h%0x", 32, lhs); }
std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_NX("'h%0x", 64, lhs); }
std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_NX("%d", 64, lhs); }
std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 8, lhs); }
std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 16, lhs); }
std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 32, lhs); }
std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 64, lhs); }
std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_N_NX("%d", 0, 64, lhs); }
std::string VL_TO_STRING_W(int words, const WDataInP obj) {
return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj);
return VL_SFORMATF_N_NX("'h%0x", 0, words * VL_EDATASIZE, obj);
}
std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE {
@@ -2422,6 +2432,7 @@ VerilatedContext::VerilatedContext()
: m_impdatap{new VerilatedContextImpData} {
Verilated::lastContextp(this);
Verilated::threadContextp(this);
m_ns.m_coverageFilename = "coverage.dat";
m_ns.m_profExecFilename = "profile_exec.dat";
m_ns.m_profVltFilename = "profile.vlt";
m_fdps.resize(31);
@@ -2457,6 +2468,14 @@ void VerilatedContext::calcUnusedSigs(bool flag) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_s.m_calcUnusedSigs = flag;
}
void VerilatedContext::coverageFilename(const std::string& flag) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_ns.m_coverageFilename = flag;
}
std::string VerilatedContext::coverageFilename() const VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
return m_ns.m_coverageFilename;
}
void VerilatedContext::dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) {
const VerilatedLockGuard lock{m_timeDumpMutex};
m_dumpfile = flag;
@@ -2685,7 +2704,7 @@ std::pair<int, char**> VerilatedContextImp::argc_argv() VL_MT_SAFE_EXCLUDES(m_ar
int in = 0;
for (const auto& i : m_args.m_argVec) {
s_argvp[in] = new char[i.length() + 1];
std::strcpy(s_argvp[in], i.c_str());
std::memcpy(s_argvp[in], i.c_str(), i.length() + 1);
++in;
}
s_argvp[s_argc] = nullptr;
@@ -2697,7 +2716,9 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
if (0 == std::strncmp(arg.c_str(), "+verilator+", std::strlen("+verilator+"))) {
std::string str;
uint64_t u64;
if (arg == "+verilator+debug") {
if (commandArgVlString(arg, "+verilator+coverage+file+", str)) {
coverageFilename(str);
} else if (arg == "+verilator+debug") {
Verilated::debug(4);
} else if (commandArgVlUint64(arg, "+verilator+debugi+", u64, 0,
std::numeric_limits<int>::max())) {
@@ -2969,7 +2990,7 @@ void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE {
void Verilated::overWidthError(const char* signame) VL_MT_SAFE {
// Slowpath - Called only when signal sets too high of a bit
const std::string msg = (std::string{"Testbench C set input '"} + signame
const std::string msg = ("Testbench C set input '"s + signame
+ "' to value that overflows what the signal's width can fit");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
VL_UNREACHABLE;
@@ -2995,6 +3016,29 @@ void Verilated::scTraceBeforeElaborationError() VL_MT_SAFE {
VL_UNREACHABLE;
}
void Verilated::stackCheck(QData needSize) VL_MT_UNSAFE {
// Slowpath - Called only when constructing
#ifdef _VL_HAVE_GETRLIMIT
QData haveSize = 0;
rlimit rlim;
if (0 == getrlimit(RLIMIT_STACK, &rlim)) {
haveSize = rlim.rlim_cur;
if (haveSize == RLIM_INFINITY) haveSize = rlim.rlim_max;
if (haveSize == RLIM_INFINITY) haveSize = 0;
}
// VL_PRINTF_MT("-Info: stackCheck(%" PRIu64 ") have %" PRIu64 "\n", needSize, haveSize);
// Check for 1.5x need, but suggest 2x so small model increase won't cause warning
// if the user follows the suggestions
if (VL_UNLIKELY(haveSize && needSize && haveSize < (needSize + needSize / 2))) {
VL_PRINTF_MT("%%Warning: System has stack size %" PRIu64 " kb"
" which may be too small; suggest 'ulimit -c %" PRIu64 "' or larger\n",
haveSize / 1024, (needSize * 2) / 1024);
}
#else
if (false && needSize) {} // Unused argument
#endif
}
void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE {
#if defined(_WIN32) || defined(__MINGW32__)
::mkdir(dirname);
@@ -3168,8 +3212,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, boo
} else {
// We could have a linked list of ranges, but really this whole thing needs
// to be generalized to support structs and unions, etc.
const std::string msg
= std::string{"Unsupported multi-dimensional public varInsert: "} + namep;
const std::string msg = "Unsupported multi-dimensional public varInsert: "s + namep;
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
}
@@ -3189,10 +3232,9 @@ VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTIN
void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
// Slowpath - Called only when find has failed
const std::string msg
= (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum)
+ "' but scope wasn't set, perhaps due to dpi import call without "
+ "'context', or missing svSetScope. See IEEE 1800-2017 35.5.3.");
const std::string msg = ("Testbench C called '"s + VerilatedImp::exportName(funcnum)
+ "' but scope wasn't set, perhaps due to dpi import call without "
+ "'context', or missing svSetScope. See IEEE 1800-2017 35.5.3.");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return nullptr;
}
@@ -3200,7 +3242,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
void* VerilatedScope::exportFindError(int funcnum) const VL_MT_SAFE {
// Slowpath - Called only when find has failed
const std::string msg
= (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum)
= ("Testbench C called '"s + VerilatedImp::exportName(funcnum)
+ "' but this DPI export function exists only in other scopes, not scope '" + name()
+ "'");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
+12 -3
View File
@@ -73,6 +73,8 @@
#endif
// clang-format on
using namespace std::literals; // "<std::string literal>"s; see SF.7 core guideline
//=============================================================================
// Switches
@@ -349,7 +351,7 @@ protected:
// Slow path variables
mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members
struct Serialized { // All these members serialized/deserialized
struct Serialized final { // All these members serialized/deserialized
// No std::strings or pointers or will serialize badly!
// Fast path
bool m_assertOn = true; // Assertions are enabled
@@ -379,12 +381,13 @@ protected:
std::string m_timeFormatSuffix VL_GUARDED_BY(m_timeDumpMutex); // $timeformat printf format
std::string m_dumpfile VL_GUARDED_BY(m_timeDumpMutex); // $dumpfile setting
struct NonSerialized { // Non-serialized information
struct NonSerialized final { // Non-serialized information
// These are reloaded from on command-line settings, so do not need to persist
// Fast path
uint64_t m_profExecStart = 1; // +prof+exec+start time
uint32_t m_profExecWindow = 2; // +prof+exec+window size
// Slow path
std::string m_coverageFilename; // +coverage+file filename
std::string m_profExecFilename; // +prof+exec+file filename
std::string m_profVltFilename; // +prof+vlt filename
} m_ns;
@@ -392,7 +395,7 @@ protected:
mutable VerilatedMutex m_argMutex; // Protect m_argVec, m_argVecLoaded
// no need to be save-restored (serialized) the
// assumption is that the restore is allowed to pass different arguments
struct NonSerializedCommandArgs {
struct NonSerializedCommandArgs final {
// Medium speed
std::vector<std::string> m_argVec; // Argument list
bool m_argVecLoaded = false; // Ever loaded argument list
@@ -576,6 +579,10 @@ public:
VerilatedVirtualBase*
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
// Internal: coverage
void coverageFilename(const std::string& flag) VL_MT_SAFE;
std::string coverageFilename() const VL_MT_SAFE;
// Internal: $dumpfile
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
@@ -898,6 +905,7 @@ public:
static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE;
static void scTimePrecisionError(int sc_prec, int vl_prec) VL_ATTR_NORETURN VL_MT_SAFE;
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
static void stackCheck(QData needSize) VL_MT_UNSAFE;
// Internal: Get and set DPI context
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
@@ -971,6 +979,7 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) {
sc_prec = 15;
}
// SC_AS, SC_ZS, SC_YS not supported as no Verilog equivalent; will error below
#endif
}
#if VM_SC
-3
View File
@@ -101,9 +101,6 @@ LDFLAGS += $(CFG_LDFLAGS_VERILATED)
#OPT = -ggdb -DPRINTINITSTR
CPPFLAGS += $(OPT)
CPPFLAGS += $(M32)
LDFLAGS += $(M32)
# On macOS, specify all weak symbols as dynamic_lookup.
# Otherwise, you get undefined symbol errors.
ifeq ($(UNAME_S),Darwin)
+17 -11
View File
@@ -106,6 +106,7 @@ private:
using ItemList = std::deque<VerilatedCovImpItem*>;
// MEMBERS
VerilatedContext* const m_contextp; // Context VerilatedCovImp is pointed-to by
mutable VerilatedMutex m_mutex; // Protects all members
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); // Unique arbitrary value for values
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); // Unique arbitrary value for keys
@@ -120,7 +121,8 @@ private:
public:
// CONSTRUCTORS
VerilatedCovImp() = default;
VerilatedCovImp(VerilatedContext* contextp)
: m_contextp{contextp} {}
VL_UNCOPYABLE(VerilatedCovImp);
protected:
@@ -166,11 +168,11 @@ private:
const std::string& value) VL_PURE {
std::string name;
if (key.length() == 1 && std::isalpha(key[0])) {
name += std::string{"\001"} + key;
name += "\001"s + key;
} else {
name += std::string{"\001"} + dequote(key);
name += "\001"s + dequote(key);
}
name += std::string{"\002"} + dequote(value);
name += "\002"s + dequote(value);
return name;
}
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
@@ -253,6 +255,7 @@ private:
public:
// PUBLIC METHODS
std::string defaultFilename() VL_MT_SAFE { return m_contextp->coverageFilename(); }
void forcePerInstance(const bool flag) VL_MT_SAFE_EXCLUDES(m_mutex) {
Verilated::quiesce();
const VerilatedLockGuard lock{m_mutex};
@@ -302,7 +305,7 @@ public:
// First two key/vals are filename
ckeyps[0] = "filename";
valps[0] = m_insertFilenamep;
const std::string linestr = vlCovCvtToStr(m_insertLineno);
const std::string linestr = std::to_string(m_insertLineno);
ckeyps[1] = "lineno";
valps[1] = linestr.c_str();
// Default page if not specified
@@ -354,14 +357,14 @@ public:
m_insertp = nullptr;
}
void write(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
void write(const std::string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
Verilated::quiesce();
const VerilatedLockGuard lock{m_mutex};
selftest();
std::ofstream os{filename};
if (os.fail()) {
const std::string msg = std::string{"%Error: Can't write '"} + filename + "'";
const std::string msg = "%Error: Can't write '"s + filename + "'";
VL_FATAL_MT("", 0, "", msg.c_str());
return;
}
@@ -426,6 +429,7 @@ public:
//=============================================================================
// VerilatedCovContext
std::string VerilatedCovContext::defaultFilename() VL_MT_SAFE { return impp()->defaultFilename(); }
void VerilatedCovContext::forcePerInstance(bool flag) VL_MT_SAFE {
impp()->forcePerInstance(flag);
}
@@ -434,7 +438,9 @@ void VerilatedCovContext::clearNonMatch(const char* matchp) VL_MT_SAFE {
impp()->clearNonMatch(matchp);
}
void VerilatedCovContext::zero() VL_MT_SAFE { impp()->zero(); }
void VerilatedCovContext::write(const char* filenamep) VL_MT_SAFE { impp()->write(filenamep); }
void VerilatedCovContext::write(const std::string& filename) VL_MT_SAFE {
impp()->write(filename);
}
void VerilatedCovContext::_inserti(uint32_t* itemp) VL_MT_SAFE {
impp()->inserti(new VerilatedCoverItemSpec<uint32_t>{itemp});
}
@@ -484,8 +490,8 @@ void VerilatedCovContext::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7
// Backward compatibility for Verilator
void VerilatedCovContext::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
const std::string& val4, A(5), A(6), A(7)) VL_MT_SAFE {
std::string val2str = vlCovCvtToStr(val2);
std::string val3str = vlCovCvtToStr(val3);
const std::string val2str = std::to_string(val2);
const std::string val3str = std::to_string(val3);
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
C(6), C(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
@@ -516,7 +522,7 @@ VerilatedCovContext* VerilatedContext::coveragep() VL_MT_SAFE {
const VerilatedLockGuard lock{s_mutex};
// cppcheck-suppress identicalInnerCondition
if (VL_LIKELY(!m_coveragep)) { // LCOV_EXCL_LINE // Not redundant, prevents race
m_coveragep.reset(new VerilatedCovImp);
m_coveragep.reset(new VerilatedCovImp{this});
}
}
return reinterpret_cast<VerilatedCovContext*>(m_coveragep.get());
+14 -22
View File
@@ -63,26 +63,18 @@ class VerilatedCovImp;
/// for (int i = 0; i < 10; ++i) m_cases[i] = 0;
/// // Insert
/// for (int i = 0; i < 10; ++i)
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// VL_COVER_INSERT(covp, name(), &m_cases[i], "comment", "Coverage Case",
/// "i", cvtToNumStr(i));
/// }
#define VL_COVER_INSERT(covcontextp, countp, ...) \
#define VL_COVER_INSERT(covcontextp, name, countp, ...) \
do { \
covcontextp->_inserti(countp); \
covcontextp->_insertf(__FILE__, __LINE__); \
covcontextp->_insertp("hier", name(), __VA_ARGS__); \
auto const ccontextp = covcontextp; \
ccontextp->_inserti(countp); \
ccontextp->_insertf(__FILE__, __LINE__); \
ccontextp->_insertp("hier", name, __VA_ARGS__); \
} while (false)
//=============================================================================
// Convert VL_COVER_INSERT value arguments to strings, is \internal
template <class T>
std::string vlCovCvtToStr(const T& t) VL_PURE {
std::ostringstream os;
os << t;
return os.str();
}
//=============================================================================
// VerilatedCov
/// Per-VerilatedContext coverage data class.
@@ -96,12 +88,13 @@ class VerilatedCovContext VL_NOT_FINAL : public VerilatedVirtualBase {
public:
// METHODS
/// Return default filename
static const char* defaultFilename() VL_PURE { return "coverage.dat"; }
/// Return default filename, may override with +verilator+coverage+file
std::string defaultFilename() VL_MT_SAFE;
/// Make all data per_instance, overriding point's per_instance
void forcePerInstance(bool flag) VL_MT_SAFE;
/// Write all coverage data to a file
void write(const char* filenamep = defaultFilename()) VL_MT_SAFE;
void write(const std::string& filename) VL_MT_SAFE;
void write() VL_MT_SAFE { write(defaultFilename()); }
/// Clear coverage points (and call delete on all items)
void clear() VL_MT_SAFE;
/// Clear items not matching the provided string
@@ -170,11 +163,10 @@ class VerilatedCov final {
public:
// METHODS
/// Return default filename for the current thread
static const char* defaultFilename() VL_PURE { return VerilatedCovContext::defaultFilename(); }
static std::string defaultFilename() VL_MT_SAFE { return threadCovp()->defaultFilename(); }
/// Write all coverage data to a file for the current thread
static void write(const char* filenamep = defaultFilename()) VL_MT_SAFE {
threadCovp()->write(filenamep);
}
static void write(const std::string filename) VL_MT_SAFE { threadCovp()->write(filename); }
static void write() VL_MT_SAFE { write(defaultFilename()); }
/// Clear coverage points (and call delete on all items) for the current thread
static void clear() VL_MT_SAFE { threadCovp()->clear(); }
/// Clear items not matching the provided string for the current thread
+2 -1
View File
@@ -29,6 +29,7 @@
// GTKWave configuration
#define HAVE_LIBPTHREAD
#define FST_WRITER_PARALLEL
#define LZ4_DISABLE_DEPRECATE_WARNINGS
// Include the GTKWave implementation directly
#define FST_CONFIG_INCLUDE "fst_config.h"
@@ -174,7 +175,7 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
if (dtypenum > 0) fstWriterEmitEnumTableRef(m_fst, m_local2fstdtype[dtypenum]);
fstVarDir varDir;
fstVarDir varDir = FST_VD_IMPLICIT;
switch (direction) {
case VerilatedTraceSigDirection::INOUT: varDir = FST_VD_INOUT; break;
case VerilatedTraceSigDirection::OUTPUT: varDir = FST_VD_OUTPUT; break;
+35 -19
View File
@@ -125,19 +125,27 @@ extern void VL_FCLOSE_I(IData fdi) VL_MT_SAFE;
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
IData start, IData count) VL_MT_SAFE;
extern void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE;
extern void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE;
extern void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
extern void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IWX(int lbits, WDataInP const lwp, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_FSCANF_INX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IINX(int lbits, IData ld, const std::string& format, int argc,
...) VL_MT_SAFE;
extern IData VL_SSCANF_IQNX(int lbits, QData ld, const std::string& format, int argc,
...) VL_MT_SAFE;
extern IData VL_SSCANF_IWNX(int lbits, WDataInP const lwp, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, CData& destr, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, SData& destr, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, IData& destr, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, QData& destr, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, void* destp, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_STACKTRACE() VL_MT_SAFE;
extern std::string VL_STACKTRACE_N() VL_MT_SAFE;
@@ -305,7 +313,8 @@ uint64_t VerilatedContext::time() const VL_MT_SAFE {
// Time scaled from 1-per-precision into a module's time units ("Unit"-ed, not "United")
// Optimized assuming scale is always constant.
// Can't use multiply in Q flavor, as might lose precision
#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast<QData>(scale))
#define VL_TIME_ROUND(t, p) (((t) + ((p) / 2)) / (p))
#define VL_TIME_UNITED_Q(scale) VL_TIME_ROUND(VL_TIME_Q(), static_cast<QData>(scale))
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast<double>(scale))
// Return time precision as multiplier of time units
@@ -511,6 +520,7 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \
*chunkp = msb_data & VL_MASK_E((obits)-lsb); \
} \
_butemp.set(0, *(rwp).data() & 1); /* force update the sign */ \
(svar).write(_butemp); \
}
@@ -1265,6 +1275,7 @@ static inline void _vl_insert_QQ(QData& lhsr, QData ld, int hbit, int lbit, int
}
static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
// Insert value ld into iowp at bit slice [hbit:lbit]. iowp is rbits wide.
const int hoffset = VL_BITBIT_E(hbit);
const int loffset = VL_BITBIT_E(lbit);
const int roffset = VL_BITBIT_E(rbits);
@@ -1275,7 +1286,7 @@ static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit,
if (hoffset == VL_SIZEBITS_E && loffset == 0) {
// Fast and common case, word based insertion
iowp[VL_BITWORD_E(lbit)] = ld & cleanmask;
iowp[lword] = ld & cleanmask;
} else {
const EData lde = static_cast<EData>(ld);
if (hword == lword) { // know < EData bits because above checks it
@@ -1288,8 +1299,12 @@ static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit,
const EData linsmask = (VL_MASK_E((VL_EDATASIZE - 1) - loffset + 1)) << loffset;
const int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword
iowp[lword] = (iowp[lword] & ~linsmask) | ((lde << loffset) & linsmask);
iowp[hword]
= (iowp[hword] & ~hinsmask) | ((lde >> nbitsonright) & (hinsmask & cleanmask));
// Prevent unsafe write where lword was final writable location and hword is
// out-of-bounds.
if (VL_LIKELY(!(hword == rword && roffset == 0))) {
iowp[hword]
= (iowp[hword] & ~hinsmask) | ((lde >> nbitsonright) & (hinsmask & cleanmask));
}
}
}
}
@@ -2284,10 +2299,11 @@ extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, const void* memp, QData start,
QData end) VL_MT_SAFE;
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp,
...) VL_MT_SAFE;
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_INNX(int lbits, const std::string& ld, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits_ignored, std::string& output, const std::string& format,
int argc, ...) VL_MT_SAFE;
extern std::string VL_SFORMATF_N_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix, int width,
VerilatedContext* contextp) VL_MT_SAFE;
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
+4 -4
View File
@@ -54,7 +54,7 @@ class VerilatedScope;
class VerilatedMsg final {
public:
// TYPES
struct Cmp {
struct Cmp final {
bool operator()(const VerilatedMsg& a, const VerilatedMsg& b) const {
return a.mtaskId() < b.mtaskId();
}
@@ -221,7 +221,7 @@ class VerilatedContextImp final : VerilatedContext {
// Internal note: Globals may multi-construct, see verilated.cpp top.
// Medium speed, so uses singleton accessing
struct Statics {
struct Statics final {
VerilatedMutex s_randMutex; // Mutex protecting s_randSeedEpoch
// Number incrementing on each reseed, 0=illegal
int s_randSeedEpoch = 1; // Reads ok, wish had a VL_WRITE_GUARDED_BY(s_randMutex)
@@ -294,7 +294,7 @@ public: // But only for verilated*.cpp
std::fill(m_fdps.begin() + start, m_fdps.end(), static_cast<FILE*>(nullptr));
m_fdFree.resize(excess);
for (std::size_t i = 0, id = start; i < m_fdFree.size(); ++i, ++id) {
m_fdFree[i] = id;
m_fdFree[i] = static_cast<IData>(id);
}
}
const IData idx = m_fdFree.back();
@@ -552,7 +552,7 @@ public:
const VerilatedLockGuard lock{s().m_exportMutex};
const auto& it = s().m_exportMap.find(namep);
if (VL_LIKELY(it != s().m_exportMap.end())) return it->second;
const std::string msg = (std::string{"%Error: Testbench C called "} + namep
const std::string msg = ("%Error: Testbench C called "s + namep
+ " but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return -1;
+1 -1
View File
@@ -106,7 +106,7 @@ VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context)
if (VlThreadPool* const threadPoolp = static_cast<VlThreadPool*>(context.threadPoolp())) {
for (int i = 0; i < threadPoolp->numThreads(); ++i) {
// Data to pass to worker thread initialization
struct Data {
struct Data final {
VlExecutionProfiler* const selfp;
const uint32_t threadId;
} data{selfp, static_cast<uint32_t>(i + 1)};
+1 -2
View File
@@ -114,8 +114,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, std::strlen(VLTSAVE_TRAILER_STR)))) {
const std::string fn = filename();
const std::string msg
= std::string{"Can't deserialize; file has wrong end-of-file signature: "}
+ filename();
= "Can't deserialize; file has wrong end-of-file signature: "s + filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
// Die before we close() as close would infinite loop
}
+44 -9
View File
@@ -24,8 +24,13 @@
#include "verilated.h"
#include "verilated_sc.h"
#if SYSTEMC_VERSION < 20140417 // SystemC's simulation phase callback introduced in 2.3.1
#define _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#if SYSTEMC_VERSION >= 20140417 && SYSTEMC_VERSION < 20231124
// SystemC's simulation phase callback introduced in 2.3.1, and removed since 3.0.0 (PubRev)
#define _VL_HAVE_SYSTEMC_PHASE_CALLBACK
#endif
#if SYSTEMC_VERSION >= 20231124
// SystemC's stage callback introduced in 3.0.0 (PubRev)
#define _VL_HAVE_SYSTEMC_STAGE_CALLBACK
#endif
//=============================================================================
@@ -49,6 +54,9 @@
/// instead.
class VerilatedScTraceBase VL_NOT_FINAL : private sc_core::sc_object,
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
private sc_core::sc_stage_callback_if,
#endif
private sc_core::sc_trace_file {
bool m_enableDeltaCycles = false;
bool m_traceFileAdded = false;
@@ -56,8 +64,8 @@ class VerilatedScTraceBase VL_NOT_FINAL : private sc_core::sc_object,
public:
void enableDeltaCycles(bool flag = true) {
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
using namespace sc_core;
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// Save old report handler before overriding it
const auto oldHandler = sc_report_handler::get_handler();
// Override the old handler to hide 'phase callbacks not enabled' message
@@ -70,6 +78,13 @@ public:
}
// Restore the old handler
sc_report_handler::set_handler(oldHandler);
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
if (flag) {
sc_register_stage_callback(*this, SC_POST_UPDATE);
} else {
sc_unregister_stage_callback(*this, SC_POST_UPDATE);
}
#endif
m_enableDeltaCycles = flag;
}
@@ -81,15 +96,22 @@ protected:
registerTraceCallback();
};
~VerilatedScTraceBase() override {
#if SYSTEMC_VERSION >= 20140417 // remove_trace_file added in 2.3.1
using namespace sc_core;
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// remove_trace_file added in 2.3.1 and removed in 3.0.0
// Phase callback is automatically unregistered in ~sc_object(). Only the trace file is
// needed to be removed here
if (m_traceFileAdded) simcontext()->remove_trace_file(this);
#else
(void)m_traceFileAdded;
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
sc_unregister_stage_callback(*this, SC_PRE_TIMESTEP | SC_POST_UPDATE);
#endif
};
void registerTraceCallback() {
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
using namespace sc_core;
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// Save old report handler before overriding it
const auto oldHandler = sc_report_handler::get_handler();
// Override the old handler to hide 'phase callbacks not enabled' message
@@ -98,13 +120,18 @@ protected:
phase_cb_mask cb_mask = sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP);
if (cb_mask == SC_UNITIALIZED) {
#endif
#if SYSTEMC_VERSION < 20231124 // add_trace_file removed in 3.0.0
// Phase callback not enabled, use trace file instead
simcontext()->add_trace_file(this);
m_traceFileAdded = true;
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#endif
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
}
// Restore the old handler
sc_report_handler::set_handler(oldHandler);
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
sc_register_stage_callback(*this, SC_PRE_TIMESTEP);
#endif
}
static std::string getScTimeUnit() {
@@ -129,9 +156,13 @@ protected:
}
// METHODS - for SC kernel
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// Override sc_object. Called if using phase callback
void simulation_phase_callback() final { cycle(); }
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
// Override sc_stage_callback_if. Called if using stage callback
void stage_callback(const sc_core::sc_stage&) final { cycle(); }
#endif
// Override sc_trace_file. Called if using trace file
void cycle(bool delta_cycle) final {
@@ -155,6 +186,7 @@ private:
// SystemC 2.1.v1
void write_comment(const std::string&) override {}
void trace(sc_core::sc_trace_file*) const override {}
void trace(const unsigned int&, const std::string&, const char**) override {}
#define DECL_TRACE_METHOD_A(tp) \
@@ -205,8 +237,11 @@ private:
#undef DECL_TRACE_METHOD_B
};
#ifdef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#undef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
#undef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
#undef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
#endif
#endif // Guard
+1 -1
View File
@@ -42,7 +42,7 @@
// Types
// Class to sort maps keyed by const char*'s
struct VerilatedCStrCmp {
struct VerilatedCStrCmp final {
bool operator()(const char* a, const char* b) const { return std::strcmp(a, b) < 0; }
};
+3 -3
View File
@@ -127,7 +127,7 @@ public:
class VlWorkerThread final {
private:
// TYPES
struct ExecRec {
struct ExecRec final {
VlExecFnp m_fnp = nullptr; // Function to execute
VlSelfP m_selfp = nullptr; // Symbol table to execute
bool m_evenCycle = false; // Even/odd for flag alternation
@@ -214,10 +214,10 @@ public:
~VlThreadPool() override;
// METHODS
int numThreads() const { return m_workers.size(); }
int numThreads() const { return static_cast<int>(m_workers.size()); }
VlWorkerThread* workerp(int index) {
assert(index >= 0);
assert(static_cast<size_t>(index) < m_workers.size());
assert(index < static_cast<int>(m_workers.size()));
return m_workers[index];
}
+7 -7
View File
@@ -189,7 +189,7 @@ public:
// Used by coroutines for co_awaiting a certain simulation time
auto delay(uint64_t delay, VlProcessRef process, const char* filename = VL_UNKNOWN,
int lineno = 0) {
struct Awaitable {
struct Awaitable final {
VlProcessRef process; // Data of the suspended process, null if not needed
VlDelayedCoroutineQueue& queue;
std::vector<VlCoroutineHandle>& queueZeroDelay;
@@ -260,7 +260,7 @@ public:
const char* filename = VL_UNKNOWN, int lineno = 0) {
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
eventDescription, filename, lineno););
struct Awaitable {
struct Awaitable final {
VlCoroutineVec& suspended; // Coros waiting on trigger
VlProcessRef process; // Data of the suspended process, null if not needed
VlFileLineDebug fileline;
@@ -308,7 +308,7 @@ class VlDynamicTriggerScheduler final {
// METHODS
auto awaitable(VlProcessRef process, VlCoroutineVec& queue, const char* filename, int lineno) {
struct Awaitable {
struct Awaitable final {
VlProcessRef process; // Data of the suspended process, null if not needed
VlCoroutineVec& suspended; // Coros waiting on trigger
VlFileLineDebug fileline;
@@ -362,7 +362,7 @@ public:
// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant
// wait statements.
struct VlForever {
struct VlForever final {
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) const { coro.destroy(); }
void await_resume() const {}
@@ -374,7 +374,7 @@ struct VlForever {
class VlForkSync final {
// VlJoin stores the handle of a suspended coroutine that did a fork..join or fork..join_any.
// If the counter reaches 0, the suspended coroutine shall be resumed.
struct VlJoin {
struct VlJoin final {
size_t m_counter = 0; // When reaches 0, resume suspended coroutine
VlCoroutineHandle m_susp; // Coroutine to resume
};
@@ -393,7 +393,7 @@ public:
assert(m_join);
VL_DEBUG_IF(
VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno););
struct Awaitable {
struct Awaitable final {
VlProcessRef process; // Data of the suspended process, null if not needed
const std::shared_ptr<VlJoin> join; // Join to await on
VlFileLineDebug fileline;
@@ -415,7 +415,7 @@ public:
class VlCoroutine final {
private:
// TYPES
struct VlPromise {
struct VlPromise final {
std::coroutine_handle<> m_continuation; // Coroutine to resume after this one finishes
VlCoroutine* m_corop = nullptr; // Pointer to the coroutine return object
+7 -7
View File
@@ -204,16 +204,16 @@ private:
friend Buffer;
friend OffloadBuffer;
struct CallbackRecord {
struct CallbackRecord final {
// Note: would make these fields const, but some old STL implementations
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
// assignment operator on inserting into collections, so they don't work
// with const fields...
const union { // The callback
initCb_t m_initCb;
dumpCb_t m_dumpCb;
dumpOffloadCb_t m_dumpOffloadCb;
cleanupCb_t m_cleanupCb;
union { // The callback
const initCb_t m_initCb;
const dumpCb_t m_dumpCb;
const dumpOffloadCb_t m_dumpOffloadCb;
const cleanupCb_t m_cleanupCb;
};
const uint32_t m_fidx; // The index of the tracing function
void* const m_userp; // The user pointer to pass to the callback (the symbol table)
@@ -238,7 +238,7 @@ private:
bool m_offload = false; // Use the offload thread
bool m_parallel = false; // Use parallel tracing
struct ParallelWorkerData {
struct ParallelWorkerData final {
const dumpCb_t m_cb; // The callback
void* const m_userp; // The use pointer to pass to the callback
Buffer* const m_bufp; // The buffer pointer to pass to the callback
+8 -8
View File
@@ -263,7 +263,7 @@ public:
inline std::string VL_TO_STRING(const VlEventBase& e);
inline std::string VL_TO_STRING(const VlEvent& e) {
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
return "triggered="s + (e.isTriggered() ? "true" : "false");
}
inline std::string VL_TO_STRING(const VlAssignableEvent& e) {
@@ -274,7 +274,7 @@ inline std::string VL_TO_STRING(const VlEventBase& e) {
if (const VlAssignableEvent& assignable = dynamic_cast<const VlAssignableEvent&>(e)) {
return VL_TO_STRING(assignable);
}
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
return "triggered="s + (e.isTriggered() ? "true" : "false");
}
//===================================================================
@@ -1592,7 +1592,7 @@ public:
// Represents the null pointer. Used for setting VlClassRef to null instead of
// via nullptr_t, to prevent the implicit conversion of 0 to nullptr.
struct VlNull {
struct VlNull final {
operator bool() const { return false; }
};
@@ -1648,7 +1648,7 @@ public:
}
// cppcheck-suppress noExplicitConstructor
VlClassRef(VlClassRef&& moved)
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
: m_objp{std::exchange(moved.m_objp, nullptr)} {}
// cppcheck-suppress noExplicitConstructor
template <typename T_OtherClass>
VlClassRef(const VlClassRef<T_OtherClass>& copied)
@@ -1658,7 +1658,7 @@ public:
// cppcheck-suppress noExplicitConstructor
template <typename T_OtherClass>
VlClassRef(VlClassRef<T_OtherClass>&& moved)
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
: m_objp{std::exchange(moved.m_objp, nullptr)} {}
~VlClassRef() { refCountDec(); }
// METHODS
@@ -1673,7 +1673,7 @@ public:
VlClassRef& operator=(VlClassRef&& moved) {
if (m_objp == moved.m_objp) return *this;
refCountDec();
m_objp = vlstd::exchange(moved.m_objp, nullptr);
m_objp = std::exchange(moved.m_objp, nullptr);
return *this;
}
template <typename T_OtherClass>
@@ -1688,7 +1688,7 @@ public:
VlClassRef& operator=(VlClassRef<T_OtherClass>&& moved) {
if (m_objp == moved.m_objp) return *this;
refCountDec();
m_objp = vlstd::exchange(moved.m_objp, nullptr);
m_objp = std::exchange(moved.m_objp, nullptr);
return *this;
}
// Assign with nullptr
@@ -1751,7 +1751,7 @@ template <typename T_Sampled>
class VlSampleQueue final {
// TYPES
// Type representing a single value sample at a point in time
struct VlSample {
struct VlSample final {
uint64_t m_timestamp; // Timestamp at which the value was sampled
T_Sampled m_value; // The sampled value
};
+4 -5
View File
@@ -118,11 +118,11 @@ void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
printStr(" $end\n");
// Scope and signal definitions
assert(m_indent == 0);
assert(m_indent >= 0);
++m_indent;
Super::traceInit();
--m_indent;
assert(m_indent == 0);
assert(m_indent >= 0);
printStr("$enddefinitions $end\n\n\n");
@@ -282,8 +282,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
const std::string msg
= std::string{"VerilatedVcd::bufferFlush: "} + std::strerror(errno);
const std::string msg = "VerilatedVcd::bufferFlush: "s + std::strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
closeErr();
break;
@@ -301,7 +300,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
void VerilatedVcd::printIndent(int level_change) {
if (level_change < 0) m_indent += level_change;
for (int i = 0; i < m_indent; i++) printStr(" ");
for (int i = 0; i < m_indent; ++i) printStr(" ");
if (level_change > 0) m_indent += level_change;
}
+1 -1
View File
@@ -50,7 +50,7 @@ private:
bool m_isOpen = false; // True indicates open file
std::string m_filename; // Filename we're writing to (if open)
uint64_t m_rolloverSize = 0; // File size to rollover at
unsigned m_indent = 0; // Indentation depth
int m_indent = 0; // Indentation depth
char* m_wrBufp; // Output buffer
char* m_wrFlushp; // Output buffer flush trigger location
+63 -23
View File
@@ -419,10 +419,19 @@ public:
}
if (m_onlyParams && !m_it->second.isParam()) continue;
if (VL_UNLIKELY(m_topscopep)) {
if (const VerilatedVar* topvarp = m_topscopep->varFind(m_it->second.name()))
return ((new VerilatedVpioVar{topvarp, m_topscopep})->castVpiHandle());
if (const VerilatedVar* topvarp = m_topscopep->varFind(m_it->second.name())) {
if (topvarp->isParam()) {
return ((new VerilatedVpioParam{topvarp, m_topscopep})->castVpiHandle());
} else {
return ((new VerilatedVpioVar{topvarp, m_topscopep})->castVpiHandle());
}
}
}
if (m_it->second.isParam()) {
return ((new VerilatedVpioParam{&(m_it->second), m_scopep})->castVpiHandle());
} else {
return ((new VerilatedVpioVar{&(m_it->second), m_scopep})->castVpiHandle());
}
return ((new VerilatedVpioVar{&(m_it->second), m_scopep})->castVpiHandle());
}
}
};
@@ -498,9 +507,9 @@ public:
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
const VerilatedScope::Type type = (*m_it)->type();
const VerilatedScope::Type itype = (*m_it)->type();
const VerilatedScope* const modp = *m_it++;
if (type == VerilatedScope::SCOPE_MODULE) {
if (itype == VerilatedScope::SCOPE_MODULE) {
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
}
@@ -514,9 +523,9 @@ class VerilatedVpioPackage final : public VerilatedVpioScope {
public:
explicit VerilatedVpioPackage(const VerilatedScope* modulep)
: VerilatedVpioScope{modulep} {
const char* fullname = m_scopep->name();
if (std::strncmp(fullname, "TOP.", 4) == 0) fullname += 4;
m_fullname = std::string{fullname} + "::";
const char* sfullname = m_scopep->name();
if (std::strncmp(sfullname, "TOP.", 4) == 0) sfullname += 4;
m_fullname = std::string{sfullname} + "::";
if (m_fullname == "\\$unit ::") m_fullname = "$unit::";
m_name = std::string(m_scopep->identifier());
if (m_name == "\\$unit ") m_name = "$unit";
@@ -549,12 +558,12 @@ public:
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
const VerilatedScope::Type type = (*m_it)->type();
const VerilatedScope::Type itype = (*m_it)->type();
const VerilatedScope* const modp = *m_it++;
if (type == VerilatedScope::SCOPE_MODULE) {
if (itype == VerilatedScope::SCOPE_MODULE) {
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
if (type == VerilatedScope::SCOPE_PACKAGE) {
if (itype == VerilatedScope::SCOPE_PACKAGE) {
return (new VerilatedVpioPackage{modp})->castVpiHandle();
}
}
@@ -595,7 +604,7 @@ public:
void invalidate() { m_id = 0; }
};
struct VerilatedVpiTimedCbsCmp {
struct VerilatedVpiTimedCbsCmp final {
// Ordering sets keyed by time, then callback unique id
bool operator()(const std::pair<QData, uint64_t>& a,
const std::pair<QData, uint64_t>& b) const {
@@ -855,6 +864,7 @@ public:
static const char* strFromVpiMethod(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiProp(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiConstType(PLI_INT32 vpiVal) VL_PURE;
};
//======================================================================
@@ -1372,11 +1382,27 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_PURE {
if (vpiVal == vpiUndefined) return "vpiUndefined";
return names[(vpiVal <= vpiIsProtected) ? vpiVal : 0];
}
const char* VerilatedVpiError::strFromVpiConstType(PLI_INT32 constType) VL_PURE {
// clang-format off
static const char* const names[] = {
"*undefined*",
"vpiDecConst",
"vpiRealConst",
"vpiBinaryConst",
"vpiOctConst",
"vpiHexConst",
"vpiStringConst",
"vpiIntConst",
"vpiTimeConst",
};
// clang-format on
if (VL_UNCOVERABLE(constType < 0)) return names[0];
return names[(constType <= vpiTimeConst) ? constType : 0];
}
#define SELF_CHECK_RESULT_CSTR(got, exp) \
if (0 != std::strcmp((got), (exp))) { \
const std::string msg \
= std::string{"%Error: "} + "GOT = '" + (got) + "'" + " EXP = '" + (exp) + "'"; \
const std::string msg = "%Error: GOT = '"s + (got) + "'" + " EXP = '" + (exp) + "'"; \
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
}
@@ -1643,6 +1669,15 @@ void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE {
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiOffset);
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiStop);
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiDecConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiRealConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiBinaryConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiOctConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiHexConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiStringConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiIntConst);
SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiTimeConst);
}
#undef SELF_CHECK_ENUM_STR
@@ -1991,41 +2026,41 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
}
case vpiType: {
const VerilatedVpio* const vop = VerilatedVpio::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return vpiUndefined;
return vop->type();
}
case vpiConstType: {
const VerilatedVpio* const vop = VerilatedVpio::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return vpiUndefined;
return vop->constType();
}
case vpiDirection: {
// By forethought, the directions already are vpi enumerated
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return vpiUndefined;
return vop->varp()->vldir();
}
case vpiScalar: // FALLTHRU
case vpiVector: {
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return vpiUndefined;
return (property == vpiVector) ^ (vop->varp()->dims() == 0);
}
case vpiSize: {
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return vpiUndefined;
return vop->size();
}
default:
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
__func__, VerilatedVpiError::strFromVpiProp(property));
return 0;
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported property %s, nothing will be returned",
__func__, VerilatedVpiError::strFromVpiProp(property));
return vpiUndefined;
}
}
PLI_INT64 vpi_get64(PLI_INT32 /*property*/, vpiHandle /*object*/) {
VL_VPI_UNIMP_();
return 0;
return vpiUndefined;
}
PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
@@ -2047,6 +2082,11 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
case vpiType: {
return const_cast<PLI_BYTE8*>(VerilatedVpiError::strFromVpiObjType(vop->type()));
}
case vpiConstType: {
const PLI_INT32 constType = vpi_get(vpiConstType, object);
VL_VPI_ERROR_RESET_();
return const_cast<PLI_BYTE8*>(VerilatedVpiError::strFromVpiConstType(constType));
}
default:
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
__func__, VerilatedVpiError::strFromVpiProp(property));
+2 -2
View File
@@ -260,7 +260,7 @@
//=========================================================================
// C++-2014
#if __cplusplus >= 201402L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK) || defined(_MSC_VER)
#if __cplusplus >= 201402L || defined(VL_CPPCHECK) || defined(_MSC_VER)
#else
# error "Verilator requires a C++14 or newer compiler"
#endif
@@ -612,7 +612,7 @@ static inline double VL_ROUND(double n) {
namespace vlstd {
template <typename T>
struct reverse_wrapper {
struct reverse_wrapper final {
const T& m_v;
explicit reverse_wrapper(const T& a_v)
+3 -1
View File
@@ -149,6 +149,7 @@ set(HEADERS
V3Split.h
V3SplitAs.h
V3SplitVar.h
V3StackCount.h
V3Stats.h
V3StdFuture.h
V3String.h
@@ -258,8 +259,8 @@ set(COMMON_SOURCES
V3LinkDot.cpp
V3LinkInc.cpp
V3LinkJump.cpp
V3LinkLevel.cpp
V3LinkLValue.cpp
V3LinkLevel.cpp
V3LinkParse.cpp
V3LinkResolve.cpp
V3Localize.cpp
@@ -289,6 +290,7 @@ set(COMMON_SOURCES
V3Split.cpp
V3SplitAs.cpp
V3SplitVar.cpp
V3StackCount.cpp
V3Stats.cpp
V3StatsReport.cpp
V3String.cpp
+1
View File
@@ -281,6 +281,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Split.o \
V3SplitAs.o \
V3SplitVar.o \
V3StackCount.o \
V3Subst.o \
V3TSP.o \
V3Table.o \
+1 -1
View File
@@ -648,5 +648,5 @@ public:
void V3Active::activeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -142,5 +142,5 @@ public:
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveTopVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeEitherLevel() >= 3);
}
+67 -30
View File
@@ -26,6 +26,13 @@ VL_DEFINE_DEBUG_FUNCTIONS;
// Assert class functions
class AssertVisitor final : public VNVisitor {
// TYPES
enum assertType_e : uint8_t {
ASSERT_TYPE_INTRINSIC, // AstNodeAssertIntrinsinc
ASSERT_TYPE_SVA, // SVA, PSL
ASSERT_TYPE_CASE, // unique/unique0/priority case related checks
ASSERT_TYPE_IF // unique/unique0/priority if related checks
};
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user() -> bool. True if processed
@@ -47,6 +54,12 @@ class AssertVisitor final : public VNVisitor {
bool m_inSampled = false; // True inside a sampled expression
// METHODS
static bool assertTypeOn(assertType_e assertType) {
if (assertType == ASSERT_TYPE_INTRINSIC) return true;
if (v3Global.opt.assertOn()) return true;
if (assertType == ASSERT_TYPE_CASE && v3Global.opt.assertCaseOn()) return true;
return false;
}
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message,
VDisplayType severity) {
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
@@ -99,7 +112,7 @@ class AssertVisitor final : public VNVisitor {
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
return varrefp;
}
AstNode* newIfAssertOn(AstNode* nodep, bool force) {
AstNode* newIfAssertOn(AstNode* nodep, assertType_e assertType) {
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
FileLine* const fl = nodep->fileline();
@@ -107,8 +120,9 @@ class AssertVisitor final : public VNVisitor {
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
AstNodeExpr* const condp
= force ? static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitTrue{}})
: v3Global.opt.assertOn()
= assertType == ASSERT_TYPE_INTRINSIC
? static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitTrue{}})
: assertTypeOn(assertType)
? static_cast<AstNodeExpr*>(
new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
: static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitFalse{}});
@@ -118,20 +132,23 @@ class AssertVisitor final : public VNVisitor {
return newp;
}
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message,
AstNodeExpr* exprsp = nullptr) {
// Like newFireAssert() but omits the asserts-on check
AstDisplay* const dispp
= new AstDisplay{nodep->fileline(), VDisplayType::DT_ERROR, message, nullptr, nullptr};
dispp->fmtp()->timeunit(m_modp->timeunit());
AstNode* const bodysp = dispp;
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
bodysp->addNext(new AstStop{nodep->fileline(), true});
if (exprsp) dispp->fmtp()->exprsp()->addNext(exprsp);
if (v3Global.opt.stopFail()) bodysp->addNext(new AstStop{nodep->fileline(), true});
return bodysp;
}
AstNode* newFireAssert(AstNode* nodep, const string& message) {
AstNode* bodysp = newFireAssertUnchecked(nodep, message);
bodysp = newIfAssertOn(bodysp, false);
AstNode* newFireAssert(AstNode* nodep, assertType_e assertType, const string& message,
AstNodeExpr* exprsp = nullptr) {
AstNode* bodysp = newFireAssertUnchecked(nodep, message, exprsp);
bodysp = newIfAssertOn(bodysp, assertType);
return bodysp;
}
@@ -183,16 +200,17 @@ class AssertVisitor final : public VNVisitor {
} else {
++m_statAsNotImm;
}
const bool force = VN_IS(nodep, AssertIntrinsic);
if (passsp) passsp = newIfAssertOn(passsp, force);
if (failsp) failsp = newIfAssertOn(failsp, force);
const assertType_e assertType
= VN_IS(nodep, AssertIntrinsic) ? ASSERT_TYPE_INTRINSIC : ASSERT_TYPE_SVA;
if (passsp) passsp = newIfAssertOn(passsp, assertType);
if (failsp) failsp = newIfAssertOn(failsp, assertType);
if (!passsp && !failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
ifp = new AstIf{nodep->fileline(), propp, passsp, failsp};
ifp->isBoundsCheck(true); // To avoid LATCH warning
// It's more LIKELY that we'll take the nullptr if clause
// than the sim-killing else clause:
ifp->branchPred(VBranchPred::BP_LIKELY);
bodysp = newIfAssertOn(ifp, force);
bodysp = newIfAssertOn(ifp, assertType);
} else {
nodep->v3fatalSrc("Unknown node type");
}
@@ -263,9 +281,9 @@ class AssertVisitor final : public VNVisitor {
= ((allow_none || hasDefaultElse)
? static_cast<AstNodeExpr*>(new AstOneHot0{nodep->fileline(), propp})
: static_cast<AstNodeExpr*>(new AstOneHot{nodep->fileline(), propp}));
AstIf* const checkifp
= new AstIf{nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
newFireAssert(nodep, "'unique if' statement violated"), newifp};
AstIf* const checkifp = new AstIf{
nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
newFireAssert(nodep, ASSERT_TYPE_IF, "'unique if' statement violated"), newifp};
checkifp->isBoundsCheck(true); // To avoid LATCH warning
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->replaceWith(checkifp);
@@ -284,13 +302,20 @@ class AssertVisitor final : public VNVisitor {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) has_default = true;
}
const AstNodeDType* exprDtypep = nodep->exprp()->dtypep()->skipRefp();
string valFmt;
if (exprDtypep->isIntegralOrPacked())
valFmt = " for '" + cvtToStr(exprDtypep->widthMin()) + "'h%X'";
if (nodep->fullPragma() || nodep->priorityPragma()) {
// Need to add a default if there isn't one already
++m_statAsFull;
if (!has_default) {
nodep->addItemsp(new AstCaseItem{
nodep->fileline(), nullptr /*DEFAULT*/,
newFireAssert(nodep, "synthesis full_case, but non-match found")});
newFireAssert(nodep, ASSERT_TYPE_CASE,
nodep->pragmaString() + ", but non-match found" + valFmt,
valFmt.empty() ? nullptr
: nodep->exprp()->cloneTreePure(false))});
}
}
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
@@ -328,20 +353,32 @@ class AssertVisitor final : public VNVisitor {
}
// Empty case means no property
if (!propp) propp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
const bool allow_none = has_default || nodep->unique0Pragma();
AstNodeExpr* const ohot
= (allow_none ? static_cast<AstNodeExpr*>(
new AstOneHot0{nodep->fileline(), propp})
: static_cast<AstNodeExpr*>(
new AstOneHot{nodep->fileline(), propp}));
AstIf* const ifp = new AstIf{
nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
newFireAssert(nodep,
"synthesis parallel_case, but multiple matches found")};
ifp->isBoundsCheck(true); // To avoid LATCH warning
ifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->addNotParallelp(ifp);
// The following assertion lools as below.
// if (!$onehot(propp)) begin
// if (propp == '0) begin if (!allow_none) $error("none match"); end
// else $error("multiple match");
// end
AstNodeExpr* const ohot = new AstOneHot{nodep->fileline(), propp};
AstIf* const ohotIfp
= new AstIf{nodep->fileline(), new AstLogNot{nodep->fileline(), ohot}};
AstIf* const zeroIfp
= new AstIf{nodep->fileline(),
new AstLogNot{nodep->fileline(), propp->cloneTreePure(false)}};
AstNodeExpr* const exprp = nodep->exprp();
const string pragmaStr = nodep->pragmaString();
if (!allow_none)
zeroIfp->addThensp(newFireAssert(
nodep, ASSERT_TYPE_CASE, pragmaStr + ", but none matched" + valFmt,
valFmt.empty() ? nullptr : exprp->cloneTreePure(false)));
zeroIfp->addElsesp(
newFireAssert(nodep, ASSERT_TYPE_CASE,
pragmaStr + ", but multiple matches found" + valFmt,
valFmt.empty() ? nullptr : exprp->cloneTreePure(false)));
ohotIfp->addThensp(zeroIfp);
ohotIfp->isBoundsCheck(true); // To avoid LATCH warning
ohotIfp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->addNotParallelp(ohotIfp);
}
}
}
@@ -540,5 +577,5 @@ public:
void V3Assert::assertAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeEitherLevel() >= 3);
}
+4 -2
View File
@@ -189,7 +189,9 @@ private:
m_clockingp->addNextHere(new AstAlwaysObserved{
flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, forkp});
if (v3Global.opt.timing().isSetTrue()) {
assignp->timingControlp(new AstDelay{flp, skewp->unlinkFrBack(), false});
AstDelay* const delayp = new AstDelay{flp, skewp->unlinkFrBack(), false};
delayp->timeunit(m_modp->timeunit());
assignp->timingControlp(delayp);
} else if (v3Global.opt.timing().isSetFalse()) {
nodep->v3warn(E_NOTIMING,
"Clocking output skew greater than #0 requires --timing");
@@ -493,5 +495,5 @@ public:
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertPreVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeEitherLevel() >= 3);
}
+26 -1
View File
@@ -22,6 +22,7 @@
#include <iomanip>
#include <memory>
#include <sstream>
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -1116,6 +1117,7 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
// private: Check a tree and children
UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent");
// cppcheck-suppress danglingTempReference
const VNTypeInfo& typeInfo = *type().typeInfo();
for (int i = 1; i <= 4; i++) {
AstNode* nodep = nullptr;
@@ -1126,6 +1128,7 @@ void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
case 4: nodep = op4p(); break;
default: this->v3fatalSrc("Bad case"); break;
}
// cppcheck-suppress danglingTempReference
const char* opName = typeInfo.m_opNamep[i - 1];
switch (typeInfo.m_opType[i - 1]) {
case VNTypeInfo::OP_UNUSED:
@@ -1142,7 +1145,7 @@ void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
case VNTypeInfo::OP_LIST:
if (const AstNode* const headp = nodep) {
const AstNode* backp = this;
const AstNode* tailp = headp;
const AstNode* tailp;
const AstNode* opp = headp;
do {
opp->checkTreeIter(backp);
@@ -1328,6 +1331,28 @@ void AstNode::dumpTreeDot(std::ostream& os) const {
drawChildren(os, this, m_op4p, "op4");
}
void AstNode::dumpTreeJsonFile(const string& filename, bool doDump) {
if (!doDump) return;
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treejsonp{V3File::new_ofstream(filename)};
if (treejsonp->fail()) v3fatal("Can't write " << filename);
dumpTreeJson(*treejsonp);
*treejsonp << '\n';
}
void AstNode::dumpJsonMetaFile(const string& filename) {
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treejsonp{V3File::new_ofstream(filename)};
if (treejsonp->fail()) v3fatal("Can't write " << filename);
*treejsonp << '{';
FileLine::fileNameNumMapDumpJson(*treejsonp);
*treejsonp << ',';
v3Global.idPtrMapDumpJson(*treejsonp);
*treejsonp << ',';
v3Global.ptrNamesDumpJson(*treejsonp);
*treejsonp << "}\n";
}
void AstNode::dumpTreeDotFile(const string& filename, bool doDump) {
if (doDump) {
UINFO(2, "Dumping " << filename << endl);
+31 -3
View File
@@ -31,6 +31,7 @@
#include "V3Ast__gen_forward_class_decls.h" // From ./astgen
#include <cmath>
#include <cstdint>
#include <functional>
#include <map>
#include <set>
@@ -98,7 +99,7 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
//######################################################################
struct VNTypeInfo {
struct VNTypeInfo final {
const char* m_namep;
enum uint8_t {
OP_UNUSED,
@@ -125,6 +126,7 @@ public:
constexpr VNType(en _e) VL_MT_SAFE : m_e{_e} {}
explicit VNType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
// cppcheck-suppress danglingTempReference
const VNTypeInfo* typeInfo() const VL_MT_SAFE { return &typeInfoTable[m_e]; }
constexpr operator en() const VL_MT_SAFE { return m_e; }
};
@@ -291,6 +293,8 @@ public:
NO_INLINE_TASK,
PUBLIC_MODULE,
PUBLIC_TASK,
UNROLL_DISABLE,
UNROLL_FULL,
FULL_CASE,
PARALLEL_CASE,
ENUM_SIZE
@@ -683,7 +687,7 @@ public:
/* UNKNOWN: */ "", // Should not be traced
/* BIT: */ "BIT",
/* BYTE: */ "BYTE",
/* CHANDLE: */ "",
/* CHANDLE: */ "LONGINT",
/* EVENT: */ "EVENT",
/* INT: */ "INT",
/* INTEGER: */ "INTEGER",
@@ -1969,7 +1973,7 @@ public:
static string prettyName(const string& namein) VL_PURE; // Name for printing out to the user
static string vpiName(const string& namein); // Name for vpi access
static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors)
return std::string{"'"} + prettyName(namein) + "'";
return "'"s + prettyName(namein) + "'";
}
// Encode user name into internal C representation
static string encodeName(const string& namein);
@@ -2216,6 +2220,23 @@ public:
static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
void dumpTreeDot(std::ostream& os = std::cout) const;
void dumpTreeDotFile(const string& filename, bool doDump = true);
virtual void dumpJson(std::ostream& os) const { dumpJsonGen(os); }; // node specific fields
// Generated by 'astgen'. Dumps node-specific pointers and calls 'dumpJson()' of parent class
// Note that we don't make it virtual as it would result in infinite recursion
void dumpJsonGen(std::ostream& os) const {};
virtual void dumpTreeJsonOpGen(std::ostream& os, const string& indent) const {};
void dumpTreeJson(std::ostream& os, const string& indent = "") const;
void dumpTreeJsonFile(const string& filename, bool doDump = true);
void dumpJsonMetaFile(const string& filename);
// Render node address for dumps. By default this is just the address
// printed as hex, but with --dump-tree-addrids we map addresses to short
// strings with a bijection to aid human readability. Observe that this might
// not actually be a unique identifier as the address can get reused after a
// node has been freed.
static std::string nodeAddr(const AstNode* nodep) {
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
}
// METHODS - static advancement
static AstNode* afterCommentp(AstNode* nodep) {
@@ -2288,6 +2309,11 @@ protected:
// Use instead VNVisitor::iterateSubtreeReturnEdits
AstNode* iterateSubtreeReturnEdits(VNVisitor& v);
static void dumpJsonNum(std::ostream& os, const std::string& name, int64_t val);
static void dumpJsonBool(std::ostream& os, const std::string& name, bool val);
static void dumpJsonStr(std::ostream& os, const std::string& name, const std::string& val);
static void dumpJsonPtr(std::ostream& os, const std::string& name, const AstNode* const valp);
private:
void iterateListBackwardsConst(VNVisitorConst& v);
@@ -2842,5 +2868,7 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
// Inline function definitions need to go last
#include "V3AstInlines.h"
void dumpNodeListJson(std::ostream& os, const AstNode* nodep, const std::string& listName,
const string& indent);
#endif // Guard
+10 -1
View File
@@ -52,6 +52,7 @@ public:
ASTGEN_MEMBERS_AstNodeDType;
// ACCESSORS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
virtual void dumpSmall(std::ostream& str) const;
bool hasDType() const override { return true; }
/// Require VlUnpacked, instead of [] for POD elements.
@@ -148,6 +149,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeArrayDType;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
void dumpSmall(std::ostream& str) const override;
const char* broken() const override {
BROKEN_RTN(!((m_refDTypep && !childDTypep()) || (!m_refDTypep && childDTypep())));
@@ -212,6 +214,7 @@ public:
ASTGEN_MEMBERS_AstNodeUOrStructDType;
int uniqueNum() const { return m_uniqueNum; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isCompound() const override { return !packed(); }
// For basicp() we reuse the size to indicate a "fake" basic type of same size
AstBasicDType* basicp() const override {
@@ -339,7 +342,7 @@ public:
class AstBasicDType final : public AstNodeDType {
// Builtin atomic/vectored data type
// @astgen op1 := rangep : Optional[AstRange] // Range of variable
struct Members {
struct Members final {
VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type
VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword)
bool operator==(const Members& rhs) const {
@@ -377,6 +380,7 @@ private:
public:
ASTGEN_MEMBERS_AstBasicDType;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// width/widthMin/numeric compared elsewhere
bool same(const AstNode* samep) const override;
bool similarDType(const AstNodeDType* samep) const override {
@@ -536,6 +540,7 @@ public:
return this == samep || (type() == samep->type() && same(samep));
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
string name() const override VL_MT_STABLE;
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
@@ -793,6 +798,7 @@ public:
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& flag) override { m_name = flag; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
// METHODS
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
@@ -850,6 +856,7 @@ public:
// METHODS
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
@@ -963,6 +970,7 @@ public:
}
ASTGEN_MEMBERS_AstParamTypeDType;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
@@ -1112,6 +1120,7 @@ public:
return skipRefp()->similarDType(samep->skipRefp());
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
string prettyDTypeName() const override {
+30
View File
@@ -50,6 +50,7 @@ public:
ASTGEN_MEMBERS_AstNodeExpr;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// TODO: The only AstNodeExpr without dtype is AstArg. Otherwise this could be final.
bool hasDType() const override { return true; }
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
@@ -196,6 +197,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeCCall;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
int instrCount() const override { return INSTR_COUNT_CALL; }
bool same(const AstNode* samep) const override {
const AstNodeCCall* const asamep = VN_DBG_AS(samep, NodeCCall);
@@ -248,6 +250,7 @@ protected:
public:
const char* broken() const override;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool isGateOptimizable() const override;
string dotted() const { return m_dotted; } // * = Scope name or ""
@@ -357,6 +360,7 @@ public:
// cppcheck-suppress functionConst
void iterateChildren(VNVisitorConst& v) {}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
// Ternary expression
@@ -377,6 +381,7 @@ public:
ASTGEN_MEMBERS_AstNodeTriop;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// Set out to evaluation of a AstConst'ed
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths)
@@ -458,6 +463,7 @@ public:
ASTGEN_MEMBERS_AstNodeUniop;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// Set out to evaluation of a AstConst'ed lhs
virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0;
virtual bool cleanLhs() const = 0;
@@ -510,6 +516,7 @@ protected:
public:
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return widthInstrs(); }
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
@@ -591,6 +598,7 @@ public:
ASTGEN_MEMBERS_AstAttrOf;
VAttrType attrType() const { return m_attrType; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -765,6 +773,7 @@ public:
== VN_DBG_AS(samep, ClassOrPackageRef)->m_classOrPackageNodep);
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
@@ -1120,6 +1129,7 @@ public:
return new AstDot{fl, true, packageOrClassp, rhsp};
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool colon() const { return m_colon; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
@@ -1148,6 +1158,7 @@ public:
}
ASTGEN_MEMBERS_AstEnumItemRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return itemp()->name(); }
int instrCount() const override { return 0; }
bool same(const AstNode* samep) const override {
@@ -1425,6 +1436,9 @@ public:
private:
KeyItemMap m_map; // Node value for each array index
// METHODS
void dumpInitList(std::ostream& str) const;
public:
AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNodeExpr* defaultp)
: ASTGEN_SUPER_InitArray(fl) {
@@ -1433,6 +1447,7 @@ public:
}
ASTGEN_MEMBERS_AstInitArray;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
const char* broken() const override;
void cloneRelink() override;
bool same(const AstNode* samep) const override {
@@ -1524,6 +1539,7 @@ public:
}
ASTGEN_MEMBERS_AstMemberSel;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& name) override { m_name = name; }
VAccess access() const { return m_access; }
@@ -1591,6 +1607,7 @@ public:
}
ASTGEN_MEMBERS_AstParseRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool same(const AstNode* samep) const override {
const AstParseRef* const asamep = VN_DBG_AS(samep, ParseRef);
@@ -1647,6 +1664,7 @@ public:
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs() * 2; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool isDefault() const { return m_default; }
void isDefault(bool flag) { m_default = flag; }
};
@@ -1877,6 +1895,7 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string scopeSymName() const { // Name for __Vscope variable including children
return scopeNameFormatter(scopeAttrp());
}
@@ -2072,6 +2091,7 @@ public:
string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
// but isPure() true
bool cleanOut() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -3479,6 +3499,7 @@ public:
bool sizeMattersRhs() const override { return false; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
int instrCount() const override { return INSTR_COUNT_PLI; }
};
@@ -4350,6 +4371,7 @@ public:
int instrCount() const override { return INSTR_COUNT_TIME; }
bool same(const AstNode* /*samep*/) const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
};
@@ -4370,6 +4392,7 @@ public:
int instrCount() const override { return INSTR_COUNT_TIME; }
bool same(const AstNode* /*samep*/) const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
};
@@ -4518,6 +4541,7 @@ public:
}
ASTGEN_MEMBERS_AstSel;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit,
const V3Number& width) override {
out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt());
@@ -4558,6 +4582,7 @@ public:
, m_declRange{declRange} {}
ASTGEN_MEMBERS_AstSliceSel;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo,
const V3Number& width) override {
V3ERROR_NA;
@@ -4720,6 +4745,7 @@ public:
ASTGEN_MEMBERS_AstCAwait;
bool isTimingControl() const override { return true; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
AstSenTree* sensesp() const { return m_sensesp; }
void clearSensesp() { m_sensesp = nullptr; }
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
@@ -4758,6 +4784,7 @@ public:
return size() == VN_DBG_AS(samep, CCast)->size();
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
//
int size() const { return m_size; }
};
@@ -5250,6 +5277,7 @@ public:
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
};
@@ -5516,6 +5544,7 @@ public:
ASTGEN_MEMBERS_AstVarRef;
inline string name() const override; // * = Var name
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
const char* broken() const override;
bool same(const AstNode* samep) const override;
inline bool same(const AstVarRef* samep) const;
@@ -5540,6 +5569,7 @@ public:
ASTGEN_MEMBERS_AstVarXRef;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string dotted() const { return m_dotted; }
void dotted(const string& dotted) { m_dotted = dotted; }
string inlinedDots() const { return m_inlinedDots; }
+70 -12
View File
@@ -47,6 +47,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeBlock;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
void name(const string& name) override { m_name = name; }
bool unnamed() const { return m_unnamed; }
@@ -123,6 +124,7 @@ public:
ASTGEN_MEMBERS_AstNodeFTask;
virtual AstNodeFTask* cloneType(const string& name) = 0;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool maybePointedTo() const override { return true; }
bool isGateOptimizable() const override {
@@ -210,6 +212,7 @@ public:
, m_name{name} {}
ASTGEN_MEMBERS_AstNodeFile;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -258,6 +261,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeModule;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override { return true; }
string name() const override VL_MT_STABLE { return m_name; }
virtual bool timescaleMatters() const = 0;
@@ -313,6 +317,7 @@ public:
ASTGEN_MEMBERS_AstNodeProcedure;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); }
bool isSuspendable() const { return m_suspendable; }
void setSuspendable() { m_suspendable = true; }
@@ -328,6 +333,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeRange;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstNodeStmt VL_NOT_FINAL : public AstNode {
// Procedural statement
@@ -341,6 +347,7 @@ public:
void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
// Iteration is in order, and we want rhsp to be visited first (which is the execution order)
@@ -407,6 +414,7 @@ public:
bool same(const AstNode* samep) const override { return samep->name() == name(); }
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool immediate() const { return m_immediate; }
};
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
@@ -505,6 +513,8 @@ public:
};
class AstNodeText VL_NOT_FINAL : public AstNode {
string m_text;
// METHODS
string shortText() const;
protected:
// Node that puts text into the output stream
@@ -515,6 +525,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeText;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool same(const AstNode* samep) const override {
const AstNodeText* asamep = VN_DBG_AS(samep, NodeText);
return text() == asamep->text();
@@ -554,6 +565,7 @@ public:
}
ASTGEN_MEMBERS_AstActive;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; }
// Statements are broken into pieces, as some must come before others.
void sensesp(AstSenTree* nodep) { m_sensesp = nodep; }
@@ -593,7 +605,6 @@ class AstCFunc final : public AstNode {
string m_cname; // C name, for dpiExports
string m_rtnType; // void, bool, or other return type
string m_argTypes; // Argument types
string m_baseCtors; // Base class constructor
string m_ifdef; // #ifdef symbol around this function
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
@@ -653,11 +664,11 @@ public:
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool same(const AstNode* samep) const override {
const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc);
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
&& (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors())
&& isLoose() == asamep->isLoose()
&& (argTypes() == asamep->argTypes()) && isLoose() == asamep->isLoose()
&& (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name()));
}
//
@@ -689,8 +700,6 @@ public:
void funcPublic(bool flag) { m_funcPublic = flag; }
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
void baseCtors(const string& str) { m_baseCtors = str; }
string baseCtors() const { return m_baseCtors; }
void ifdef(const string& str) { m_ifdef = str; }
string ifdef() const { return m_ifdef; }
bool isConstructor() const { return m_isConstructor; }
@@ -756,6 +765,7 @@ public:
, m_useType{useType} {}
ASTGEN_MEMBERS_AstCUse;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; }
VUseType useType() const { return m_useType; }
};
@@ -810,6 +820,7 @@ public:
// No cloneRelink, we presume cloneee's want the same module linkages
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override { return true; }
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
@@ -849,6 +860,7 @@ public:
, m_timeunit{timeunit} {}
ASTGEN_MEMBERS_AstCellInline;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
@@ -875,6 +887,7 @@ public:
}
ASTGEN_MEMBERS_AstClassExtends;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool hasDType() const override { return true; }
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
// Class being extended (after link and instantiation if needed)
@@ -907,6 +920,7 @@ public:
}
ASTGEN_MEMBERS_AstClocking;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
std::string name() const override VL_MT_STABLE { return m_name; }
bool isDefault() const { return m_isDefault; }
bool isGlobal() const { return m_isGlobal; }
@@ -1170,6 +1184,7 @@ public:
ExecMTask* execMTaskp() const { return m_execMTaskp; }
void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstModport final : public AstNode {
// A modport in an interface
@@ -1201,6 +1216,7 @@ public:
, m_export{isExport} {}
ASTGEN_MEMBERS_AstModportFTaskRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
bool isImport() const { return !m_export; }
bool isExport() const { return m_export; }
@@ -1222,6 +1238,7 @@ public:
, m_direction{direction} {}
ASTGEN_MEMBERS_AstModportVarRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
void direction(const VDirection& flag) { m_direction = flag; }
VDirection direction() const { return m_direction; }
@@ -1259,6 +1276,7 @@ public:
void cloneRelink() override { V3ERROR_NA; }
string name() const override VL_MT_STABLE { return "$root"; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy
return modulesp(); // First one in the list, for now
}
@@ -1309,6 +1327,7 @@ public:
, m_packagep{packagep} {}
ASTGEN_MEMBERS_AstPackageExport;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
@@ -1334,6 +1353,7 @@ public:
, m_packagep{packagep} {}
ASTGEN_MEMBERS_AstPackageImport;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
@@ -1360,6 +1380,7 @@ public:
ASTGEN_MEMBERS_AstPin;
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
void name(const string& name) override { m_name = name; }
string prettyOperatorName() const override;
@@ -1473,6 +1494,7 @@ public:
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool same(const AstNode* samep) const override;
string nameDotless() const;
AstNodeModule* modp() const { return m_modp; }
@@ -1523,6 +1545,7 @@ public:
, m_edgeType{VEdgeType::ET_NEVER} {}
ASTGEN_MEMBERS_AstSenItem;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool same(const AstNode* samep) const override {
return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType();
}
@@ -1553,6 +1576,7 @@ public:
}
ASTGEN_MEMBERS_AstSenTree;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override { return true; }
bool isMulti() const { return m_multi; }
void multi(bool flag) { m_multi = true; }
@@ -1585,6 +1609,7 @@ public:
VStrength strength0() { return m_s0; }
VStrength strength1() { return m_s1; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstTopScope final : public AstNode {
// A singleton, held under the top level AstModule. Holds the top level
@@ -1637,6 +1662,7 @@ public:
void clearCache();
void repairCache();
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstTypedef final : public AstNode {
// @astgen op1 := childDTypep : Optional[AstNodeDType]
@@ -1657,6 +1683,7 @@ public:
}
ASTGEN_MEMBERS_AstTypedef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
@@ -1863,6 +1890,7 @@ public:
}
ASTGEN_MEMBERS_AstVar;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool same(const AstNode* samep) const override;
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
bool hasDType() const override { return true; }
@@ -2113,6 +2141,7 @@ public:
bool maybePointedTo() const override { return true; }
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool same(const AstNode* samep) const override;
bool hasDType() const override { return true; }
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
@@ -2141,6 +2170,7 @@ public:
, m_implied{implied} {}
ASTGEN_MEMBERS_AstBegin;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
void generate(bool flag) { m_generate = flag; }
bool generate() const { return m_generate; }
void setNeedProcess() { m_needProcess = true; }
@@ -2160,6 +2190,7 @@ public:
ASTGEN_MEMBERS_AstFork;
bool isTimingControl() const override { return !joinType().joinNone(); }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
VJoinType joinType() const { return m_joinType; }
void joinType(const VJoinType& flag) { m_joinType = flag; }
};
@@ -2230,6 +2261,7 @@ public:
, m_support{false} {}
ASTGEN_MEMBERS_AstCFile;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool slow() const { return m_slow; }
void slow(bool flag) { m_slow = flag; }
bool source() const { return m_source; }
@@ -2245,6 +2277,7 @@ public:
: ASTGEN_SUPER_VFile(fl, name) {}
ASTGEN_MEMBERS_AstVFile;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
// === AstNodeModule ===
@@ -2255,8 +2288,9 @@ class AstClass final : public AstNodeModule {
bool m_extended = false; // Is extension or extended by other classes
bool m_interfaceClass = false; // Interface class
bool m_needRNG = false; // Need RNG, uses srandom/randomize
bool m_virtual = false; // Virtual class
bool m_parameterized = false; // Parameterized class
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
bool m_virtual = false; // Virtual class
public:
AstClass(FileLine* fl, const string& name)
@@ -2265,6 +2299,7 @@ public:
string verilogKwd() const override { return "class"; }
bool maybePointedTo() const override { return true; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool timescaleMatters() const override { return false; }
AstClassPackage* classOrPackagep() const VL_MT_SAFE { return m_classOrPackagep; }
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
@@ -2274,12 +2309,14 @@ public:
void isExtended(bool flag) { m_extended = flag; }
bool isInterfaceClass() const { return m_interfaceClass; }
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
bool isParameterized() const { return m_parameterized; }
void isParameterized(bool flag) { m_parameterized = flag; }
bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; }
bool needRNG() const { return m_needRNG; }
void needRNG(bool flag) { m_needRNG = flag; }
bool isParameterized() const { return m_parameterized; }
void isParameterized(bool flag) { m_parameterized = flag; }
bool useVirtualPublic() const { return m_useVirtualPublic; }
void useVirtualPublic(bool flag) { m_useVirtualPublic = flag; }
// Return true if this class is an extension of base class (SLOW)
// Accepts nullptrs
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
@@ -2367,6 +2404,7 @@ public:
ASTGEN_MEMBERS_AstAlways;
//
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
VAlwaysKwd keyword() const { return m_keyword; }
};
class AstAlwaysObserved final : public AstNodeProcedure {
@@ -2484,6 +2522,7 @@ public:
int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; }
bool ascending() const { return leftConst() < rightConst(); }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
virtual string emitC() { V3ERROR_NA_RETURN(""); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -2652,12 +2691,14 @@ public:
, m_offset{offset} {}
ASTGEN_MEMBERS_AstCoverDecl;
const char* broken() const override {
if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing
v3fatalSrc("dataDeclp should point to real data, not be a list");
if (m_dataDeclp
&& (m_dataDeclp == this || m_dataDeclp->m_dataDeclp)) { // Avoid O(n^2) accessing
v3fatalSrc("dataDeclp should point to real data, not be a list: " << cvtToHex(this));
}
return nullptr;
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
bool maybePointedTo() const override { return true; }
void binNum(int flag) { m_binNum = flag; }
@@ -2691,6 +2732,7 @@ public:
, m_declp{declp} {}
ASTGEN_MEMBERS_AstCoverInc;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
bool same(const AstNode* samep) const override {
return declp() == VN_DBG_AS(samep, CoverInc)->declp();
@@ -2728,6 +2770,7 @@ class AstDelay final : public AstNodeStmt {
// Delay statement
// @astgen op1 := lhsp : AstNodeExpr // Delay value
// @astgen op2 := stmtsp : List[AstNode] // Statements under delay
VTimescale m_timeunit; // Delay's time unit
const bool m_isCycle; // True if it is a cycle delay
public:
@@ -2738,9 +2781,12 @@ public:
}
ASTGEN_MEMBERS_AstDelay;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isTimingControl() const override { return true; }
bool isCycleDelay() const { return m_isCycle; }
bool same(const AstNode* /*samep*/) const override { return true; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
bool isCycleDelay() const { return m_isCycle; }
};
class AstDisable final : public AstNodeStmt {
string m_name; // Name of block
@@ -2785,6 +2831,7 @@ public:
}
ASTGEN_MEMBERS_AstDisplay;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
const char* broken() const override {
BROKEN_RTN(!fmtp());
return nullptr;
@@ -2837,8 +2884,9 @@ public:
ASTGEN_MEMBERS_AstDumpCtl;
string verilogKwd() const override { return ctlType().ascii(); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isOutputter() override { return true; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
virtual bool cleanOut() const { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
VDumpCtlType ctlType() const { return m_ctlType; }
@@ -2957,6 +3005,7 @@ public:
ASTGEN_MEMBERS_AstJumpGo;
const char* broken() const override;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* samep) const override {
return labelp() == VN_DBG_AS(samep, JumpGo)->labelp();
@@ -2984,6 +3033,7 @@ public:
return nullptr;
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 0; }
bool same(const AstNode* samep) const override {
return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp();
@@ -3020,6 +3070,7 @@ public:
void name(const string& name) override { m_name = name; }
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string verilogKwd() const override { return "$printtimescale"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
@@ -3229,6 +3280,7 @@ public:
this->valuep(valuep);
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 100; } // Large...
ASTGEN_MEMBERS_AstTraceDecl;
string name() const override VL_MT_STABLE { return m_showname; }
@@ -3272,6 +3324,7 @@ public:
}
ASTGEN_MEMBERS_AstTraceInc;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; }
bool hasDType() const override { return true; }
bool same(const AstNode* samep) const override {
@@ -3346,6 +3399,7 @@ class AstWhile final : public AstNodeStmt {
// @astgen op2 := condp : AstNodeExpr
// @astgen op3 := stmtsp : List[AstNode]
// @astgen op4 := incsp : List[AstNode]
VOptionBool m_unrollFull; // Full, disable, or default unrolling
public:
AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
: ASTGEN_SUPER_While(fl) {
@@ -3354,12 +3408,15 @@ public:
this->addIncsp(incsp);
}
ASTGEN_MEMBERS_AstWhile;
void dump(std::ostream& str) const override;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* /*samep*/) const override { return true; }
// Stop statement searchback here
void addNextStmt(AstNode* newp, AstNode* belowp) override;
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
void unrollFull(const VOptionBool flag) { m_unrollFull = flag; }
VOptionBool unrollFull() const { return m_unrollFull; }
};
// === AstNodeAssign ===
@@ -3503,6 +3560,7 @@ public:
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
bool priorityPragma() const { return m_priorityPragma; }
void priorityPragma(bool flag) { m_priorityPragma = flag; }
string pragmaString() const;
};
class AstGenCase final : public AstNodeCase {
// Generate Case statement
+449 -16
View File
@@ -18,6 +18,7 @@
#include "V3EmitCBase.h"
#include "V3File.h"
#include "V3Global.h"
#include "V3Graph.h"
#include "V3Hasher.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
@@ -28,8 +29,34 @@
#include <iomanip>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
// Routines for dumping dict fields (NOTE: due to leading ',' they can't be used for first field in
// dict)
void AstNode::dumpJsonNum(std::ostream& os, const std::string& name, int64_t val) {
os << ",\"" << name << "\":" << val;
}
void AstNode::dumpJsonBool(std::ostream& os, const std::string& name, bool val) {
os << ",\"" << name << "\":" << (val ? "true" : "false");
}
void AstNode::dumpJsonStr(std::ostream& os, const std::string& name, const std::string& val) {
os << ",\"" << name << "\":\"" << V3OutFormatter::quoteNameControls(val) << '"';
}
void AstNode::dumpJsonPtr(std::ostream& os, const std::string& name, const AstNode* const valp) {
v3Global.saveJsonPtrFieldName(name);
std::string addr = "UNLINKED";
if (valp) addr = (v3Global.opt.jsonIds() ? v3Global.ptrToId(valp) : cvtToHex(valp));
os << ",\"" << name << "\":\"" << addr << '"';
}
// Shorthands for dumping fields that use func name as key
#define dumpJsonNumFunc(os, func) dumpJsonNum(os, #func, func())
#define dumpJsonBoolFunc(os, func) dumpJsonBool(os, #func, func())
#define dumpJsonStrFunc(os, func) dumpJsonStr(os, #func, func())
#define dumpJsonPtrFunc(os, func) dumpJsonPtr(os, #func, func())
//======================================================================
// Special methods
@@ -74,6 +101,7 @@ int AstNodeSel::bitConst() const {
}
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeStmt::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstNodeCCall::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
@@ -84,6 +112,10 @@ void AstNodeCCall::dump(std::ostream& str) const {
str << " " << name();
}
}
void AstNodeCCall::dumpJson(std::ostream& str) const {
if (funcp()) dumpJsonStr(str, "funcName", funcp()->name());
dumpJsonGen(str);
}
bool AstNodeCCall::isPure() { return funcp()->dpiPure(); }
bool AstNodeUniop::isPure() {
if (!m_purity.isCached()) m_purity.set(lhsp()->isPure());
@@ -1291,15 +1323,6 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
//======================================================================
// Per-type Debugging
// Render node address for dumps. By default this is just the address
// printed as hex, but with --dump-tree-addrids we map addresses to short
// strings with a bijection to aid human readability. Observe that this might
// not actually be a unique identifier as the address can get reused after a
// node has been freed.
static std::string nodeAddr(const AstNode* nodep) {
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
}
void AstNode::dump(std::ostream& str) const {
str << typeName() << " " << nodeAddr(this)
#ifdef VL_DEBUG
@@ -1331,26 +1354,91 @@ void AstNode::dump(std::ostream& str) const {
}
}
void dumpNodeListJson(std::ostream& os, const AstNode* nodep, const std::string& listName,
const string& indent) {
os << ',';
if (!nodep) { // empty list, print inline
os << '"' << listName << "\": []";
} else {
os << '\n' << indent + " \"" << listName << "\": [\n";
for (; nodep; nodep = nodep->nextp()) {
nodep->dumpTreeJson(os, indent + " ");
if (nodep->nextp()) os << ',';
os << '\n';
}
os << indent << ']';
}
}
static void dumpFileInfo(std::ostream& os, const FileLine* fileinfop) {
const std::string filename
= v3Global.opt.jsonIds() ? fileinfop->filenameLetters() : fileinfop->filename();
os << ",\"loc\":\"" << filename << ',' << fileinfop->firstLineno() << ':'
<< fileinfop->firstColumn() << ',' << fileinfop->lastLineno() << ':'
<< fileinfop->lastColumn() << '"';
}
void AstNode::dumpTreeJson(std::ostream& os, const string& indent) const {
os << indent << "{\"type\":\"" << typeName() << '"';
dumpJsonStr(os, "name", V3OutFormatter::quoteNameControls(prettyName()));
dumpJsonPtr(os, "addr", this);
dumpFileInfo(os, fileline());
#ifdef VL_DEBUG
if (v3Global.opt.jsonEditNums()) dumpJsonNum(os, "editNum", editCount());
#endif
if (hasDType()) {
dumpJsonPtrFunc(os, dtypep);
} else { // V3Broken will throw an error
if (dtypep()) {
dumpJsonStr(os, "dtypep", " %Error-dtype-exp=null,got=" + nodeAddr(dtypep()));
}
}
dumpJson(os);
dumpTreeJsonOpGen(os, indent);
os << "}";
}
void AstNodeProcedure::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isSuspendable()) str << " [SUSP]";
if (needProcess()) str << " [NPRC]";
}
void AstNodeProcedure::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isSuspendable);
dumpJsonBoolFunc(str, needProcess);
dumpJsonGen(str);
}
void AstAlways::dump(std::ostream& str) const {
this->AstNodeProcedure::dump(str);
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
}
void AstAlways::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "keyword", keyword().ascii());
dumpJsonGen(str);
}
void AstAttrOf::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << attrType().ascii() << "]";
}
void AstAttrOf::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "attrType", attrType().ascii());
dumpJsonGen(str);
}
void AstBasicDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
str << " kwd=" << keyword().ascii();
if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]";
}
void AstBasicDType::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "keyword", keyword().ascii());
if (isRanged() && !rangep()) {
dumpJsonStr(str, "range", std::to_string(left()) + ":" + std::to_string(right()));
}
dumpJsonGen(str);
}
string AstBasicDType::prettyDTypeName() const {
std::ostringstream os;
os << keyword().ascii();
@@ -1361,12 +1449,18 @@ string AstBasicDType::prettyDTypeName() const {
}
void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeExpr::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstNodeUniop::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstCCast::dump(std::ostream& str) const {
this->AstNodeUniop::dump(str);
str << " sz" << size();
}
void AstCCast::dumpJson(std::ostream& str) const {
dumpJsonNumFunc(str, size);
dumpJsonGen(str);
}
void AstCell::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (recursive()) str << " [RECURSIVE]";
@@ -1377,11 +1471,20 @@ void AstCell::dump(std::ostream& str) const {
str << " ->UNLINKED:" << modName();
}
}
void AstCell::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, origName);
dumpJsonBoolFunc(str, recursive);
dumpJsonGen(str);
}
void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << origModName();
str << " [scopep=" << nodeAddr(scopep()) << "]";
}
void AstCellInline::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, origModName);
dumpJsonGen(str);
}
bool AstClass::isCacheableChild(const AstNode* nodep) {
return (VN_IS(nodep, Var) || VN_IS(nodep, Constraint) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
@@ -1406,11 +1509,22 @@ void AstClass::dump(std::ostream& str) const {
if (isExtended()) str << " [EXT]";
if (isInterfaceClass()) str << " [IFCCLS]";
if (isVirtual()) str << " [VIRT]";
if (useVirtualPublic()) str << " [VIRPUB]";
}
void AstClass::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isExtended);
dumpJsonBoolFunc(str, isInterfaceClass);
dumpJsonBoolFunc(str, isVirtual);
dumpJsonGen(str);
}
void AstClassExtends::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isImplements()) str << " [IMPLEMENTS]";
}
void AstClassExtends::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isImplements);
dumpJsonGen(str);
}
AstClass* AstClassExtends::classOrNullp() const {
const AstNodeDType* const dtp = dtypep() ? dtypep() : childDTypep();
const AstClassRefDType* const refp = VN_CAST(dtp, ClassRefDType);
@@ -1436,6 +1550,7 @@ void AstClassRefDType::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstClassRefDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstClassRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "class:" << name();
@@ -1445,19 +1560,33 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
if (immediate()) str << " [IMMEDIATE]";
}
void AstNodeCoverOrAssert::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, immediate);
dumpJsonGen(str);
}
void AstClocking::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isDefault()) str << " [DEFAULT]";
if (isGlobal()) str << " [GLOBAL]";
}
void AstClocking::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isDefault);
dumpJsonBoolFunc(str, isGlobal);
dumpJsonGen(str);
}
void AstDisplay::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
// str << " " << displayType().ascii();
}
void AstDisplay::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstEnumDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
str << " enum";
}
void AstEnumDType::dumpJson(std::ostream& str) const {
dumpJsonBool(str, "enum", 1);
dumpJsonGen(str);
}
void AstEnumDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "enum";
@@ -1478,6 +1607,7 @@ const char* AstEnumDType::broken() const {
return nullptr;
}
void AstEnumItemRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstIfaceRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (cellName() != "") str << " cell=" << cellName();
@@ -1493,12 +1623,17 @@ void AstIfaceRefDType::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstIfaceRefDType::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, cellName);
dumpJsonStrFunc(str, ifaceName);
dumpJsonStrFunc(str, modportName);
dumpJsonGen(str);
}
void AstIfaceRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "iface";
}
void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str);
void AstInitArray::dumpInitList(std::ostream& str) const {
int n = 0;
const auto& mapr = map();
for (const auto& itr : mapr) {
@@ -1506,9 +1641,21 @@ void AstInitArray::dump(std::ostream& str) const {
str << " ...";
break;
}
str << " [" << itr.first << "]=" << nodeAddr(itr.second);
const string addr
= (v3Global.opt.jsonIds() ? v3Global.ptrToId(itr.second) : nodeAddr(itr.second));
str << " [" << itr.first << "]=" << addr;
}
}
void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str);
dumpInitList(str);
}
void AstInitArray::dumpJson(std::ostream& str) const {
str << ',' << '"' << "initList" << '"' << ':' << '"';
dumpInitList(str);
str << '"';
dumpJsonGen(str);
}
const char* AstInitArray::broken() const {
for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
BROKEN_RTN(!it->second);
@@ -1555,6 +1702,7 @@ void AstJumpGo::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstJumpGo::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
const char* AstJumpGo::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return nullptr;
@@ -1569,6 +1717,7 @@ void AstJumpLabel::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstMemberDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
@@ -1597,6 +1746,7 @@ void AstMemberSel::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstMemberSel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstModportFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isExport()) str << " EXPORT";
@@ -1608,6 +1758,11 @@ void AstModportFTaskRef::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstModportFTaskRef::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isExport);
dumpJsonBoolFunc(str, isImport);
dumpJsonGen(str);
}
void AstModportVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (direction().isAny()) str << " " << direction();
@@ -1618,6 +1773,10 @@ void AstModportVarRef::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstModportVarRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "direction", direction().ascii());
dumpJsonGen(str);
}
void AstPin::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (modVarp()) {
@@ -1629,6 +1788,11 @@ void AstPin::dump(std::ostream& str) const {
if (svDotName()) str << " [.n]";
if (svImplicit()) str << " [.SV]";
}
void AstPin::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, svDotName);
dumpJsonBoolFunc(str, svImplicit);
dumpJsonGen(str);
}
string AstPin::prettyOperatorName() const {
return modVarp()
? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " : "")
@@ -1639,20 +1803,37 @@ void AstPrintTimeScale::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
str << " " << timeunit();
}
void AstPrintTimeScale::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "timeunit", timeunit().ascii());
dumpJsonGen(str);
}
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstNodeTermop::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstTime::dump(std::ostream& str) const {
this->AstNodeTermop::dump(str);
str << " " << timeunit();
}
void AstTime::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "timeunit", timeunit().ascii());
dumpJsonGen(str);
}
void AstTimeD::dump(std::ostream& str) const {
this->AstNodeTermop::dump(str);
str << " " << timeunit();
}
void AstTimeD::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "timeunit", timeunit().ascii());
dumpJsonGen(str);
}
void AstTimeImport::dump(std::ostream& str) const {
this->AstNodeUniop::dump(str);
str << " " << timeunit();
}
void AstTimeImport::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "timeunit", timeunit().ascii());
dumpJsonGen(str);
}
void AstTypedef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (attrPublic()) str << " [PUBLIC]";
@@ -1661,11 +1842,20 @@ void AstTypedef::dump(std::ostream& str) const {
subDTypep()->dump(str);
}
}
void AstTypedef::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, attrPublic);
dumpJsonGen(str);
}
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeRange::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstRange::dump(std::ostream& str) const {
this->AstNodeRange::dump(str);
if (ascending()) str << " [ASCENDING]";
}
void AstRange::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, ascending);
dumpJsonGen(str);
}
void AstParamTypeDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (subDTypep()) {
@@ -1675,6 +1865,7 @@ void AstParamTypeDType::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstParamTypeDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (typedefp() || subDTypep()) {
@@ -1693,6 +1884,7 @@ void AstRefDType::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstRefDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "ref";
@@ -1707,6 +1899,11 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
if (isFourstate()) str << " [4STATE]";
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
}
void AstNodeUOrStructDType::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, packed);
dumpJsonBoolFunc(str, isFourstate);
dumpJsonGen(str);
}
void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (generic()) str << " [GENERIC]";
@@ -1715,6 +1912,10 @@ void AstNodeDType::dump(std::ostream& str) const {
dtp->dumpSmall(str);
}
}
void AstNodeDType::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, generic);
dumpJsonGen(str);
}
void AstNodeDType::dumpSmall(std::ostream& str) const {
str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "")
<< (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : "");
@@ -1737,6 +1938,11 @@ void AstNodeArrayDType::dump(std::ostream& str) const {
if (isCompound()) str << " [COMPOUND]";
str << " " << declRange();
}
void AstNodeArrayDType::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isCompound);
dumpJsonStr(str, "declRange", cvtToStr(declRange()));
dumpJsonGen(str);
}
string AstPackArrayDType::prettyDTypeName() const {
std::ostringstream os;
if (const auto subp = subDTypep()) os << subp->prettyDTypeName();
@@ -1772,6 +1978,11 @@ void AstNetlist::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << timeunit() << "/" << timeprecision() << "]";
}
void AstNetlist::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "timeunit", timeunit().ascii());
dumpJsonStr(str, "timeprecision", timeprecision().ascii());
dumpJsonGen(str);
}
AstPackage* AstNetlist::dollarUnitPkgAddp() {
if (!m_dollarUnitPkgp) {
m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName()};
@@ -1802,19 +2013,37 @@ void AstNodeModule::dump(std::ostream& str) const {
}
str << " [" << timeunit() << "]";
}
void AstNodeModule::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, origName);
dumpJsonNumFunc(str, level);
dumpJsonBoolFunc(str, modPublic);
dumpJsonBoolFunc(str, inLibrary);
dumpJsonBoolFunc(str, dead);
dumpJsonBoolFunc(str, recursiveClone);
dumpJsonBoolFunc(str, recursive);
dumpJsonStr(str, "timeunit", timeunit().ascii());
dumpJsonGen(str);
}
void AstPackageExport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstPackageExport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstPackageImport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstPatMember::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (isDefault()) str << " [DEFAULT]";
}
void AstPatMember::dumpJson(std::ostream& str) const {
if (isDefault()) dumpJsonBoolFunc(str, isDefault);
dumpJsonGen(str);
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstNodeTriop::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str);
if (declRange().ranged()) {
@@ -1822,15 +2051,32 @@ void AstSel::dump(std::ostream& str) const {
if (declElWidth() != 1) str << "/" << declElWidth();
}
}
void AstSel::dumpJson(std::ostream& str) const {
if (declRange().ranged()) {
dumpJsonStr(str, "declRange", cvtToStr(declRange()));
dumpJsonNumFunc(str, declElWidth);
}
dumpJsonGen(str);
}
void AstSliceSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str);
if (declRange().ranged()) str << " decl" << declRange();
}
void AstSliceSel::dumpJson(std::ostream& str) const {
if (declRange().ranged()) { dumpJsonStr(str, "declRange", cvtToStr(declRange())); }
dumpJsonGen(str);
}
void AstMTaskBody::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " ";
m_execMTaskp->dump(str);
}
void AstMTaskBody::dumpJson(std::ostream& str) const {
str << ',' << '"' << "execMTask" << '"' << ':' << '"';
m_execMTaskp->dump(str); // TODO: Consider dumping it as json object
str << '"';
dumpJsonGen(str);
}
void AstTypeTable::dump(std::ostream& str) const {
this->AstNode::dump(str);
for (int i = 0; i < static_cast<int>(VBasicDTypeKwd::_ENUM_MAX); ++i) {
@@ -1852,6 +2098,7 @@ void AstTypeTable::dump(std::ostream& str) const {
}
// Note get newline from caller too.
}
void AstTypeTable::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "[assoc-" << nodeAddr(keyDTypep()) << "]";
@@ -1930,6 +2177,10 @@ void AstVarScope::dump(std::ostream& str) const {
str << " ->UNLINKED";
}
}
void AstVarScope::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isTrace);
dumpJsonGen(str);
}
bool AstVarScope::same(const AstNode* samep) const {
const AstVarScope* const asamep = VN_DBG_AS(samep, VarScope);
return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep());
@@ -1939,6 +2190,10 @@ void AstNodeVarRef::dump(std::ostream& str) const {
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " " << access().arrow() << " ";
}
void AstNodeVarRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "access", access().ascii());
dumpJsonGen(str);
}
void AstVarXRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
str << ".=" << dotted() << " ";
@@ -1951,6 +2206,11 @@ void AstVarXRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
void AstVarXRef::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, dotted);
dumpJsonStrFunc(str, inlinedDots);
dumpJsonGen(str);
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
if (varScopep()) {
@@ -1961,6 +2221,7 @@ void AstVarRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
void AstVarRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
const char* AstVarRef::broken() const {
BROKEN_RTN(!varp());
return nullptr;
@@ -2005,16 +2266,54 @@ void AstVar::dump(std::ostream& str) const {
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
}
void AstVar::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, origName);
dumpJsonBoolFunc(str, isSc);
dumpJsonBoolFunc(str, isPrimaryIO);
dumpJsonStr(str, "direction", direction().ascii());
dumpJsonBoolFunc(str, isConst);
dumpJsonBoolFunc(str, isPullup);
dumpJsonBoolFunc(str, isPulldown);
dumpJsonBoolFunc(str, isUsedClock);
dumpJsonBoolFunc(str, isSigPublic);
dumpJsonBoolFunc(str, isLatched);
dumpJsonBoolFunc(str, isUsedLoopIdx);
dumpJsonBoolFunc(str, noReset);
dumpJsonBoolFunc(str, attrIsolateAssign);
dumpJsonBoolFunc(str, attrFileDescr);
dumpJsonBoolFunc(str, isDpiOpenArray);
dumpJsonBoolFunc(str, isFuncReturn);
dumpJsonBoolFunc(str, isFuncLocal);
dumpJsonStr(str, "attrClocker", (attrClocker().unknown() ? "UNKNOWN" : attrClocker().ascii()));
dumpJsonStr(str, "lifetime", lifetime().ascii());
dumpJsonStr(str, "varType", varType().ascii());
if (dtypep()) dumpJsonStr(str, "dtypeName", dtypep()->name());
dumpJsonBoolFunc(str, isSigUserRdPublic);
dumpJsonBoolFunc(str, isSigUserRWPublic);
dumpJsonBoolFunc(str, isGParam);
dumpJsonBoolFunc(str, isParam);
dumpJsonBoolFunc(str, attrScBv);
dumpJsonBoolFunc(str, attrSFormat);
dumpJsonGen(str);
}
bool AstVar::same(const AstNode* samep) const {
const AstVar* const asamep = VN_DBG_AS(samep, Var);
return name() == asamep->name() && varType() == asamep->varType();
}
void AstWhile::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (unrollFull().isSetTrue())
str << " [unrollfull]";
else if (unrollFull().isSetFalse())
str << " [unrolldis]";
}
void AstScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [abovep=" << nodeAddr(aboveScopep()) << "]";
str << " [cellp=" << nodeAddr(aboveCellp()) << "]";
str << " [modp=" << nodeAddr(modp()) << "]";
}
void AstScope::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
bool AstScope::same(const AstNode* samep) const {
const AstScope* const asamep = VN_DBG_AS(samep, Scope);
return name() == asamep->name()
@@ -2027,22 +2326,44 @@ void AstScopeName::dump(std::ostream& str) const {
if (dpiExport()) str << " [DPIEX]";
if (forFormat()) str << " [FMT]";
}
void AstScopeName::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, dpiExport);
dumpJsonBoolFunc(str, forFormat);
dumpJsonGen(str);
}
void AstSenTree::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isMulti()) str << " [MULTI]";
}
void AstSenTree::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isMulti);
dumpJsonGen(str);
}
void AstSenItem::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << edgeType().ascii() << "]";
}
void AstSenItem::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "edgeType", edgeType().ascii());
dumpJsonGen(str);
}
void AstStrengthSpec::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")";
}
void AstStrengthSpec::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "strength0", m_s0.ascii());
dumpJsonStr(str, "strength1", m_s1.ascii());
dumpJsonGen(str);
}
void AstParseRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << expect().ascii() << "]";
}
void AstParseRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "expect", expect().ascii());
dumpJsonGen(str);
}
void AstClassOrPackageRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (classOrPackageNodep()) str << " cpkg=" << nodeAddr(classOrPackageNodep());
@@ -2053,6 +2374,7 @@ void AstClassOrPackageRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
void AstClassOrPackageRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
AstNodeModule* AstClassOrPackageRef::classOrPackagep() const {
AstNode* foundp = m_classOrPackageNodep;
if (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
@@ -2065,6 +2387,10 @@ void AstDot::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (colon()) str << " [::]";
}
void AstDot::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, colon);
dumpJsonGen(str);
}
void AstActive::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " => ";
@@ -2074,6 +2400,7 @@ void AstActive::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
void AstActive::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
@@ -2085,6 +2412,10 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, dotted);
dumpJsonGen(str);
}
void AstNodeFTask::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (classMethod()) str << " [METHOD]";
@@ -2122,10 +2453,26 @@ bool AstNodeFTask::getPurityRecurse() const {
}
return true;
}
void AstNodeFTask::dumpJson(std::ostream& str) const {
dumpJsonBool(str, "method", classMethod());
dumpJsonBoolFunc(str, dpiExport);
dumpJsonBoolFunc(str, dpiImport);
dumpJsonBoolFunc(str, dpiOpenChild);
dumpJsonBoolFunc(str, dpiOpenParent);
dumpJsonBoolFunc(str, prototype);
dumpJsonBoolFunc(str, recursive);
dumpJsonBoolFunc(str, taskPublic);
dumpJsonStrFunc(str, cname);
dumpJsonGen(str);
}
void AstNodeBlock::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (unnamed()) str << " [UNNAMED]";
}
void AstNodeBlock::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, unnamed);
dumpJsonGen(str);
}
void AstBegin::dump(std::ostream& str) const {
this->AstNodeBlock::dump(str);
if (generate()) str << " [GEN]";
@@ -2133,17 +2480,37 @@ void AstBegin::dump(std::ostream& str) const {
if (implied()) str << " [IMPLIED]";
if (needProcess()) str << " [NPRC]";
}
void AstBegin::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, generate);
dumpJsonBool(str, "genfor", bool(genforp()));
dumpJsonBoolFunc(str, implied);
dumpJsonBoolFunc(str, needProcess);
dumpJsonGen(str);
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
if (!page().empty()) str << " page=" << page();
if (!linescov().empty()) str << " lc=" << linescov();
if (this->dataDeclNullp()) {
static bool s_recursing = false;
str << " -> ";
this->dataDeclNullp()->dump(str);
if (s_recursing) {
str << "%ErrorRECURSIVE";
} else {
s_recursing = true;
this->dataDeclNullp()->dump(str);
s_recursing = false;
}
} else {
if (binNum()) str << " bin" << std::dec << binNum();
}
}
void AstCoverDecl::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, page);
dumpJsonStrFunc(str, linescov);
dumpJsonNumFunc(str, binNum);
dumpJsonGen(str);
}
void AstCoverInc::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
str << " -> ";
@@ -2153,14 +2520,23 @@ void AstCoverInc::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstCoverInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstFork::dump(std::ostream& str) const {
this->AstNodeBlock::dump(str);
if (!joinType().join()) str << " [" << joinType() << "]";
}
void AstFork::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "joinType", joinType().ascii());
dumpJsonGen(str);
}
void AstTraceDecl::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
if (code()) str << " [code=" << code() << "]";
}
void AstTraceDecl::dumpJson(std::ostream& str) const {
dumpJsonNumFunc(str, code);
dumpJsonGen(str);
}
void AstTraceInc::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
str << " -> ";
@@ -2170,25 +2546,41 @@ void AstTraceInc::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstNodeText::dump(std::ostream& str) const {
this->AstNode::dump(str);
void AstTraceInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
string AstNodeText::shortText() const {
string out = text();
string::size_type pos;
if ((pos = out.find('\n')) != string::npos) {
out.erase(pos, out.length() - pos);
out += "...";
}
str << " \"" << out << "\"";
return out;
}
void AstNodeText::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " \"" << shortText() << "\"";
}
void AstNodeText::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, shortText);
dumpJsonGen(str);
}
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeFile::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
void AstVFile::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstCFile::dump(std::ostream& str) const {
this->AstNodeFile::dump(str);
if (source()) str << " [SRC]";
if (slow()) str << " [SLOW]";
}
void AstCFile::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, source);
dumpJsonBoolFunc(str, slow);
dumpJsonGen(str);
}
void AstCFunc::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (slow()) str << " [SLOW]";
@@ -2206,6 +2598,22 @@ void AstCFunc::dump(std::ostream& str) const {
if (needProcess()) str << " [NPRC]";
if (entryPoint()) str << " [ENTRY]";
}
void AstCFunc::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, slow);
dumpJsonBoolFunc(str, isStatic);
dumpJsonBoolFunc(str, dpiExportDispatcher);
dumpJsonBoolFunc(str, dpiExportImpl);
dumpJsonBoolFunc(str, dpiImportPrototype);
dumpJsonBoolFunc(str, dpiImportWrapper);
dumpJsonBoolFunc(str, dpiContext);
dumpJsonBoolFunc(str, isConstructor);
dumpJsonBoolFunc(str, isDestructor);
dumpJsonBoolFunc(str, isVirtual);
dumpJsonBoolFunc(str, isCoroutine);
dumpJsonBoolFunc(str, needProcess);
dumpJsonGen(str);
// TODO: maybe try to shorten these flags somehow
}
void AstCAwait::dump(std::ostream& str) const {
this->AstNodeUniop::dump(str);
if (sensesp()) {
@@ -2213,6 +2621,7 @@ void AstCAwait::dump(std::ostream& str) const {
sensesp()->dump(str);
}
}
void AstCAwait::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
int AstCMethodHard::instrCount() const {
if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) {
// TODO: add a more structured description of library methods, rather than using string
@@ -2300,6 +2709,10 @@ void AstCUse::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << useType() << "]";
}
void AstCUse::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "useType", useType().ascii());
dumpJsonGen(str);
}
AstAlways* AstAssignW::convertToAlways() {
const bool hasTimingControl = isTimingControl();
@@ -2320,7 +2733,27 @@ AstAlways* AstAssignW::convertToAlways() {
return newp;
}
string AstCase::pragmaString() const {
if (fullPragma() && parallelPragma())
return "synthesis full_case parallel_case";
else if (fullPragma())
return "synthesis full_case";
else if (parallelPragma())
return "synthesis parallel_case";
else if (uniquePragma())
return "unique case";
else if (unique0Pragma())
return "unique0 case";
else if (priorityPragma())
return "priority case";
return "";
}
void AstDelay::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
if (isCycleDelay()) str << " [CYCLE]";
}
void AstDelay::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isCycleDelay);
dumpJsonGen(str);
}
+1 -1
View File
@@ -366,5 +366,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
{ BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeEitherLevel() >= 3);
}
+3 -3
View File
@@ -67,10 +67,10 @@ class V3CCtorsBuilder final {
string preventUnusedStmt;
if (m_type.isClass()) {
funcp->argTypes(EmitCBase::symClassVar());
preventUnusedStmt = "if (false && vlSymsp) {} // Prevent unused\n";
preventUnusedStmt = "(void)vlSymsp; // Prevent unused variable warning\n";
} else if (m_type.isCoverage()) {
funcp->argTypes("bool first");
preventUnusedStmt = "if (false && first) {} // Prevent unused\n";
preventUnusedStmt = "(void)first; // Prevent unused variable warning\n";
}
if (!preventUnusedStmt.empty()) {
funcp->addStmtsp(new AstCStmt{m_modp->fileline(), preventUnusedStmt});
@@ -252,5 +252,5 @@ void V3CCtors::cctorsAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
evalAsserts();
{ CCtorsVisitor{v3Global.rootp()}; }
V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -117,5 +117,5 @@ void V3CUse::cUseAll() {
// for each output file and put under that
CUseVisitor{modp};
}
V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -602,7 +602,7 @@ public:
void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("case", 0, dumpTreeEitherLevel() >= 3);
}
void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
+1 -1
View File
@@ -236,5 +236,5 @@ public:
void V3Cast::castAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CastVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeEitherLevel() >= 3);
}
+28 -1
View File
@@ -49,12 +49,39 @@ class ClassVisitor final : public VNVisitor {
// METHODS
bool recurseImplements(AstClass* nodep, bool setit) {
// Returns true to set useVirtualPublic().
// If there's an implements of an interface class then we have
// multiple classes that point to same object, that need same
// VlClass (the diamond problem). C++ will require we use 'virtual
// public' for VlClass. So, we need the interface class, and all
// classes above, and any below using any implements to use
// 'virtual public' via useVirtualPublic().
if (nodep->useVirtualPublic()) return true; // Short-circuit
if (nodep->isInterfaceClass()) setit = true;
for (const AstClassExtends* extp = nodep->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
if (recurseImplements(extp->classp(), setit)) setit = true;
}
if (setit) {
nodep->useVirtualPublic(true);
for (const AstClassExtends* extp = nodep->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
(void)recurseImplements(extp->classp(), true);
}
}
return setit;
}
// VISITORS
void visit(AstClass* nodep) override {
if (nodep->user1SetOnce()) return;
// Move this class
nodep->name(m_prefix + nodep->name());
nodep->unlinkFrBack();
v3Global.rootp()->addModulesp(nodep);
(void)recurseImplements(nodep, false);
// Make containing package
// Note origName is the same as the class origName so errors look correct
AstClassPackage* const packagep
@@ -240,5 +267,5 @@ public:
void V3Class::classAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClassVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("class", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("class", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -320,5 +320,5 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CleanVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeEitherLevel() >= 3);
}
+10 -3
View File
@@ -122,8 +122,15 @@ class ClockVisitor final : public VNVisitor {
AstNodeExpr* const origp = nodep->origp()->unlinkFrBack();
AstNodeExpr* const changeWrp = nodep->changep()->unlinkFrBack();
AstNodeExpr* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
AstIf* const newp
= new AstIf{nodep->fileline(), new AstXor{nodep->fileline(), origp, changeRdp}, incp};
AstNodeExpr* comparedp = nullptr;
// Xor will optimize better than Eq, when CoverToggle has bit selects,
// but can only use Xor with non-opaque types
if (const AstBasicDType* const bdtypep
= VN_CAST(origp->dtypep()->skipRefp(), BasicDType)) {
if (!bdtypep->isOpaque()) comparedp = new AstXor{nodep->fileline(), origp, changeRdp};
}
if (!comparedp) comparedp = AstEq::newTyped(nodep->fileline(), origp, changeRdp);
AstIf* const newp = new AstIf{nodep->fileline(), comparedp, incp};
// We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though versus a potential memory miss.
// We'll go with the miss.
@@ -217,5 +224,5 @@ public:
void V3Clock::clockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clock", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("clock", 0, dumpTreeEitherLevel() >= 3);
}
+2 -2
View File
@@ -43,7 +43,7 @@ class CombineVisitor final : VNVisitor {
// TYPES
using funcit_t = std::list<AstCFunc*>::iterator;
struct CFuncs {
struct CFuncs final {
std::list<AstCFunc*> m_fast;
std::list<AstCFunc*> m_slow;
};
@@ -235,5 +235,5 @@ public:
void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
CombineVisitor::apply(nodep);
V3Global::dumpCheckGlobalTree("combine", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("combine", 0, dumpTreeEitherLevel() >= 3);
}
+2 -2
View File
@@ -98,7 +98,7 @@ static void makeToString(AstClass* nodep) {
funcp->isStatic(false);
funcp->protect(false);
AstCExpr* const exprp
= new AstCExpr{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0};
= new AstCExpr{nodep->fileline(), R"("'{"s + to_string_middle() + "}")", 0};
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp);
@@ -172,5 +172,5 @@ void V3Common::commonAll() {
if (!dtypep->packed()) makeVlToString(dtypep);
}
}
V3Global::dumpCheckGlobalTree("common", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("common", 0, dumpTreeEitherLevel() >= 3);
}
+32 -12
View File
@@ -41,6 +41,14 @@
VL_DEFINE_DEBUG_FUNCTIONS;
#define TREE_SKIP_VISIT(...)
#define TREEOP1(...)
#define TREEOPA(...)
#define TREEOP(...)
#define TREEOPS(...)
#define TREEOPC(...)
#define TREEOPV(...)
//######################################################################
// Utilities
@@ -533,10 +541,11 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp());
restorer.disableRestore(); // Now all checks passed
} else if (nodep->type() == m_rootp->type()) { // And, Or, Xor
// subtree under NOT can be optimized only in XOR tree.
CONST_BITOP_RETURN_IF(!m_polarity && !isXorTree(), nodep);
incrOps(nodep, __LINE__);
VL_RESTORER(m_leafp);
for (const bool right : {false, true}) {
VL_RESTORER(m_leafp);
Restorer restorer{*this};
LeafInfo leafInfo{m_lsb};
m_leafp = &leafInfo;
@@ -549,6 +558,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
// Reach past a cast then add to frozen nodes to be added to final reduction
if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp();
const bool pol = isXorTree() || m_polarity; // Only AND/OR tree needs polarity
UASSERT(pol, "AND/OR tree expects m_polarity==true");
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{pol, m_lsb});
m_failed = origFailed;
continue;
@@ -576,6 +586,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
} else if ((isAndTree() && VN_IS(nodep, Eq)) || (isOrTree() && VN_IS(nodep, Neq))) {
Restorer restorer{*this};
CONST_BITOP_RETURN_IF(!m_polarity, nodep);
CONST_BITOP_RETURN_IF(m_lsb, nodep); // the result of EQ/NE is 1 bit width
const AstNode* lhsp = nodep->lhsp();
if (const AstCCast* const castp = VN_CAST(lhsp, CCast)) lhsp = castp->lhsp();
const AstConst* const constp = VN_CAST(lhsp, Const);
@@ -584,7 +595,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
const V3Number& compNum = constp->num();
auto setPolarities = [this, &compNum](const LeafInfo& ref, const V3Number* maskp) {
const bool maskFlip = isOrTree();
const bool maskFlip = isAndTree() ^ ref.polarity();
int constantWidth = compNum.width();
if (maskp) constantWidth = std::max(constantWidth, maskp->width());
const int maxBitIdx = std::max(ref.lsb() + constantWidth, ref.msb() + 1);
@@ -1430,16 +1441,22 @@ class ConstVisitor final : public VNVisitor {
static bool operandsSame(AstNode* node1p, AstNode* node2p) {
// For now we just detect constants & simple vars, though it could be more generic
if (VN_IS(node1p, Const) && VN_IS(node2p, Const)) {
return node1p->sameGateTree(node2p);
} else if (VN_IS(node1p, VarRef) && VN_IS(node2p, VarRef)) {
if (VN_IS(node1p, Const) && VN_IS(node2p, Const)) return node1p->sameGateTree(node2p);
if (VN_IS(node1p, VarRef) && VN_IS(node2p, VarRef)) {
// Avoid comparing widthMin's, which results in lost optimization attempts
// If cleanup sameGateTree to be smarter, this can be restored.
// return node1p->sameGateTree(node2p);
return node1p->isSame(node2p);
} else {
return false;
}
// Pattern created by coverage-line; avoid compiler tautological-compare warning
if (AstAnd* const and1p = VN_CAST(node1p, And)) {
if (AstAnd* const and2p = VN_CAST(node2p, And)) {
if (VN_IS(and1p->lhsp(), Const) && VN_IS(and1p->rhsp(), NodeVarRef)
&& VN_IS(and2p->lhsp(), Const) && VN_IS(and2p->rhsp(), NodeVarRef))
return node1p->sameGateTree(node2p);
}
}
return false;
}
bool ifSameAssign(const AstNodeIf* nodep) {
const AstNodeAssign* const thensp = VN_CAST(nodep->thensp(), NodeAssign);
@@ -1882,6 +1899,8 @@ class ConstVisitor final : public VNVisitor {
}
void replaceShiftOp(AstNodeBiop* nodep) {
UINFO(5, "SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl);
const int width = nodep->width();
const int widthMin = nodep->widthMin();
VNRelinker handle;
nodep->unlinkFrBack(&handle);
AstNodeBiop* const lhsp = VN_AS(nodep->lhsp(), NodeBiop);
@@ -1898,6 +1917,7 @@ class ConstVisitor final : public VNVisitor {
AstNodeBiop* const newp = lhsp;
newp->lhsp(shift1p);
newp->rhsp(shift2p);
newp->dtypeChgWidth(width, widthMin); // The new AND must have width of the original SHIFT
handle.relink(newp);
iterate(newp); // Further reduce, either node may have more reductions.
}
@@ -3873,7 +3893,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeEitherLevel() >= 3);
}
void V3Const::constifyCpp(AstNetlist* nodep) {
@@ -3882,7 +3902,7 @@ void V3Const::constifyCpp(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTreeEitherLevel() >= 3);
}
AstNode* V3Const::constifyEdit(AstNode* nodep) {
@@ -3906,7 +3926,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeEitherLevel() >= 3);
}
void V3Const::constifyAll(AstNetlist* nodep) {
@@ -3916,7 +3936,7 @@ void V3Const::constifyAll(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeEitherLevel() >= 3);
}
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {
+30 -18
View File
@@ -39,7 +39,7 @@ class CoverageVisitor final : public VNVisitor {
// TYPES
using LinenoSet = std::set<int>;
struct ToggleEnt {
struct ToggleEnt final {
const string m_comment; // Comment for coverage dump
AstNodeExpr* m_varRefp; // How to get to this element
AstNodeExpr* m_chgRefp; // How to get to this element
@@ -54,7 +54,7 @@ class CoverageVisitor final : public VNVisitor {
}
};
struct CheckState { // State save-restored on each new coverage scope/block
struct CheckState final { // State save-restored on each new coverage scope/block
bool m_on = false; // Should this block get covered?
bool m_inModOff = false; // In module with no coverage
int m_handle = 0; // Opaque handle for index into line tracking
@@ -273,7 +273,7 @@ class CoverageVisitor final : public VNVisitor {
// We'll do this, and make the if(...) coverinc later.
// Add signal to hold the old value
const string newvarname = std::string{"__Vtogcov__"} + nodep->shortName();
const string newvarname = "__Vtogcov__"s + nodep->shortName();
FileLine* const fl_nowarn = new FileLine{nodep->fileline()};
fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
AstVar* const chgVarp
@@ -284,7 +284,7 @@ class CoverageVisitor final : public VNVisitor {
// This is necessarily an O(n^2) expansion, which is why
// we limit coverage to signals with < 256 bits.
ToggleEnt newvec{std::string{""}, new AstVarRef{fl_nowarn, nodep, VAccess::READ},
ToggleEnt newvec{""s, new AstVarRef{fl_nowarn, nodep, VAccess::READ},
new AstVarRef{fl_nowarn, chgVarp, VAccess::WRITE}};
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp);
newvec.cleanup();
@@ -308,8 +308,7 @@ class CoverageVisitor final : public VNVisitor {
for (int index_docs = bdtypep->lo(); index_docs < bdtypep->hi() + 1;
++index_docs) {
const int index_code = index_docs - bdtypep->lo();
ToggleEnt newent{above.m_comment + std::string{"["} + cvtToStr(index_docs)
+ "]",
ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]",
new AstSel{varp->fileline(), above.m_varRefp->cloneTree(true),
index_code, 1},
new AstSel{varp->fileline(), above.m_chgRefp->cloneTree(true),
@@ -323,7 +322,7 @@ class CoverageVisitor final : public VNVisitor {
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent{above.m_comment + std::string{"["} + cvtToStr(index_docs) + "]",
ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]",
new AstArraySel{varp->fileline(),
above.m_varRefp->cloneTree(true), index_code},
new AstArraySel{varp->fileline(),
@@ -336,7 +335,7 @@ class CoverageVisitor final : public VNVisitor {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
const AstNodeDType* const subtypep = adtypep->subDTypep()->skipRefp();
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent{above.m_comment + std::string{"["} + cvtToStr(index_docs) + "]",
ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]",
new AstSel{varp->fileline(), above.m_varRefp->cloneTree(true),
index_code * subtypep->width(), subtypep->width()},
new AstSel{varp->fileline(), above.m_chgRefp->cloneTree(true),
@@ -351,7 +350,7 @@ class CoverageVisitor final : public VNVisitor {
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
const int index_code = itemp->lsb();
ToggleEnt newent{above.m_comment + std::string{"."} + itemp->name(),
ToggleEnt newent{above.m_comment + "."s + itemp->name(),
new AstSel{varp->fileline(), above.m_varRefp->cloneTree(true),
index_code, subtypep->width()},
new AstSel{varp->fileline(), above.m_chgRefp->cloneTree(true),
@@ -366,11 +365,10 @@ class CoverageVisitor final : public VNVisitor {
AstNodeExpr* const varRefp = new AstStructSel{
varp->fileline(), above.m_varRefp->cloneTree(true), itemp->name()};
AstNodeExpr* const chgRefp = new AstStructSel{
varp->fileline(), above.m_varRefp->cloneTree(true), itemp->name()};
varp->fileline(), above.m_chgRefp->cloneTree(true), itemp->name()};
varRefp->dtypep(subtypep);
chgRefp->dtypep(subtypep);
ToggleEnt newent{above.m_comment + std::string{"."} + itemp->name(), varRefp,
chgRefp};
ToggleEnt newent{above.m_comment + "."s + itemp->name(), varRefp, chgRefp};
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
newent.cleanup();
}
@@ -379,12 +377,26 @@ class CoverageVisitor final : public VNVisitor {
// Arbitrarily handle only the first member of the union
if (const AstMemberDType* const itemp = adtypep->membersp()) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
ToggleEnt newent{above.m_comment + std::string{"."} + itemp->name(),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true)};
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
newent.cleanup();
if (adtypep->packed()) {
ToggleEnt newent{above.m_comment + "."s + itemp->name(),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true)};
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
newent.cleanup();
} else {
AstNodeExpr* const varRefp = new AstStructSel{
varp->fileline(), above.m_varRefp->cloneTree(true), itemp->name()};
AstNodeExpr* const chgRefp = new AstStructSel{
varp->fileline(), above.m_chgRefp->cloneTree(true), itemp->name()};
varRefp->dtypep(subtypep);
chgRefp->dtypep(subtypep);
ToggleEnt newent{above.m_comment + "."s + itemp->name(), varRefp, chgRefp};
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
newent.cleanup();
}
}
} else if (VN_IS(dtypep, QueueDType)) {
// Not covered
} else {
dtypep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "
<< dtypep->prettyTypeName());
@@ -556,5 +568,5 @@ public:
void V3Coverage::coverage(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coverage", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("coverage", 0, dumpTreeEitherLevel() >= 3);
}
+35 -33
View File
@@ -48,45 +48,47 @@ class CoverageJoinVisitor final : public VNVisitor {
V3DupFinder dupFinder; // Duplicate code detection
// Hash all of the original signals we toggle cover
for (AstCoverToggle* nodep : m_toggleps) dupFinder.insert(nodep->origp());
if (dumpLevel() || debug() >= 9)
dupFinder.dumpFile(v3Global.debugFilename("coveragejoin") + ".hash", false);
// Find if there are any duplicates
for (AstCoverToggle* nodep : m_toggleps) {
// nodep->backp() is null if we already detected it's a duplicate and unlinked it.
if (nodep->backp()) {
// Want to choose a base node, and keep finding duplicates that are identical.
// This prevents making chains where a->b, then c->d, then b->c, as we'll
// find a->b, a->c, a->d directly.
while (true) {
const auto dupit = dupFinder.findDuplicate(nodep->origp());
if (dupit == dupFinder.end()) break;
//
const AstNode* const duporigp = dupit->second;
// Note hashed will point to the original variable (what's
// duplicated), not the covertoggle, but we need to get back to the
// covertoggle which is immediately above, so:
AstCoverToggle* const removep = VN_AS(duporigp->backp(), CoverToggle);
UASSERT_OBJ(removep, nodep, "CoverageJoin duplicate of wrong type");
UINFO(8, " Orig " << nodep << " -->> " << nodep->incp()->declp() << endl);
UINFO(8, " dup " << removep << " -->> " << removep->incp()->declp() << endl);
// The CoverDecl the duplicate pointed to now needs to point to the
// original's data. I.e. the duplicate will get the coverage number
// from the non-duplicate
AstCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
removep->incp()->declp()->dataDeclp(datadeclp);
UINFO(8, " new " << removep->incp()->declp() << endl);
// Mark the found node as a duplicate of the first node
// (Not vice-versa as we have the iterator for the found node)
removep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(removep), removep);
// Remove node from comparison so don't hit it again
dupFinder.erase(dupit);
++m_statToggleJoins;
}
// nodep->backp() is null if we already detected it's a duplicate and unlinked earlier
if (!nodep->backp()) continue;
// Want to choose a base node, and keep finding duplicates that are identical.
// This prevents making chains where a->b, then c->d, then b->c, as we'll
// find a->b, a->c, a->d directly.
while (true) {
const auto dupit = dupFinder.findDuplicate(nodep->origp());
if (dupit == dupFinder.end()) break;
const AstNode* const duporigp = dupit->second;
// Remove node from comparison so don't hit it again
dupFinder.erase(dupit);
//
// Note dupFinder will point to the original toggle-increment equation (what's
// duplicated), not the covertoggle, but we need to get back to the
// covertoggle which is immediately above, so:
AstCoverToggle* const removep = VN_AS(duporigp->backp(), CoverToggle);
UASSERT_OBJ(removep, nodep, "CoverageJoin duplicate of wrong type");
UINFO(8, " Orig " << nodep << " -->> " << nodep->incp()->declp() << endl);
UINFO(8, " dup " << removep << " -->> " << removep->incp()->declp() << endl);
// The CoverDecl the duplicate pointed to now needs to point to the
// original's data. I.e. the duplicate will get the coverage number
// from the non-duplicate
AstCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
removep->incp()->declp()->dataDeclp(datadeclp);
UINFO(8, " new " << removep->incp()->declp() << endl);
// Mark the found node as a duplicate of the first node
// (Not vice-versa as we have the iterator for the found node)
removep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(removep), removep);
++m_statToggleJoins;
}
}
}
// VISITORS
void visit(AstNetlist* nodep) override {
void visit(AstActive* nodep) override {
m_toggleps.clear();
// Find all Coverage's
iterateChildren(nodep);
// Simplify
@@ -114,5 +116,5 @@ public:
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageJoinVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeEitherLevel() >= 3);
}
+5 -5
View File
@@ -543,29 +543,29 @@ void V3Dead::deadifyModules(AstNetlist* nodep) {
{
DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeLevel() >= 6);
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeEitherLevel() >= 6);
}
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeEitherLevel() >= 3);
}
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeEitherLevel() >= 3);
}
void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeEitherLevel() >= 3);
}
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -649,5 +649,5 @@ public:
void V3Delayed::delayedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DelayedVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("delayed", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("delayed", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -160,5 +160,5 @@ public:
void V3Depth::depthAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("depth", 0, dumpTreeLevel() >= 6);
V3Global::dumpCheckGlobalTree("depth", 0, dumpTreeEitherLevel() >= 6);
}
+1 -1
View File
@@ -121,5 +121,5 @@ public:
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthBlockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTreeEitherLevel() >= 3);
}
+1 -1
View File
@@ -300,5 +300,5 @@ public:
void V3Descope::descopeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DescopeVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("descope", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("descope", 0, dumpTreeEitherLevel() >= 3);
}
+2 -2
View File
@@ -109,12 +109,12 @@ class DfgGraph final {
// cppcheck-suppress noExplicitConstructor
UserDataInUse(UserDataInUse&& that) {
UASSERT(that.m_graphp, "Moving from empty");
m_graphp = vlstd::exchange(that.m_graphp, nullptr);
m_graphp = std::exchange(that.m_graphp, nullptr);
}
VL_UNCOPYABLE(UserDataInUse);
UserDataInUse& operator=(UserDataInUse&& that) {
UASSERT(that.m_graphp, "Moving from empty");
m_graphp = vlstd::exchange(that.m_graphp, nullptr);
m_graphp = std::exchange(that.m_graphp, nullptr);
return *this;
}
+1 -1
View File
@@ -77,7 +77,7 @@ class AstToDfgVisitor final : public VNVisitor {
// TYPES
// Represents a driver during canonicalization
struct Driver {
struct Driver final {
FileLine* m_fileline;
DfgVertex* m_vtxp;
uint32_t m_lsb;
+1 -1
View File
@@ -122,7 +122,7 @@ class ExtractCyclicComponents final {
static constexpr size_t UNASSIGNED = std::numeric_limits<size_t>::max();
// TYPES
struct VertexState {
struct VertexState final {
size_t index = UNASSIGNED; // Used by Pearce's algorithm for detecting SCCs
size_t component = UNASSIGNED; // Result component number (0 stays in input graph)
bool merged = false; // Visited in the merging pass
+30 -2
View File
@@ -25,6 +25,8 @@
#include "V3AstUserAllocator.h"
#include "V3Dfg.h"
#include "V3DfgPasses.h"
#include "V3DfgPatternStats.h"
#include "V3File.h"
#include "V3Graph.h"
#include "V3UniqueNames.h"
@@ -233,7 +235,7 @@ void V3DfgOptimizer::extract(AstNetlist* netlistp) {
UINFO(2, __FUNCTION__ << ": " << endl);
// Extract more optimization candidates
DataflowExtractVisitor::apply(netlistp);
V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeLevel() >= 3);
V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeEitherLevel() >= 3);
}
void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
@@ -252,6 +254,8 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
V3DfgOptimizationContext ctx{label};
V3DfgPatternStats patternStats;
// Run the optimization phase
for (AstNode* nodep = netlistp->modulesp(); nodep; nodep = nodep->nextp()) {
// Only optimize proper modules
@@ -295,10 +299,34 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
dfg->addGraph(*component);
}
// Accumulate patterns from the optimized graph for reporting
if (v3Global.opt.stats()) patternStats.accumulate(*dfg);
// Convert back to Ast
if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized");
AstModule* const resultModp = V3DfgPasses::dfgToAst(*dfg, ctx);
UASSERT_OBJ(resultModp == modp, modp, "Should be the same module");
}
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeLevel() >= 3);
// Print the collected patterns
if (v3Global.opt.stats()) {
// Label to lowercase, without spaces
std::string ident = label;
std::transform(ident.begin(), ident.end(), ident.begin(), [](unsigned char c) { //
return c == ' ' ? '_' : std::tolower(c);
});
// File to dump to
const std::string filename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
+ "__stats_dfg_patterns__" + ident + ".txt";
// Open, write, close
std::ofstream* const ofp = V3File::new_ofstream(filename);
if (ofp->fail()) v3fatal("Can't write " << filename);
patternStats.dump(label, *ofp);
ofp->close();
VL_DO_DANGLING(delete ofp, ofp);
}
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3);
}
+197
View File
@@ -0,0 +1,197 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Implementations of simple passes over DfgGraph
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#include "V3PchAstNoMT.h"
#include "V3Dfg.h"
#include "V3DfgPasses.h"
#include <algorithm>
#include <map>
#include <unordered_map>
class V3DfgPatternStats final {
static constexpr uint32_t MIN_PATTERN_DEPTH = 1;
static constexpr uint32_t MAX_PATTERN_DEPTH = 4;
std::map<std::string, std::string> m_internedConsts; // Interned constants
std::map<const AstVar*, std::string> m_internedVars; // Interned variables
std::map<uint32_t, std::string> m_internedSelLsbs; // Interned lsb value for selects
std::map<uint32_t, std::string> m_internedWordWidths; // Interned widths
std::map<uint32_t, std::string> m_internedWideWidths; // Interned widths
std::map<const DfgVertex*, std::string> m_internedVertices; // Interned vertices
// Maps from pattern to the number of times it appears, for each pattern depth
std::vector<std::unordered_map<std::string, size_t>> m_patterCounts{MAX_PATTERN_DEPTH + 1};
static std::string toLetters(size_t value, bool lowerCase = false) {
const char base = lowerCase ? 'a' : 'A';
std::string s;
do { s += static_cast<char>(base + value % 26); } while (value /= 26);
return s;
}
const std::string& internConst(const DfgConst& vtx) {
const auto pair = m_internedConsts.emplace(vtx.num().ascii(false), "c");
if (pair.second) pair.first->second += toLetters(m_internedConsts.size() - 1);
return pair.first->second;
}
const std::string& internVar(const DfgVertexVar& vtx) {
const auto pair = m_internedVars.emplace(vtx.varp(), "v");
if (pair.second) pair.first->second += toLetters(m_internedVars.size() - 1);
return pair.first->second;
}
const std::string& internSelLsb(uint32_t value) {
const auto pair = m_internedSelLsbs.emplace(value, "");
if (pair.second) pair.first->second += toLetters(m_internedSelLsbs.size() - 1);
return pair.first->second;
}
const std::string& internWordWidth(uint32_t value) {
const auto pair = m_internedWordWidths.emplace(value, "");
if (pair.second) pair.first->second += toLetters(m_internedWordWidths.size() - 1, true);
return pair.first->second;
}
const std::string& internWideWidth(uint32_t value) {
const auto pair = m_internedWideWidths.emplace(value, "");
if (pair.second) pair.first->second += toLetters(m_internedWideWidths.size() - 1);
return pair.first->second;
}
const std::string& internVertex(const DfgVertex& vtx) {
const auto pair = m_internedVertices.emplace(&vtx, "_");
if (pair.second) pair.first->second += toLetters(m_internedVertices.size() - 1);
return pair.first->second;
}
// Render the vertx into ss, and return true if the recursion reached the given depth,
// meaning an S-expression with that nesting level has been rendered.
bool render(std::ostringstream& ss, const DfgVertex& vtx, uint32_t depth) {
bool deep = depth == 0;
if (const DfgConst* const constp = vtx.cast<DfgConst>()) {
// Base case 1: constant
if (constp->isZero()) {
ss << "'0";
} else if (constp->isOnes()) {
ss << "'1";
} else {
ss << internConst(*constp);
}
} else if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
// Base case 2: variable
ss << internVar(*varp);
} else if (depth == 0) {
// Base case 3: deep vertex
ss << internVertex(vtx);
} else {
// Recursively print an S-expression for the vertex
// S-expression begin
ss << '(';
// Name
ss << vtx.typeName();
// Specials
if (const DfgSel* const selp = vtx.cast<DfgSel>()) {
ss << '@';
if (selp->lsb() == 0) {
ss << '0';
} else {
ss << internSelLsb(selp->lsb());
}
}
// Operands
vtx.forEachSource([&](const DfgVertex& src) {
ss << ' ';
if (render(ss, src, depth - 1)) deep = true;
});
// S-expression end
ss << ')';
// Mark it if it has multiple sinks
if (vtx.hasMultipleSinks()) ss << '*';
}
// Annotate type
ss << ':';
const AstNodeDType* const dtypep = vtx.dtypep();
if (!VN_IS(dtypep, BasicDType)) {
dtypep->dumpSmall(ss);
} else {
const uint32_t width = dtypep->width();
if (width == 1) {
ss << '1';
} else if (width <= VL_QUADSIZE) {
ss << internWordWidth(width);
} else {
ss << internWideWidth(width);
}
}
// Done
return deep;
}
public:
V3DfgPatternStats() = default;
void accumulate(const DfgGraph& dfg) {
dfg.forEachVertex([&](const DfgVertex& vtx) {
for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) {
std::ostringstream ss;
if (render(ss, vtx, i)) m_patterCounts[i][ss.str()] += 1;
m_internedConsts.clear();
m_internedVars.clear();
m_internedSelLsbs.clear();
m_internedWordWidths.clear();
m_internedWideWidths.clear();
m_internedVertices.clear();
}
});
}
void dump(const std::string& stage, std::ostream& os) {
using Line = std::pair<std::string, size_t>;
for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) {
os << "DFG '" << stage << "' patterns with depth " << i << '\n';
// Pick up pattern accumulators with given depth
const auto& patternCounts = m_patterCounts[i];
// Sort patterns, first by descending frequency, then lexically
std::vector<Line> lines;
lines.reserve(patternCounts.size());
for (const auto& pair : patternCounts) lines.emplace_back(pair);
std::sort(lines.begin(), lines.end(), [](const Line& a, const Line& b) {
if (a.second != b.second) return a.second > b.second;
return a.first < b.first;
});
// Print each pattern
for (const auto& line : lines) {
os << ' ' << std::setw(12) << std::right << line.second;
os << ' ' << std::left << line.first << '\n';
}
// Trailing new-line to separate sections
os << '\n';
}
}
};

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