mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Merge from master for release.
This commit is contained in:
+18
-45
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract context variables
|
||||
run: |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
==============
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+771
-265
File diff suppressed because it is too large
Load Diff
+129
-87
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -281,6 +281,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3SplitVar.o \
|
||||
V3StackCount.o \
|
||||
V3Subst.o \
|
||||
V3TSP.o \
|
||||
V3Table.o \
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user