mirror of
https://github.com/verilator/verilator.git
synced 2026-10-04 17:13:40 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77553d23fc | ||
|
|
3b9c8b64f7 | ||
|
|
7e5f562500 | ||
|
|
d4d3ae4dfc | ||
|
|
79b1b07fcd | ||
|
|
e3cf5c07e4 | ||
|
|
8750352495 | ||
|
|
3d8dc2774b | ||
|
|
0a9ae154be | ||
|
|
e25a6334cf | ||
|
|
070bead9f9 | ||
|
|
549921be2e | ||
|
|
7c05033b79 | ||
|
|
215d3614c0 | ||
|
|
1ebf937a6c | ||
|
|
7be343fd7c | ||
|
|
fb2d78520f | ||
|
|
c5da072ff6 | ||
|
|
efbcb094ca | ||
|
|
5033c906fd | ||
|
|
f8ab30d127 | ||
|
|
222ca4b009 | ||
|
|
e3a1954e20 | ||
|
|
4ba2637360 | ||
|
|
6430743b6f | ||
|
|
0c49cca527 | ||
|
|
7a9e79ea79 | ||
|
|
157948c552 | ||
|
|
1a127a479c | ||
|
|
87e4a86fbb | ||
|
|
1c1b95161b | ||
|
|
66d1754d19 | ||
|
|
57a53c014d | ||
|
|
e48a859b86 | ||
|
|
430238a6b4 | ||
|
|
9a4c5509fc | ||
|
|
0765443353 | ||
|
|
d07a6f81e4 | ||
|
|
fac04521db | ||
|
|
d0819f156f | ||
|
|
b77eab3f83 | ||
|
|
30f3774134 | ||
|
|
1899a875a4 | ||
|
|
cc134b38ee | ||
|
|
993115d30a | ||
|
|
c1d35c8622 | ||
|
|
16fba59480 | ||
|
|
4266c789ce | ||
|
|
627d83e807 | ||
|
|
80f5738544 | ||
|
|
600641b4a1 | ||
|
|
70eb99b050 | ||
|
|
dc1ad16b03 | ||
|
|
ba5779c69e | ||
|
|
069eb97eca | ||
|
|
96a959154a | ||
|
|
4f88ec3518 | ||
|
|
ef4f91ae5a | ||
|
|
45eccaecaf | ||
|
|
0397e19726 | ||
|
|
687edba969 | ||
|
|
02e83da2fa | ||
|
|
ef04ada12b | ||
|
|
bed3101dfc | ||
|
|
4265f9499d | ||
|
|
6acd5847e7 | ||
|
|
16547077a1 | ||
|
|
3ad3944f2c | ||
|
|
be8f1a25c6 | ||
|
|
f7f3d3fd43 | ||
|
|
4003e01283 | ||
|
|
917d3b0fb3 | ||
|
|
3d073c9534 | ||
|
|
20206b1e2e | ||
|
|
fefe731105 | ||
|
|
1dce6b2500 | ||
|
|
d2fac4aa2f | ||
|
|
132cc1d068 | ||
|
|
f4a72946eb | ||
|
|
e10156548d | ||
|
|
4e6d2cfe38 | ||
|
|
7f3a73e314 | ||
|
|
143050e034 | ||
|
|
8455ee7091 | ||
|
|
9702d11657 | ||
|
|
decbf79f39 | ||
|
|
2d7d2c5992 | ||
|
|
2abbd5c145 | ||
|
|
583605b218 | ||
|
|
67fab0b4fc | ||
|
|
43213fcdc2 | ||
|
|
f632ea500c | ||
|
|
dbb69412e5 | ||
|
|
d7bc0ff5e5 | ||
|
|
14604a24d6 | ||
|
|
816c5e0dc9 | ||
|
|
aa39d020d8 | ||
|
|
b67f1f0e94 | ||
|
|
f5546febe8 | ||
|
|
27181d534e | ||
|
|
698e0fbbd1 | ||
|
|
ea9b65fe6d | ||
|
|
3c1ed075e5 | ||
|
|
6013b54f7b | ||
|
|
d75a8624c1 | ||
|
|
ac04e85a1c | ||
|
|
78aee6f4e7 | ||
|
|
ee9d6dd63f | ||
|
|
034737d2a8 | ||
|
|
72d2cff0a1 | ||
|
|
033e7ac020 | ||
|
|
042d3eed23 | ||
|
|
ea4031cbd3 | ||
|
|
c0127599df | ||
|
|
7c54a451a9 | ||
|
|
2118038cb9 | ||
|
|
9927e8b3ee | ||
|
|
953a442827 | ||
|
|
f3b28c5c74 | ||
|
|
7a33fe2bf2 | ||
|
|
bdecf6c4e1 | ||
|
|
6fcf05e2b6 | ||
|
|
4a5e4b04f3 | ||
|
|
5d98035170 | ||
|
|
20c906261b | ||
|
|
74754d94c3 | ||
|
|
98cd925fda | ||
|
|
e029ba845e | ||
|
|
e53a522662 | ||
|
|
2bc813da4a | ||
|
|
555408b5d3 | ||
|
|
a07f2b3611 | ||
|
|
c85589371a | ||
|
|
1280070abb | ||
|
|
a52f975bd7 | ||
|
|
0c70f0c786 | ||
|
|
edf6a40f19 | ||
|
|
58739a0a99 | ||
|
|
1488f9130d | ||
|
|
a18d8cbe86 | ||
|
|
bfea4b7f99 | ||
|
|
84b8307938 | ||
|
|
ce340658d6 | ||
|
|
a02c420064 | ||
|
|
d55c233427 | ||
|
|
25bbbbd37b | ||
|
|
fdb4d3a145 | ||
|
|
ced1af8cb8 | ||
|
|
f0a6e4c2b2 | ||
|
|
9e5cd463e5 | ||
|
|
bb8899f307 | ||
|
|
1194dbf19c | ||
|
|
0cd4a57ad9 | ||
|
|
1bd1e21a69 | ||
|
|
7e7447812c | ||
|
|
af3ab13012 | ||
|
|
b35b5aacfa | ||
|
|
9c01665078 | ||
|
|
a500140f1d | ||
|
|
dced49a804 | ||
|
|
f8a67b2fe8 | ||
|
|
8cdecd5668 | ||
|
|
75d255a3bf | ||
|
|
0674267333 | ||
|
|
1632160fb1 | ||
|
|
e609328ebb | ||
|
|
8291ef6537 | ||
|
|
30600bf1a3 | ||
|
|
b968f57711 | ||
|
|
ee7b399bf5 | ||
|
|
50c28fa9d3 | ||
|
|
a17f51eac0 | ||
|
|
cc50126ad3 | ||
|
|
9d1a39a5e4 | ||
|
|
82cc1a319f | ||
|
|
2fd23458ce | ||
|
|
271fa5fe3c | ||
|
|
04c96694e6 | ||
|
|
e7bd44561c | ||
|
|
4d5e448664 | ||
|
|
236c2141e3 | ||
|
|
788fe3dc27 | ||
|
|
a2abd361db | ||
|
|
09806d7576 | ||
|
|
a2aa678278 | ||
|
|
0b09636c58 | ||
|
|
af197f2ceb | ||
|
|
748c818ccb | ||
|
|
ad55564905 | ||
|
|
ad2cb45a14 | ||
|
|
277fd9197f | ||
|
|
61ff7039b4 | ||
|
|
7342cf278a | ||
|
|
958654909f | ||
|
|
d9be86d69a | ||
|
|
378d947702 | ||
|
|
98b5417e04 | ||
|
|
0af971292e | ||
|
|
43a2fa080a | ||
|
|
0cdc2e038c | ||
|
|
d4a411db6c | ||
|
|
8d367dc8a3 | ||
|
|
5a4cc333fb | ||
|
|
f13fd4478c | ||
|
|
23e4a0f784 | ||
|
|
aa595d40de | ||
|
|
fa828ac9ba | ||
|
|
b1495f0742 | ||
|
|
8006b5479c | ||
|
|
19c2906a64 | ||
|
|
c367b671b6 | ||
|
|
35226d5e1a | ||
|
|
fac89c5d62 | ||
|
|
f40f0464e2 | ||
|
|
262ed9c03a | ||
|
|
a7edf13d62 | ||
|
|
6e57076726 | ||
|
|
cef56c6fca | ||
|
|
91f30af01f | ||
|
|
3c8953fec2 | ||
|
|
6de78d58fa | ||
|
|
d42f9c095b | ||
|
|
46e10173f8 | ||
|
|
d84c7df38f | ||
|
|
6e2d8df9e5 | ||
|
|
e2b40195b4 | ||
|
|
541f983dba | ||
|
|
5658cd3394 | ||
|
|
3963a50aef | ||
|
|
47f040a5fd | ||
|
|
7b7a2e99e3 | ||
|
|
25397e7612 | ||
|
|
4984d19ae9 | ||
|
|
305448ea86 | ||
|
|
4a1d18f0e9 | ||
|
|
30482f3eea | ||
|
|
b469feb44b | ||
|
|
466fd56d18 | ||
|
|
1aaf3f3424 | ||
|
|
b5e4917405 | ||
|
|
140671300c | ||
|
|
820a4dbbdd | ||
|
|
53d8ccd149 | ||
|
|
418b36ea71 | ||
|
|
05e51d0d18 | ||
|
|
575c565e77 | ||
|
|
01255082a6 | ||
|
|
0098e67e59 | ||
|
|
3798a472b5 | ||
|
|
0e322e2e85 | ||
|
|
5cd5c05c05 | ||
|
|
933e796cc2 | ||
|
|
ae701e014d | ||
|
|
3a0b8c8870 | ||
|
|
dea0e6793f | ||
|
|
4862916f39 | ||
|
|
870ec27b73 | ||
|
|
a21947d887 | ||
|
|
893dee3434 | ||
|
|
f083805ab5 | ||
|
|
7067afde5d | ||
|
|
1eaec2aa8a | ||
|
|
da01810d98 | ||
|
|
4c7d5a1dc0 | ||
|
|
d15e3d93c4 | ||
|
|
aae2bf872c |
+1
-1
@@ -104,7 +104,7 @@ SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp03
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
\#*
|
||||
.#*
|
||||
.nfs*
|
||||
*~
|
||||
*.tidy
|
||||
*.old
|
||||
|
||||
+33
-2
@@ -35,18 +35,28 @@ before_install:
|
||||
- clang++ -E -dM -c -x c++ /dev/null | sort
|
||||
|
||||
# Install all dependencies
|
||||
# We run twice to attempt on failure to recover from temp network problems
|
||||
install:
|
||||
- ./ci/travis-install.bash
|
||||
- ./ci/travis-install.bash || ./ci/travis-install.bash
|
||||
|
||||
before_script:
|
||||
# ccache maintenance
|
||||
- ./ci/travis-ccache-maint.bash
|
||||
# Don't produce core dumps (esp. on FreeBSD)
|
||||
- ulimit -c 0
|
||||
# On Focal, set the SystemC installation location
|
||||
- |
|
||||
if [ "$TRAVIS_DIST" = "focal" ]; then
|
||||
if [ "$TRAVIS_DIST" = "focal" ] && [ "$M32" != "1" ]; then
|
||||
export SYSTEMC_INCLUDE=/usr/include
|
||||
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
|
||||
fi
|
||||
# Override compiler for M32
|
||||
- |
|
||||
if [ "$M32" = "1" ]; then
|
||||
export CC="$CC -m32"
|
||||
export CXX="$CXX -m32"
|
||||
unset M32 # verilated.mk actually references $(M32) so unset
|
||||
fi
|
||||
|
||||
before_cache:
|
||||
- ccache -s -z
|
||||
@@ -70,6 +80,12 @@ jobs:
|
||||
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
|
||||
# Coverage build
|
||||
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
|
||||
# 32-bit build
|
||||
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc-m32, paths: .}}, env: M32=1}
|
||||
# OS X build
|
||||
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
|
||||
# FreeBSD build
|
||||
#- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
|
||||
############################################################################
|
||||
# Jobs in the 'test' stage
|
||||
############################################################################
|
||||
@@ -109,6 +125,21 @@ jobs:
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
|
||||
# 32-bit tests
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-0]}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-1]}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-0]}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-1]}
|
||||
# OS X tests
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
# FreeBSD tests
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
@@ -3,6 +3,126 @@ Revision history for Verilator
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
* Verilator 4.102 2020-10-15
|
||||
|
||||
**** Support const object new() assignments.
|
||||
|
||||
**** Support # as a comment in -f files (#2497). [phantom-killua]
|
||||
|
||||
**** Support 'this' (#2585). [Rafal Kapuscik]
|
||||
|
||||
**** Support defines for FST tracing (#2592). [Markus Krause]
|
||||
|
||||
**** Support |=> inside properties (#1292). [Peter Monsson]
|
||||
|
||||
**** Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Fix -G dropping public indication (#2561). [Andrew Goessling]
|
||||
|
||||
**** Fix $urandom_range passed variable (#2563). [nanduraj1]
|
||||
|
||||
**** Fix method calls to package class functions (#2565). [Peter Monsson]
|
||||
|
||||
**** Fix class wide member display (#2567). [Nandu Raj P]
|
||||
|
||||
**** Fix hierarchical references inside function (#2267) (#2572). [James Pallister]
|
||||
|
||||
**** Fix flushCall for backward compatibility (#2580). [chenguokai]
|
||||
|
||||
**** Fix preprocessor stringify of undefined macro. [Martin Whitaker]
|
||||
|
||||
|
||||
* Verilator 4.100 2020-09-07
|
||||
|
||||
** C++11 or newer compilers are now required.
|
||||
|
||||
** SystemC 2.3.0 or newer (SYSTEMC_VERSION >= 20111121) is now required.
|
||||
|
||||
** Support hierarchical Verilation (#2206). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Support (with limitations) class extern, class extends, virtual class.
|
||||
|
||||
**** Support $urandom, $urandom_range without stability.
|
||||
|
||||
**** Fix false DECLFILENAME on black-boxed modules (#2430). [Philipp Wagner]
|
||||
|
||||
**** Fix naming of "id : begin" blocks.
|
||||
|
||||
**** Fix class constructor error on assignments to const.
|
||||
|
||||
**** Fix splitting eval functions with --output-split-cfuncs (#2368). [Geza Lore]
|
||||
|
||||
**** Fix queues as class members (#2525). [nanduraj1]
|
||||
|
||||
**** Add support for assume property. [Peter Monsson]
|
||||
|
||||
**** Add support for |=> inside properties (#1292). [Peter Monsson]
|
||||
|
||||
|
||||
* Verilator 4.040 2020-08-15
|
||||
|
||||
** Version 4.040 is planned to be the final version that will
|
||||
support pre-C++11 compilers. Please move to C++11 or newer compilers.
|
||||
|
||||
*** Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford]
|
||||
|
||||
**** Support $stable, $rose and $fell. (#2148) (#2501) [Peter Monsson]
|
||||
|
||||
**** Support simple function localparams (#2461). [James Hanlon]
|
||||
|
||||
**** Miscellaneous parsing error changes towards UVM support.
|
||||
|
||||
**** Fix arrayed interfaces (#2469). [Josh Redford]
|
||||
|
||||
**** Fix protect lib VCS warning. (#2479) [Julien Margetts]
|
||||
|
||||
**** Fix combining different-width parameters (#2484). [abirkmanis]
|
||||
|
||||
**** Fix protect-lib without sequential logic (#2492). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Fix V3Unknown from running with flat XML output (#2494). [James Hanlon]
|
||||
|
||||
**** Fix non-32 bit conversion to float (#2495). [dsvf]
|
||||
|
||||
**** Fix casting non-self-determined subexpressions (#2493). [phantom-killua]
|
||||
|
||||
**** Fix SystemC net names (#2500). [Edgar E. Iglesias]
|
||||
|
||||
**** Fix build with Bison 3.7 and newer (#2505). [Rupert Swarbrick]
|
||||
|
||||
**** Fix slice of unpacked array (#2506) (#2507). [Yutetsu TAKATSUKASA]
|
||||
|
||||
|
||||
* Verilator 4.038 2020-07-11
|
||||
|
||||
** Versions 4.038 and 4.040 are planned to be the final versions that will
|
||||
support pre-C++11 compilers. Please move to C++11 or newer compilers.
|
||||
|
||||
*** Support VPI access to parameters and localparam. [Ludwig Rogiers]
|
||||
|
||||
*** Support parsing (not elaboration, yet) of UVM.
|
||||
|
||||
**** Add new UNSUPPORTED error code to replace most previous Unsupported: messages.
|
||||
|
||||
**** With --bbox-unsup continue parsing on many (not all) UVM constructs.
|
||||
|
||||
**** Support for-loop increments with commas.
|
||||
|
||||
**** Support $swrite with arbitrary arguments.
|
||||
|
||||
**** Support $writememb (#2450). [Fan Shupei]
|
||||
|
||||
**** Fix OS X, Free BSD, and -m32 portability issues. [Geza Lore]
|
||||
|
||||
**** Fix to flush FST trace on termination due to $stop or assertion failure.
|
||||
|
||||
**** Fix part select error when multipling by power-of-two (#2413). [Conor McCullough]
|
||||
|
||||
**** Fix division exception (#2460) [Kuoping Hsu]
|
||||
|
||||
|
||||
* Verilator 4.036 2020-06-06
|
||||
|
||||
** OPT_FAST is now -Os by default. See the BENCHMARKING & OPTIMIZATION part
|
||||
|
||||
+7
-6
@@ -89,7 +89,6 @@ datarootdir = @datarootdir@
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
CFG_WITH_THREADED = @CFG_WITH_THREADED@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
@@ -171,6 +170,8 @@ DISTFILES_INC = $(INFOS) .gitignore \
|
||||
test_regress/t/t*/*.v* \
|
||||
test_regress/t/t*/*/*.sv* \
|
||||
test_regress/t/t*/*/*.v* \
|
||||
test_regress/t/t*/*.cpp \
|
||||
test_regress/t/t*/CMakeLists.txt \
|
||||
test_regress/t/*.cpp \
|
||||
test_regress/t/*.h \
|
||||
test_regress/t/*.dat \
|
||||
@@ -425,6 +426,9 @@ CPPCHECK_CPP = $(wildcard \
|
||||
CPPCHECK_H = $(wildcard \
|
||||
$(srcdir)/include/*.h \
|
||||
$(srcdir)/src/*.h )
|
||||
CPPCHECK_YL = $(wildcard \
|
||||
$(srcdir)/src/*.y \
|
||||
$(srcdir)/src/*.l )
|
||||
CPPCHECK = src/cppcheck_filtered
|
||||
CPPCHECK_FLAGS = --enable=all --inline-suppr \
|
||||
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
|
||||
@@ -435,7 +439,7 @@ CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
|
||||
|
||||
cppcheck: $(CPPCHECK_DEP)
|
||||
%.cppcheck: %.cpp
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $<
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
|
||||
|
||||
CLANGTIDY = clang-tidy
|
||||
CLANGTIDY_FLAGS = -config=''
|
||||
@@ -462,7 +466,7 @@ CLANGFORMAT_FLAGS = -i
|
||||
clang-format:
|
||||
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H)
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
|
||||
|
||||
ftp: info
|
||||
|
||||
@@ -543,9 +547,6 @@ dist-file-list:
|
||||
@echo $(wildcard $(DISTFILES))
|
||||
@echo "end-dist-file-list:"; # Scripts look for this
|
||||
|
||||
print-cfg-with-threaded:
|
||||
@echo $(CFG_WITH_THREADED)
|
||||
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
|
||||
+534
-414
File diff suppressed because it is too large
Load Diff
+8
-1
@@ -156,7 +156,8 @@ sub report {
|
||||
print "\nAnalysis:\n";
|
||||
printf " Total threads = %d\n", $nthreads;
|
||||
printf " Total mtasks = %d\n", scalar(keys %Mtasks);
|
||||
printf " Total cpus used = %d\n", scalar(keys %{$Global{cpus}});
|
||||
my $ncpus = scalar(keys %{$Global{cpus}});
|
||||
printf " Total cpus used = %d\n", $ncpus;
|
||||
printf " Total yields = %d\n", $Global{stats}{yields};
|
||||
printf " Total eval time = %d rdtsc ticks\n", $Global{last_end};
|
||||
printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time;
|
||||
@@ -206,6 +207,12 @@ sub report {
|
||||
print " stddev = " . ($stddev) . "\n";
|
||||
print " e ^ stddev = " . exp($stddev). "\n";
|
||||
print "\n";
|
||||
|
||||
if ($nthreads > $ncpus) {
|
||||
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
|
||||
print " : See docs on use of numactl.\n";
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub report_graph {
|
||||
|
||||
+37
-5
@@ -25,11 +25,21 @@ fatal() {
|
||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||
}
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
MAKE=make
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
MAKE=make
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
MAKE=gmake
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
|
||||
install-vcddiff() {
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
|
||||
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
|
||||
make -C "${TMP_DIR}"
|
||||
"$MAKE" -C "${TMP_DIR}"
|
||||
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
|
||||
}
|
||||
|
||||
@@ -39,12 +49,20 @@ if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||
# build Verilator
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
time sudo apt-get update
|
||||
sudo apt-get update
|
||||
sudo apt-get install libfl-dev
|
||||
sudo apt-get install libgoogle-perftools-dev
|
||||
if [ "$COVERAGE" = 1 ]; then
|
||||
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||
fi
|
||||
if [ "$M32" = 1 ]; then
|
||||
sudo apt-get install gcc-multilib g++-multilib
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
brew install ccache perl gperftools
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
sudo pkg install -y autoconf bison ccache gmake perl5
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
@@ -59,12 +77,26 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||
if [ "$TRAVIS_DIST" = "focal" ]; then
|
||||
sudo apt-get install libsystemc-dev
|
||||
fi
|
||||
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||
# Not listing Bit::Vector as slow to install, and only skips one test
|
||||
install-vcddiff
|
||||
if [ "$M32" = 1 ]; then
|
||||
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
||||
brew install ccache perl
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
# fst2vcd fails with "Could not open '<input file>', exiting."
|
||||
sudo pkg install -y ccache gmake perl5 python3
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
# Common installs
|
||||
if [ "$TRAVIS_DIST" != "trusty" ]; then
|
||||
TRAVIS_CPAN_REPO=https://cpan.org
|
||||
fi
|
||||
# Not listing Bit::Vector as slow to install, and only skips one test
|
||||
yes yes | sudo cpan -M $TRAVIS_CPAN_REPO -fi Unix::Processors Parallel::Forker
|
||||
install-vcddiff
|
||||
else
|
||||
##############################################################################
|
||||
# Unknown build stage
|
||||
|
||||
+93
-60
@@ -22,77 +22,110 @@ fatal() {
|
||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||
}
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export MAKE=make
|
||||
NPROC=$(nproc)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export MAKE=make
|
||||
NPROC=$(sysctl -n hw.logicalcpu)
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
export MAKE=gmake
|
||||
NPROC=$(sysctl -n hw.ncpu)
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||
##############################################################################
|
||||
# Build verilator
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ "$COVERAGE" != 1 ]; then
|
||||
autoconf
|
||||
./configure --enable-longtests --enable-ccwarn
|
||||
make -j $(nproc)
|
||||
else
|
||||
nodist/code_coverage --stages 1-2
|
||||
if [ "$COVERAGE" != 1 ]; then
|
||||
autoconf
|
||||
./configure --enable-longtests --enable-ccwarn
|
||||
"$MAKE" -j "$NPROC" -k
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
file bin/verilator_bin
|
||||
file bin/verilator_bin_dbg
|
||||
md5 bin/verilator_bin
|
||||
md5 bin/verilator_bin_dbg
|
||||
stat bin/verilator_bin
|
||||
stat bin/verilator_bin_dbg
|
||||
fi
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
nodist/code_coverage --stages 1-2
|
||||
fi
|
||||
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||
##############################################################################
|
||||
# Run tests
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
# Run the specified test
|
||||
case $TESTS in
|
||||
dist-vlt-0)
|
||||
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
dist-vlt-1)
|
||||
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
vltmt-0)
|
||||
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
vltmt-1)
|
||||
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
coverage-dist)
|
||||
nodist/code_coverage --stages 3- --scenarios=--dist
|
||||
;;
|
||||
coverage-vlt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
|
||||
;;
|
||||
coverage-vlt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
|
||||
;;
|
||||
coverage-vlt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
|
||||
;;
|
||||
coverage-vlt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
|
||||
;;
|
||||
coverage-vltmt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
|
||||
;;
|
||||
coverage-vltmt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
|
||||
;;
|
||||
coverage-vltmt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
|
||||
;;
|
||||
coverage-vltmt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
|
||||
;;
|
||||
*)
|
||||
fatal "Unknown test: $TESTS"
|
||||
;;
|
||||
esac
|
||||
# Upload coverage data to codecov.io
|
||||
if [[ $TESTS == coverage-* ]]; then
|
||||
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
|
||||
fi
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
||||
export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg
|
||||
# export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd
|
||||
file bin/verilator_bin
|
||||
file bin/verilator_bin_dbg
|
||||
md5 bin/verilator_bin
|
||||
md5 bin/verilator_bin_dbg
|
||||
stat bin/verilator_bin
|
||||
stat bin/verilator_bin_dbg
|
||||
# For some reason, the dbg exe is corrupted by this point ('file' reports
|
||||
# it as data rather than a Mach-O). Unclear if this is an OS X issue or
|
||||
# one for Travis. Remove the file and re-link...
|
||||
rm bin/verilator_bin_dbg
|
||||
"$MAKE" -j "$NPROC" -k
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run
|
||||
export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable
|
||||
fi
|
||||
|
||||
# Run the specified test
|
||||
case $TESTS in
|
||||
dist-vlt-0)
|
||||
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
dist-vlt-1)
|
||||
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
vltmt-0)
|
||||
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
vltmt-1)
|
||||
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
coverage-dist)
|
||||
nodist/code_coverage --stages 3- --scenarios=--dist
|
||||
;;
|
||||
coverage-vlt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
|
||||
;;
|
||||
coverage-vlt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
|
||||
;;
|
||||
coverage-vlt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
|
||||
;;
|
||||
coverage-vlt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
|
||||
;;
|
||||
coverage-vltmt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
|
||||
;;
|
||||
coverage-vltmt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
|
||||
;;
|
||||
coverage-vltmt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
|
||||
;;
|
||||
coverage-vltmt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
|
||||
;;
|
||||
*)
|
||||
fatal "Unknown test: $TESTS"
|
||||
;;
|
||||
esac
|
||||
# Upload coverage data to codecov.io
|
||||
if [[ $TESTS == coverage-* ]]; then
|
||||
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
|
||||
fi
|
||||
else
|
||||
##############################################################################
|
||||
|
||||
+47
-48
@@ -7,11 +7,12 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.036 2020-06-06],
|
||||
AC_INIT([Verilator],[4.102 2020-10-15],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
# and commit using "devel release" or "Version bump" message
|
||||
# Then 'make maintainer-dist'
|
||||
|
||||
AC_CONFIG_HEADER(src/config_build.h)
|
||||
AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
|
||||
@@ -112,27 +113,11 @@ AC_ARG_ENABLE([longtests],
|
||||
AC_SUBST(CFG_WITH_LONGTESTS)
|
||||
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
||||
|
||||
# CFG_WITH_PREC11
|
||||
AC_MSG_CHECKING(whether allow pre-C++11)
|
||||
AC_ARG_ENABLE([prec11],
|
||||
[AS_HELP_STRING([--enable-prec11],
|
||||
[enable pre-C++11 compilers for Verilator binary
|
||||
and Verilated makefiles])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_PREC11=yes ;;
|
||||
no) CFG_WITH_PREC11=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11]) ;;
|
||||
esac],
|
||||
[CFG_WITH_PREC11=no;]
|
||||
)
|
||||
AC_SUBST(CFG_WITH_PREC11)
|
||||
AC_MSG_RESULT($CFG_WITH_PREC11)
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS+=" -I${includedir}"
|
||||
CPPFLAGS+=" -I${includedir}"
|
||||
CXXFLAGS+=" -I${includedir}"
|
||||
LDFLAGS+=" -L${libdir}"
|
||||
# Compiler flags (ensure they are not empty to avoid configure defaults)
|
||||
CFLAGS+=" "
|
||||
CPPFLAGS+=" "
|
||||
CXXFLAGS+=" "
|
||||
LDFLAGS+=" "
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
@@ -153,14 +138,20 @@ AC_PATH_PROG(PERL,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(LEX,flex)
|
||||
if test "x$LEX" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
||||
fi
|
||||
flex_version=$($LEX --version | head -1)
|
||||
AC_MSG_RESULT([$LEX --version = $flex_version])
|
||||
|
||||
AC_PATH_PROG(YACC,bison)
|
||||
if test "x$YACC" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||
fi
|
||||
bison_version=$($YACC --version | head -1)
|
||||
AC_MSG_RESULT([$YACC --version = $bison_version])
|
||||
|
||||
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
|
||||
if test "x$OBJCACHE" != "x" ; then
|
||||
@@ -403,12 +394,17 @@ _MY_LDLIBS_CHECK_IFELSE(
|
||||
fi])
|
||||
AC_SUBST(CFG_LIBS)
|
||||
|
||||
# Set CFG_WITH_THREADED if can support threading
|
||||
AC_MSG_CHECKING(whether $CXX supports Verilated threads)
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST $CFG_CXXFLAGS_NO_UNUSED"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <thread>], [[ ]])],
|
||||
# Need C++11 at least
|
||||
#Alternative: AX_CXX_COMPILE_STDCXX([11])
|
||||
AC_DEFUN([_MY_CXX_CHECK_CXX_VER],
|
||||
[# _MY_CXX_CHECK_CXX_VER(flag) -- Check if compiler runs C++11
|
||||
# Set $_my_result
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <thread>
|
||||
#if (__cplusplus < 201103L)
|
||||
# error "Too old"
|
||||
#endif
|
||||
], [[ ]])],
|
||||
[_my_result=yes
|
||||
if test -s conftest.err; then
|
||||
if grep -e "$1" conftest.err >/dev/null; then
|
||||
@@ -416,25 +412,24 @@ AC_LINK_IFELSE(
|
||||
fi
|
||||
fi],
|
||||
[_my_result=no])
|
||||
CFG_WITH_THREADED=$_my_result
|
||||
AC_SUBST(CFG_WITH_THREADED)
|
||||
AC_MSG_RESULT($CFG_WITH_THREADED)
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
])
|
||||
|
||||
# Check compiler flag
|
||||
if test "$CFG_WITH_THREADED" = "no" ; then
|
||||
if test "$CFG_WITH_PREC11" = "no" ; then
|
||||
AC_MSG_NOTICE([[]])
|
||||
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
|
||||
AC_MSG_CHECKING(whether $CXX supports C++11)
|
||||
_MY_CXX_CHECK_CXX_VER()
|
||||
AC_MSG_RESULT($_my_result)
|
||||
if test "$_my_result" = "no" ; then
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST"
|
||||
CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE $CFG_CXXFLAGS_STD_NEWEST"
|
||||
AC_MSG_CHECKING(whether $CXX supports C++11 with $CFG_CXXFLAGS_STD_NEWEST)
|
||||
_MY_CXX_CHECK_CXX_VER()
|
||||
AC_MSG_RESULT($_my_result)
|
||||
fi
|
||||
if test "$_my_result" = "no" ; then
|
||||
AC_MSG_NOTICE([[]])
|
||||
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
|
||||
|
||||
Verilator plans to require a C++11 or newer compiler in a future release,
|
||||
unless sufficient people report problems. Therefore, if you do not have a
|
||||
C++11 compiler, please post a message to
|
||||
https://www.veripool.org/boards/3/topics/2580-Verilator-Requiring-C-11-compiler
|
||||
indicating your OS and when you think C++11 might be ok, and then rerun
|
||||
configure with the --enable-prec11 argument. Thanks.]])
|
||||
Verilator requires a C++11 or newer compiler.]])
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
# Checks for library functions.
|
||||
@@ -447,14 +442,18 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
|
||||
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
|
||||
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
|
||||
AC_MSG_CHECKING([whether SystemC is found (in system path)])
|
||||
AC_COMPILE_IFELSE(
|
||||
ACO_SAVE_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lsystemc"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([[#include <systemc.h>
|
||||
]],[])],
|
||||
extern "C" int sc_main(int argc, char* argv[]) {}
|
||||
]],[[sc_version()]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])],
|
||||
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
|
||||
[_my_result=no])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
AC_SUBST(HAVE_SYSTEMC_H)
|
||||
LIBS="$ACO_SAVE_LIBS"
|
||||
AC_SUBST(HAVE_SYSTEMC)
|
||||
|
||||
# Checks for system services
|
||||
|
||||
|
||||
@@ -6,25 +6,31 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||
Ahmed El-Mahmoudy
|
||||
Alex Chadwick
|
||||
Chris Randall
|
||||
Conor McCullough
|
||||
Dan Petrisko
|
||||
David Horton
|
||||
David Stanford
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Rippey
|
||||
Fan Shupei
|
||||
Garrett Smith
|
||||
Geza Lore
|
||||
Gianfranco Costamagna
|
||||
Glen Gibb
|
||||
Harald Heckmann
|
||||
Howard Su
|
||||
Huang Rui
|
||||
Iztok Jeras
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
Jamey Hicks
|
||||
James Pallister
|
||||
Jan Van Winkel
|
||||
Jeremy Bennett
|
||||
John Coiner
|
||||
John Demme
|
||||
Josh Redford
|
||||
Julien Margetts
|
||||
Kanad Kanhere
|
||||
Kevin Kiningham
|
||||
@@ -34,6 +40,8 @@ Lukasz Dalek
|
||||
Maarten De Braekeleer
|
||||
Maciej Sobkowski
|
||||
Marco Widmer
|
||||
Markus Krause
|
||||
Marshal Qiao
|
||||
Matthew Ballance
|
||||
Michael Killough
|
||||
Mike Popoloski
|
||||
@@ -44,8 +52,11 @@ Peter Horvath
|
||||
Peter Monsson
|
||||
Philipp Wagner
|
||||
Pieter Kapsenberg
|
||||
Piotr Binkowski
|
||||
Qingyao Sun
|
||||
Rafal Kapuscik
|
||||
Richard Myers
|
||||
Rupert Swarbrick
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
@@ -57,6 +68,7 @@ Tobias Wölfel
|
||||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Tymoteusz Blazejczyk
|
||||
Victor Besyakov
|
||||
Vassilis Papaefstathiou
|
||||
Veripool API Bot
|
||||
Wilson Snyder
|
||||
|
||||
+9
-9
@@ -39,7 +39,7 @@ brief:
|
||||
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
|
||||
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
|
||||
|
||||
git clone https://git.veripool.org/git/verilator # Only first time
|
||||
git clone https://github.com/verilator/verilator # Only first time
|
||||
## Note the URL above is not a page you can see with a browser, it's for git only
|
||||
|
||||
# Every time you need to build:
|
||||
@@ -69,12 +69,12 @@ Linux distribution, see instead <<Install From a Package Manager>>.
|
||||
|
||||
=== OS Requirements
|
||||
|
||||
Verilator is developed and has primary testing on Ubuntu. Versions have
|
||||
also built on Redhat Linux, Apple OS-X, HPUX and Solaris. It should run
|
||||
with minor porting on any GNU/Linux-ish platform. Verilator also works on
|
||||
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
|
||||
output (not Verilator itself) compiles under all the options above, plus
|
||||
MSVC++.
|
||||
Verilator is developed and has primary testing on Ubuntu, with additional
|
||||
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
|
||||
Linux, HPUX and Solaris. It should run with minor porting on any
|
||||
GNU/Linux-ish platform. Verilator also works on Windows under Cygwin, and
|
||||
Windows under MinGW (gcc -mno-cygwin). Verilated output (not Verilator
|
||||
itself) compiles under all the options above, plus MSVC++.
|
||||
|
||||
=== Install Prerequisites
|
||||
|
||||
@@ -89,7 +89,7 @@ To build or run the following are optional but should be installed for
|
||||
good performance:
|
||||
|
||||
sudo apt-get install ccache # If present at build, needed for run
|
||||
sudo apt-get install libgoogle-perftools-dev numactl
|
||||
sudo apt-get install libgoogle-perftools-dev numactl perl-doc
|
||||
|
||||
To build Verilator you will need to install these packages; these do not
|
||||
need to be present to run Verilator:
|
||||
@@ -128,7 +128,7 @@ Downloads]; we presume you know how to use it, and is not described here.)
|
||||
|
||||
Get the sources from the repository: (You need do this only once, ever.)
|
||||
|
||||
git clone https://git.veripool.org/git/verilator # Only first time
|
||||
git clone https://github.com/verilator/verilator # Only first time
|
||||
## Note the URL above is not a page you can see with a browser, it's for git only
|
||||
|
||||
Enter the checkout and determine what version/branch to use:
|
||||
|
||||
+16
-8
@@ -387,10 +387,8 @@ changed; if clear, checking those signals for changes may be skipped.
|
||||
|
||||
=== Compiler Version and C++11
|
||||
|
||||
Verilator supports GCC 4.4.7 and newer. GCC 4.4.7 does not support C++11,
|
||||
therefore C++11 is generally not required. Exceptions may be made to
|
||||
require C++11 for features that are only practical with C++11,
|
||||
e.g. threads.
|
||||
Verilator requires C++11. Verilator does not require any newer versions,
|
||||
but is maintained to build successfully with C++14/C++17/C++20.
|
||||
|
||||
=== Indentation and Naming Style
|
||||
|
||||
@@ -588,7 +586,7 @@ dealing with. For example a visitor might not implement separate `visit`
|
||||
methods for `AstIf` and `AstGenIf`, but just a single method for the base
|
||||
class:
|
||||
|
||||
void visit (AstNodeIf* nodep)
|
||||
void visit(AstNodeIf* nodep)
|
||||
|
||||
However that method might want to specify additional code if it is called
|
||||
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
|
||||
@@ -674,7 +672,7 @@ Set to 1 to indicate that the compilation or execution is intended to fail.
|
||||
For example the following would specify that compilation requires two
|
||||
defines and is expected to fail.
|
||||
|
||||
compile (
|
||||
compile(
|
||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||
fails => 1,
|
||||
);
|
||||
@@ -760,6 +758,15 @@ may be required to setup the system for fuzzing.
|
||||
|
||||
== Debugging
|
||||
|
||||
=== Debug Levels
|
||||
|
||||
The "UINFO" calls in the source indicate a debug level. Messages level 3
|
||||
and below are globally enabled with `--debug`. Higher levels may be
|
||||
controlled with `--debugi <level>`. An individual source file levels may
|
||||
be controlled with `-debugi-<srcfile> <level>`. For example `--debug
|
||||
--debugi 5 --debugi-V3Width 9` will use the debug binary at default debug
|
||||
level 5, with the V3Width.cpp file at level 9.
|
||||
|
||||
=== --debug
|
||||
|
||||
When you run with `--debug` there are two primary output file types placed
|
||||
@@ -777,9 +784,10 @@ output, for example:
|
||||
You can then print a.ps. You may prefer gif format, which doesn't get
|
||||
scaled so can be more useful with large graphs.
|
||||
|
||||
For dynamic graph viewing consider
|
||||
For interactive graph viewing consider
|
||||
https://github.com/jrfonseca/xdot.py[xdot] or
|
||||
http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of
|
||||
better viewers let us know; ZGRViewer isn't great for large graphs.
|
||||
better viewers (especially for large graphs) please let us know.
|
||||
|
||||
=== .tree Output
|
||||
|
||||
|
||||
@@ -29,19 +29,11 @@ int sc_main(int argc, char* argv[]) {
|
||||
Vtop* top = new Vtop("top");
|
||||
|
||||
// Initialize SC model
|
||||
#if (SYSTEMC_VERSION >= 20070314)
|
||||
sc_start(1, SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
#if (SYSTEMC_VERSION >= 20070314)
|
||||
sc_start(1, SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
|
||||
@@ -68,7 +68,7 @@ run:
|
||||
@echo " library (libverilated_secret.a) generated from the previous"
|
||||
@echo " step"
|
||||
@echo "---------------------------------------------------------------"
|
||||
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
||||
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '../obj_dir_secret/libverilated_secret.a' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE entire design --------------------------------------"
|
||||
|
||||
@@ -31,7 +31,7 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
#if VM_TRACE
|
||||
// When tracing, the contents of the secret module will not be seen
|
||||
VerilatedVcdC* tfp = NULL;
|
||||
VerilatedVcdC* tfp = nullptr;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||
Verilated::traceEverOn(true);
|
||||
@@ -62,13 +62,13 @@ int main(int argc, char** argv, char** env) {
|
||||
#if VM_TRACE
|
||||
if (tfp) {
|
||||
tfp->close();
|
||||
tfp = NULL;
|
||||
tfp = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Destroy model
|
||||
delete top;
|
||||
top = NULL;
|
||||
top = nullptr;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
|
||||
@@ -99,7 +99,7 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
// Destroy model
|
||||
delete top;
|
||||
top = NULL;
|
||||
top = nullptr;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
|
||||
@@ -44,21 +44,9 @@ int sc_main(int argc, char* argv[]) {
|
||||
// General logfile
|
||||
ios::sync_with_stdio();
|
||||
|
||||
// Defaults time
|
||||
#if (SYSTEMC_VERSION > 20011000)
|
||||
#else
|
||||
sc_time dut(1.0, sc_ns);
|
||||
sc_set_default_time_unit(dut);
|
||||
#endif
|
||||
|
||||
// Define clocks
|
||||
#if (SYSTEMC_VERSION >= 20070314)
|
||||
sc_clock clk("clk", 10, SC_NS, 0.5, 3, SC_NS, true);
|
||||
sc_clock fastclk("fastclk", 2, SC_NS, 0.5, 2, SC_NS, true);
|
||||
#else
|
||||
sc_clock clk("clk", 10, 0.5, 3, true);
|
||||
sc_clock fastclk("fastclk", 2, 0.5, 2, true);
|
||||
#endif
|
||||
|
||||
// Define interconnect
|
||||
sc_signal<bool> reset_l;
|
||||
@@ -89,16 +77,12 @@ int sc_main(int argc, char* argv[]) {
|
||||
|
||||
// You must do one evaluation before enabling waves, in order to allow
|
||||
// SystemC to interconnect everything for testing.
|
||||
#if (SYSTEMC_VERSION >= 20070314)
|
||||
sc_start(1, SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
// If verilator was invoked with --trace argument,
|
||||
// and if at run time passed the +trace argument, turn on tracing
|
||||
VerilatedVcdSc* tfp = NULL;
|
||||
VerilatedVcdSc* tfp = nullptr;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
||||
@@ -125,11 +109,7 @@ int sc_main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
// Simulate 1ns
|
||||
#if (SYSTEMC_VERSION >= 20070314)
|
||||
sc_start(1, SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
@@ -139,7 +119,7 @@ int sc_main(int argc, char* argv[]) {
|
||||
#if VM_TRACE
|
||||
if (tfp) {
|
||||
tfp->close();
|
||||
tfp = NULL;
|
||||
tfp = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -151,7 +131,7 @@ int sc_main(int argc, char* argv[]) {
|
||||
|
||||
// Destroy model
|
||||
delete top;
|
||||
top = NULL;
|
||||
top = nullptr;
|
||||
|
||||
// Fin
|
||||
return 0;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||
#if !defined(__MINGW32__)
|
||||
#if !defined(__MINGW32__) && !defined(__FreeBSD__)
|
||||
# define HAVE_ALLOCA_H 1
|
||||
#endif
|
||||
|
||||
|
||||
@@ -794,6 +794,7 @@ pthread_t thread;
|
||||
pthread_attr_t thread_attr;
|
||||
struct fstWriterContext *xc_parent;
|
||||
#endif
|
||||
unsigned in_pthread : 1;
|
||||
|
||||
size_t fst_orig_break_size;
|
||||
size_t fst_orig_break_add_size;
|
||||
@@ -1806,10 +1807,9 @@ static void *fstWriterFlushContextPrivate1(void *ctx)
|
||||
{
|
||||
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
||||
|
||||
pthread_mutex_lock(&(xc->xc_parent->mutex));
|
||||
fstWriterFlushContextPrivate2(xc);
|
||||
|
||||
pthread_mutex_unlock(&(xc->xc_parent->mutex));
|
||||
|
||||
#ifdef FST_REMOVE_DUPLICATE_VC
|
||||
free(xc->curval_mem);
|
||||
#endif
|
||||
@@ -1818,6 +1818,9 @@ free(xc->vchg_mem);
|
||||
tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
|
||||
free(xc);
|
||||
|
||||
xc->xc_parent->in_pthread = 0;
|
||||
pthread_mutex_unlock(&(xc->xc_parent->mutex));
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
@@ -1865,7 +1868,15 @@ if(xc->parallel_enabled)
|
||||
xc->section_header_only = 0;
|
||||
xc->secnum++;
|
||||
|
||||
while (xc->in_pthread)
|
||||
{
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
xc->in_pthread = 1;
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
|
||||
pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
|
||||
}
|
||||
@@ -1947,6 +1958,12 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
|
||||
#ifdef FST_WRITER_PARALLEL
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
|
||||
while (xc->in_pthread)
|
||||
{
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
+247
-140
@@ -31,6 +31,8 @@
|
||||
#include <cerrno>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h> // mkdir
|
||||
#include <list>
|
||||
#include <utility>
|
||||
|
||||
// clang-format off
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
@@ -38,7 +40,8 @@
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#define VL_VALUE_STRING_MAX_WIDTH 8192 ///< Max static char array for VL_VALUE_STRING
|
||||
/// Max static char array for VL_VALUE_STRING
|
||||
constexpr unsigned VL_VALUE_STRING_MAX_WIDTH = 8192;
|
||||
|
||||
//===========================================================================
|
||||
// Static sanity checks (when get C++11 can use static_assert)
|
||||
@@ -59,7 +62,6 @@ typedef union {
|
||||
|
||||
// Slow path variables
|
||||
VerilatedMutex Verilated::m_mutex;
|
||||
VerilatedVoidCb Verilated::s_flushCb = NULL;
|
||||
|
||||
// Keep below together in one cache line
|
||||
Verilated::Serialized Verilated::s_s;
|
||||
@@ -68,7 +70,12 @@ VL_THREAD_LOCAL Verilated::ThreadLocal Verilated::t_s;
|
||||
|
||||
Verilated::CommandArgValues Verilated::s_args;
|
||||
|
||||
VerilatedImp VerilatedImp::s_s;
|
||||
VerilatedImp::VerilatedImpU VerilatedImp::s_s;
|
||||
|
||||
struct VerilatedImpInitializer {
|
||||
VerilatedImpInitializer() { VerilatedImp::setup(); }
|
||||
~VerilatedImpInitializer() { VerilatedImp::teardown(); }
|
||||
} g_VerilatedImpInitializer;
|
||||
|
||||
//===========================================================================
|
||||
// User definable functions
|
||||
@@ -83,7 +90,8 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
|
||||
if (Verilated::gotFinish()) {
|
||||
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
|
||||
"- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
||||
Verilated::flushCall();
|
||||
Verilated::runFlushCallbacks();
|
||||
Verilated::runExitCallbacks();
|
||||
exit(0);
|
||||
}
|
||||
Verilated::gotFinish(true);
|
||||
@@ -93,7 +101,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
|
||||
#ifndef VL_USER_STOP ///< Define this to override this function
|
||||
void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
|
||||
Verilated::gotFinish(true);
|
||||
Verilated::flushCall();
|
||||
Verilated::runFlushCallbacks();
|
||||
vl_fatal(filename, linenum, hier, "Verilog $stop");
|
||||
}
|
||||
#endif
|
||||
@@ -108,10 +116,15 @@ void vl_fatal(const char* filename, int linenum, const char* hier, const char* m
|
||||
} else {
|
||||
VL_PRINTF("%%Error: %s\n", msg);
|
||||
}
|
||||
Verilated::flushCall();
|
||||
Verilated::runFlushCallbacks();
|
||||
|
||||
VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread
|
||||
Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush
|
||||
|
||||
// Second flush in case VL_PRINTF does something needing a flush
|
||||
Verilated::runFlushCallbacks();
|
||||
|
||||
// Callbacks prior to termination
|
||||
Verilated::runExitCallbacks();
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
@@ -169,7 +182,7 @@ void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char
|
||||
std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
|
||||
va_list aq;
|
||||
va_copy(aq, ap);
|
||||
int len = VL_VSNPRINTF(NULL, 0, formatp, aq);
|
||||
int len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
|
||||
va_end(aq);
|
||||
if (VL_UNLIKELY(len < 1)) return "";
|
||||
|
||||
@@ -248,19 +261,17 @@ Verilated::Serialized::Serialized() {
|
||||
}
|
||||
|
||||
Verilated::NonSerialized::NonSerialized() {
|
||||
s_profThreadsStart = 1;
|
||||
s_profThreadsWindow = 2;
|
||||
s_profThreadsFilenamep = strdup("profile_threads.dat");
|
||||
}
|
||||
Verilated::NonSerialized::~NonSerialized() {
|
||||
if (s_profThreadsFilenamep) {
|
||||
VL_DO_CLEAR(free(const_cast<char*>(s_profThreadsFilenamep)),
|
||||
s_profThreadsFilenamep = NULL);
|
||||
s_profThreadsFilenamep = nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::s_s.m_ser); }
|
||||
void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.m_ser; }
|
||||
size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::s_s.v.m_ser); }
|
||||
void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.v.m_ser; }
|
||||
|
||||
//===========================================================================
|
||||
// Random -- Mostly called at init time, so not inline.
|
||||
@@ -309,8 +320,6 @@ vluint64_t vl_rand64() VL_MT_SAFE {
|
||||
return result;
|
||||
}
|
||||
|
||||
IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
|
||||
QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
|
||||
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
|
||||
// LCOV_EXCL_START
|
||||
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
@@ -577,6 +586,30 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsig
|
||||
return VL_POW_QQW(obits, rbits, rbits, lhs, rwp);
|
||||
}
|
||||
|
||||
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE {
|
||||
int ms_word = VL_WORDS_I(lbits) - 1;
|
||||
for (; !lwp[ms_word] && ms_word > 0;) --ms_word;
|
||||
if (ms_word == 0) return static_cast<double>(lwp[0]);
|
||||
if (ms_word == 1) return static_cast<double>(VL_SET_QW(lwp));
|
||||
// We need 53 bits of mantissa, which might mean looking at 3 words
|
||||
// namely ms_word, ms_word-1 and ms_word-2
|
||||
EData ihi = lwp[ms_word];
|
||||
EData imid = lwp[ms_word - 1];
|
||||
EData ilo = lwp[ms_word - 2];
|
||||
double hi = static_cast<double>(ihi) * exp2(2 * VL_EDATASIZE);
|
||||
double mid = static_cast<double>(imid) * exp2(VL_EDATASIZE);
|
||||
double lo = static_cast<double>(ilo);
|
||||
double d = (hi + mid + lo) * exp2(VL_EDATASIZE * (ms_word - 2));
|
||||
return d;
|
||||
}
|
||||
double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE {
|
||||
if (!VL_SIGN_W(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp);
|
||||
vluint32_t pos[VL_MULS_MAX_WORDS + 1]; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
VL_NEGATE_W(VL_WORDS_I(lbits), pos, lwp);
|
||||
_VL_CLEAN_INPLACE_W(lbits, pos);
|
||||
return -VL_ITOR_D_W(lbits, pos);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Formatting
|
||||
|
||||
@@ -656,7 +689,7 @@ 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 VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH];
|
||||
const char* pctp = NULL; // Most recent %##.##g format
|
||||
const char* pctp = nullptr; // Most recent %##.##g format
|
||||
bool inPct = false;
|
||||
bool widthSet = false;
|
||||
bool left = false;
|
||||
@@ -735,8 +768,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
if (!widthSet) width = VerilatedImp::timeFormatWidth();
|
||||
output += _vl_vsformat_time(tmp, d, left, width);
|
||||
} else {
|
||||
std::string fmt(pctp, pos - pctp + 1);
|
||||
sprintf(tmp, fmt.c_str(), d);
|
||||
std::string fmts(pctp, pos - pctp + 1);
|
||||
sprintf(tmp, fmts.c_str(), d);
|
||||
output += tmp;
|
||||
}
|
||||
break;
|
||||
@@ -746,7 +779,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
const int lbits = va_arg(ap, int);
|
||||
QData ld = 0;
|
||||
WData qlwp[VL_WQ_WORDS_E];
|
||||
WDataInP lwp = NULL;
|
||||
WDataInP lwp = nullptr;
|
||||
if (lbits <= VL_QUADSIZE) {
|
||||
ld = _VL_VA_ARG_Q(ap, lbits);
|
||||
VL_SET_WQ(qlwp, ld);
|
||||
@@ -880,10 +913,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
output += "0123456789abcdef"[charval];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default: { // LCOV_EXCL_START
|
||||
std::string msg = std::string("Unknown _vl_vsformat code: ") + pos[0];
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
} // switch
|
||||
}
|
||||
} // switch
|
||||
@@ -916,7 +950,7 @@ static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp,
|
||||
} else {
|
||||
if (floc < 0) return EOF;
|
||||
floc = floc & ~7; // Align to closest character
|
||||
if (fromp == NULL) {
|
||||
if (fromp == nullptr) {
|
||||
return fstr[fstr.length() - 1 - (floc >> 3)];
|
||||
} else {
|
||||
return VL_BITRSHIFT_W(fromp, floc) & 0xff;
|
||||
@@ -938,7 +972,7 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, WDataInP fromp, const
|
||||
while (true) {
|
||||
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
if (c == EOF || isspace(c)) break;
|
||||
if (acceptp && NULL == strchr(acceptp, c)) break; // String - allow anything
|
||||
if (acceptp && nullptr == strchr(acceptp, c)) break; // String - allow anything
|
||||
if (acceptp) c = tolower(c); // Non-strings we'll simplify
|
||||
*cp++ = c;
|
||||
_vl_vsss_advance(fp, floc);
|
||||
@@ -953,7 +987,7 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, WDataInP fromp, const
|
||||
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
|
||||
while (n-- > 0) {
|
||||
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
|
||||
if (c == EOF) return NULL;
|
||||
if (c == EOF) return nullptr;
|
||||
if (!inhibit) *beginp++ = c;
|
||||
_vl_vsss_advance(fp, floc);
|
||||
}
|
||||
@@ -1057,7 +1091,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
}
|
||||
case 's': {
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, NULL);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, nullptr);
|
||||
if (!tmp[0]) goto done;
|
||||
int lpos = (static_cast<int>(strlen(tmp))) - 1;
|
||||
int lsb = 0;
|
||||
@@ -1087,7 +1121,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
double r;
|
||||
vlsint64_t ld;
|
||||
} u;
|
||||
u.r = strtod(tmp, NULL);
|
||||
u.r = strtod(tmp, nullptr);
|
||||
VL_SET_WQ(owp, u.ld);
|
||||
break;
|
||||
}
|
||||
@@ -1149,10 +1183,12 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
default: { // LCOV_EXCL_START
|
||||
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
} // switch
|
||||
|
||||
if (!inIgnore) ++got;
|
||||
@@ -1378,7 +1414,7 @@ IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
IData got = _vl_vsscanf(fp, 0, NULL, "", formatp, ap);
|
||||
IData got = _vl_vsscanf(fp, 0, nullptr, "", formatp, ap);
|
||||
va_end(ap);
|
||||
return got;
|
||||
}
|
||||
@@ -1389,7 +1425,7 @@ IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE {
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
IData got = _vl_vsscanf(NULL, lbits, fnw, "", formatp, ap);
|
||||
IData got = _vl_vsscanf(nullptr, lbits, fnw, "", formatp, ap);
|
||||
va_end(ap);
|
||||
return got;
|
||||
}
|
||||
@@ -1399,21 +1435,21 @@ IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE {
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
IData got = _vl_vsscanf(NULL, lbits, fnw, "", formatp, ap);
|
||||
IData got = _vl_vsscanf(nullptr, lbits, fnw, "", formatp, ap);
|
||||
va_end(ap);
|
||||
return got;
|
||||
}
|
||||
IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) VL_MT_SAFE {
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
IData got = _vl_vsscanf(NULL, lbits, lwp, "", formatp, ap);
|
||||
IData got = _vl_vsscanf(nullptr, lbits, lwp, "", formatp, ap);
|
||||
va_end(ap);
|
||||
return got;
|
||||
}
|
||||
IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_SAFE {
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
IData got = _vl_vsscanf(NULL, ld.length() * 8, NULL, ld, formatp, ap);
|
||||
IData got = _vl_vsscanf(nullptr, ld.length() * 8, nullptr, ld, formatp, ap);
|
||||
va_end(ap);
|
||||
return got;
|
||||
}
|
||||
@@ -1590,7 +1626,7 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_S
|
||||
const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE {
|
||||
const std::string& match = VerilatedImp::argPlusMatch(prefixp);
|
||||
static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||
if (match.empty()) return NULL;
|
||||
if (match.empty()) return nullptr;
|
||||
outstr[0] = '\0';
|
||||
strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+"
|
||||
VL_VALUE_STRING_MAX_WIDTH - 1);
|
||||
@@ -1610,12 +1646,12 @@ std::string VL_TO_STRING_W(int words, WDataInP obj) {
|
||||
|
||||
std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE {
|
||||
std::string out = ld;
|
||||
for (std::string::iterator it = out.begin(); it != out.end(); ++it) *it = tolower(*it);
|
||||
for (auto& cr : out) cr = tolower(cr);
|
||||
return out;
|
||||
}
|
||||
std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
|
||||
std::string out = ld;
|
||||
for (std::string::iterator it = out.begin(); it != out.end(); ++it) *it = toupper(*it);
|
||||
for (auto& cr : out) cr = toupper(cr);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -1670,7 +1706,7 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
|
||||
str_mod.erase(std::remove(str_mod.begin(), str_mod.end(), '_'), str_mod.end());
|
||||
|
||||
errno = 0;
|
||||
long v = std::strtol(str_mod.c_str(), NULL, base);
|
||||
auto v = std::strtol(str_mod.c_str(), nullptr, base);
|
||||
if (errno != 0) v = 0;
|
||||
return static_cast<IData>(v);
|
||||
}
|
||||
@@ -1700,7 +1736,7 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_
|
||||
static const char* memhFormat(int nBits) {
|
||||
assert((nBits >= 1) && (nBits <= 32));
|
||||
|
||||
static char buf[32];
|
||||
static VL_THREAD_LOCAL char buf[32];
|
||||
switch ((nBits - 1) / 4) {
|
||||
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
|
||||
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
|
||||
@@ -1715,25 +1751,37 @@ static const char* memhFormat(int nBits) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char* formatBinary(int nBits, vluint32_t bits) {
|
||||
assert((nBits >= 1) && (nBits <= 32));
|
||||
|
||||
static VL_THREAD_LOCAL char buf[64];
|
||||
for (int i = 0; i < nBits; i++) {
|
||||
bool isOne = bits & (1 << (nBits - 1 - i));
|
||||
buf[i] = (isOne ? '1' : '0');
|
||||
}
|
||||
buf[nBits] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
|
||||
: m_hex(hex)
|
||||
, m_bits(bits)
|
||||
, m_filename(filename)
|
||||
, m_end(end)
|
||||
, m_addr(start)
|
||||
, m_linenum(0) {
|
||||
: m_hex{hex}
|
||||
, m_bits{bits}
|
||||
, m_filename(filename) // Need () or GCC 4.8 false warning
|
||||
, m_end{end}
|
||||
, m_addr{start}
|
||||
, m_linenum{0} {
|
||||
m_fp = fopen(filename.c_str(), "r");
|
||||
if (VL_UNLIKELY(!m_fp)) {
|
||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
|
||||
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
|
||||
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
|
||||
return;
|
||||
}
|
||||
}
|
||||
VlReadMem::~VlReadMem() {
|
||||
if (m_fp) {
|
||||
fclose(m_fp);
|
||||
m_fp = NULL;
|
||||
m_fp = nullptr;
|
||||
}
|
||||
}
|
||||
bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
||||
@@ -1821,8 +1869,8 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
||||
QData shift = m_hex ? 4ULL : 1ULL;
|
||||
bool innum = false;
|
||||
// Shift value in
|
||||
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
|
||||
char c = tolower(*it);
|
||||
for (const auto& i : rhs) {
|
||||
char c = tolower(i);
|
||||
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
|
||||
if (m_bits <= 8) {
|
||||
CData* datap = reinterpret_cast<CData*>(valuep);
|
||||
@@ -1852,14 +1900,9 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
||||
}
|
||||
|
||||
VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end)
|
||||
: m_bits(bits)
|
||||
, m_addr(0) {
|
||||
if (VL_UNLIKELY(!hex)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "",
|
||||
"Unsupported: $writemem binary format (suggest hex format)");
|
||||
return;
|
||||
}
|
||||
|
||||
: m_hex{hex}
|
||||
, m_bits{bits}
|
||||
, m_addr{0} {
|
||||
if (VL_UNLIKELY(start > end)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range");
|
||||
return;
|
||||
@@ -1868,14 +1911,14 @@ VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData st
|
||||
m_fp = fopen(filename.c_str(), "w");
|
||||
if (VL_UNLIKELY(!m_fp)) {
|
||||
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
|
||||
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
|
||||
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
|
||||
return;
|
||||
}
|
||||
}
|
||||
VlWriteMem::~VlWriteMem() {
|
||||
if (m_fp) {
|
||||
fclose(m_fp);
|
||||
m_fp = NULL;
|
||||
m_fp = nullptr;
|
||||
}
|
||||
}
|
||||
void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
|
||||
@@ -1886,23 +1929,40 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
|
||||
m_addr = addr + 1;
|
||||
if (m_bits <= 8) {
|
||||
const CData* datap = reinterpret_cast<const CData*>(valuep);
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
if (m_hex) {
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
} else {
|
||||
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
|
||||
}
|
||||
} else if (m_bits <= 16) {
|
||||
const SData* datap = reinterpret_cast<const SData*>(valuep);
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
if (m_hex) {
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
} else {
|
||||
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
|
||||
}
|
||||
} else if (m_bits <= 32) {
|
||||
const IData* datap = reinterpret_cast<const IData*>(valuep);
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
if (m_hex) {
|
||||
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
|
||||
fprintf(m_fp, "\n");
|
||||
} else {
|
||||
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
|
||||
}
|
||||
} else if (m_bits <= 64) {
|
||||
const QData* datap = reinterpret_cast<const QData*>(valuep);
|
||||
vluint64_t value = VL_MASK_Q(m_bits) & *datap;
|
||||
vluint32_t lo = value & 0xffffffff;
|
||||
vluint32_t hi = value >> 32;
|
||||
fprintf(m_fp, memhFormat(m_bits - 32), hi);
|
||||
fprintf(m_fp, "%08x\n", lo);
|
||||
if (m_hex) {
|
||||
fprintf(m_fp, memhFormat(m_bits - 32), hi);
|
||||
fprintf(m_fp, "%08x\n", lo);
|
||||
} else {
|
||||
fprintf(m_fp, "%s", formatBinary(m_bits - 32, hi));
|
||||
fprintf(m_fp, "%s\n", formatBinary(32, lo));
|
||||
}
|
||||
} else {
|
||||
WDataInP datap = reinterpret_cast<WDataInP>(valuep);
|
||||
// output as a sequence of VL_EDATASIZE'd words
|
||||
@@ -1915,9 +1975,17 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
|
||||
if (first) {
|
||||
data &= VL_MASK_E(m_bits);
|
||||
int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1;
|
||||
fprintf(m_fp, memhFormat(top_word_nbits), data);
|
||||
if (m_hex) {
|
||||
fprintf(m_fp, memhFormat(top_word_nbits), data);
|
||||
} else {
|
||||
fprintf(m_fp, "%s", formatBinary(top_word_nbits, data));
|
||||
}
|
||||
} else {
|
||||
fprintf(m_fp, "%08x", data);
|
||||
if (m_hex) {
|
||||
fprintf(m_fp, "%08x", data);
|
||||
} else {
|
||||
fprintf(m_fp, "%s", formatBinary(32, data));
|
||||
}
|
||||
}
|
||||
word_idx--;
|
||||
first = false;
|
||||
@@ -2111,17 +2179,7 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
|
||||
//===========================================================================
|
||||
// Verilated:: Methods
|
||||
|
||||
Verilated::ThreadLocal::ThreadLocal()
|
||||
:
|
||||
#ifdef VL_THREADED
|
||||
t_mtaskId(0)
|
||||
, t_endOfEvalReqd(0)
|
||||
,
|
||||
#endif
|
||||
t_dpiScopep(NULL)
|
||||
, t_dpiFilename(0)
|
||||
, t_dpiLineno(0) {
|
||||
}
|
||||
Verilated::ThreadLocal::ThreadLocal() {}
|
||||
Verilated::ThreadLocal::~ThreadLocal() {}
|
||||
|
||||
void Verilated::debug(int level) VL_MT_SAFE {
|
||||
@@ -2228,7 +2286,7 @@ void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
|
||||
const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE {
|
||||
// Returns new'ed data
|
||||
// Used by symbol table creation to make module names
|
||||
static VL_THREAD_LOCAL char* strp = NULL;
|
||||
static VL_THREAD_LOCAL char* strp = nullptr;
|
||||
static VL_THREAD_LOCAL size_t len = 0;
|
||||
size_t newlen = strlen(n1) + strlen(n2) + strlen(delimiter) + 1;
|
||||
if (!strp || newlen > len) {
|
||||
@@ -2242,29 +2300,60 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
|
||||
return strp;
|
||||
}
|
||||
|
||||
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
if (s_flushCb == cb) { // Ok - don't duplicate
|
||||
} else if (!s_flushCb) {
|
||||
s_flushCb = cb;
|
||||
} else { // LCOV_EXCL_LINE
|
||||
// Someday we may allow multiple callbacks ala atexit(), but until then
|
||||
VL_FATAL_MT("unknown", 0, "", // LCOV_EXCL_LINE
|
||||
"Verilated::flushCb called twice with different callbacks");
|
||||
}
|
||||
//=========================================================================
|
||||
// Flush and exit callbacks
|
||||
|
||||
// Keeping these out of class Verilated to avoid having to include <list>
|
||||
// in verilated.h (for compilation speed)
|
||||
typedef std::list<std::pair<Verilated::VoidPCb, void*>> VoidPCbList;
|
||||
static VoidPCbList g_flushCbs;
|
||||
static VoidPCbList g_exitCbs;
|
||||
|
||||
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
|
||||
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
|
||||
cbs.remove(pair); // Just in case it's a duplicate
|
||||
cbs.push_back(pair);
|
||||
}
|
||||
static void removeCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
|
||||
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
|
||||
cbs.remove(pair);
|
||||
}
|
||||
static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE {
|
||||
for (const auto& i : cbs) i.first(i.second);
|
||||
}
|
||||
|
||||
// When running internal code coverage (gcc --coverage, as opposed to
|
||||
// verilator --coverage), dump coverage data to properly cover failing
|
||||
// tests.
|
||||
void Verilated::flushCall() VL_MT_SAFE {
|
||||
void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
if (s_flushCb) (*s_flushCb)();
|
||||
addCb(cb, datap, g_flushCbs);
|
||||
}
|
||||
void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
removeCb(cb, datap, g_flushCbs);
|
||||
}
|
||||
void Verilated::runFlushCallbacks() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
runCallbacks(g_flushCbs);
|
||||
fflush(stderr);
|
||||
fflush(stdout);
|
||||
// When running internal code coverage (gcc --coverage, as opposed to
|
||||
// verilator --coverage), dump coverage data to properly cover failing
|
||||
// tests.
|
||||
VL_GCOV_FLUSH();
|
||||
}
|
||||
|
||||
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
addCb(cb, datap, g_exitCbs);
|
||||
}
|
||||
void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
removeCb(cb, datap, g_exitCbs);
|
||||
}
|
||||
void Verilated::runExitCallbacks() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
runCallbacks(g_exitCbs);
|
||||
}
|
||||
|
||||
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
|
||||
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
|
||||
|
||||
@@ -2341,31 +2430,60 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
}
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedImp:: Constructors
|
||||
|
||||
// verilated.o may exist both in protect-lib and main module.
|
||||
// Both the main module and the protec-lib refer the same instance of
|
||||
// static variables such as Verilated or VerilatedImplData.
|
||||
// This is important to share the state such as Verilated::gotFinish.
|
||||
// But the sharing may cause double-free error when shutting down because destructors
|
||||
// are called twice.
|
||||
// 1st time:From protec-lib shared object on the way of unloading after exitting main()
|
||||
// 2nd time:From main executable.
|
||||
//
|
||||
// To avoid the trouble, all member variables are enclosed in VerilatedImpU union.
|
||||
// ctor nor dtor of members are not called automatically.
|
||||
// VerilatedImp::setup() and teardown() guarantees to initialize/destruct just once.
|
||||
|
||||
void VerilatedImp::setup() {
|
||||
static bool done = false;
|
||||
if (!done) {
|
||||
new (&VerilatedImp::s_s) VerilatedImpData();
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
void VerilatedImp::teardown() {
|
||||
static bool done = false;
|
||||
if (!done) {
|
||||
VerilatedImp::s_s.~VerilatedImpU();
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedImp:: Methods
|
||||
|
||||
std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_sergMutex);
|
||||
return s_s.m_serg.m_timeFormatSuffix;
|
||||
const VerilatedLockGuard lock(s_s.v.m_sergMutex);
|
||||
return s_s.v.m_serg.m_timeFormatSuffix;
|
||||
}
|
||||
void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_sergMutex);
|
||||
s_s.m_serg.m_timeFormatSuffix = value;
|
||||
const VerilatedLockGuard lock(s_s.v.m_sergMutex);
|
||||
s_s.v.m_serg.m_timeFormatSuffix = value;
|
||||
}
|
||||
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = value; }
|
||||
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.v.m_ser.m_timeFormatUnits = value; }
|
||||
void VerilatedImp::timeFormatPrecision(int value) VL_MT_SAFE {
|
||||
s_s.m_ser.m_timeFormatPrecision = value;
|
||||
s_s.v.m_ser.m_timeFormatPrecision = value;
|
||||
}
|
||||
void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; }
|
||||
void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.v.m_ser.m_timeFormatWidth = value; }
|
||||
|
||||
void VerilatedImp::internalsDump() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_argMutex);
|
||||
VL_PRINTF_MT("internalsDump:\n");
|
||||
versionDump();
|
||||
VL_PRINTF_MT(" Argv:");
|
||||
for (ArgVec::const_iterator it = s_s.m_argVec.begin(); it != s_s.m_argVec.end(); ++it) {
|
||||
VL_PRINTF_MT(" %s", it->c_str());
|
||||
}
|
||||
for (const auto& i : s_s.v.m_argVec) VL_PRINTF_MT(" %s", i.c_str());
|
||||
VL_PRINTF_MT("\n");
|
||||
scopesDump();
|
||||
exportsDump();
|
||||
@@ -2375,22 +2493,22 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
|
||||
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||
}
|
||||
|
||||
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
s_s.m_argVec.clear(); // Always clear
|
||||
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_argMutex);
|
||||
s_s.v.m_argVec.clear(); // Always clear
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_argMutex);
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
|
||||
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
|
||||
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.v.m_argMutex) {
|
||||
if (!s_s.v.m_argVecLoaded) s_s.v.m_argVec.clear();
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.v.m_argVec.push_back(argv[i]);
|
||||
commandArgVl(argv[i]);
|
||||
}
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
s_s.v.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
void VerilatedImp::commandArgVl(const std::string& arg) {
|
||||
if (0 == strncmp(arg.c_str(), "+verilator+", strlen("+verilator+"))) {
|
||||
@@ -2460,12 +2578,12 @@ VerilatedSyms::~VerilatedSyms() {
|
||||
// VerilatedModule:: Methods
|
||||
|
||||
VerilatedModule::VerilatedModule(const char* namep)
|
||||
: m_namep(strdup(namep)) {}
|
||||
: m_namep{strdup(namep)} {}
|
||||
|
||||
VerilatedModule::~VerilatedModule() {
|
||||
// Memory cleanup - not called during normal operation
|
||||
// NOLINTNEXTLINE(google-readability-casting)
|
||||
if (m_namep) VL_DO_CLEAR(free((void*)(m_namep)), m_namep = NULL);
|
||||
if (m_namep) VL_DO_CLEAR(free((void*)(m_namep)), m_namep = nullptr);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
@@ -2481,7 +2599,7 @@ vluint32_t VerilatedVarProps::entSize() const {
|
||||
case VLVT_UINT32: size = sizeof(IData); break;
|
||||
case VLVT_UINT64: size = sizeof(QData); break;
|
||||
case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break;
|
||||
default: size = 0; break;
|
||||
default: size = 0; break; // LCOV_EXCL_LINE
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -2493,8 +2611,8 @@ size_t VerilatedVarProps::totalSize() const {
|
||||
}
|
||||
|
||||
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
|
||||
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return NULL;
|
||||
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL;
|
||||
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
|
||||
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
|
||||
int indxAdj = indx - low(dim);
|
||||
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
|
||||
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
|
||||
@@ -2507,23 +2625,14 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
|
||||
//======================================================================
|
||||
// VerilatedScope:: Methods
|
||||
|
||||
VerilatedScope::VerilatedScope() {
|
||||
m_callbacksp = NULL;
|
||||
m_namep = NULL;
|
||||
m_identifierp = NULL;
|
||||
m_funcnumMax = 0;
|
||||
m_symsp = NULL;
|
||||
m_varsp = NULL;
|
||||
m_timeunit = 0;
|
||||
m_type = SCOPE_OTHER;
|
||||
}
|
||||
VerilatedScope::VerilatedScope() {}
|
||||
|
||||
VerilatedScope::~VerilatedScope() {
|
||||
// Memory cleanup - not called during normal operation
|
||||
VerilatedImp::scopeErase(this);
|
||||
if (m_namep) VL_DO_CLEAR(delete[] m_namep, m_namep = NULL);
|
||||
if (m_callbacksp) VL_DO_CLEAR(delete[] m_callbacksp, m_callbacksp = NULL);
|
||||
if (m_varsp) VL_DO_CLEAR(delete m_varsp, m_varsp = NULL);
|
||||
if (m_namep) VL_DO_CLEAR(delete[] m_namep, m_namep = nullptr);
|
||||
if (m_callbacksp) VL_DO_CLEAR(delete[] m_callbacksp, m_callbacksp = nullptr);
|
||||
if (m_varsp) VL_DO_CLEAR(delete m_varsp, m_varsp = nullptr);
|
||||
m_funcnumMax = 0; // Force callback table to empty
|
||||
}
|
||||
|
||||
@@ -2565,7 +2674,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
||||
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE {
|
||||
// Grab dimensions
|
||||
// In the future we may just create a large table at emit time and
|
||||
@@ -2573,7 +2682,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
||||
if (!finalize) return;
|
||||
|
||||
if (!m_varsp) m_varsp = new VerilatedVarNameMap();
|
||||
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims);
|
||||
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims, isParam);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, dims);
|
||||
@@ -2602,10 +2711,10 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
||||
// cppcheck-suppress unusedFunction // Used by applications
|
||||
VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTINIT {
|
||||
if (VL_LIKELY(m_varsp)) {
|
||||
VerilatedVarNameMap::iterator it = m_varsp->find(namep);
|
||||
const auto it = m_varsp->find(namep);
|
||||
if (VL_LIKELY(it != m_varsp->end())) return &(it->second);
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
|
||||
@@ -2614,7 +2723,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
|
||||
+ "' 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 NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFindError(int funcnum) const {
|
||||
@@ -2623,7 +2732,7 @@ void* VerilatedScope::exportFindError(int funcnum) const {
|
||||
+ "' but this DPI export function exists only in other scopes, not scope '"
|
||||
+ name() + "'");
|
||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VerilatedScope::scopeDump() const {
|
||||
@@ -2635,9 +2744,7 @@ void VerilatedScope::scopeDump() const {
|
||||
}
|
||||
}
|
||||
if (VerilatedVarNameMap* varsp = this->varsp()) {
|
||||
for (VerilatedVarNameMap::const_iterator it = varsp->begin(); it != varsp->end(); ++it) {
|
||||
VL_PRINTF_MT(" VAR %p: %s\n", &(it->second), it->first);
|
||||
}
|
||||
for (const auto& i : *varsp) VL_PRINTF_MT(" VAR %p: %s\n", &(i.second), i.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+87
-57
@@ -61,7 +61,7 @@
|
||||
|
||||
// Version check
|
||||
#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION < 20111121)
|
||||
# warning "Verilator soon requires SystemC 2.3.*; see manual for deprecated other versions."
|
||||
# warning "Verilator requires SystemC 2.3.* or newer."
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
@@ -84,10 +84,6 @@ typedef EData WData; ///< Verilated pack data, >64 bits, as an array
|
||||
typedef const WData* WDataInP; ///< Array input to a function
|
||||
typedef WData* WDataOutP; ///< Array output from a function
|
||||
|
||||
typedef void (*VerilatedVoidCb)(void);
|
||||
|
||||
class SpTraceVcd;
|
||||
class SpTraceVcdCFile;
|
||||
class VerilatedEvalMsgQueue;
|
||||
class VerilatedScopeNameMap;
|
||||
class VerilatedVar;
|
||||
@@ -98,7 +94,7 @@ class VerilatedVcdSc;
|
||||
class VerilatedFst;
|
||||
class VerilatedFstC;
|
||||
|
||||
enum VerilatedVarType {
|
||||
enum VerilatedVarType : vluint8_t {
|
||||
VLVT_UNKNOWN = 0,
|
||||
VLVT_PTR, // Pointer to something
|
||||
VLVT_UINT8, // AKA CData
|
||||
@@ -167,7 +163,7 @@ private:
|
||||
|
||||
public:
|
||||
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr)
|
||||
: m_mutexr(mutexr) {
|
||||
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
|
||||
m_mutexr.lock();
|
||||
}
|
||||
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
|
||||
@@ -207,7 +203,7 @@ public:
|
||||
/// The constructor establishes the thread id for all later calls.
|
||||
/// If necessary, a different class could be made that inits it otherwise.
|
||||
VerilatedAssertOneThread()
|
||||
: m_threadid(VL_THREAD_ID()) {}
|
||||
: m_threadid{VL_THREAD_ID()} {}
|
||||
~VerilatedAssertOneThread() { check(); }
|
||||
// METHODS
|
||||
/// Check that the current thread ID is the same as the construction thread ID
|
||||
@@ -317,21 +313,21 @@ public: // But for internal use only
|
||||
|
||||
class VerilatedScope {
|
||||
public:
|
||||
typedef enum {
|
||||
typedef enum : vluint8_t {
|
||||
SCOPE_MODULE,
|
||||
SCOPE_OTHER
|
||||
} Type; // Type of a scope, currently module is only interesting
|
||||
private:
|
||||
// Fastpath:
|
||||
VerilatedSyms* m_symsp; ///< Symbol table
|
||||
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
||||
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
||||
VerilatedSyms* m_symsp = nullptr; ///< Symbol table
|
||||
void** m_callbacksp = nullptr; ///< Callback table pointer (Fastpath)
|
||||
int m_funcnumMax = 0; ///< Maxium function number stored (Fastpath)
|
||||
// 4 bytes padding (on -m64), for rent.
|
||||
VerilatedVarNameMap* m_varsp; ///< Variable map
|
||||
const char* m_namep; ///< Scope name (Slowpath)
|
||||
const char* m_identifierp; ///< Identifier of scope (with escapes removed)
|
||||
vlsint8_t m_timeunit; ///< Timeunit in negative power-of-10
|
||||
Type m_type; ///< Type of the scope
|
||||
VerilatedVarNameMap* m_varsp = nullptr; ///< Variable map
|
||||
const char* m_namep = nullptr; ///< Scope name (Slowpath)
|
||||
const char* m_identifierp = nullptr; ///< Identifier of scope (with escapes removed)
|
||||
vlsint8_t m_timeunit = 0; ///< Timeunit in negative power-of-10
|
||||
Type m_type = SCOPE_OTHER; ///< Type of the scope
|
||||
|
||||
public: // But internals only - called from VerilatedModule's
|
||||
VerilatedScope();
|
||||
@@ -339,8 +335,8 @@ public: // But internals only - called from VerilatedModule's
|
||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
|
||||
const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
|
||||
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
||||
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
|
||||
int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||
// ACCESSORS
|
||||
const char* name() const { return m_namep; }
|
||||
const char* identifier() const { return m_identifierp; }
|
||||
@@ -376,8 +372,6 @@ class Verilated {
|
||||
// Slow path variables
|
||||
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
|
||||
|
||||
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
||||
|
||||
static struct Serialized { // All these members serialized/deserialized
|
||||
// Fast path
|
||||
int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||
@@ -399,8 +393,8 @@ class Verilated {
|
||||
static struct NonSerialized { // Non-serialized information
|
||||
// These are reloaded from on command-line settings, so do not need to persist
|
||||
// Fast path
|
||||
vluint64_t s_profThreadsStart; ///< +prof+threads starting time
|
||||
vluint32_t s_profThreadsWindow; ///< +prof+threads window size
|
||||
vluint64_t s_profThreadsStart = 1; ///< +prof+threads starting time
|
||||
vluint32_t s_profThreadsWindow = 2; ///< +prof+threads window size
|
||||
// Slow path
|
||||
const char* s_profThreadsFilenamep; ///< +prof+threads filename
|
||||
NonSerialized();
|
||||
@@ -411,23 +405,22 @@ class Verilated {
|
||||
// assumption is that the restore is allowed to pass different arguments
|
||||
static struct CommandArgValues {
|
||||
VerilatedMutex m_argMutex; ///< Mutex for s_args members, when VL_THREADED
|
||||
int argc;
|
||||
const char** argv;
|
||||
CommandArgValues()
|
||||
: argc(0)
|
||||
, argv(NULL) {}
|
||||
int argc = 0;
|
||||
const char** argv = nullptr;
|
||||
CommandArgValues() {}
|
||||
~CommandArgValues() {}
|
||||
} s_args;
|
||||
|
||||
// Not covered by mutex, as per-thread
|
||||
static VL_THREAD_LOCAL struct ThreadLocal {
|
||||
#ifdef VL_THREADED
|
||||
vluint32_t t_mtaskId; ///< Current mtask# executing on this thread
|
||||
vluint32_t t_endOfEvalReqd; ///< Messages may be pending, thread needs endOf-eval calls
|
||||
vluint32_t t_mtaskId = 0; ///< Current mtask# executing on this thread
|
||||
vluint32_t t_endOfEvalReqd
|
||||
= 0; ///< Messages may be pending, thread needs endOf-eval calls
|
||||
#endif
|
||||
const VerilatedScope* t_dpiScopep; ///< DPI context scope
|
||||
const char* t_dpiFilename; ///< DPI context filename
|
||||
int t_dpiLineno; ///< DPI context line number
|
||||
const VerilatedScope* t_dpiScopep = nullptr; ///< DPI context scope
|
||||
const char* t_dpiFilename = nullptr; ///< DPI context filename
|
||||
int t_dpiLineno = 0; ///< DPI context line number
|
||||
|
||||
ThreadLocal();
|
||||
~ThreadLocal();
|
||||
@@ -501,9 +494,16 @@ public:
|
||||
static void profThreadsFilenamep(const char* flagp) VL_MT_SAFE;
|
||||
static const char* profThreadsFilenamep() VL_MT_SAFE { return s_ns.s_profThreadsFilenamep; }
|
||||
|
||||
/// Flush callback for VCD waves
|
||||
static void flushCb(VerilatedVoidCb cb) VL_MT_SAFE;
|
||||
static void flushCall() VL_MT_SAFE;
|
||||
typedef void (*VoidPCb)(void*); // Callback type for below
|
||||
/// Callbacks to run on global flush
|
||||
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void runFlushCallbacks() VL_MT_SAFE;
|
||||
static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated
|
||||
/// Callbacks to run prior to termination
|
||||
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void runExitCallbacks() VL_MT_SAFE;
|
||||
|
||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs,
|
||||
/// and for parsing +verilator+ run-time arguments.
|
||||
@@ -561,8 +561,8 @@ public:
|
||||
t_s.t_dpiFilename = filenamep;
|
||||
t_s.t_dpiLineno = lineno;
|
||||
}
|
||||
static void dpiClearContext() VL_MT_SAFE { t_s.t_dpiScopep = NULL; }
|
||||
static bool dpiInContext() VL_MT_SAFE { return t_s.t_dpiScopep != NULL; }
|
||||
static void dpiClearContext() VL_MT_SAFE { t_s.t_dpiScopep = nullptr; }
|
||||
static bool dpiInContext() VL_MT_SAFE { return t_s.t_dpiScopep != nullptr; }
|
||||
static const char* dpiFilenamep() VL_MT_SAFE { return t_s.t_dpiFilename; }
|
||||
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
|
||||
static int exportFuncNum(const char* namep) VL_MT_SAFE;
|
||||
@@ -644,9 +644,19 @@ extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||
/// Print a debug message from internals with standard prefix, with printf style format
|
||||
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||
|
||||
extern IData VL_RANDOM_I(int obits); ///< Randomize a signal
|
||||
extern QData VL_RANDOM_Q(int obits); ///< Randomize a signal
|
||||
extern vluint64_t vl_rand64() VL_MT_SAFE;
|
||||
inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
|
||||
inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
|
||||
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signal
|
||||
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
|
||||
vluint64_t rnd = vl_rand64();
|
||||
if (VL_LIKELY(hi > lo)) {
|
||||
// Modulus isn't very fast but it's common that hi-low is power-of-two
|
||||
return (rnd % (hi - lo)) + lo;
|
||||
} else {
|
||||
return (rnd % (lo - hi)) + hi;
|
||||
}
|
||||
}
|
||||
|
||||
/// Init time only, so slow is fine
|
||||
extern IData VL_RAND_RESET_I(int obits); ///< Random reset a signal
|
||||
@@ -764,9 +774,27 @@ static inline QData VL_CVT_Q_D(double lhs) VL_PURE {
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
/// Return double from QData (numeric)
|
||||
static inline double VL_ITOR_D_I(IData lhs) VL_PURE {
|
||||
return static_cast<double>(static_cast<vlsint32_t>(lhs));
|
||||
/// Return double from lhs (numeric) unsigned
|
||||
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE;
|
||||
static inline double VL_ITOR_D_I(int, IData lhs) VL_PURE {
|
||||
return static_cast<double>(static_cast<vluint32_t>(lhs));
|
||||
}
|
||||
static inline double VL_ITOR_D_Q(int, QData lhs) VL_PURE {
|
||||
return static_cast<double>(static_cast<vluint64_t>(lhs));
|
||||
}
|
||||
/// Return double from lhs (numeric) signed
|
||||
double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE;
|
||||
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_PURE {
|
||||
if (lbits == 32) return static_cast<double>(static_cast<vlsint32_t>(lhs));
|
||||
WData lwp[VL_WQ_WORDS_E];
|
||||
VL_SET_WI(lwp, lhs);
|
||||
return VL_ISTOR_D_W(lbits, lwp);
|
||||
}
|
||||
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_PURE {
|
||||
if (lbits == 64) return static_cast<double>(static_cast<vlsint64_t>(lhs));
|
||||
WData lwp[VL_WQ_WORDS_E];
|
||||
VL_SET_WQ(lwp, lhs);
|
||||
return VL_ISTOR_D_W(lbits, lwp);
|
||||
}
|
||||
/// Return QData from double (numeric)
|
||||
static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
|
||||
@@ -819,13 +847,8 @@ extern int VL_TIME_STR_CONVERT(const char* strp) VL_PURE;
|
||||
|
||||
/// Return current simulation time
|
||||
#if defined(SYSTEMC_VERSION)
|
||||
# if SYSTEMC_VERSION > 20011000
|
||||
// Already defined: extern sc_time sc_time_stamp();
|
||||
inline vluint64_t vl_time_stamp64() { return sc_time_stamp().value(); }
|
||||
# else // Before SystemC changed to integral time representation
|
||||
// Already defined: extern double sc_time_stamp();
|
||||
inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_stamp()); }
|
||||
# endif
|
||||
#else // Non-SystemC
|
||||
# ifdef VL_TIME_STAMP64
|
||||
extern vluint64_t vl_time_stamp64();
|
||||
@@ -843,7 +866,7 @@ inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_sta
|
||||
// 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_UNITED_D(scale) (VL_TIME_D() * (1.0 / (scale)))
|
||||
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast<double>(scale))
|
||||
/// Time imported from units to time precision
|
||||
double vl_time_multiplier(int scale);
|
||||
|
||||
@@ -1453,6 +1476,7 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
//=========================================================================
|
||||
// Math
|
||||
|
||||
// Output NOT clean
|
||||
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE {
|
||||
EData carry = 1;
|
||||
for (int i = 0; i < words; ++i) {
|
||||
@@ -1571,24 +1595,30 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
|
||||
|
||||
static inline IData VL_DIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
|
||||
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
|
||||
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
|
||||
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
|
||||
return lhs_signed / rhs_signed;
|
||||
}
|
||||
static inline QData VL_DIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
|
||||
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
|
||||
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
|
||||
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
|
||||
return lhs_signed / rhs_signed;
|
||||
}
|
||||
static inline IData VL_MODDIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
|
||||
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
|
||||
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
|
||||
return lhs_signed % rhs_signed;
|
||||
}
|
||||
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
|
||||
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
|
||||
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
|
||||
return lhs_signed % rhs_signed;
|
||||
@@ -2532,25 +2562,25 @@ static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase,
|
||||
EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0;
|
||||
_END(obits,1);
|
||||
_END(obits, VL_WORDS_I(lsb) + 1);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase,
|
||||
EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1;
|
||||
_END(obits,2);
|
||||
_END(obits, VL_WORDS_I(lsb) + 2);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase,
|
||||
EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2;
|
||||
_END(obits,3);
|
||||
_END(obits, VL_WORDS_I(lsb) + 3);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase,
|
||||
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
_END(obits,4);
|
||||
_END(obits, VL_WORDS_I(lsb) + 4);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
|
||||
EData d4,
|
||||
@@ -2558,7 +2588,7 @@ static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4;
|
||||
_END(obits,5);
|
||||
_END(obits, VL_WORDS_I(lsb) + 5);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
|
||||
EData d5, EData d4,
|
||||
@@ -2566,7 +2596,7 @@ static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4; o[5] = d5;
|
||||
_END(obits,6);
|
||||
_END(obits, VL_WORDS_I(lsb) + 6);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
|
||||
EData d6, EData d5, EData d4,
|
||||
@@ -2574,7 +2604,7 @@ static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4; o[5] = d5; o[6] = d6;
|
||||
_END(obits,7);
|
||||
_END(obits, VL_WORDS_I(lsb) + 7);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
|
||||
EData d7, EData d6, EData d5, EData d4,
|
||||
@@ -2582,7 +2612,7 @@ static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4; o[5] = d5; o[6] = d6; o[7] = d7;
|
||||
_END(obits,8);
|
||||
_END(obits, VL_WORDS_I(lsb) + 8);
|
||||
}
|
||||
|
||||
#undef _END
|
||||
|
||||
+24
-3
@@ -54,6 +54,7 @@ VK_CPPFLAGS_ALWAYS += \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
-DVM_SC=$(VM_SC) \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
@@ -200,9 +201,29 @@ else
|
||||
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
|
||||
endif
|
||||
|
||||
$(VM_PREFIX)__ALL.a: $(VK_OBJS)
|
||||
$(AR) -cr $@ $^
|
||||
$(RANLIB) $@
|
||||
# When archiving just objects (.o), single $(AR) run is enough.
|
||||
# When merging objects (.o) and archives (.a), the following steps are taken.
|
||||
# 1. Extract object files from .a
|
||||
# 2. Create a new archive from extracted .o and given .o
|
||||
%.a:
|
||||
@echo "Archive $(AR) -cr $@ $^"
|
||||
@if test $(words $(filter %.a,$^)) -eq 0; then \
|
||||
$(AR) -cr $@ $^; \
|
||||
$(RANLIB) $@; \
|
||||
else \
|
||||
$(RM) -rf $*__tmpdir; \
|
||||
for archive in $(filter %.a,$^); do \
|
||||
mkdir -p $*__tmpdir/$$(basename $${archive}); \
|
||||
cd $*__tmpdir/$$(basename $${archive}); \
|
||||
$(AR) -x ../../$${archive}; \
|
||||
cd ../..; \
|
||||
done; \
|
||||
$(AR) -cr $@ $(filter %.o,$^) $*__tmpdir/*/*.o; \
|
||||
$(RM) -rf $*__tmpdir; \
|
||||
fi
|
||||
|
||||
$(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
|
||||
|
||||
|
||||
######################################################################
|
||||
### Compile rules
|
||||
|
||||
+38
-50
@@ -70,15 +70,15 @@ private:
|
||||
public:
|
||||
// METHODS
|
||||
// cppcheck-suppress truncLongCastReturn
|
||||
virtual vluint64_t count() const VL_OVERRIDE { return *m_countp; }
|
||||
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
|
||||
virtual vluint64_t count() const override { return *m_countp; }
|
||||
virtual void zero() const override { *m_countp = 0; }
|
||||
// CONSTRUCTORS
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
explicit VerilatedCoverItemSpec(T* countp)
|
||||
: m_countp(countp) {
|
||||
: m_countp{countp} {
|
||||
*m_countp = 0;
|
||||
}
|
||||
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
|
||||
virtual ~VerilatedCoverItemSpec() override {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -100,16 +100,12 @@ private:
|
||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for keys
|
||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||
|
||||
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert
|
||||
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert
|
||||
int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert
|
||||
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex) = nullptr; ///< Item about to insert
|
||||
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex) = nullptr; ///< Filename about to insert
|
||||
int m_insertLineno VL_GUARDED_BY(m_mutex) = 0; ///< Line number about to insert
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedCovImp() {
|
||||
m_insertp = NULL;
|
||||
m_insertFilenamep = NULL;
|
||||
m_insertLineno = 0;
|
||||
}
|
||||
VerilatedCovImp() {}
|
||||
VL_UNCOPYABLE(VerilatedCovImp);
|
||||
|
||||
public:
|
||||
@@ -123,7 +119,7 @@ private:
|
||||
// PRIVATE METHODS
|
||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||
static int nextIndex = KEY_UNDEF + 1;
|
||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||
const auto iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
nextIndex++;
|
||||
assert(nextIndex > 0); // Didn't rollover
|
||||
@@ -220,26 +216,22 @@ private:
|
||||
}
|
||||
static void selftest() VL_MT_SAFE {
|
||||
// Little selftest
|
||||
#define VL_CST_CHECK(got, exp) \
|
||||
#define SELF_CHECK(got, exp) \
|
||||
do { \
|
||||
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
|
||||
} while (0)
|
||||
|
||||
VL_CST_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
|
||||
VL_CST_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
|
||||
VL_CST_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
|
||||
VL_CST_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
|
||||
VL_CST_CHECK(combineHier("z", "a"), "*");
|
||||
VL_CST_CHECK(combineHier("q.a", "q.b"), "q.*");
|
||||
VL_CST_CHECK(combineHier("q.za", "q.zb"), "q.z*");
|
||||
VL_CST_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
|
||||
#undef VL_CST_CHECK
|
||||
SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
|
||||
SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
|
||||
SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
|
||||
SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
|
||||
SELF_CHECK(combineHier("z", "a"), "*");
|
||||
SELF_CHECK(combineHier("q.a", "q.b"), "q.*");
|
||||
SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*");
|
||||
SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
|
||||
#undef SELF_CHECK
|
||||
}
|
||||
void clearGuts() VL_REQUIRES(m_mutex) {
|
||||
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
VL_DO_DANGLING(delete itemp, itemp);
|
||||
}
|
||||
for (const auto& itemp : m_items) VL_DO_DANGLING(delete itemp, itemp);
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
@@ -257,8 +249,7 @@ public:
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
for (const auto& itemp : m_items) {
|
||||
if (!itemMatchesString(itemp, matchp)) {
|
||||
VL_DO_DANGLING(delete itemp, itemp);
|
||||
} else {
|
||||
@@ -271,9 +262,7 @@ public:
|
||||
void zero() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
for (const auto& itemp : m_items) itemp->zero();
|
||||
}
|
||||
|
||||
// We assume there's always call to i/f/p in that order
|
||||
@@ -341,7 +330,7 @@ public:
|
||||
}
|
||||
m_items.push_back(m_insertp);
|
||||
// Prepare for next
|
||||
m_insertp = NULL;
|
||||
m_insertp = nullptr;
|
||||
}
|
||||
|
||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||
@@ -361,10 +350,9 @@ public:
|
||||
os << "# SystemC::Coverage-3\n";
|
||||
|
||||
// Build list of events; totalize if collapsing hierarchy
|
||||
typedef std::map<std::string, std::pair<std::string, vluint64_t> > EventMap;
|
||||
typedef std::map<std::string, std::pair<std::string, vluint64_t>> EventMap;
|
||||
EventMap eventCounts;
|
||||
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
for (const auto& itemp : m_items) {
|
||||
std::string name;
|
||||
std::string hier;
|
||||
bool per_instance = false;
|
||||
@@ -395,7 +383,7 @@ public:
|
||||
// inefficient)
|
||||
|
||||
// Find or insert the named event
|
||||
EventMap::iterator cit = eventCounts.find(name);
|
||||
const auto cit = eventCounts.find(name);
|
||||
if (cit != eventCounts.end()) {
|
||||
const std::string& oldhier = cit->second.first;
|
||||
cit->second.second += itemp->count();
|
||||
@@ -406,11 +394,11 @@ public:
|
||||
}
|
||||
|
||||
// Output body
|
||||
for (EventMap::const_iterator it = eventCounts.begin(); it != eventCounts.end(); ++it) {
|
||||
for (const auto& i : eventCounts) {
|
||||
os << "C '" << std::dec;
|
||||
os << it->first;
|
||||
if (!it->second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, it->second.first);
|
||||
os << "' " << it->second.second;
|
||||
os << i.first;
|
||||
if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first);
|
||||
os << "' " << i.second.second;
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -446,15 +434,15 @@ void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8)
|
||||
A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28),
|
||||
A(29)) VL_MT_SAFE {
|
||||
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
|
||||
= {NULL, NULL, NULL, // filename,lineno,page
|
||||
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
|
||||
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
|
||||
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
|
||||
= {nullptr, nullptr, nullptr, // filename,lineno,page
|
||||
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
|
||||
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
|
||||
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
|
||||
const char* valps[VerilatedCovImpBase::MAX_KEYS]
|
||||
= {NULL, NULL, NULL, // filename,lineno,page
|
||||
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
|
||||
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
|
||||
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
|
||||
= {nullptr, nullptr, nullptr, // filename,lineno,page
|
||||
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
|
||||
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
|
||||
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
|
||||
VerilatedCovImp::imp().insertp(keyps, valps);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
// there's not much more gain in having a version for each number of args.
|
||||
#define K(n) const char* key##n
|
||||
#define A(n) const char *key##n, const char *valp##n // Argument list
|
||||
#define D(n) const char *key##n = NULL, const char *valp##n = NULL // Argument list
|
||||
#define D(n) const char *key##n = nullptr, const char *valp##n = nullptr // Argument list
|
||||
static void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9));
|
||||
static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11),
|
||||
D(12), D(13), D(14), D(15), D(16), D(17), D(18), D(19));
|
||||
|
||||
+10
-10
@@ -181,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
|
||||
static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
|
||||
if (VL_UNLIKELY(!h)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"%%Error: DPI svOpenArrayHandle function called with NULL handle");
|
||||
"%%Error: DPI svOpenArrayHandle function called with nullptr handle");
|
||||
}
|
||||
const VerilatedDpiOpenVar* varp = reinterpret_cast<const VerilatedDpiOpenVar*>(h);
|
||||
if (VL_UNLIKELY(!varp->magicOk())) {
|
||||
@@ -202,10 +202,10 @@ int svIncrement(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h
|
||||
int svSize(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->elements(d); }
|
||||
int svDimensions(const svOpenArrayHandle h) { return _vl_openhandle_varp(h)->udims(); }
|
||||
|
||||
/// Return pointer to open array data, or NULL if not in IEEE standard C layout
|
||||
/// Return pointer to open array data, or nullptr if not in IEEE standard C layout
|
||||
void* svGetArrayPtr(const svOpenArrayHandle h) {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return nullptr;
|
||||
return varp->datap();
|
||||
}
|
||||
/// Return size of open array, or 0 if not in IEEE standard C layout
|
||||
@@ -226,7 +226,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
|
||||
" %d dimensional array using %d dimensional function.\n",
|
||||
varp->udims(), nargs);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (nargs >= 1) {
|
||||
datap = varp->datapAdjustIndex(datap, 1, indx1);
|
||||
@@ -234,7 +234,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 "
|
||||
"out of bounds; %d outside [%d:%d].\n",
|
||||
indx1, varp->left(1), varp->right(1));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (nargs >= 2) {
|
||||
@@ -243,7 +243,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 "
|
||||
"out of bounds; %d outside [%d:%d].\n",
|
||||
indx2, varp->left(2), varp->right(2));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (nargs >= 3) {
|
||||
@@ -252,7 +252,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 "
|
||||
"out of bounds; %d outside [%d:%d].\n",
|
||||
indx1, varp->left(3), varp->right(3));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return datap;
|
||||
@@ -268,11 +268,11 @@ static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
|
||||
return indx - varp->low(0);
|
||||
}
|
||||
|
||||
/// Return pointer to simulator open array element, or NULL if outside range
|
||||
/// Return pointer to simulator open array element, or nullptr if outside range
|
||||
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, int nargs, int indx1, int indx2,
|
||||
int indx3) VL_MT_SAFE {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return nullptr;
|
||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
return datap;
|
||||
}
|
||||
@@ -794,7 +794,7 @@ void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int
|
||||
svScope svGetScope() {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) {
|
||||
_VL_SVDPI_CONTEXT_WARN();
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
// NOLINTNEXTLINE(google-readability-casting)
|
||||
return (svScope)(Verilated::dpiScope());
|
||||
|
||||
+15
-20
@@ -58,14 +58,12 @@
|
||||
// VerilatedFst
|
||||
|
||||
VerilatedFst::VerilatedFst(void* fst)
|
||||
: m_fst(fst)
|
||||
, m_symbolp(NULL)
|
||||
, m_strbuf(NULL) {}
|
||||
: m_fst{fst} {}
|
||||
|
||||
VerilatedFst::~VerilatedFst() {
|
||||
if (m_fst) fstWriterClose(m_fst);
|
||||
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL);
|
||||
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = NULL);
|
||||
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = nullptr);
|
||||
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = nullptr);
|
||||
}
|
||||
|
||||
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
@@ -82,7 +80,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
VerilatedTrace<VerilatedFst>::traceInit();
|
||||
|
||||
// Clear the scope stack
|
||||
std::list<std::string>::iterator it = m_curScope.begin();
|
||||
auto it = m_curScope.begin();
|
||||
while (it != m_curScope.end()) {
|
||||
fstWriterSetUpscope(m_fst);
|
||||
it = m_curScope.erase(it);
|
||||
@@ -91,10 +89,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
// convert m_code2symbol into an array for fast lookup
|
||||
if (!m_symbolp) {
|
||||
m_symbolp = new fstHandle[nextCode()];
|
||||
for (Code2SymbolType::iterator it = m_code2symbol.begin(); it != m_code2symbol.end();
|
||||
++it) {
|
||||
m_symbolp[it->first] = it->second;
|
||||
}
|
||||
for (const auto& i : m_code2symbol) m_symbolp[i.first] = i.second;
|
||||
}
|
||||
m_code2symbol.clear();
|
||||
|
||||
@@ -106,7 +101,7 @@ void VerilatedFst::close() {
|
||||
m_assertOne.check();
|
||||
VerilatedTrace<VerilatedFst>::close();
|
||||
fstWriterClose(m_fst);
|
||||
m_fst = NULL;
|
||||
m_fst = nullptr;
|
||||
}
|
||||
|
||||
void VerilatedFst::flush() {
|
||||
@@ -133,8 +128,6 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
|
||||
|
||||
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
|
||||
|
||||
std::pair<Code2SymbolType::iterator, bool> p
|
||||
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
|
||||
std::istringstream nameiss(name);
|
||||
std::istream_iterator<std::string> beg(nameiss);
|
||||
std::istream_iterator<std::string> end;
|
||||
@@ -144,8 +137,8 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
|
||||
tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy
|
||||
|
||||
// Find point where current and new scope diverge
|
||||
std::list<std::string>::iterator cur_it = m_curScope.begin();
|
||||
std::list<std::string>::iterator new_it = tokens.begin();
|
||||
auto cur_it = m_curScope.begin();
|
||||
auto new_it = tokens.begin();
|
||||
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
|
||||
if (*cur_it != *new_it) break;
|
||||
++cur_it;
|
||||
@@ -160,7 +153,7 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
|
||||
|
||||
// Follow the hierarchy of the new variable from the common scope point
|
||||
while (new_it != tokens.end()) {
|
||||
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), NULL);
|
||||
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), nullptr);
|
||||
m_curScope.push_back(*new_it);
|
||||
new_it = tokens.erase(new_it);
|
||||
}
|
||||
@@ -174,11 +167,13 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
|
||||
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
|
||||
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
||||
}
|
||||
if (p.second) { // New
|
||||
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
|
||||
assert(p.first->second);
|
||||
|
||||
const auto it = vlstd::as_const(m_code2symbol).find(code);
|
||||
if (it == m_code2symbol.end()) { // New
|
||||
m_code2symbol[code]
|
||||
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
|
||||
} else { // Alias
|
||||
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second);
|
||||
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ private:
|
||||
Code2SymbolType m_code2symbol;
|
||||
Local2FstDtype m_local2fstdtype;
|
||||
std::list<std::string> m_curScope;
|
||||
fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array
|
||||
char* m_strbuf; ///< String buffer long enough to hold maxBits() chars
|
||||
fstHandle* m_symbolp = nullptr; ///< same as m_code2symbol, but as an array
|
||||
char* m_strbuf = nullptr; ///< String buffer long enough to hold maxBits() chars
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFst);
|
||||
@@ -63,11 +63,11 @@ protected:
|
||||
// Implementation of VerilatedTrace interface
|
||||
|
||||
// Implementations of protected virtual methods for VerilatedTrace
|
||||
void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;
|
||||
virtual void emitTimeChange(vluint64_t timeui) override;
|
||||
|
||||
// Hooks called from VerilatedTrace
|
||||
bool preFullDump() VL_OVERRIDE { return isOpen(); }
|
||||
bool preChangeDump() VL_OVERRIDE { return isOpen(); }
|
||||
virtual bool preFullDump() override { return isOpen(); }
|
||||
virtual bool preChangeDump() override { return isOpen(); }
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTrace. These are
|
||||
// called from only one place (namely full*) so always inline them.
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
explicit VerilatedFst(void* fst = NULL);
|
||||
explicit VerilatedFst(void* fst = nullptr);
|
||||
~VerilatedFst();
|
||||
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
/// Flush any remaining data to this file
|
||||
void flush() VL_MT_UNSAFE;
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_fst != NULL; }
|
||||
bool isOpen() const { return m_fst != nullptr; }
|
||||
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
@@ -135,8 +135,8 @@ class VerilatedFstC {
|
||||
VL_UNCOPYABLE(VerilatedFstC);
|
||||
|
||||
public:
|
||||
explicit VerilatedFstC(void* filep = NULL)
|
||||
: m_sptrace(filep) {}
|
||||
explicit VerilatedFstC(void* filep = nullptr)
|
||||
: m_sptrace{filep} {}
|
||||
~VerilatedFstC() { close(); }
|
||||
/// Routines can only be called from one thread; allow next call from different thread
|
||||
void changeThread() { spTrace()->changeThread(); }
|
||||
|
||||
+19
-26
@@ -55,28 +55,28 @@ class VlReadMem {
|
||||
public:
|
||||
VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlReadMem();
|
||||
bool isOpen() const { return m_fp != NULL; }
|
||||
bool isOpen() const { return m_fp != nullptr; }
|
||||
int linenum() const { return m_linenum; }
|
||||
bool get(QData& addrr, std::string& valuer);
|
||||
void setData(void* valuep, const std::string& rhs);
|
||||
};
|
||||
|
||||
class VlWriteMem {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to write
|
||||
public:
|
||||
VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlWriteMem();
|
||||
bool isOpen() const { return m_fp != NULL; }
|
||||
bool isOpen() const { return m_fp != nullptr; }
|
||||
void print(QData addr, bool addrstamp, const void* valuep);
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Verilog array container
|
||||
// Similar to std::array<WData, N>, but:
|
||||
// 1. Doesn't require C++11
|
||||
// 2. Lighter weight, only methods needed by Verilator, to help compile time.
|
||||
// Similar to std::array<WData, N>, but lighter weight, only methods needed
|
||||
// by Verilator, to help compile time.
|
||||
//
|
||||
// This is only used when we need an upper-level container and so can't
|
||||
// simply use a C style array (which is just a pointer).
|
||||
@@ -145,21 +145,21 @@ public:
|
||||
int exists(const T_Key& index) const { return m_map.find(index) != m_map.end(); }
|
||||
// Return first element. Verilog: function int first(ref index);
|
||||
int first(T_Key& indexr) const {
|
||||
typename Map::const_iterator it = m_map.begin();
|
||||
const auto it = m_map.cbegin();
|
||||
if (it == m_map.end()) return 0;
|
||||
indexr = it->first;
|
||||
return 1;
|
||||
}
|
||||
// Return last element. Verilog: function int last(ref index)
|
||||
int last(T_Key& indexr) const {
|
||||
typename Map::const_reverse_iterator it = m_map.rbegin();
|
||||
const auto it = m_map.crbegin();
|
||||
if (it == m_map.rend()) return 0;
|
||||
indexr = it->first;
|
||||
return 1;
|
||||
}
|
||||
// Return next element. Verilog: function int next(ref index)
|
||||
int next(T_Key& indexr) const {
|
||||
typename Map::const_iterator it = m_map.find(indexr);
|
||||
auto it = m_map.find(indexr);
|
||||
if (VL_UNLIKELY(it == m_map.end())) return 0;
|
||||
++it;
|
||||
if (VL_UNLIKELY(it == m_map.end())) return 0;
|
||||
@@ -168,7 +168,7 @@ public:
|
||||
}
|
||||
// Return prev element. Verilog: function int prev(ref index)
|
||||
int prev(T_Key& indexr) const {
|
||||
typename Map::const_iterator it = m_map.find(indexr);
|
||||
auto it = m_map.find(indexr);
|
||||
if (VL_UNLIKELY(it == m_map.end())) return 0;
|
||||
if (VL_UNLIKELY(it == m_map.begin())) return 0;
|
||||
--it;
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
// Can't just overload operator[] or provide a "at" reference to set,
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(const T_Key& index) {
|
||||
typename Map::iterator it = m_map.find(index);
|
||||
const auto it = m_map.find(index);
|
||||
if (it == m_map.end()) {
|
||||
std::pair<typename Map::iterator, bool> pit
|
||||
= m_map.insert(std::make_pair(index, m_defaultValue));
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(const T_Key& index) const {
|
||||
typename Map::iterator it = m_map.find(index);
|
||||
const auto it = m_map.find(index);
|
||||
if (it == m_map.end()) {
|
||||
return m_defaultValue;
|
||||
} else {
|
||||
@@ -204,8 +204,8 @@ public:
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (typename Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
out += comma + VL_TO_STRING(it->first) + ":" + VL_TO_STRING(it->second);
|
||||
for (const auto& i : m_map) {
|
||||
out += comma + VL_TO_STRING(i.first) + ":" + VL_TO_STRING(i.second);
|
||||
comma = ", ";
|
||||
}
|
||||
// Default not printed - maybe random init data
|
||||
@@ -239,10 +239,9 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
const VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
|
||||
VlWriteMem wmem(hex, bits, filename, start, end);
|
||||
if (VL_UNLIKELY(!wmem.isOpen())) return;
|
||||
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = obj.begin(); it != obj.end();
|
||||
++it) {
|
||||
QData addr = it->first;
|
||||
if (addr >= start && addr <= end) wmem.print(addr, true, &(it->second));
|
||||
for (const auto& i : obj) {
|
||||
QData addr = i.first;
|
||||
if (addr >= start && addr <= end) wmem.print(addr, true, &(i.second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,8 +360,8 @@ public:
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (typename Deque::const_iterator it = m_deque.begin(); it != m_deque.end(); ++it) {
|
||||
out += comma + VL_TO_STRING(*it);
|
||||
for (const auto& i : m_deque) {
|
||||
out += comma + VL_TO_STRING(i);
|
||||
comma = ", ";
|
||||
}
|
||||
return out + "} ";
|
||||
@@ -379,13 +378,7 @@ template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||
// be protected by other means
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || (__cplusplus >= 201103L)
|
||||
# define VlClassRef std::shared_ptr
|
||||
#else
|
||||
# define VlClassRef VlClassRef__SystemVerilog_class_support_requires_a_C11_or_newer_compiler
|
||||
#endif
|
||||
// clang-format on
|
||||
#define VlClassRef std::shared_ptr
|
||||
|
||||
template <class T> // T typically of type VlClassRef<x>
|
||||
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
|
||||
|
||||
+140
-130
@@ -62,8 +62,8 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedMsg(const std::function<void()>& cb)
|
||||
: m_mtaskId(Verilated::mtaskId())
|
||||
, m_cb(cb) {}
|
||||
: m_mtaskId{Verilated::mtaskId()}
|
||||
, m_cb{cb} {}
|
||||
~VerilatedMsg() {}
|
||||
// METHODS
|
||||
vluint32_t mtaskId() const { return m_mtaskId; }
|
||||
@@ -84,7 +84,7 @@ class VerilatedEvalMsgQueue {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedEvalMsgQueue()
|
||||
: m_depth(0) {
|
||||
: m_depth{0} {
|
||||
assert(atomic_is_lock_free(&m_depth));
|
||||
}
|
||||
~VerilatedEvalMsgQueue() {}
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
// Unfortunately to release the lock we need to copy the message
|
||||
// (Or have the message be a pointer, but then new/delete cost on each message)
|
||||
// We assume messages are small, so copy
|
||||
auto it = m_queue.begin();
|
||||
const auto it = m_queue.begin();
|
||||
const VerilatedMsg msg = *(it);
|
||||
m_queue.erase(it);
|
||||
m_mutex.unlock();
|
||||
@@ -172,12 +172,11 @@ public:
|
||||
// FILE* list constructed from a file-descriptor
|
||||
class VerilatedFpList {
|
||||
FILE* m_fp[31];
|
||||
std::size_t m_sz;
|
||||
std::size_t m_sz = 0;
|
||||
|
||||
public:
|
||||
typedef FILE* const* const_iterator;
|
||||
explicit VerilatedFpList()
|
||||
: m_sz(0) {}
|
||||
explicit VerilatedFpList() {}
|
||||
const_iterator begin() const { return m_fp; }
|
||||
const_iterator end() const { return m_fp + m_sz; }
|
||||
std::size_t size() const { return m_sz; }
|
||||
@@ -190,10 +189,11 @@ public:
|
||||
//======================================================================
|
||||
// VerilatedImp
|
||||
|
||||
class VerilatedImp {
|
||||
class VerilatedImpData {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
protected:
|
||||
friend class Verilated;
|
||||
friend class VerilatedImp;
|
||||
|
||||
// TYPES
|
||||
typedef std::vector<std::string> ArgVec;
|
||||
@@ -201,17 +201,13 @@ protected:
|
||||
typedef std::map<const char*, int, VerilatedCStrCmp> ExportNameMap;
|
||||
|
||||
// MEMBERS
|
||||
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
struct Serialized { // All these members serialized/deserialized
|
||||
int m_timeFormatUnits; // $timeformat units
|
||||
int m_timeFormatPrecision; // $timeformat number of decimal places
|
||||
int m_timeFormatWidth; // $timeformat character width
|
||||
int m_timeFormatUnits = UNITS_NONE; // $timeformat units
|
||||
int m_timeFormatPrecision = 0; // $timeformat number of decimal places
|
||||
int m_timeFormatWidth = 20; // $timeformat character width
|
||||
enum { UNITS_NONE = 99 }; // Default based on precision
|
||||
Serialized()
|
||||
: m_timeFormatUnits(UNITS_NONE)
|
||||
, m_timeFormatPrecision(0)
|
||||
, m_timeFormatWidth(20) {}
|
||||
Serialized() {}
|
||||
~Serialized() {}
|
||||
} m_ser;
|
||||
|
||||
@@ -252,19 +248,37 @@ protected:
|
||||
// List of free descriptors in the MCT region [4, 32)
|
||||
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedImpData()
|
||||
: m_argVecLoaded{false}
|
||||
, m_exportNext{0} {
|
||||
|
||||
m_fdps.resize(31);
|
||||
std::fill(m_fdps.begin(), m_fdps.end(), (FILE*)0);
|
||||
m_fdFreeMct.resize(30);
|
||||
for (std::size_t i = 0, id = 1; i < m_fdFreeMct.size(); ++i, ++id) { m_fdFreeMct[i] = id; }
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
protected:
|
||||
friend class Verilated;
|
||||
|
||||
// MEMBERS
|
||||
union VerilatedImpU { ///< Enclose in an union to call ctor/dtor manually
|
||||
VerilatedImpData v;
|
||||
VerilatedImpU() {}
|
||||
~VerilatedImpU() {}
|
||||
};
|
||||
static VerilatedImpU s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp()
|
||||
: m_argVecLoaded(false)
|
||||
, m_exportNext(0) {
|
||||
s_s.m_fdps.resize(31);
|
||||
std::fill(s_s.m_fdps.begin(), s_s.m_fdps.end(), (FILE*)0);
|
||||
s_s.m_fdFreeMct.resize(30);
|
||||
for (std::size_t i = 0, id = 1; i < s_s.m_fdFreeMct.size(); ++i, ++id) {
|
||||
s_s.m_fdFreeMct[i] = id;
|
||||
}
|
||||
}
|
||||
VerilatedImp() {}
|
||||
~VerilatedImp() {}
|
||||
static void setup();
|
||||
static void teardown();
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedImp);
|
||||
@@ -276,28 +290,28 @@ public:
|
||||
|
||||
// METHODS - arguments
|
||||
public:
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex);
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex);
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.v.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_argMutex);
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
if (VL_UNLIKELY(!s_s.v.m_argVecLoaded)) {
|
||||
s_s.v.m_argVecLoaded = true; // Complain only once
|
||||
VL_FATAL_MT("unknown", 0, "",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::const_iterator it = s_s.m_argVec.begin(); it != s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0] == '+') {
|
||||
if (0 == strncmp(prefixp, it->c_str() + 1, len)) return *it;
|
||||
for (const auto& i : s_s.v.m_argVec) {
|
||||
if (i[0] == '+') {
|
||||
if (0 == strncmp(prefixp, i.c_str() + 1, len)) return i;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.v.m_argMutex);
|
||||
static void commandArgVl(const std::string& arg);
|
||||
static bool commandArgVlValue(const std::string& arg, const std::string& prefix,
|
||||
std::string& valuer);
|
||||
@@ -308,18 +322,18 @@ public:
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (it != s_s.m_userMap.end()) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
|
||||
const auto it = s_s.v.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (it != s_s.v.m_userMap.end()) {
|
||||
it->second = userData;
|
||||
} else {
|
||||
s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||
s_s.v.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||
}
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::const_iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL;
|
||||
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
|
||||
const auto& it = vlstd::as_const(s_s.v.m_userMap).find(std::make_pair(scopep, userKey));
|
||||
if (VL_UNLIKELY(it == s_s.v.m_userMap.end())) return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -327,25 +341,26 @@ private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
const VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
|
||||
for (auto it = s_s.v.m_userMap.begin(); it != s_s.v.m_userMap.end();) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
s_s.v.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void userDump() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
const VerilatedLockGuard lock(
|
||||
s_s.v.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
bool first = true;
|
||||
for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) {
|
||||
for (const auto& i : s_s.v.m_userMap) {
|
||||
if (first) {
|
||||
VL_PRINTF_MT(" userDump:\n");
|
||||
first = false;
|
||||
}
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", it->first.first,
|
||||
it->first.second, it->second);
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", i.first.first, i.first.second,
|
||||
i.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,51 +368,50 @@ public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at construction
|
||||
const VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
const auto it = s_s.v.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.v.m_nameMap.end()) {
|
||||
s_s.v.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep);
|
||||
if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL;
|
||||
const auto& it = s_s.v.m_nameMap.find(namep);
|
||||
if (VL_UNLIKELY(it == s_s.v.m_nameMap.end())) return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at destruction
|
||||
const VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
userEraseScope(scopep);
|
||||
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
const auto it = s_s.v.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.v.m_nameMap.end()) s_s.v.m_nameMap.erase(it);
|
||||
}
|
||||
static void scopesDump() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
VL_PRINTF_MT(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
|
||||
it != s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
for (const auto& i : s_s.v.m_nameMap) {
|
||||
const VerilatedScope* scopep = i.second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF_MT("\n");
|
||||
}
|
||||
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
return &s_s.m_nameMap;
|
||||
return &s_s.v.m_nameMap;
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - hierarchy
|
||||
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
|
||||
// Slow ok - called at construction for VPI accessible elements
|
||||
const VerilatedLockGuard lock(s_s.m_hierMapMutex);
|
||||
s_s.m_hierMap[fromp].push_back(top);
|
||||
const VerilatedLockGuard lock(s_s.v.m_hierMapMutex);
|
||||
s_s.v.m_hierMap[fromp].push_back(top);
|
||||
}
|
||||
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
return &s_s.m_hierMap;
|
||||
return &s_s.v.m_hierMap;
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
@@ -411,19 +425,19 @@ public: // But only for verilated*.cpp
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||
// Slow ok - called once/function at creation
|
||||
const VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::iterator it = s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||
return s_s.m_exportNext++;
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
const auto it = s_s.v.m_exportMap.find(namep);
|
||||
if (it == s_s.v.m_exportMap.end()) {
|
||||
s_s.v.m_exportMap.insert(it, std::make_pair(namep, s_s.v.m_exportNext++));
|
||||
return s_s.v.m_exportNext++;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
const auto& it = s_s.v.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.v.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ") + namep
|
||||
+ " but no such DPI export function name exists in ANY model");
|
||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||
@@ -431,23 +445,21 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
const VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
|
||||
it != s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
for (const auto& i : s_s.v.m_exportMap) {
|
||||
if (i.second == funcnum) return i.first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
static void exportsDump() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
bool first = true;
|
||||
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
|
||||
it != s_s.m_exportMap.end(); ++it) {
|
||||
for (const auto& i : s_s.v.m_exportMap) {
|
||||
if (first) {
|
||||
VL_PRINTF_MT(" exportDump:\n");
|
||||
first = false;
|
||||
}
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", i.second, i.first);
|
||||
}
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
@@ -458,13 +470,13 @@ public: // But only for verilated*.cpp
|
||||
static std::string timeFormatSuffix() VL_MT_SAFE;
|
||||
static void timeFormatSuffix(const std::string& value) VL_MT_SAFE;
|
||||
static int timeFormatUnits() VL_MT_SAFE {
|
||||
if (s_s.m_ser.m_timeFormatUnits == Serialized::UNITS_NONE) {
|
||||
if (s_s.v.m_ser.m_timeFormatUnits == VerilatedImpData::Serialized::UNITS_NONE) {
|
||||
return Verilated::timeprecision();
|
||||
}
|
||||
return s_s.m_ser.m_timeFormatUnits;
|
||||
return s_s.v.m_ser.m_timeFormatUnits;
|
||||
}
|
||||
static int timeFormatPrecision() VL_MT_SAFE { return s_s.m_ser.m_timeFormatPrecision; }
|
||||
static int timeFormatWidth() VL_MT_SAFE { return s_s.m_ser.m_timeFormatWidth; }
|
||||
static int timeFormatPrecision() VL_MT_SAFE { return s_s.v.m_ser.m_timeFormatPrecision; }
|
||||
static int timeFormatWidth() VL_MT_SAFE { return s_s.v.m_ser.m_timeFormatWidth; }
|
||||
static void timeFormatUnits(int value) VL_MT_SAFE;
|
||||
static void timeFormatPrecision(int value) VL_MT_SAFE;
|
||||
static void timeFormatWidth(int value) VL_MT_SAFE;
|
||||
@@ -472,93 +484,91 @@ public: // But only for verilated*.cpp
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFreeMct.empty()) return 0;
|
||||
IData idx = s_s.m_fdFreeMct.back();
|
||||
s_s.m_fdFreeMct.pop_back();
|
||||
s_s.m_fdps[idx] = fopen(filenamep, "w");
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return 0;
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
if (s_s.v.m_fdFreeMct.empty()) return 0;
|
||||
IData idx = s_s.v.m_fdFreeMct.back();
|
||||
s_s.v.m_fdFreeMct.pop_back();
|
||||
s_s.v.m_fdps[idx] = fopen(filenamep, "w");
|
||||
if (VL_UNLIKELY(!s_s.v.m_fdps[idx])) return 0;
|
||||
return (1 << idx);
|
||||
}
|
||||
static IData fdNew(const char* filenamep, const char* modep) VL_MT_SAFE {
|
||||
FILE* fp = fopen(filenamep, modep);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
if (s_s.v.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
|
||||
const size_t excess = 10;
|
||||
s_s.m_fdps.resize(start + excess);
|
||||
std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0);
|
||||
s_s.m_fdFree.resize(excess);
|
||||
for (std::size_t i = 0, id = start; i < s_s.m_fdFree.size(); ++i, ++id) {
|
||||
s_s.m_fdFree[i] = id;
|
||||
const std::size_t start = std::max<std::size_t>(31UL + 1UL + 3UL, s_s.v.m_fdps.size());
|
||||
const std::size_t excess = 10;
|
||||
s_s.v.m_fdps.resize(start + excess);
|
||||
std::fill(s_s.v.m_fdps.begin() + start, s_s.v.m_fdps.end(), (FILE*)0);
|
||||
s_s.v.m_fdFree.resize(excess);
|
||||
for (std::size_t i = 0, id = start; i < s_s.v.m_fdFree.size(); ++i, ++id) {
|
||||
s_s.v.m_fdFree[i] = id;
|
||||
}
|
||||
}
|
||||
IData idx = s_s.m_fdFree.back();
|
||||
s_s.m_fdFree.pop_back();
|
||||
s_s.m_fdps[idx] = fp;
|
||||
IData idx = s_s.v.m_fdFree.back();
|
||||
s_s.v.m_fdFree.pop_back();
|
||||
s_s.v.m_fdps[idx] = fp;
|
||||
return (idx | (1UL << 31)); // bit 31 indicates not MCD
|
||||
}
|
||||
static void fdFlush(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
|
||||
fflush(*it);
|
||||
}
|
||||
for (const auto& i : fdlist) fflush(i);
|
||||
}
|
||||
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
|
||||
return static_cast<IData>(
|
||||
fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
|
||||
}
|
||||
static IData fdTell(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
|
||||
return static_cast<IData>(ftell(*fdlist.begin()));
|
||||
}
|
||||
static void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
|
||||
if (VL_UNLIKELY(!*it)) continue;
|
||||
fwrite(output.c_str(), 1, output.size(), *it);
|
||||
for (const auto& i : fdlist) {
|
||||
if (VL_UNLIKELY(!i)) continue;
|
||||
(void)fwrite(output.c_str(), 1, output.size(), i);
|
||||
}
|
||||
}
|
||||
static void fdClose(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
if ((fdi & (1 << 31)) != 0) {
|
||||
// Non-MCD case
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(idx >= s_s.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||
fclose(s_s.m_fdps[idx]);
|
||||
s_s.m_fdps[idx] = (FILE*)0;
|
||||
s_s.m_fdFree.push_back(idx);
|
||||
if (VL_UNLIKELY(idx >= s_s.v.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.v.m_fdps[idx])) return; // Already free
|
||||
fclose(s_s.v.m_fdps[idx]);
|
||||
s_s.v.m_fdps[idx] = (FILE*)0;
|
||||
s_s.v.m_fdFree.push_back(idx);
|
||||
} else {
|
||||
// MCD case
|
||||
for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) {
|
||||
if (fdi & VL_MASK_I(1)) {
|
||||
fclose(s_s.m_fdps[i]);
|
||||
s_s.m_fdps[i] = NULL;
|
||||
s_s.m_fdFreeMct.push_back(i);
|
||||
fclose(s_s.v.m_fdps[i]);
|
||||
s_s.v.m_fdps[i] = nullptr;
|
||||
s_s.v.m_fdFreeMct.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return NULL;
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr;
|
||||
return *fdlist.begin();
|
||||
}
|
||||
|
||||
private:
|
||||
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.m_fdMutex) {
|
||||
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.v.m_fdMutex) {
|
||||
VerilatedFpList fp;
|
||||
if ((fdi & (1 << 31)) != 0) {
|
||||
// Non-MCD case
|
||||
@@ -568,13 +578,13 @@ private:
|
||||
case 1: fp.push_back(stdout); break;
|
||||
case 2: fp.push_back(stderr); break;
|
||||
default:
|
||||
if (VL_LIKELY(idx < s_s.m_fdps.size())) fp.push_back(s_s.m_fdps[idx]);
|
||||
if (VL_LIKELY(idx < s_s.v.m_fdps.size())) fp.push_back(s_s.v.m_fdps[idx]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// MCD Case
|
||||
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
|
||||
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.m_fdps[i]);
|
||||
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.v.m_fdps[i]);
|
||||
}
|
||||
}
|
||||
return fp;
|
||||
|
||||
+14
-11
@@ -42,9 +42,10 @@
|
||||
// clang-format on
|
||||
|
||||
// CONSTANTS
|
||||
static const char* const VLTSAVE_HEADER_STR
|
||||
= "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||
/// Value of first bytes of each file (must be multiple of 8 bytes)
|
||||
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n";
|
||||
/// Value of last bytes of each file (must be multiple of 8 bytes)
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved";
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
@@ -64,10 +65,10 @@ VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict da
|
||||
size_t size) VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg
|
||||
= "Can't deserialize save-restore file as was made from different model:" + filename();
|
||||
std::string msg = "Can't deserialize save-restore file as was made from different model: "
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
@@ -88,9 +89,11 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg
|
||||
= std::string("Can't deserialize; file has wrong header signature: ") + filename();
|
||||
= std::string(
|
||||
"Can't deserialize; file has wrong header signature, or file not found: ")
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size());
|
||||
os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size());
|
||||
@@ -109,7 +112,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open(filenamep,
|
||||
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
||||
if (m_fd < 0) {
|
||||
if (VL_UNLIKELY(m_fd < 0)) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
@@ -151,7 +154,7 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
|
||||
if (m_fd < 0) {
|
||||
if (VL_UNLIKELY(m_fd < 0)) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
|
||||
+19
-25
@@ -34,7 +34,7 @@ protected:
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
bool m_isOpen = false; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
@@ -49,13 +49,12 @@ protected:
|
||||
|
||||
public:
|
||||
VerilatedSerialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t[bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
}
|
||||
virtual ~VerilatedSerialize() {
|
||||
close();
|
||||
if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL);
|
||||
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
@@ -94,8 +93,8 @@ protected:
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
vluint8_t* m_endp = nullptr; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen = false; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
@@ -111,14 +110,12 @@ protected:
|
||||
|
||||
public:
|
||||
VerilatedDeserialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t[bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
m_endp = NULL;
|
||||
}
|
||||
virtual ~VerilatedDeserialize() {
|
||||
close();
|
||||
if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL);
|
||||
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
@@ -159,19 +156,18 @@ private:
|
||||
|
||||
class VerilatedSave : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd = -1; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSave()
|
||||
: m_fd(-1) {}
|
||||
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
|
||||
VerilatedSave() {}
|
||||
virtual ~VerilatedSave() override { close(); }
|
||||
// METHODS
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void close() override VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() override VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -180,21 +176,20 @@ public:
|
||||
|
||||
class VerilatedRestore : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd = -1; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedRestore()
|
||||
: m_fd(-1) {}
|
||||
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
|
||||
VerilatedRestore() {}
|
||||
virtual ~VerilatedRestore() override { close(); }
|
||||
|
||||
// METHODS
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void close() override VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() override VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() override VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -257,10 +252,9 @@ VerilatedSerialize& operator<<(VerilatedSerialize& os, VlAssocArray<T_Key, T_Val
|
||||
os << rhs.atDefault();
|
||||
vluint32_t len = rhs.size();
|
||||
os << len;
|
||||
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = rhs.begin(); it != rhs.end();
|
||||
++it) {
|
||||
T_Key index = it->first; // Copy to get around const_iterator
|
||||
T_Value value = it->second;
|
||||
for (const auto& i : rhs) {
|
||||
T_Key index = i.first; // Copy to get around const_iterator
|
||||
T_Value value = i.second;
|
||||
os << index << value;
|
||||
}
|
||||
return os;
|
||||
|
||||
@@ -44,11 +44,11 @@ protected:
|
||||
friend class VerilatedVarProps;
|
||||
friend class VerilatedScope;
|
||||
VerilatedRange()
|
||||
: m_left(0)
|
||||
, m_right(0) {}
|
||||
: m_left{0}
|
||||
, m_right{0} {}
|
||||
VerilatedRange(int left, int right)
|
||||
: m_left(left)
|
||||
, m_right(right) {}
|
||||
: m_left{left}
|
||||
, m_right{right} {}
|
||||
void init(int left, int right) {
|
||||
m_left = left;
|
||||
m_right = right;
|
||||
@@ -92,48 +92,48 @@ class VerilatedVarProps {
|
||||
protected:
|
||||
friend class VerilatedScope;
|
||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
|
||||
: m_magic(MAGIC)
|
||||
, m_vltype(vltype)
|
||||
, m_vlflags(vlflags)
|
||||
, m_pdims(pdims)
|
||||
, m_udims(udims) {
|
||||
initUnpacked(NULL);
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags{vlflags}
|
||||
, m_pdims{pdims}
|
||||
, m_udims{udims} {
|
||||
initUnpacked(nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
class Unpacked {};
|
||||
// Without packed
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||
: m_magic(MAGIC)
|
||||
, m_vltype(vltype)
|
||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||
, m_pdims(0)
|
||||
, m_udims(0) {}
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{0}
|
||||
, m_udims{0} {}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
||||
: m_magic(MAGIC)
|
||||
, m_vltype(vltype)
|
||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||
, m_pdims(0)
|
||||
, m_udims(udims) {
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{0}
|
||||
, m_udims{udims} {
|
||||
initUnpacked(ulims);
|
||||
}
|
||||
// With packed
|
||||
class Packed {};
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
|
||||
: m_magic(MAGIC)
|
||||
, m_vltype(vltype)
|
||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||
, m_pdims(1)
|
||||
, m_udims(0)
|
||||
, m_packed(pl, pr) {}
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{1}
|
||||
, m_udims{0}
|
||||
, m_packed{pl, pr} {}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
||||
int udims, const int* ulims)
|
||||
: m_magic(MAGIC)
|
||||
, m_vltype(vltype)
|
||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||
, m_pdims(1)
|
||||
, m_udims(udims)
|
||||
, m_packed(pl, pr) {
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{1}
|
||||
, m_udims{udims}
|
||||
, m_packed{pl, pr} {
|
||||
initUnpacked(ulims);
|
||||
}
|
||||
|
||||
@@ -196,11 +196,11 @@ class VerilatedDpiOpenVar {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
|
||||
: m_propsp(propsp)
|
||||
, m_datap(datap) {}
|
||||
: m_propsp{propsp}
|
||||
, m_datap{datap} {}
|
||||
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap)
|
||||
: m_propsp(propsp)
|
||||
, m_datap(const_cast<void*>(datap)) {}
|
||||
: m_propsp{propsp}
|
||||
, m_datap{const_cast<void*>(datap)} {}
|
||||
~VerilatedDpiOpenVar() {}
|
||||
// METHODS
|
||||
void* datap() const { return m_datap; }
|
||||
@@ -232,13 +232,15 @@ class VerilatedVar : public VerilatedVarProps {
|
||||
void* m_datap; // Location of data
|
||||
const char* m_namep; // Name - slowpath
|
||||
protected:
|
||||
bool m_isParam;
|
||||
friend class VerilatedScope;
|
||||
// CONSTRUCTORS
|
||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||
VerilatedVarFlags vlflags, int dims)
|
||||
: VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0))
|
||||
, m_datap(datap)
|
||||
, m_namep(namep) {}
|
||||
VerilatedVarFlags vlflags, int dims, bool isParam)
|
||||
: VerilatedVarProps{vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)}
|
||||
, m_datap{datap}
|
||||
, m_namep{namep}
|
||||
, m_isParam{isParam} {}
|
||||
|
||||
public:
|
||||
~VerilatedVar() {}
|
||||
@@ -247,6 +249,7 @@ public:
|
||||
const VerilatedRange& range() const { return packed(); } // Deprecated
|
||||
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
||||
const char* name() const { return m_namep; }
|
||||
bool isParam() const { return m_isParam; }
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
std::atomic<vluint64_t> VlMTaskVertex::s_yields;
|
||||
|
||||
VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = NULL;
|
||||
VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = nullptr;
|
||||
|
||||
//=============================================================================
|
||||
// VlMTaskVertex
|
||||
|
||||
VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
|
||||
: m_upstreamDepsDone(0)
|
||||
, m_upstreamDepCount(upstreamDepCount) {
|
||||
: m_upstreamDepsDone{0}
|
||||
, m_upstreamDepCount{upstreamDepCount} {
|
||||
assert(atomic_is_lock_free(&m_upstreamDepsDone));
|
||||
}
|
||||
|
||||
@@ -36,13 +36,11 @@ VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
|
||||
// VlWorkerThread
|
||||
|
||||
VlWorkerThread::VlWorkerThread(VlThreadPool* poolp, bool profiling)
|
||||
: m_waiting(false)
|
||||
, m_ready_size(0)
|
||||
, m_poolp(poolp)
|
||||
, m_profiling(profiling)
|
||||
, m_exiting(false)
|
||||
// Must init this last -- after setting up fields that it might read:
|
||||
, m_cthread(startWorker, this) {}
|
||||
: m_waiting{false}
|
||||
, m_poolp{poolp}
|
||||
, m_profiling{profiling} // Must init this last -- after setting up fields that it might read:
|
||||
, m_exiting{false}
|
||||
, m_cthread{startWorker, this} {}
|
||||
|
||||
VlWorkerThread::~VlWorkerThread() {
|
||||
m_exiting.store(true, std::memory_order_release);
|
||||
@@ -55,7 +53,7 @@ void VlWorkerThread::workerLoop() {
|
||||
if (VL_UNLIKELY(m_profiling)) m_poolp->setupProfilingClientThread();
|
||||
|
||||
ExecRec work;
|
||||
work.m_fnp = NULL;
|
||||
work.m_fnp = nullptr;
|
||||
|
||||
while (true) {
|
||||
if (VL_LIKELY(!work.m_fnp)) dequeWork(&work);
|
||||
@@ -65,7 +63,7 @@ void VlWorkerThread::workerLoop() {
|
||||
|
||||
if (VL_LIKELY(work.m_fnp)) {
|
||||
work.m_fnp(work.m_evenCycle, work.m_sym);
|
||||
work.m_fnp = NULL;
|
||||
work.m_fnp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +76,7 @@ void VlWorkerThread::startWorker(VlWorkerThread* workerp) { workerp->workerLoop(
|
||||
// VlThreadPool
|
||||
|
||||
VlThreadPool::VlThreadPool(int nThreads, bool profiling)
|
||||
: m_profiling(profiling) {
|
||||
: m_profiling{profiling} {
|
||||
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
|
||||
unsigned cpus = std::thread::hardware_concurrency();
|
||||
if (cpus < nThreads + 1) {
|
||||
@@ -110,7 +108,7 @@ VlThreadPool::~VlThreadPool() {
|
||||
void VlThreadPool::tearDownProfilingClientThread() {
|
||||
assert(t_profilep);
|
||||
delete t_profilep;
|
||||
t_profilep = NULL;
|
||||
t_profilep = nullptr;
|
||||
}
|
||||
|
||||
void VlThreadPool::setupProfilingClientThread() {
|
||||
@@ -127,9 +125,9 @@ void VlThreadPool::setupProfilingClientThread() {
|
||||
|
||||
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
|
||||
const VerilatedLockGuard lk(m_mutex);
|
||||
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
|
||||
for (const auto& profilep : m_allProfiles) {
|
||||
// Every thread's profile trace gets a copy of rec.
|
||||
(*it)->emplace_back(rec);
|
||||
profilep->emplace_back(rec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +139,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
|
||||
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
|
||||
return;
|
||||
return; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// TODO Perhaps merge with verilated_coverage output format, so can
|
||||
@@ -154,13 +152,12 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
||||
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n", VlMTaskVertex::yields());
|
||||
|
||||
vluint32_t thread_id = 0;
|
||||
for (ProfileSet::const_iterator pit = m_allProfiles.begin(); pit != m_allProfiles.end();
|
||||
++pit) {
|
||||
for (const auto& pi : m_allProfiles) {
|
||||
++thread_id;
|
||||
|
||||
bool printing = false; // False while in warmup phase
|
||||
for (ProfileTrace::const_iterator eit = (*pit)->begin(); eit != (*pit)->end(); ++eit) {
|
||||
switch (eit->m_type) {
|
||||
for (const auto& ei : *pi) {
|
||||
switch (ei.m_type) {
|
||||
case VlProfileRec::TYPE_BARRIER: //
|
||||
printing = true;
|
||||
break;
|
||||
@@ -170,9 +167,8 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
||||
"VLPROF mtask %d"
|
||||
" start %" VL_PRI64 "u end %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
|
||||
" predict_time %u cpu %u on thread %u\n",
|
||||
eit->m_mtaskId, eit->m_startTime, eit->m_endTime,
|
||||
(eit->m_endTime - eit->m_startTime), eit->m_predictTime, eit->m_cpu,
|
||||
thread_id);
|
||||
ei.m_mtaskId, ei.m_startTime, ei.m_endTime,
|
||||
(ei.m_endTime - ei.m_startTime), ei.m_predictTime, ei.m_cpu, thread_id);
|
||||
break;
|
||||
default: assert(false); break; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
+21
-19
@@ -22,6 +22,15 @@
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h" // for VerilatedMutex and clang annotations
|
||||
|
||||
#ifndef VL_THREADED
|
||||
// Hitting this likely means verilated_threads.cpp is being compiled when
|
||||
// 'verilator --threads' was not used. 'verilator --threads' sets
|
||||
// VL_THREADED.
|
||||
// Alternatively it is always safe but may harm performance to always
|
||||
// define VL_THREADED for all compiles.
|
||||
#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)"
|
||||
#endif
|
||||
|
||||
#include <condition_variable>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
@@ -119,23 +128,16 @@ class VlProfileRec {
|
||||
protected:
|
||||
friend class VlThreadPool;
|
||||
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
|
||||
VlProfileE m_type; // Record type
|
||||
vluint32_t m_mtaskId; // Mtask we're logging
|
||||
vluint32_t m_predictTime; // How long scheduler predicted would take
|
||||
vluint64_t m_startTime; // Tick at start of execution
|
||||
vluint64_t m_endTime; // Tick at end of execution
|
||||
VlProfileE m_type = TYPE_BARRIER; // Record type
|
||||
vluint32_t m_mtaskId = 0; // Mtask we're logging
|
||||
vluint32_t m_predictTime = 0; // How long scheduler predicted would take
|
||||
vluint64_t m_startTime = 0; // Tick at start of execution
|
||||
vluint64_t m_endTime = 0; // Tick at end of execution
|
||||
unsigned m_cpu; // Execution CPU number (at start anyways)
|
||||
public:
|
||||
class Barrier {};
|
||||
VlProfileRec() {}
|
||||
explicit VlProfileRec(Barrier) {
|
||||
m_type = TYPE_BARRIER;
|
||||
m_mtaskId = 0;
|
||||
m_predictTime = 0;
|
||||
m_startTime = 0;
|
||||
m_endTime = 0;
|
||||
m_cpu = getcpu();
|
||||
}
|
||||
explicit VlProfileRec(Barrier) { m_cpu = getcpu(); }
|
||||
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
|
||||
m_type = VlProfileRec::TYPE_MTASK_RUN;
|
||||
m_mtaskId = mtask;
|
||||
@@ -174,13 +176,13 @@ private:
|
||||
VlThrSymTab m_sym; // Symbol table to execute
|
||||
bool m_evenCycle; // Even/odd for flag alternation
|
||||
ExecRec()
|
||||
: m_fnp(NULL)
|
||||
, m_sym(NULL)
|
||||
, m_evenCycle(false) {}
|
||||
: m_fnp{nullptr}
|
||||
, m_sym{nullptr}
|
||||
, m_evenCycle{false} {}
|
||||
ExecRec(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym)
|
||||
: m_fnp(fnp)
|
||||
, m_sym(sym)
|
||||
, m_evenCycle(evenCycle) {}
|
||||
: m_fnp{fnp}
|
||||
, m_sym{sym}
|
||||
, m_evenCycle{evenCycle} {}
|
||||
};
|
||||
|
||||
// MEMBERS
|
||||
|
||||
@@ -87,7 +87,7 @@ class VerilatedTraceCommand {
|
||||
public:
|
||||
// These must all fit in 4 bit at the moment, as the tracing routines
|
||||
// pack parameters in the top bits.
|
||||
enum {
|
||||
enum : vluint8_t {
|
||||
CHG_BIT_0 = 0x0,
|
||||
CHG_BIT_1 = 0x1,
|
||||
CHG_CDATA = 0x2,
|
||||
@@ -130,11 +130,11 @@ private:
|
||||
};
|
||||
void* m_userp; // The user pointer to pass to the callback (the symbol table)
|
||||
CallbackRecord(initCb_t cb, void* userp)
|
||||
: m_initCb(cb)
|
||||
, m_userp(userp) {}
|
||||
: m_initCb{cb}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(dumpCb_t cb, void* userp)
|
||||
: m_dumpCb(cb)
|
||||
, m_userp(userp) {}
|
||||
: m_dumpCb{cb}
|
||||
, m_userp{userp} {}
|
||||
};
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Old value store
|
||||
@@ -158,6 +158,11 @@ private:
|
||||
// to access duck-typed functions to avoid a virtual function call.
|
||||
T_Derived* self() { return static_cast<T_Derived*>(this); }
|
||||
|
||||
// Flush any remaining data for this file
|
||||
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
// Close the file on termination
|
||||
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Number of total trace buffers that have been allocated
|
||||
vluint32_t m_numTraceBuffers;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
// Static utility functions
|
||||
|
||||
static double timescaleToDouble(const char* unitp) {
|
||||
char* endp = NULL;
|
||||
char* endp = nullptr;
|
||||
double value = strtod(unitp, &endp);
|
||||
// On error so we allow just "ns" to return 1e-9.
|
||||
if (value == 0.0 && endp == unitp) value = 1;
|
||||
@@ -258,22 +258,37 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flush() {
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks to run on global events
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
|
||||
// Note this calls 'flush' on the derived class
|
||||
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::onExit(void* selfp) {
|
||||
// Note this calls 'close' on the derived class
|
||||
reinterpret_cast<VL_DERIVED_T*>(selfp)->close();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
template <>
|
||||
VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
|
||||
: m_sigs_oldvalp(NULL)
|
||||
, m_timeLastDump(0)
|
||||
, m_fullDump(true)
|
||||
, m_nextCode(0)
|
||||
, m_numSignals(0)
|
||||
, m_maxBits(0)
|
||||
, m_scopeEscape('.')
|
||||
, m_timeRes(1e-9)
|
||||
, m_timeUnit(1e-9)
|
||||
: m_sigs_oldvalp{nullptr}
|
||||
, m_timeLastDump{0}
|
||||
, m_fullDump{true}
|
||||
, m_nextCode{0}
|
||||
, m_numSignals{0}
|
||||
, m_maxBits{0}
|
||||
, m_scopeEscape{'.'}
|
||||
, m_timeRes{1e-9}
|
||||
, m_timeUnit {
|
||||
1e-9
|
||||
}
|
||||
#ifdef VL_TRACE_THREADED
|
||||
, m_numTraceBuffers(0)
|
||||
, m_numTraceBuffers { 0 }
|
||||
#endif
|
||||
{
|
||||
set_time_unit(Verilated::timeunitString());
|
||||
@@ -281,7 +296,9 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
|
||||
}
|
||||
|
||||
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
|
||||
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
|
||||
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = nullptr);
|
||||
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
|
||||
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
|
||||
#ifdef VL_TRACE_THREADED
|
||||
close();
|
||||
#endif
|
||||
@@ -318,6 +335,10 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
|
||||
// holding previous signal values.
|
||||
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
|
||||
|
||||
// Set callback so flush/abort will flush this file
|
||||
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
|
||||
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Compute trace buffer size. we need to be able to store a new value for
|
||||
// each signal, which is 'nextCode()' entries after the init callbacks
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: pre-C++11 replacements for std::unordered_set
|
||||
// and std::unordered_map.
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 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
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
//*************************************************************************
|
||||
// This file has clones of the std::unordered_set and std::unordered_map
|
||||
// hash table types. They are here so that Verilator can use hash tables
|
||||
// in pre-C++11 compilers, and the same client code can link against the
|
||||
// std:: types when they are available.
|
||||
//
|
||||
// The implementations in this file do not implement the complete APIs
|
||||
// of the std:: types. Nor are they correct in every detail,
|
||||
// notably, the const_iterators do not enforce constness. We can extend
|
||||
// these implementations to cover more of the std API as needed.
|
||||
//
|
||||
// TODO: In the future, when Verilator requires C++11 to compile,
|
||||
// remove this entire file and switch to the std:: types.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _VERILATED_UNORDERED_SET_MAP_H_
|
||||
#define _VERILATED_UNORDERED_SET_MAP_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// Abstract 'vl_hash' and 'vl_equal_to' templates.
|
||||
template <typename T> struct vl_hash { size_t operator()(const T& k) const; };
|
||||
|
||||
template <typename T> struct vl_equal_to { bool operator()(const T& a, const T& b) const; };
|
||||
|
||||
// Specializations of 'vl_hash' and 'vl_equal_to'.
|
||||
inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
|
||||
const vluint8_t* bufp = static_cast<const vluint8_t*>(vbufp);
|
||||
size_t hash = 0;
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
hash = bufp[i] + 31U * hash; // the K&R classic!
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <> inline size_t vl_hash<int>::operator()(const int& k) const { return k; }
|
||||
|
||||
template <> inline bool vl_equal_to<int>::operator()(const int& a, const int& b) const {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
||||
return k;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool vl_equal_to<unsigned int>::operator()(const unsigned int& a,
|
||||
const unsigned int& b) const {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template <> inline size_t vl_hash<std::string>::operator()(const std::string& k) const {
|
||||
return vl_hash_bytes(k.data(), k.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool vl_equal_to<std::string>::operator()(const std::string& a,
|
||||
const std::string& b) const {
|
||||
// Don't scan the strings if the sizes are different.
|
||||
if (a.size() != b.size()) return false;
|
||||
return (0 == a.compare(b)); // Must scan.
|
||||
}
|
||||
|
||||
template <typename T> struct vl_hash<T*> {
|
||||
size_t operator()(T* kp) const {
|
||||
return ((sizeof(size_t) == sizeof(kp)) ? reinterpret_cast<size_t>(kp)
|
||||
: vl_hash_bytes(&kp, sizeof(kp)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct vl_equal_to<T*> {
|
||||
bool operator()(T* ap, T* bp) const { return ap == bp; }
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
/// Functional clone of the std::unordered_set hash table.
|
||||
template <class T_Key, class T_Hash = vl_hash<T_Key>, class T_Equal = vl_equal_to<T_Key> >
|
||||
class vl_unordered_set {
|
||||
public:
|
||||
// TYPES
|
||||
typedef std::list<T_Key> Bucket;
|
||||
enum RehashType { GROW, SHRINK };
|
||||
|
||||
template <class KK, class VV, class HH, class EQ> friend class vl_unordered_map;
|
||||
|
||||
class iterator {
|
||||
protected:
|
||||
// MEMBERS
|
||||
size_t m_bucketIdx; // Bucket this iterator points into
|
||||
typename Bucket::iterator m_bit; // Bucket-local iterator
|
||||
const vl_unordered_set* m_setp; // The containing set
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
iterator(size_t bucketIdx, typename Bucket::iterator bit, const vl_unordered_set* setp)
|
||||
: m_bucketIdx(bucketIdx)
|
||||
, m_bit(bit)
|
||||
, m_setp(setp) {}
|
||||
|
||||
// METHODS
|
||||
const T_Key& operator*() const { return *m_bit; }
|
||||
// This should really be 'const T_Key*' type for unordered_set,
|
||||
// however this iterator is shared with unordered_map whose
|
||||
// operator-> returns a non-const ValueType*, so keep this
|
||||
// non-const to avoid having to define a whole separate iterator
|
||||
// for unordered_map.
|
||||
T_Key* operator->() const { return &(*m_bit); }
|
||||
bool operator==(const iterator& other) const {
|
||||
return ((m_bucketIdx == other.m_bucketIdx) && (m_bit == other.m_bit));
|
||||
}
|
||||
bool operator!=(const iterator& other) const { return (!this->operator==(other)); }
|
||||
void advanceUntilValid() {
|
||||
while (true) {
|
||||
if (m_bit != m_setp->m_bucketsp[m_bucketIdx].end()) {
|
||||
// Valid iterator in this bucket; we're done.
|
||||
return;
|
||||
}
|
||||
|
||||
// Try the next bucket?
|
||||
m_bucketIdx++;
|
||||
if (m_bucketIdx == m_setp->numBuckets()) {
|
||||
// Ran past the end of buckets, set to end().
|
||||
*this = m_setp->end();
|
||||
return;
|
||||
}
|
||||
m_bit = m_setp->m_bucketsp[m_bucketIdx].begin();
|
||||
}
|
||||
}
|
||||
void operator++() {
|
||||
++m_bit;
|
||||
advanceUntilValid();
|
||||
}
|
||||
|
||||
typename Bucket::iterator bit() const { return m_bit; }
|
||||
};
|
||||
|
||||
// TODO: there's no real const enforcement on the 'const_iterator'.
|
||||
typedef iterator const_iterator;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
size_t m_numElements; // Number of entries present.
|
||||
size_t m_log2Buckets; // Log-base-2 of the number of buckets.
|
||||
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
|
||||
// // we'll allocate it on the fly when
|
||||
// // the first entries are created.
|
||||
Bucket m_emptyBucket; // A fake bucket, used to construct end().
|
||||
T_Hash m_hash; // Hash function provider.
|
||||
T_Equal m_equal; // Equal-to function provider.
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
vl_unordered_set()
|
||||
: m_numElements(0)
|
||||
, m_log2Buckets(initLog2Buckets())
|
||||
, m_bucketsp(NULL)
|
||||
, m_hash()
|
||||
, m_equal() {}
|
||||
|
||||
vl_unordered_set(const vl_unordered_set& other)
|
||||
: m_numElements(other.m_numElements)
|
||||
, m_log2Buckets(other.m_log2Buckets)
|
||||
, m_bucketsp(NULL)
|
||||
, m_hash()
|
||||
, m_equal() {
|
||||
if (other.m_bucketsp) {
|
||||
m_bucketsp = new Bucket[numBuckets()];
|
||||
for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i];
|
||||
}
|
||||
}
|
||||
~vl_unordered_set() { VL_DO_DANGLING(delete[] m_bucketsp, m_bucketsp); }
|
||||
|
||||
vl_unordered_set& operator=(const vl_unordered_set& other) {
|
||||
if (this != &other) {
|
||||
clear();
|
||||
delete[] m_bucketsp;
|
||||
m_numElements = other.m_numElements;
|
||||
m_log2Buckets = other.m_log2Buckets;
|
||||
if (other.m_bucketsp) {
|
||||
m_bucketsp = new Bucket[numBuckets()];
|
||||
for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i];
|
||||
} else {
|
||||
m_bucketsp = NULL;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
static size_t initLog2Buckets() { return 4; }
|
||||
|
||||
iterator begin() {
|
||||
if (m_numElements) {
|
||||
initBuckets();
|
||||
iterator result = iterator(0, m_bucketsp[0].begin(), this);
|
||||
result.advanceUntilValid();
|
||||
return result;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
const_iterator begin() const {
|
||||
if (m_numElements) {
|
||||
initBuckets();
|
||||
const_iterator result = iterator(0, m_bucketsp[0].begin(), this);
|
||||
result.advanceUntilValid();
|
||||
return result;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
const_iterator end() const {
|
||||
return iterator(0xFFFFFFFFFFFFFFFFULL, const_cast<Bucket&>(m_emptyBucket).begin(), this);
|
||||
}
|
||||
|
||||
bool empty() const { return m_numElements == 0; }
|
||||
|
||||
size_t size() const { return m_numElements; }
|
||||
|
||||
size_t count(const T_Key& key) const { return (find(key) == end()) ? 0 : 1; }
|
||||
|
||||
size_t hashToBucket(size_t hashVal) const { return hashToBucket(hashVal, m_log2Buckets); }
|
||||
static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) {
|
||||
// Fibonacci hashing, see
|
||||
// https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization
|
||||
// -that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
|
||||
//
|
||||
// * The magic numbers below are UINT_MAX/phi where phi is the
|
||||
// golden ratio number (1.618...) for either 64- or 32-bit
|
||||
// values of UINT_MAX.
|
||||
//
|
||||
// * Fibonacci hashing mixes the result of the client's hash
|
||||
// function further. This permits the use of very fast client
|
||||
// hash funcs (like just returning the int or pointer value as
|
||||
// is!) and tolerates crappy client hash functions pretty well.
|
||||
size_t mult = hashVal * ((sizeof(size_t) == 8) ? 11400714819323198485ULL : 2654435769lu);
|
||||
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
|
||||
return result;
|
||||
}
|
||||
|
||||
iterator find_internal(const T_Key& key, size_t& bucketIdxOut) {
|
||||
size_t hash = m_hash.operator()(key);
|
||||
bucketIdxOut = hashToBucket(hash);
|
||||
initBuckets();
|
||||
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
|
||||
|
||||
for (typename Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) {
|
||||
if (m_equal.operator()(*it, key)) return iterator(bucketIdxOut, it, this);
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
const_iterator find(const T_Key& key) const {
|
||||
size_t bucketIdx;
|
||||
return const_cast<vl_unordered_set*>(this)->find_internal(key, bucketIdx);
|
||||
}
|
||||
|
||||
iterator find(const T_Key& key) {
|
||||
size_t bucketIdx;
|
||||
return find_internal(key, bucketIdx);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const T_Key& val) {
|
||||
size_t bucketIdx;
|
||||
iterator existIt = find_internal(val, bucketIdx);
|
||||
if (existIt != end()) {
|
||||
// Collision with existing element.
|
||||
//
|
||||
// An element may be inserted only if it is not
|
||||
// equal to an existing element. So fail.
|
||||
return std::pair<iterator, bool>(end(), false);
|
||||
}
|
||||
|
||||
// No collision, so insert it.
|
||||
m_numElements++;
|
||||
|
||||
m_bucketsp[bucketIdx].push_front(val);
|
||||
|
||||
// Compute result iterator. This pointer will be valid
|
||||
// if we don't rehash:
|
||||
iterator result_it(bucketIdx, m_bucketsp[bucketIdx].begin(), this);
|
||||
|
||||
if (needToRehash(GROW)) {
|
||||
rehash(GROW);
|
||||
// ... since we rehashed, do a lookup to get the result iterator.
|
||||
result_it = find(val);
|
||||
}
|
||||
|
||||
return std::pair<iterator, bool>(result_it, true);
|
||||
}
|
||||
|
||||
iterator erase(iterator it) {
|
||||
iterator next_it = it;
|
||||
++next_it;
|
||||
erase(*it);
|
||||
return next_it;
|
||||
}
|
||||
|
||||
size_t erase(const T_Key& key) {
|
||||
size_t bucketIdx;
|
||||
iterator it = find_internal(key, bucketIdx);
|
||||
if (it != end()) {
|
||||
m_bucketsp[bucketIdx].erase(it.bit());
|
||||
m_numElements--;
|
||||
// Rehashing to handle a shrinking data set is important
|
||||
// for the Scoreboard in V3Partition, which begins tracking
|
||||
// a huge number of vertices and then tracks a successively
|
||||
// smaller number over time.
|
||||
if (needToRehash(SHRINK)) rehash(SHRINK);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (m_bucketsp) {
|
||||
delete[] m_bucketsp;
|
||||
m_bucketsp = NULL;
|
||||
}
|
||||
m_numElements = 0;
|
||||
m_log2Buckets = initLog2Buckets();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t numBuckets() const { return (1ULL << m_log2Buckets); }
|
||||
|
||||
Bucket* getBucket(size_t idx) {
|
||||
initBuckets();
|
||||
return &m_bucketsp[idx];
|
||||
}
|
||||
|
||||
void initBuckets() const {
|
||||
if (!m_bucketsp) m_bucketsp = new Bucket[numBuckets()];
|
||||
}
|
||||
|
||||
bool needToRehash(RehashType rt) const {
|
||||
if (rt == GROW) {
|
||||
return ((4 * numBuckets()) < m_numElements);
|
||||
} else {
|
||||
return (numBuckets() > (4 * m_numElements));
|
||||
}
|
||||
}
|
||||
|
||||
void rehash(RehashType rt) {
|
||||
size_t new_log2Buckets;
|
||||
if (rt == GROW) {
|
||||
new_log2Buckets = m_log2Buckets + 2;
|
||||
} else {
|
||||
if (m_log2Buckets <= 4) {
|
||||
// On shrink, saturate m_log2Buckets at its
|
||||
// initial size of 2^4 == 16 buckets. Don't risk
|
||||
// underflowing!
|
||||
return;
|
||||
}
|
||||
new_log2Buckets = m_log2Buckets - 2;
|
||||
}
|
||||
|
||||
size_t new_num_buckets = 1ULL << new_log2Buckets;
|
||||
Bucket* new_bucketsp = new Bucket[new_num_buckets];
|
||||
|
||||
for (size_t i = 0; i < numBuckets(); i++) {
|
||||
while (!m_bucketsp[i].empty()) {
|
||||
typename Bucket::iterator bit = m_bucketsp[i].begin();
|
||||
size_t hash = m_hash.operator()(*bit);
|
||||
size_t new_idx = hashToBucket(hash, new_log2Buckets);
|
||||
// Avoid mallocing one list elem and freeing another;
|
||||
// splice just moves it over.
|
||||
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(), m_bucketsp[i], bit);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] m_bucketsp;
|
||||
m_bucketsp = new_bucketsp;
|
||||
m_log2Buckets = new_log2Buckets;
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
/// Functional clone of the std::unordered_map hash table.
|
||||
template <class T_Key, class T_Value, class T_Hash = vl_hash<T_Key>,
|
||||
class T_Equal = vl_equal_to<T_Key> >
|
||||
class vl_unordered_map {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::pair<T_Key, T_Value> KeyValPair;
|
||||
|
||||
class KeyHash {
|
||||
private:
|
||||
T_Hash key_hash;
|
||||
|
||||
public:
|
||||
KeyHash() {}
|
||||
size_t operator()(const KeyValPair& kv_pair) const {
|
||||
return key_hash.operator()(kv_pair.first);
|
||||
}
|
||||
};
|
||||
|
||||
class KeyEqual {
|
||||
private:
|
||||
T_Equal key_eq;
|
||||
|
||||
public:
|
||||
KeyEqual() {}
|
||||
bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const {
|
||||
return key_eq.operator()(kv_a.first, kv_b.first);
|
||||
}
|
||||
};
|
||||
|
||||
// MEMBERS
|
||||
typedef vl_unordered_set<KeyValPair, KeyHash, KeyEqual> MapSet;
|
||||
MapSet m_set; // Wrap this vl_unordered_set which holds all state.
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
vl_unordered_map() {}
|
||||
~vl_unordered_map() {}
|
||||
|
||||
typedef typename MapSet::iterator iterator;
|
||||
typedef typename MapSet::const_iterator const_iterator;
|
||||
|
||||
// METHODS
|
||||
iterator begin() { return m_set.begin(); }
|
||||
const_iterator begin() const { return m_set.begin(); }
|
||||
const_iterator end() const { return m_set.end(); }
|
||||
bool empty() const { return m_set.empty(); }
|
||||
iterator find(const T_Key& k) {
|
||||
// We can't assume that T_Value() is defined.
|
||||
// ie, this does not work:
|
||||
// return m_set.find(std::make_pair(k, T_Value()));
|
||||
|
||||
// So, do this instead:
|
||||
T_Hash mapHash;
|
||||
T_Equal mapEq;
|
||||
size_t hash = mapHash.operator()(k);
|
||||
size_t bucketIdxOut = m_set.hashToBucket(hash);
|
||||
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
|
||||
|
||||
for (typename MapSet::Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) {
|
||||
if (mapEq.operator()(it->first, k)) return iterator(bucketIdxOut, it, &m_set);
|
||||
}
|
||||
return end();
|
||||
}
|
||||
const_iterator find(const T_Key& k) const {
|
||||
return const_cast<vl_unordered_map*>(this)->find(k);
|
||||
}
|
||||
std::pair<iterator, bool> insert(const KeyValPair& val) { return m_set.insert(val); }
|
||||
iterator erase(iterator it) { return m_set.erase(it); }
|
||||
size_t erase(const T_Key& k) {
|
||||
iterator it = find(k);
|
||||
if (it == end()) return 0;
|
||||
m_set.erase(it);
|
||||
return 1;
|
||||
}
|
||||
T_Value& operator[](const T_Key& k) {
|
||||
// Here we can assume T_Value() is defined, as
|
||||
// std::unordered_map::operator[] relies on it too.
|
||||
KeyValPair dummy = std::make_pair(k, T_Value());
|
||||
iterator it = m_set.find(dummy);
|
||||
if (it == m_set.end()) it = m_set.insert(dummy).first;
|
||||
// For the 'set', it's generally not safe to modify
|
||||
// the value after deref. For the 'map' though, we know
|
||||
// it's safe to modify the value field and we can allow it:
|
||||
return it->second;
|
||||
}
|
||||
T_Value& at(const T_Key& k) {
|
||||
iterator it = find(k);
|
||||
if (it == end()) { throw std::out_of_range("sorry"); }
|
||||
return it->second;
|
||||
}
|
||||
const T_Value& at(const T_Key& k) const {
|
||||
iterator it = find(k);
|
||||
if (it == end()) { throw std::out_of_range("sorry"); }
|
||||
return it->second;
|
||||
}
|
||||
void clear() { m_set.clear(); }
|
||||
size_t size() const { return m_set.size(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
+19
-77
@@ -51,13 +51,14 @@
|
||||
// This size comes form VCD allowing use of printable ASCII characters between
|
||||
// '!' and '~' inclusive, which are a total of 94 different values. Encoding a
|
||||
// 32 bit code hence needs a maximum of ceil(log94(2**32-1)) == 5 bytes.
|
||||
#define VL_TRACE_MAX_VCD_CODE_SIZE 5 ///< Maximum length of a VCD string code
|
||||
constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; ///< Maximum length of a VCD string code
|
||||
|
||||
// We use 8 bytes per code in a suffix buffer array.
|
||||
// 1 byte optional separator + VL_TRACE_MAX_VCD_CODE_SIZE bytes for code
|
||||
// + 1 byte '\n' + 1 byte suffix size. This luckily comes out to a power of 2,
|
||||
// meaning the array can be aligned such that entries never straddle multiple
|
||||
// cache-lines.
|
||||
#define VL_TRACE_SUFFIX_ENTRY_SIZE 8 ///< Size of a suffix entry
|
||||
constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; ///< Size of a suffix entry
|
||||
|
||||
//=============================================================================
|
||||
// Specialization of the generics for this trace format
|
||||
@@ -66,47 +67,6 @@
|
||||
#include "verilated_trace_imp.cpp"
|
||||
#undef VL_DERIVED_T
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdImp
|
||||
/// Base class to hold some static state
|
||||
/// This is an internally used class
|
||||
|
||||
class VerilatedVcdSingleton {
|
||||
private:
|
||||
typedef std::vector<VerilatedVcd*> VcdVec;
|
||||
struct Singleton {
|
||||
VerilatedMutex s_vcdMutex; ///< Protect the singleton
|
||||
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
|
||||
};
|
||||
static Singleton& singleton() {
|
||||
static Singleton s;
|
||||
return s;
|
||||
}
|
||||
|
||||
public:
|
||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
const VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||
singleton().s_vcdVecp.push_back(vcdp);
|
||||
}
|
||||
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
const VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||
VcdVec::iterator pos
|
||||
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
||||
}
|
||||
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
||||
// Thread safety: Although this function is protected by a mutex so
|
||||
// perhaps in the future we can allow tracing in separate threads,
|
||||
// vcdp->flush() assumes call from single thread
|
||||
const VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
|
||||
it != singleton().s_vcdVecp.end(); ++it) {
|
||||
VerilatedVcd* vcdp = *it;
|
||||
vcdp->flush();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
@@ -129,21 +89,15 @@ ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE {
|
||||
//=============================================================================
|
||||
// Opening/Closing
|
||||
|
||||
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
|
||||
: m_isOpen(false)
|
||||
, m_rolloverMB(0)
|
||||
, m_modDepth(0) {
|
||||
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) {
|
||||
// Not in header to avoid link issue if header is included without this .cpp file
|
||||
m_fileNewed = (filep == NULL);
|
||||
m_fileNewed = (filep == nullptr);
|
||||
m_filep = m_fileNewed ? new VerilatedVcdFile : filep;
|
||||
m_namemapp = NULL;
|
||||
m_evcd = false;
|
||||
m_wrChunkSize = 8 * 1024;
|
||||
m_wrBufp = new char[m_wrChunkSize * 8];
|
||||
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
||||
m_writep = m_wrBufp;
|
||||
m_wroteBytes = 0;
|
||||
m_suffixesp = NULL;
|
||||
m_suffixesp = nullptr;
|
||||
}
|
||||
|
||||
void VerilatedVcd::open(const char* filename) {
|
||||
@@ -152,13 +106,7 @@ void VerilatedVcd::open(const char* filename) {
|
||||
|
||||
// Set member variables
|
||||
m_filename = filename; // "" is ok, as someone may overload open
|
||||
VerilatedVcdSingleton::pushVcd(this);
|
||||
|
||||
// SPDIFF_OFF
|
||||
// Set callback so an early exit will flush us
|
||||
Verilated::flushCb(&flush_all);
|
||||
|
||||
// SPDIFF_ON
|
||||
openNext(m_rolloverMB != 0);
|
||||
if (!isOpen()) return;
|
||||
|
||||
@@ -238,15 +186,15 @@ void VerilatedVcd::makeNameMap() {
|
||||
// If no scope was specified, prefix everything with a "top"
|
||||
// This comes from user instantiations with no name - IE Vtop("").
|
||||
bool nullScope = false;
|
||||
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
|
||||
const std::string& hiername = it->first;
|
||||
for (const auto& i : *m_namemapp) {
|
||||
const std::string& hiername = i.first;
|
||||
if (!hiername.empty() && hiername[0] == '\t') nullScope = true;
|
||||
}
|
||||
if (nullScope) {
|
||||
NameMap* newmapp = new NameMap;
|
||||
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
|
||||
const std::string& hiername = it->first;
|
||||
const std::string& decl = it->second;
|
||||
for (const auto& i : *m_namemapp) {
|
||||
const std::string& hiername = i.first;
|
||||
const std::string& decl = i.second;
|
||||
std::string newname = std::string("top");
|
||||
if (hiername[0] != '\t') newname += ' ';
|
||||
newname += hiername;
|
||||
@@ -258,15 +206,14 @@ void VerilatedVcd::makeNameMap() {
|
||||
}
|
||||
|
||||
void VerilatedVcd::deleteNameMap() {
|
||||
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = NULL);
|
||||
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = nullptr);
|
||||
}
|
||||
|
||||
VerilatedVcd::~VerilatedVcd() {
|
||||
close();
|
||||
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL);
|
||||
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = nullptr);
|
||||
deleteNameMap();
|
||||
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL);
|
||||
VerilatedVcdSingleton::removeVcd(this);
|
||||
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = nullptr);
|
||||
}
|
||||
|
||||
void VerilatedVcd::closePrev() {
|
||||
@@ -334,7 +281,7 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
|
||||
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
|
||||
m_writep = m_wrBufp + (m_writep - oldbufp);
|
||||
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
||||
VL_DO_CLEAR(delete[] oldbufp, oldbufp = NULL);
|
||||
VL_DO_CLEAR(delete[] oldbufp, oldbufp = nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +345,7 @@ void VerilatedVcd::printIndent(int level_change) {
|
||||
|
||||
void VerilatedVcd::dumpHeader() {
|
||||
printStr("$version Generated by VerilatedVcd $end\n");
|
||||
time_t time_str = time(NULL);
|
||||
time_t time_str = time(nullptr);
|
||||
printStr("$date ");
|
||||
printStr(ctime(&time_str));
|
||||
printStr(" $end\n");
|
||||
@@ -421,9 +368,9 @@ void VerilatedVcd::dumpHeader() {
|
||||
|
||||
// Print the signal names
|
||||
const char* lastName = "";
|
||||
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
|
||||
const std::string& hiernamestr = it->first;
|
||||
const std::string& decl = it->second;
|
||||
for (const auto& i : *m_namemapp) {
|
||||
const std::string& hiernamestr = i.first;
|
||||
const std::string& decl = i.second;
|
||||
|
||||
// Determine difference between the old and new names
|
||||
const char* hiername = hiernamestr.c_str();
|
||||
@@ -823,11 +770,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
|
||||
|
||||
#endif // VL_TRACE_VCD_OLD_API
|
||||
|
||||
//======================================================================
|
||||
// Static members
|
||||
|
||||
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); }
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
+15
-19
@@ -36,11 +36,10 @@ class VerilatedVcd;
|
||||
|
||||
class VerilatedVcdFile {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd = 0; ///< File descriptor we're writing to
|
||||
public:
|
||||
// METHODS
|
||||
VerilatedVcdFile()
|
||||
: m_fd(0) {}
|
||||
VerilatedVcdFile() {}
|
||||
virtual ~VerilatedVcdFile() {}
|
||||
virtual bool open(const std::string& name) VL_MT_UNSAFE;
|
||||
virtual void close() VL_MT_UNSAFE;
|
||||
@@ -62,23 +61,23 @@ private:
|
||||
|
||||
VerilatedVcdFile* m_filep; ///< File we're writing to
|
||||
bool m_fileNewed; ///< m_filep needs destruction
|
||||
bool m_isOpen; ///< True indicates open file
|
||||
bool m_evcd; ///< True for evcd format
|
||||
bool m_isOpen = false; ///< True indicates open file
|
||||
bool m_evcd = false; ///< True for evcd format
|
||||
std::string m_filename; ///< Filename we're writing to (if open)
|
||||
vluint64_t m_rolloverMB; ///< MB of file size to rollover at
|
||||
int m_modDepth; ///< Depth of module hierarchy
|
||||
vluint64_t m_rolloverMB = 0; ///< MB of file size to rollover at
|
||||
int m_modDepth = 0; ///< Depth of module hierarchy
|
||||
|
||||
char* m_wrBufp; ///< Output buffer
|
||||
char* m_wrFlushp; ///< Output buffer flush trigger location
|
||||
char* m_writep; ///< Write pointer into output buffer
|
||||
vluint64_t m_wrChunkSize; ///< Output buffer size
|
||||
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
||||
vluint64_t m_wroteBytes = 0; ///< Number of bytes written to this file
|
||||
|
||||
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
|
||||
const char* m_suffixesp; ///< Pointer to first element of above
|
||||
|
||||
typedef std::map<std::string, std::string> NameMap;
|
||||
NameMap* m_namemapp; ///< List of names for the header
|
||||
NameMap* m_namemapp = nullptr; ///< List of names for the header
|
||||
|
||||
void bufferResize(vluint64_t minsize);
|
||||
void bufferFlush() VL_MT_UNSAFE_ONE;
|
||||
@@ -101,13 +100,10 @@ private:
|
||||
|
||||
void dumpHeader();
|
||||
|
||||
char* writeCode(char* writep, vluint32_t code);
|
||||
static char* writeCode(char* writep, vluint32_t code);
|
||||
|
||||
void finishLine(vluint32_t code, char* writep);
|
||||
|
||||
/// Flush any remaining data from all files
|
||||
static void flush_all() VL_MT_UNSAFE_ONE;
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcd);
|
||||
|
||||
@@ -116,11 +112,11 @@ protected:
|
||||
// Implementation of VerilatedTrace interface
|
||||
|
||||
// Implementations of protected virtual methods for VerilatedTrace
|
||||
void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;
|
||||
virtual void emitTimeChange(vluint64_t timeui) override;
|
||||
|
||||
// Hooks called from VerilatedTrace
|
||||
bool preFullDump() VL_OVERRIDE { return isOpen(); }
|
||||
bool preChangeDump() VL_OVERRIDE;
|
||||
virtual bool preFullDump() override { return isOpen(); }
|
||||
virtual bool preChangeDump() override;
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTrace. These are
|
||||
// called from only one place (namely full*) so always inline them.
|
||||
@@ -136,7 +132,7 @@ public:
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
|
||||
explicit VerilatedVcd(VerilatedVcdFile* filep = nullptr);
|
||||
~VerilatedVcd();
|
||||
|
||||
// ACCESSORS
|
||||
@@ -340,8 +336,8 @@ class VerilatedVcdC {
|
||||
VL_UNCOPYABLE(VerilatedVcdC);
|
||||
|
||||
public:
|
||||
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
|
||||
: m_sptrace(filep) {}
|
||||
explicit VerilatedVcdC(VerilatedVcdFile* filep = nullptr)
|
||||
: m_sptrace{filep} {}
|
||||
~VerilatedVcdC() { close(); }
|
||||
/// Routines can only be called from one thread; allow next call from different thread
|
||||
void changeThread() { spTrace()->changeThread(); }
|
||||
|
||||
@@ -25,22 +25,21 @@
|
||||
//======================================================================
|
||||
|
||||
//--------------------------------------------------
|
||||
#if (SYSTEMC_VERSION >= 20050714)
|
||||
// SystemC 2.1.v1
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedVcdSc::write_comment(const std::string&) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**) {}
|
||||
|
||||
// clang-format off
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const std::string& name) {}
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const std::string& name, int width) {}
|
||||
|
||||
# if (SYSTEMC_VERSION >= 20171012)
|
||||
// clang-format off
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
@@ -50,9 +49,9 @@ void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
# ifdef SYSTEMC_64BIT_PATCHES
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
# endif
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
@@ -76,92 +75,6 @@ void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
// clang-format on
|
||||
|
||||
//--------------------------------------------------
|
||||
#elif (SYSTEMC_VERSION > 20011000)
|
||||
// SystemC 2.0.1
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedVcdSc::write_comment(const sc_string&) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {}
|
||||
|
||||
// clang-format off
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
#if (SYSTEMC_VERSION > 20041000)
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
DECL_TRACE_METHOD_B( long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||
// clang-format on
|
||||
|
||||
//--------------------------------------------------
|
||||
#else
|
||||
// SystemC 1.2.1beta
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedVcdSc::write_comment(const sc_string&) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {}
|
||||
|
||||
// clang-format off
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( short unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( long unsigned int )
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short int )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long int )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_A( sc_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
|
||||
|
||||
+8
-108
@@ -38,7 +38,6 @@ class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC {
|
||||
public:
|
||||
VerilatedVcdSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
#if (SYSTEMC_VERSION >= 20060505)
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an
|
||||
// annoying "to turn off" message.
|
||||
@@ -48,25 +47,13 @@ public:
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
#elif (SYSTEMC_VERSION > 20011000)
|
||||
// To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string
|
||||
// we allow both flavors with overloaded set_time_* functions.
|
||||
spTrace()->set_time_unit(sc_get_default_time_unit().to_string());
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
#endif
|
||||
}
|
||||
virtual ~VerilatedVcdSc() { close(); }
|
||||
|
||||
// METHODS
|
||||
/// Called by SystemC simulate()
|
||||
virtual void cycle(bool delta_cycle) {
|
||||
#if (SYSTEMC_VERSION > 20011000)
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
#else
|
||||
// VCD files must have integer timestamps, so we write all times in
|
||||
// increments of time_resolution
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -76,26 +63,23 @@ private:
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
|
||||
#endif
|
||||
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100)
|
||||
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------
|
||||
#if (SYSTEMC_VERSION >= 20050714)
|
||||
// SystemC 2.1.v1
|
||||
// clang-format off
|
||||
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
// SystemC 2.1.v1
|
||||
#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace(const tp& object, const std::string& name, int width);
|
||||
|
||||
virtual void write_comment(const std::string&);
|
||||
virtual void trace(const unsigned int&, const std::string&, const char**);
|
||||
|
||||
// clang-format off
|
||||
// Formatting matches that of sc_trace.h
|
||||
# if (SYSTEMC_VERSION >= 20171012)
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
@@ -105,9 +89,9 @@ private:
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
# ifdef SYSTEMC_64BIT_PATCHES
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
# endif
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
@@ -131,90 +115,6 @@ private:
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
// clang-format on
|
||||
|
||||
//--------------------------------------------------
|
||||
#elif (SYSTEMC_VERSION > 20011000)
|
||||
// SystemC 2.0.1
|
||||
// clang-format off
|
||||
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name);
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace(const tp& object, const sc_string& name, int width);
|
||||
|
||||
virtual void write_comment(const sc_string&);
|
||||
virtual void trace(const unsigned int&, const sc_string&, const char**);
|
||||
virtual void delta_cycles(bool) {}
|
||||
virtual void space(int n) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
# ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
# endif
|
||||
# if (SYSTEMC_VERSION > 20041000)
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
DECL_TRACE_METHOD_B( long long)
|
||||
# endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||
// clang-format on
|
||||
|
||||
//--------------------------------------------------
|
||||
#else
|
||||
// SystemC 1.2.1beta
|
||||
// clang-format off
|
||||
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name);
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace(const tp& object, const sc_string& name, int width);
|
||||
|
||||
virtual void write_comment(const sc_string&);
|
||||
virtual void trace(const unsigned int&, const sc_string&, const char**);
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( short unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( long unsigned int )
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short int )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long int )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_A( sc_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||
# endif
|
||||
// clang-format on
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
};
|
||||
|
||||
+566
-619
File diff suppressed because it is too large
Load Diff
+22
-26
@@ -122,7 +122,7 @@
|
||||
# if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
# define VL_THREAD_LOCAL thread_local
|
||||
# elif defined(__GNUC__)
|
||||
# if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING)
|
||||
# if (__cplusplus < 201103L)
|
||||
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
|
||||
# endif
|
||||
# else
|
||||
@@ -152,14 +152,14 @@
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__) || __cplusplus < 201103L
|
||||
# define VL_DANGLING(var)
|
||||
#else
|
||||
/// After e.g. delete, set variable to NULL to indicate must not use later
|
||||
/// After e.g. delete, set variable to nullptr to indicate must not use later
|
||||
# define VL_DANGLING(var) \
|
||||
do { \
|
||||
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = NULL; \
|
||||
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = nullptr; \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
/// Perform an e.g. delete, then set variable to NULL to indicate must not use later.
|
||||
/// Perform an e.g. delete, then set variable to nullptr to indicate must not use later.
|
||||
/// Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
|
||||
#define VL_DO_DANGLING(stmt, var) \
|
||||
do { \
|
||||
@@ -169,7 +169,7 @@
|
||||
VL_DANGLING(var); \
|
||||
} while (false)
|
||||
|
||||
/// Perform an e.g. delete, then set variable to NULL as a requirement
|
||||
/// Perform an e.g. delete, then set variable to nullptr as a requirement
|
||||
#define VL_DO_CLEAR(stmt, stmt2) \
|
||||
do { \
|
||||
do { \
|
||||
@@ -184,30 +184,18 @@
|
||||
// C++-2011
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK)
|
||||
// These are deprecated historical defines. We leave them in case users referenced them.
|
||||
# define VL_EQ_DELETE = delete
|
||||
# define vl_unique_ptr std::unique_ptr
|
||||
// By default we use std:: types in C++11.
|
||||
// Define VL_USE_UNORDERED_TYPES to test these pre-C++11 classes
|
||||
# ifdef VL_USE_UNORDERED_TYPES
|
||||
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
||||
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
||||
# else
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# endif
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# define VL_FINAL final
|
||||
# define VL_MUTABLE mutable
|
||||
# define VL_OVERRIDE override
|
||||
#else
|
||||
# define VL_EQ_DELETE
|
||||
# define vl_unique_ptr std::auto_ptr
|
||||
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
||||
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
||||
# define VL_FINAL
|
||||
# define VL_MUTABLE
|
||||
# define VL_OVERRIDE
|
||||
# error "Verilator requires a C++11 or newer compiler"
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
@@ -388,8 +376,8 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
|
||||
// Used to declare a class as uncopyable; put after a private:
|
||||
#define VL_UNCOPYABLE(Type) \
|
||||
Type(const Type& other) VL_EQ_DELETE; \
|
||||
Type& operator=(const Type&) VL_EQ_DELETE
|
||||
Type(const Type& other) = delete; \
|
||||
Type& operator=(const Type&) = delete
|
||||
|
||||
//=========================================================================
|
||||
// Verilated function size macros
|
||||
@@ -435,7 +423,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
// Performance counters
|
||||
|
||||
/// The vluint64_t argument is loaded with a high-performance counter for profiling
|
||||
/// or 0x0 if not implemeted on this platform
|
||||
/// or 0x0 if not implemented on this platform
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define VL_RDTSC(val) \
|
||||
{ \
|
||||
@@ -500,6 +488,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#define VL_STRINGIFY(x) VL_STRINGIFY2(x)
|
||||
#define VL_STRINGIFY2(x) #x
|
||||
|
||||
//=========================================================================
|
||||
// Conversions
|
||||
|
||||
namespace vlstd {
|
||||
// C++17's std::as_const
|
||||
template <class T> T const& as_const(T& v) { return v; }
|
||||
}; // namespace vlstd
|
||||
|
||||
//=========================================================================
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -46,13 +46,17 @@ remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
|
||||
exclude_line_regexp(qr/(\bv3fatalSrc\b
|
||||
|\bfatalSrc\b
|
||||
|\bVL_UNCOVERABLE\b
|
||||
|\bVL_UNREACHABLE\b
|
||||
|\bVL_FATAL
|
||||
|\bUASSERT
|
||||
|\bNUM_ASSERT
|
||||
|\bERROR_RSVD_WORD
|
||||
|\bV3ERROR_NA
|
||||
|\bUINFO\b)/x);
|
||||
|
||||
# Exclude for branch coverage only
|
||||
exclude_branch_regexp(qr/(\bdebug\(\))/x);
|
||||
exclude_branch_regexp(qr/(\bdebug\(\)
|
||||
|\bassert\(
|
||||
|\bSELF_CHECK)/x);
|
||||
|
||||
1;
|
||||
|
||||
+11
-6
@@ -69,16 +69,21 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
|
||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
|
||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
||||
|
||||
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
|
||||
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
|
||||
endif
|
||||
endif
|
||||
|
||||
prefiles::
|
||||
prefiles:: config_rev.h
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
|
||||
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
|
||||
config_rev.h: ${srcdir}/config_rev.pl ${srcdir}/../.git/logs/HEAD
|
||||
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
else
|
||||
config_rev.h: ${srcdir}/config_rev.pl
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
endif
|
||||
|
||||
# Human convenience
|
||||
clang-format:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
|
||||
+1
-1
@@ -203,6 +203,7 @@ RAW_OBJS = \
|
||||
V3GraphPathChecker.o \
|
||||
V3GraphTest.o \
|
||||
V3Hashed.o \
|
||||
V3HierBlock.o \
|
||||
V3Inline.o \
|
||||
V3Inst.o \
|
||||
V3InstrCount.o \
|
||||
@@ -278,7 +279,6 @@ V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
|
||||
|
||||
$(TGT): $(PREDEP_H) $(OBJS)
|
||||
@echo " Linking $@..."
|
||||
-rm -rf $@ [email protected]
|
||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||
|
||||
V3Number_test: V3Number_test.o
|
||||
|
||||
+51
-71
@@ -36,7 +36,7 @@
|
||||
#include "V3Const.h"
|
||||
#include "V3SenTree.h" // for SenTreeSet
|
||||
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
|
||||
//***** See below for main transformation engine
|
||||
|
||||
@@ -51,36 +51,36 @@ protected:
|
||||
class ActiveNamer : public ActiveBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstScope* m_scopep; // Current scope to add statement to
|
||||
AstActive* m_iActivep; // For current scope, the IActive we're building
|
||||
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
|
||||
AstScope* m_scopep = nullptr; // Current scope to add statement to
|
||||
AstActive* m_iActivep = nullptr; // For current scope, the IActive we're building
|
||||
AstActive* m_cActivep = nullptr; // For current scope, the SActive(combo) we're building
|
||||
|
||||
SenTreeSet m_activeSens; // Sen lists for each active we've made
|
||||
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
|
||||
typedef std::unordered_map<AstSenTree*, AstActive*> ActiveMap;
|
||||
ActiveMap m_activeMap; // Map sentree to active, for folding.
|
||||
|
||||
// METHODS
|
||||
void addActive(AstActive* nodep) {
|
||||
UASSERT_OBJ(m_scopep, nodep, "NULL scope");
|
||||
UASSERT_OBJ(m_scopep, nodep, "nullptr scope");
|
||||
m_scopep->addActivep(nodep);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
m_scopep = nodep;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
m_iActivep = nullptr;
|
||||
m_cActivep = nullptr;
|
||||
m_activeSens.clear();
|
||||
m_activeMap.clear();
|
||||
iterateChildren(nodep);
|
||||
// Don't clear scopep, the namer persists beyond this visit
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenTree* nodep) override {
|
||||
// Simplify sensitivity list
|
||||
VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeStmt*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
@@ -106,10 +106,10 @@ public:
|
||||
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
|
||||
// Return a sentree in this scope that matches given sense list.
|
||||
|
||||
AstActive* activep = NULL;
|
||||
AstActive* activep = nullptr;
|
||||
AstSenTree* activeSenp = m_activeSens.find(sensesp);
|
||||
if (activeSenp) {
|
||||
ActiveMap::iterator it = m_activeMap.find(activeSenp);
|
||||
const auto it = m_activeMap.find(activeSenp);
|
||||
UASSERT(it != m_activeMap.end(), "Corrupt active map");
|
||||
activep = it->second;
|
||||
}
|
||||
@@ -129,14 +129,9 @@ public:
|
||||
return activep;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ActiveNamer() {
|
||||
m_scopep = NULL;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
}
|
||||
virtual ~ActiveNamer() {}
|
||||
ActiveNamer() {}
|
||||
virtual ~ActiveNamer() override {}
|
||||
void main(AstScope* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
@@ -145,14 +140,14 @@ public:
|
||||
|
||||
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
||||
public:
|
||||
enum CheckType { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||
|
||||
private:
|
||||
CheckType m_check; // Combo logic or other
|
||||
AstNode* m_alwaysp; // Always we're under
|
||||
AstNode* m_assignp; // In assign
|
||||
AstNode* m_assignp = nullptr; // In assign
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignDly* nodep) override {
|
||||
if (m_check != CT_SEQ) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5, " ASSIGNDLY " << nodep << endl);
|
||||
@@ -174,7 +169,7 @@ private:
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssign* nodep) override {
|
||||
if (m_check == CT_SEQ) {
|
||||
AstNode* las = m_assignp;
|
||||
m_assignp = nodep;
|
||||
@@ -182,7 +177,7 @@ private:
|
||||
m_assignp = las;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
AstVar* varp = nodep->varp();
|
||||
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
|
||||
&& !varp->isTemp()) {
|
||||
@@ -201,17 +196,16 @@ private:
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ActiveDlyVisitor(AstNode* nodep, CheckType check) {
|
||||
m_alwaysp = nodep;
|
||||
m_check = check;
|
||||
m_assignp = NULL;
|
||||
ActiveDlyVisitor(AstNode* nodep, CheckType check)
|
||||
: m_check{check}
|
||||
, m_alwaysp{nodep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveDlyVisitor() {}
|
||||
virtual ~ActiveDlyVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -225,23 +219,23 @@ private:
|
||||
|
||||
// STATE
|
||||
ActiveNamer m_namer; // Tracking of active names
|
||||
AstCFunc* m_scopeFinalp; // Final function for this scope
|
||||
bool m_itemCombo; // Found a SenItem combo
|
||||
bool m_itemSequent; // Found a SenItem sequential
|
||||
AstCFunc* m_scopeFinalp = nullptr; // Final function for this scope
|
||||
bool m_itemCombo = false; // Found a SenItem combo
|
||||
bool m_itemSequent = false; // Found a SenItem sequential
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
// Create required actives and add to scope
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
// Clear last scope's names, and collect this scope's existing names
|
||||
m_namer.main(nodep);
|
||||
m_scopeFinalp = NULL;
|
||||
m_scopeFinalp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
// Actives are being formed, so we can ignore any already made
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstInitial* nodep) override {
|
||||
// Relink to IACTIVE, unless already under it
|
||||
UINFO(4, " INITIAL " << nodep << endl);
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
@@ -249,28 +243,28 @@ private:
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignAlias* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignW* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4, " COVERTOGGLE " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFinal* nodep) override {
|
||||
// Relink to CFUNC for the final
|
||||
UINFO(4, " FINAL " << nodep << endl);
|
||||
if (!nodep->bodysp()) { // Empty, Kill it.
|
||||
@@ -316,14 +310,12 @@ private:
|
||||
|
||||
if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*)
|
||||
if (combo && sequent) {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity "
|
||||
"(no edge) sensitive activity list");
|
||||
}
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Mixed edge (pos/negedge) and activity "
|
||||
"(no edge) sensitive activity list");
|
||||
sequent = false;
|
||||
}
|
||||
|
||||
AstActive* wantactivep = NULL;
|
||||
AstActive* wantactivep = nullptr;
|
||||
if (combo && !sequent) {
|
||||
// Combo: Relink to ACTIVE(combo)
|
||||
wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
@@ -360,7 +352,7 @@ private:
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_SEQ);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4, " ALW " << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||
@@ -372,21 +364,13 @@ private:
|
||||
}
|
||||
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlwaysPublic* nodep) override {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4, " ALWPub " << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
AstSenItem* subitemp = nodep->sensesp();
|
||||
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|
||||
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
|
||||
nodep, "Strange activity type under SenGate");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
if (nodep->varrefp()) {
|
||||
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||
if (basicp->isEventValue()) {
|
||||
@@ -405,8 +389,9 @@ private:
|
||||
} else if (nodep->varrefp()) {
|
||||
// V3LinkResolve should have cleaned most of these up
|
||||
if (!nodep->varrefp()->width1()) {
|
||||
nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||
<< nodep->varrefp()->prettyNameQ());
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||
<< nodep->varrefp()->prettyNameQ());
|
||||
}
|
||||
m_itemSequent = true;
|
||||
nodep->varrefp()->varp()->usedClock(true);
|
||||
@@ -414,19 +399,14 @@ private:
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstVarScope*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ActiveVisitor(AstNetlist* nodep)
|
||||
: m_scopeFinalp(NULL)
|
||||
, m_itemCombo(false)
|
||||
, m_itemSequent(false) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveVisitor() {}
|
||||
explicit ActiveVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ActiveVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+16
-19
@@ -45,31 +45,31 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstTopScope* m_topscopep; // Top scope for adding sentrees under
|
||||
AstTopScope* m_topscopep = nullptr; // Top scope for adding sentrees under
|
||||
SenTreeFinder m_finder; // Find global sentree's and add them
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
m_topscopep = nodep;
|
||||
m_finder.main(m_topscopep);
|
||||
m_finder.init(m_topscopep);
|
||||
iterateChildren(nodep);
|
||||
m_topscopep = NULL;
|
||||
m_topscopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// Create required actives and add to module
|
||||
// We can start ordering at a module, or a scope
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
UINFO(4, " ACTIVE " << nodep << endl);
|
||||
// Remove duplicate clocks and such; sensesp() may change!
|
||||
V3Const::constifyExpensiveEdit(nodep);
|
||||
AstSenTree* sensesp = nodep->sensesp();
|
||||
UASSERT_OBJ(sensesp, nodep, "NULL");
|
||||
UASSERT_OBJ(sensesp, nodep, "nullptr");
|
||||
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
|
||||
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
@@ -108,30 +108,27 @@ private:
|
||||
// No need to do statements under it, they're already moved.
|
||||
// iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstVarScope*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ActiveTopVisitor(AstNetlist* nodep)
|
||||
: m_topscopep(NULL) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveTopVisitor() {}
|
||||
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ActiveTopVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+37
-45
@@ -34,9 +34,9 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Last module
|
||||
AstBegin* m_beginp; // Last begin
|
||||
unsigned m_modPastNum; // Module past numbering
|
||||
AstNodeModule* m_modp = nullptr; // Last module
|
||||
AstBegin* m_beginp = nullptr; // Last begin
|
||||
unsigned m_modPastNum = 0; // Module past numbering
|
||||
VDouble0 m_statCover; // Statistic tracking
|
||||
VDouble0 m_statAsNotImm; // Statistic tracking
|
||||
VDouble0 m_statAsImm; // Statistic tracking
|
||||
@@ -74,15 +74,15 @@ private:
|
||||
(v3Global.opt.assertOn()
|
||||
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
|
||||
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
|
||||
nodep, NULL);
|
||||
nodep, nullptr);
|
||||
newp->user1(true); // Don't assert/cover this if
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
||||
// Like newFireAssert() but omits the asserts-on check
|
||||
AstDisplay* dispp
|
||||
= new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message,
|
||||
nullptr, nullptr);
|
||||
AstNode* bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop(nodep->fileline(), true));
|
||||
@@ -112,9 +112,9 @@ private:
|
||||
sentreep->unlinkFrBack();
|
||||
}
|
||||
//
|
||||
AstNode* bodysp = NULL;
|
||||
AstNode* bodysp = nullptr;
|
||||
bool selfDestruct = false;
|
||||
AstIf* ifp = NULL;
|
||||
AstIf* ifp = nullptr;
|
||||
if (AstCover* snodep = VN_CAST(nodep, Cover)) {
|
||||
++m_statCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
@@ -129,7 +129,7 @@ private:
|
||||
}
|
||||
|
||||
if (bodysp && passsp) bodysp = bodysp->addNext(passsp);
|
||||
ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL);
|
||||
ifp = new AstIf(nodep->fileline(), propp, bodysp, nullptr);
|
||||
bodysp = ifp;
|
||||
} else if (VN_IS(nodep, Assert)) {
|
||||
if (nodep->immediate()) {
|
||||
@@ -141,7 +141,7 @@ private:
|
||||
if (failsp) failsp = newIfAssertOn(failsp);
|
||||
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||
ifp = new AstIf(nodep->fileline(), propp, passsp, failsp);
|
||||
// It's more LIKELY that we'll take the NULL if clause
|
||||
// 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);
|
||||
@@ -169,11 +169,11 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstIf* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
AstNodeIf* ifp = nodep;
|
||||
AstNode* propp = NULL;
|
||||
AstNode* propp = nullptr;
|
||||
bool hasDefaultElse = false;
|
||||
do {
|
||||
// If this statement ends with 'else if', then nextIf will point to the
|
||||
@@ -226,7 +226,7 @@ private:
|
||||
}
|
||||
|
||||
//========== Case assertions
|
||||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCase* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
bool has_default = false;
|
||||
@@ -239,7 +239,7 @@ private:
|
||||
++m_statAsFull;
|
||||
if (!has_default) {
|
||||
nodep->addItemsp(new AstCaseItem(
|
||||
nodep->fileline(), NULL /*DEFAULT*/,
|
||||
nodep->fileline(), nullptr /*DEFAULT*/,
|
||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ private:
|
||||
if (!has_default && !nodep->itemsp()) {
|
||||
// Not parallel, but harmlessly so.
|
||||
} else {
|
||||
AstNode* propp = NULL;
|
||||
AstNode* propp = nullptr;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
@@ -287,7 +287,7 @@ private:
|
||||
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep,
|
||||
"synthesis parallel_case, but multiple matches found"),
|
||||
NULL);
|
||||
nullptr);
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
nodep->addNotParallelp(ifp);
|
||||
}
|
||||
@@ -296,7 +296,7 @@ private:
|
||||
}
|
||||
|
||||
//========== Past
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPast* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
uint32_t ticks = 1;
|
||||
if (nodep->ticksp()) {
|
||||
@@ -306,32 +306,33 @@ private:
|
||||
}
|
||||
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
||||
AstNode* inp = nodep->exprp()->unlinkFrBack();
|
||||
AstVar* invarp = NULL;
|
||||
AstVar* invarp = nullptr;
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
sentreep->unlinkFrBack();
|
||||
AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, NULL);
|
||||
AstAlways* alwaysp
|
||||
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
|
||||
m_modp->addStmtp(alwaysp);
|
||||
for (uint32_t i = 0; i < ticks; ++i) {
|
||||
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
|
||||
inp->dtypep());
|
||||
m_modp->addStmtp(outvarp);
|
||||
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), outvarp, true), inp);
|
||||
AstNode* assp = new AstAssignDly(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
|
||||
alwaysp->addStmtp(assp);
|
||||
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
|
||||
invarp = outvarp;
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ);
|
||||
}
|
||||
nodep->replaceWith(inp);
|
||||
}
|
||||
virtual void visit(AstSampled* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSampled* nodep) override {
|
||||
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
//========== Statements
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDisplay* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Replace the special types with standard text
|
||||
if (nodep->displayType() == AstDisplayType::DT_INFO) {
|
||||
@@ -344,54 +345,45 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAssert* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssert* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nodep->failsp());
|
||||
}
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCover* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, NULL);
|
||||
newPslAssertion(nodep, nullptr);
|
||||
}
|
||||
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRestrict* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// IEEE says simulator ignores these
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
unsigned origPastNum = m_modPastNum;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_modPastNum);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_modPastNum = origPastNum;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBegin* nodep) override {
|
||||
// This code is needed rather than a visitor in V3Begin,
|
||||
// because V3Assert is called before V3Begin
|
||||
AstBegin* lastp = m_beginp;
|
||||
VL_RESTORER(m_beginp);
|
||||
{
|
||||
m_beginp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_beginp = lastp;
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit AssertVisitor(AstNetlist* nodep) {
|
||||
m_beginp = NULL;
|
||||
m_modp = NULL;
|
||||
m_modPastNum = 0;
|
||||
// Process
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~AssertVisitor() {
|
||||
explicit AssertVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~AssertVisitor() override {
|
||||
V3Stats::addStat("Assertions, assert non-immediate statements", m_statAsNotImm);
|
||||
V3Stats::addStat("Assertions, assert immediate statements", m_statAsImm);
|
||||
V3Stats::addStat("Assertions, cover statements", m_statCover);
|
||||
|
||||
+87
-22
@@ -34,35 +34,40 @@ private:
|
||||
// NODE STATE/TYPES
|
||||
// STATE
|
||||
// Reset each module:
|
||||
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
|
||||
AstSenItem* m_seniDefaultp = nullptr; // Default sensitivity (from AstDefClock)
|
||||
// Reset each assertion:
|
||||
AstNodeSenItem* m_senip; // Last sensitivity
|
||||
AstSenItem* m_senip = nullptr; // Last sensitivity
|
||||
// Reset each always:
|
||||
AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always
|
||||
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
|
||||
// Reset each assertion:
|
||||
AstNode* m_disablep = nullptr; // Last disable
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
AstSenTree* newSenTree(AstNode* nodep) {
|
||||
// Create sentree based on clocked or default clock
|
||||
// Return NULL for always
|
||||
AstSenTree* newp = NULL;
|
||||
AstNodeSenItem* senip = m_senip;
|
||||
// Return nullptr for always
|
||||
AstSenTree* newp = nullptr;
|
||||
AstSenItem* senip = m_senip;
|
||||
if (!senip) senip = m_seniDefaultp;
|
||||
if (!senip) senip = m_seniAlwaysp;
|
||||
if (!senip) {
|
||||
nodep->v3error("Unsupported: Unclocked assertion");
|
||||
newp = new AstSenTree(nodep->fileline(), NULL);
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
|
||||
newp = new AstSenTree(nodep->fileline(), nullptr);
|
||||
} else {
|
||||
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
void clearAssertInfo() { m_senip = NULL; }
|
||||
void clearAssertInfo() {
|
||||
m_senip = nullptr;
|
||||
m_disablep = nullptr;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
//========== Statements
|
||||
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstClocking* nodep) override {
|
||||
UINFO(8, " CLOCKING" << nodep << endl);
|
||||
// Store the new default clock, reset on new module
|
||||
m_seniDefaultp = nodep->sensesp();
|
||||
@@ -74,14 +79,14 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp();
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
m_seniAlwaysp = NULL;
|
||||
m_seniAlwaysp = nullptr;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
// Find Clocking's buried under nodep->exprsp
|
||||
@@ -89,18 +94,80 @@ private:
|
||||
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
|
||||
clearAssertInfo();
|
||||
}
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFell* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstPast* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRose* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstStable* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past, exprp->cloneTree(false));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstImplication* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
||||
if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); }
|
||||
|
||||
AstNode* past = new AstPast(fl, lhsp, nullptr);
|
||||
past->dtypeFrom(lhsp);
|
||||
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstPropClocked* nodep) override {
|
||||
// No need to iterate the body, once replace will get iterated
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
||||
if (m_senip)
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
||||
// Block is the new expression to evaluate
|
||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||
if (nodep->disablep()) {
|
||||
m_disablep = nodep->disablep()->cloneTree(false);
|
||||
if (VN_IS(nodep->backp(), Cover)) {
|
||||
blockp = new AstAnd(
|
||||
nodep->disablep()->fileline(),
|
||||
@@ -116,23 +183,21 @@ private:
|
||||
nodep->replaceWith(blockp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Reset defaults
|
||||
m_seniDefaultp = NULL;
|
||||
m_seniDefaultp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit AssertPreVisitor(AstNetlist* nodep) {
|
||||
m_seniDefaultp = NULL;
|
||||
m_seniAlwaysp = NULL;
|
||||
clearAssertInfo();
|
||||
// Process
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~AssertPreVisitor() {}
|
||||
virtual ~AssertPreVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+54
-57
@@ -58,19 +58,20 @@ std::ostream& operator<<(std::ostream& os, AstType rhs);
|
||||
//######################################################################
|
||||
// Creators
|
||||
|
||||
void AstNode::init() {
|
||||
AstNode::AstNode(AstType t, FileLine* fl)
|
||||
: m_type{t}
|
||||
, m_fileline{fl} {
|
||||
editCountInc();
|
||||
m_fileline = NULL;
|
||||
m_nextp = NULL;
|
||||
m_backp = NULL;
|
||||
m_nextp = nullptr;
|
||||
m_backp = nullptr;
|
||||
m_headtailp = this; // When made, we're a list of only a single element
|
||||
m_op1p = NULL;
|
||||
m_op2p = NULL;
|
||||
m_op3p = NULL;
|
||||
m_op4p = NULL;
|
||||
m_iterpp = NULL;
|
||||
m_dtypep = NULL;
|
||||
m_clonep = NULL;
|
||||
m_op1p = nullptr;
|
||||
m_op2p = nullptr;
|
||||
m_op3p = nullptr;
|
||||
m_op4p = nullptr;
|
||||
m_iterpp = nullptr;
|
||||
m_dtypep = nullptr;
|
||||
m_clonep = nullptr;
|
||||
m_cloneCnt = 0;
|
||||
// Attributes
|
||||
m_didWidth = false;
|
||||
@@ -275,8 +276,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
|
||||
// New tail needs the head
|
||||
AstNode* newtailp = newp->m_headtailp;
|
||||
AstNode* headp = oldtailp->m_headtailp;
|
||||
oldtailp->m_headtailp = NULL; // May be written again as new head
|
||||
newp->m_headtailp = NULL; // May be written again as new tail
|
||||
oldtailp->m_headtailp = nullptr; // May be written again as new head
|
||||
newp->m_headtailp = nullptr; // May be written again as new tail
|
||||
newtailp->m_headtailp = headp;
|
||||
headp->m_headtailp = newtailp;
|
||||
newp->editCountInc();
|
||||
@@ -321,17 +322,17 @@ void AstNode::addNextHere(AstNode* newp) {
|
||||
// tail (oldheadtailp && !oldnextp) // this was tail of list, might also
|
||||
// be head of one-node list
|
||||
//
|
||||
newp->m_headtailp = NULL; // Not at head any longer
|
||||
addlastp->m_headtailp = NULL; // Presume middle of list
|
||||
newp->m_headtailp = nullptr; // Not at head any longer
|
||||
addlastp->m_headtailp = nullptr; // Presume middle of list
|
||||
// newp might happen to be head/tail after all, if so will be set again below
|
||||
if (oldheadtailp) { // else in middle of list, no change
|
||||
if (oldheadtailp == this) { // this was one node
|
||||
this->m_headtailp = addlastp; // Was head/tail, now a tail
|
||||
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
|
||||
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or nullptr)
|
||||
} else if (!oldnextp) { // this was tail
|
||||
this->m_headtailp = NULL; // No longer a tail
|
||||
this->m_headtailp = nullptr; // No longer a tail
|
||||
oldheadtailp->m_headtailp = addlastp; // Head gets new tail
|
||||
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
|
||||
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or nullptr)
|
||||
} // else is head, and we're inserting into the middle, so no other change
|
||||
}
|
||||
|
||||
@@ -470,7 +471,7 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||
}
|
||||
}
|
||||
if (backp->m_nextp == oldp) {
|
||||
backp->m_nextp = NULL;
|
||||
backp->m_nextp = nullptr;
|
||||
// Old list gets truncated
|
||||
// New list becomes a list upon itself
|
||||
// Most common case is unlinking a entire operand tree
|
||||
@@ -486,21 +487,21 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||
oldp->m_headtailp = oldtailp;
|
||||
oldp->m_headtailp->m_headtailp = oldp;
|
||||
} else if (backp->m_op1p == oldp) {
|
||||
backp->m_op1p = NULL;
|
||||
backp->m_op1p = nullptr;
|
||||
} else if (backp->m_op2p == oldp) {
|
||||
backp->m_op2p = NULL;
|
||||
backp->m_op2p = nullptr;
|
||||
} else if (backp->m_op3p == oldp) {
|
||||
backp->m_op3p = NULL;
|
||||
backp->m_op3p = nullptr;
|
||||
} else if (backp->m_op4p == oldp) {
|
||||
backp->m_op4p = NULL;
|
||||
backp->m_op4p = nullptr;
|
||||
} else {
|
||||
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
}
|
||||
// Relink
|
||||
oldp->m_backp = NULL;
|
||||
oldp->m_backp = nullptr;
|
||||
// Iterator fixup
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = NULL;
|
||||
oldp->m_iterpp = NULL;
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
oldp->debugTreeChange("-unlinkWNextOut: ", __LINE__, true);
|
||||
return oldp;
|
||||
}
|
||||
@@ -561,10 +562,10 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
||||
// Iterator fixup
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = oldp->m_nextp;
|
||||
// Relink
|
||||
oldp->m_nextp = NULL;
|
||||
oldp->m_backp = NULL;
|
||||
oldp->m_nextp = nullptr;
|
||||
oldp->m_backp = nullptr;
|
||||
oldp->m_headtailp = this;
|
||||
oldp->m_iterpp = NULL;
|
||||
oldp->m_iterpp = nullptr;
|
||||
oldp->debugTreeChange("-unlinkFrBkOut: ", __LINE__, true);
|
||||
return oldp;
|
||||
}
|
||||
@@ -598,7 +599,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
||||
}
|
||||
// Relink
|
||||
newp->m_backp = backp;
|
||||
linkerp->m_backp = NULL;
|
||||
linkerp->m_backp = nullptr;
|
||||
// Iterator fixup
|
||||
if (linkerp->m_iterpp) {
|
||||
// If we're iterating over a next() link, we need to follow links off the
|
||||
@@ -610,7 +611,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
||||
newp->m_iterpp = linkerp->m_iterpp;
|
||||
}
|
||||
// Empty the linker so not used twice accidentally
|
||||
linkerp->m_backp = NULL;
|
||||
linkerp->m_backp = nullptr;
|
||||
this->debugTreeChange("-relinkOut: ", __LINE__, true);
|
||||
}
|
||||
|
||||
@@ -633,8 +634,8 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
|
||||
newlistlastp->m_nextp = pointpr;
|
||||
pointpr->m_backp = newlistlastp;
|
||||
// Head/tail
|
||||
pointpr->m_headtailp = NULL; // Old head
|
||||
newlistlastp->m_headtailp = NULL; // Old tail
|
||||
pointpr->m_headtailp = nullptr; // Old head
|
||||
newlistlastp->m_headtailp = nullptr; // Old tail
|
||||
newp->m_headtailp = oldlistlastp; // Head points to tail
|
||||
oldlistlastp->m_headtailp = newp; // Tail points to head
|
||||
}
|
||||
@@ -668,7 +669,7 @@ AstNode* AstNode::cloneTreeIter() {
|
||||
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
|
||||
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
|
||||
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList());
|
||||
newp->m_iterpp = NULL;
|
||||
newp->m_iterpp = nullptr;
|
||||
newp->clonep(this); // Save pointers to/from both to simplify relinking.
|
||||
this->clonep(newp); // Save pointers to/from both to simplify relinking.
|
||||
return newp;
|
||||
@@ -676,12 +677,12 @@ AstNode* AstNode::cloneTreeIter() {
|
||||
|
||||
AstNode* AstNode::cloneTreeIterList() {
|
||||
// private: Clone list of nodes, set m_headtailp
|
||||
AstNode* newheadp = NULL;
|
||||
AstNode* newtailp = NULL;
|
||||
// Audited to make sure this is never NULL
|
||||
AstNode* newheadp = nullptr;
|
||||
AstNode* newtailp = nullptr;
|
||||
// Audited to make sure this is never nullptr
|
||||
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
|
||||
AstNode* newp = oldp->cloneTreeIter();
|
||||
newp->m_headtailp = NULL;
|
||||
newp->m_headtailp = nullptr;
|
||||
newp->m_backp = newtailp;
|
||||
if (newtailp) newtailp->m_nextp = newp;
|
||||
if (!newheadp) newheadp = newp;
|
||||
@@ -700,10 +701,10 @@ AstNode* AstNode::cloneTree(bool cloneNextLink) {
|
||||
newp = cloneTreeIterList();
|
||||
} else {
|
||||
newp = cloneTreeIter();
|
||||
newp->m_nextp = NULL;
|
||||
newp->m_nextp = nullptr;
|
||||
newp->m_headtailp = newp;
|
||||
}
|
||||
newp->m_backp = NULL;
|
||||
newp->m_backp = nullptr;
|
||||
newp->cloneRelinkTree();
|
||||
newp->debugTreeChange("-cloneOut: ", __LINE__, true);
|
||||
return newp;
|
||||
@@ -739,7 +740,7 @@ void AstNode::deleteNode() {
|
||||
|
||||
void AstNode::deleteTreeIter() {
|
||||
// private: Delete list of nodes. Publicly call deleteTree() instead.
|
||||
// Audited to make sure this is never NULL
|
||||
// Audited to make sure this is never nullptr
|
||||
for (AstNode *nodep = this, *nnextp; nodep; nodep = nnextp) {
|
||||
nnextp = nodep->m_nextp;
|
||||
// MUST be depth first!
|
||||
@@ -747,8 +748,8 @@ void AstNode::deleteTreeIter() {
|
||||
if (nodep->m_op2p) nodep->m_op2p->deleteTreeIter();
|
||||
if (nodep->m_op3p) nodep->m_op3p->deleteTreeIter();
|
||||
if (nodep->m_op4p) nodep->m_op4p->deleteTreeIter();
|
||||
nodep->m_nextp = NULL;
|
||||
nodep->m_backp = NULL;
|
||||
nodep->m_nextp = nullptr;
|
||||
nodep->m_backp = nullptr;
|
||||
nodep->deleteNode();
|
||||
}
|
||||
}
|
||||
@@ -831,11 +832,11 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
|
||||
niterp->m_iterpp = &niterp;
|
||||
niterp->accept(v);
|
||||
// accept may do a replaceNode and change niterp on us...
|
||||
// niterp maybe NULL, so need cast if printing
|
||||
// niterp maybe nullptr, so need cast if printing
|
||||
// if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
|
||||
// <<" now into "<<cvtToHex(niterp)<<endl);
|
||||
if (!niterp) return; // Perhaps node deleted inside accept
|
||||
niterp->m_iterpp = NULL;
|
||||
niterp->m_iterpp = nullptr;
|
||||
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
|
||||
nodep = niterp;
|
||||
} else { // Unchanged node, just continue loop
|
||||
@@ -853,7 +854,7 @@ void AstNode::iterateListBackwards(AstNVisitor& v) {
|
||||
if (nodep->backp()->m_nextp == nodep) {
|
||||
nodep = nodep->backp();
|
||||
} else {
|
||||
nodep = NULL;
|
||||
nodep = nullptr;
|
||||
} // else: backp points up the tree.
|
||||
}
|
||||
}
|
||||
@@ -900,7 +901,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
||||
} else {
|
||||
// Use back to determine who's pointing at us (IE assume new node
|
||||
// grafts into same place as old one)
|
||||
AstNode** nextnodepp = NULL;
|
||||
AstNode** nextnodepp = nullptr;
|
||||
if (this->m_backp->m_op1p == this) {
|
||||
nextnodepp = &(this->m_backp->m_op1p);
|
||||
} else if (this->m_backp->m_op2p == this) {
|
||||
@@ -974,9 +975,7 @@ std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
|
||||
|
||||
V3Hash::V3Hash(const string& name) {
|
||||
uint32_t val = 0;
|
||||
for (string::const_iterator it = name.begin(); it != name.end(); ++it) {
|
||||
val = val * 31 + *it;
|
||||
}
|
||||
for (const auto& c : name) val = val * 31 + c;
|
||||
setBoth(1, val);
|
||||
}
|
||||
|
||||
@@ -999,7 +998,7 @@ void AstNode::checkTreeIter(AstNode* backp) {
|
||||
|
||||
void AstNode::checkTreeIterList(AstNode* backp) {
|
||||
// private: Check a (possible) list of nodes, this is always the head of the list
|
||||
// Audited to make sure this is never NULL
|
||||
// Audited to make sure this is never nullptr
|
||||
AstNode* headp = this;
|
||||
AstNode* tailp = this;
|
||||
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
|
||||
@@ -1052,7 +1051,7 @@ void AstNode::checkIter() const {
|
||||
if (m_iterpp) {
|
||||
dumpPtrs(cout);
|
||||
// Perhaps something forgot to clear m_iterpp?
|
||||
this->v3fatalSrc("Iteration link should be NULL");
|
||||
this->v3fatalSrc("Iteration link should be nullptr");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1108,7 +1107,7 @@ void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) con
|
||||
}
|
||||
|
||||
void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDepth) const {
|
||||
// Audited to make sure this is never NULL
|
||||
// Audited to make sure this is never nullptr
|
||||
for (const AstNode* nodep = this; nodep; nodep = nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent, maxDepth);
|
||||
}
|
||||
@@ -1119,7 +1118,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
if (doDump) {
|
||||
{ // Write log & close
|
||||
UINFO(2, "Dumping " << filename << endl);
|
||||
const vl_unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
|
||||
const std::unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
|
||||
if (logsp->fail()) v3fatal("Can't write " << filename);
|
||||
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
|
||||
*logsp << "> to <e" << std::dec << editCountGbl() << ">" << endl;
|
||||
@@ -1267,8 +1266,6 @@ AstNodeDType* AstNode::findVoidDType() const {
|
||||
// AstNVisitor
|
||||
|
||||
void AstNVisitor::doDeletes() {
|
||||
for (std::vector<AstNode*>::iterator it = m_deleteps.begin(); it != m_deleteps.end(); ++it) {
|
||||
(*it)->deleteTree();
|
||||
}
|
||||
for (AstNode* nodep : m_deleteps) nodep->deleteTree();
|
||||
m_deleteps.clear();
|
||||
}
|
||||
|
||||
+421
-382
File diff suppressed because it is too large
Load Diff
+117
-67
@@ -22,6 +22,7 @@
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3PartitionGraph.h" // Just for mtask dumping
|
||||
#include "V3String.h"
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
#include <iomanip>
|
||||
@@ -35,7 +36,7 @@ const char* AstIfaceRefDType::broken() const {
|
||||
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
|
||||
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
|
||||
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
|
||||
@@ -45,7 +46,7 @@ AstIface* AstIfaceRefDType::ifaceViaCellp() const {
|
||||
const char* AstNodeVarRef::broken() const {
|
||||
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
|
||||
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AstNodeVarRef::cloneRelink() {
|
||||
@@ -73,7 +74,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
|
||||
}
|
||||
|
||||
const char* AstNodeUOrStructDType::broken() const {
|
||||
vl_unordered_set<AstMemberDType*> exists;
|
||||
std::unordered_set<AstMemberDType*> exists;
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
||||
exists.insert(itemp);
|
||||
}
|
||||
@@ -83,11 +84,13 @@ const char* AstNodeUOrStructDType::broken() const {
|
||||
return "member broken";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
|
||||
void AstNodeCCall::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (funcp()) {
|
||||
str << " " << funcp()->name() << " => ";
|
||||
funcp()->dump(str);
|
||||
@@ -100,7 +103,7 @@ void AstNodeCCall::cloneRelink() {
|
||||
}
|
||||
const char* AstNodeCCall::broken() const {
|
||||
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
|
||||
string AstNodeCCall::hiernameProtect() const {
|
||||
@@ -211,7 +214,7 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
}
|
||||
|
||||
AstExecGraph::AstExecGraph(FileLine* fileline)
|
||||
: AstNode(AstType::atExecGraph, fileline) {
|
||||
: AstNode{AstType::atExecGraph, fileline} {
|
||||
m_depGraphp = new V3Graph;
|
||||
}
|
||||
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
|
||||
@@ -225,6 +228,36 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
||||
bool success = false;
|
||||
if (literal[0] == '"') {
|
||||
// This is a string
|
||||
string v = literal.substr(1, literal.find('"', 1) - 1);
|
||||
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
|
||||
} else if (literal.find_first_of(".eEpP") != string::npos) {
|
||||
// This may be a real
|
||||
double v = VString::parseDouble(literal, &success);
|
||||
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
|
||||
}
|
||||
if (!success) {
|
||||
// This is either an integer or an error
|
||||
// We first try to convert it as C literal. If strtol returns
|
||||
// 0 this is either an error or 0 was parsed. But in any case
|
||||
// we will try to parse it as a verilog literal, hence having
|
||||
// the false negative for 0 is okay. If anything remains in
|
||||
// the string after the number, this is invalid C and we try
|
||||
// the Verilog literal parser.
|
||||
char* endp;
|
||||
int v = strtol(literal.c_str(), &endp, 0);
|
||||
if ((v != 0) && (endp[0] == 0)) { // C literal
|
||||
return new AstConst(fl, AstConst::WidthedValue(), 32, v);
|
||||
} else { // Try a Verilog literal (fatals if not)
|
||||
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
|
||||
VTimescale prec = v3Global.opt.timeComputePrec(value);
|
||||
if (prec.isNone() || prec == m_timeprecision) {
|
||||
@@ -284,7 +317,7 @@ public:
|
||||
bool m_isRef; // Is it a reference?
|
||||
string m_type; // The base type, e.g.: "Foo_t"s
|
||||
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
|
||||
string render(const string& name) {
|
||||
string render(const string& name) const {
|
||||
string out;
|
||||
out += m_type;
|
||||
out += " ";
|
||||
@@ -300,7 +333,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
|
||||
string ostatic;
|
||||
if (isStatic() && namespc.empty()) ostatic = "static ";
|
||||
|
||||
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
|
||||
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
|
||||
|
||||
string oname;
|
||||
if (named) {
|
||||
@@ -431,7 +464,7 @@ string AstVar::vlEnumDir() const {
|
||||
return out;
|
||||
}
|
||||
|
||||
string AstVar::vlPropDecl(string propName) const {
|
||||
string AstVar::vlPropDecl(const string& propName) const {
|
||||
string out;
|
||||
|
||||
std::vector<int> ulims; // Unpacked dimension limits
|
||||
@@ -450,9 +483,9 @@ string AstVar::vlPropDecl(string propName) const {
|
||||
out += "static const int " + propName + "__ulims[";
|
||||
out += cvtToStr(ulims.size());
|
||||
out += "] = {";
|
||||
std::vector<int>::const_iterator it = ulims.begin();
|
||||
auto it = ulims.cbegin();
|
||||
out += cvtToStr(*it);
|
||||
while (++it != ulims.end()) {
|
||||
while (++it != ulims.cend()) {
|
||||
out += ", ";
|
||||
out += cvtToStr(*it);
|
||||
}
|
||||
@@ -495,8 +528,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
}
|
||||
if (isWide()) {
|
||||
if (forReturn) {
|
||||
v3error("Unsupported: Public functions with >64 bit outputs; "
|
||||
"make an output of a public task instead");
|
||||
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
|
||||
"make an output of a public task instead");
|
||||
}
|
||||
arg += " (& " + name();
|
||||
arg += ")[" + cvtToStr(widthWords()) + "]";
|
||||
@@ -573,13 +606,13 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
||||
if (anodep->isSc()) {
|
||||
return anodep;
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
} else if (VN_IS(nodep, VarRef)) {
|
||||
if (VN_CAST(nodep, VarRef)->varp()->isSc()) {
|
||||
return VN_CAST(nodep, VarRef)->varp();
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
} else if (VN_IS(nodep, ArraySel)) {
|
||||
if (nodep->op1p()) {
|
||||
@@ -595,15 +628,13 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
||||
if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
string AstVar::mtasksString() const {
|
||||
std::ostringstream os;
|
||||
os << "all: ";
|
||||
for (MTaskIdSet::const_iterator it = m_mtaskIds.begin(); it != m_mtaskIds.end(); ++it) {
|
||||
os << *it << " ";
|
||||
}
|
||||
for (const auto& id : m_mtaskIds) os << id << " ";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
@@ -633,17 +664,17 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
|
||||
if (adtypep->isRanged()) {
|
||||
if ((dim++) == dimension) return adtypep;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
} else if (AstNodeUOrStructDType* adtypep = VN_CAST(dtypep, NodeUOrStructDType)) {
|
||||
if (adtypep->packed()) {
|
||||
if ((dim++) == dimension) return adtypep;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
// Node no ->next in loop; use continue where necessary
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t AstNodeDType::arrayUnpackedElements() {
|
||||
@@ -730,7 +761,7 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) {
|
||||
|
||||
const char* AstJumpBlock::broken() const {
|
||||
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void AstJumpBlock::cloneRelink() {
|
||||
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
|
||||
@@ -741,7 +772,7 @@ const char* AstScope::broken() const {
|
||||
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
|
||||
BROKEN_RTN(!m_modp);
|
||||
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void AstScope::cloneRelink() {
|
||||
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
|
||||
@@ -784,28 +815,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
||||
|
||||
bool AstSenTree::hasClocked() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
if (senp->isClocked()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasSettle() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
if (senp->isSettle()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasInitial() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
if (senp->isInitial()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasCombo() const {
|
||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
if (senp->isCombo()) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -815,7 +846,7 @@ void AstTypeTable::clearCache() {
|
||||
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
|
||||
// Just clear out the maps; the search functions will be used to rebuild the map
|
||||
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
|
||||
m_basicps[i] = NULL;
|
||||
m_basicps[i] = nullptr;
|
||||
}
|
||||
m_detailedMap.clear();
|
||||
// Clear generic()'s so dead detection will work
|
||||
@@ -873,8 +904,9 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, VNumRange range,
|
||||
int widthMin, VSigning numeric) {
|
||||
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
|
||||
const VNumRange& range, int widthMin,
|
||||
VSigning numeric) {
|
||||
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
|
||||
AstBasicDType* newp = findInsertSameDType(new1p);
|
||||
if (newp != new1p) {
|
||||
@@ -889,7 +921,7 @@ AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
||||
VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
||||
nodep->nrange());
|
||||
DetailedMap& mapr = m_detailedMap;
|
||||
DetailedMap::const_iterator it = mapr.find(key);
|
||||
const auto it = mapr.find(key);
|
||||
if (it != mapr.end()) return it->second;
|
||||
mapr.insert(make_pair(key, nodep));
|
||||
nodep->generic(true);
|
||||
@@ -1005,8 +1037,10 @@ void AstNode::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
|
||||
void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
|
||||
void AstAlways::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeProcedure::dump(str);
|
||||
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
|
||||
}
|
||||
|
||||
@@ -1027,8 +1061,12 @@ string AstBasicDType::prettyDTypeName() const {
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
|
||||
void AstCCast::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeUniop::dump(str);
|
||||
str << " sz" << size();
|
||||
}
|
||||
void AstCell::dump(std::ostream& str) const {
|
||||
@@ -1048,10 +1086,12 @@ void AstCellInline::dump(std::ostream& str) const {
|
||||
const char* AstClassPackage::broken() const {
|
||||
BROKEN_BASE_RTN(AstNodeModule::broken());
|
||||
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void AstClass::insertCache(AstNode* nodep) {
|
||||
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeFTask) || VN_IS(nodep, EnumItemRef)) {
|
||||
bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|
||||
|| (VN_IS(nodep, NodeFTask) && !VN_CAST(nodep, NodeFTask)->isExternProto()));
|
||||
if (doit) {
|
||||
if (m_members.find(nodep->name()) != m_members.end()) {
|
||||
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
|
||||
} else {
|
||||
@@ -1063,7 +1103,11 @@ void AstClass::repairCache() {
|
||||
clearCache();
|
||||
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); }
|
||||
}
|
||||
void AstClass::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstClass::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isExtended()) str << " [EXT]";
|
||||
if (isVirtual()) str << " [VIRT]";
|
||||
}
|
||||
AstClass* AstClassExtends::classp() const {
|
||||
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
||||
UASSERT_OBJ(refp, this, "class extends non-ref");
|
||||
@@ -1083,15 +1127,15 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
||||
str << "class:" << name();
|
||||
}
|
||||
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (immediate()) str << " [IMMEDIATE]";
|
||||
}
|
||||
void AstDisplay::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
// str<<" "<<displayType().ascii();
|
||||
}
|
||||
void AstEnumItemRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeMath::dump(str);
|
||||
str << " -> ";
|
||||
if (itemp()) {
|
||||
itemp()->dump(str);
|
||||
@@ -1131,7 +1175,7 @@ void AstInitArray::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstJumpGo::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (labelp()) {
|
||||
labelp()->dump(str);
|
||||
@@ -1140,7 +1184,7 @@ void AstJumpGo::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstJumpLabel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (blockp()) {
|
||||
blockp()->dump(str);
|
||||
@@ -1149,7 +1193,7 @@ void AstJumpLabel::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstMemberSel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeMath::dump(str);
|
||||
str << " -> ";
|
||||
if (varp()) {
|
||||
varp()->dump(str);
|
||||
@@ -1158,7 +1202,7 @@ void AstMemberSel::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstMethodCall::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (isStatement()) str << " [STMT]";
|
||||
str << " -> ";
|
||||
if (taskp()) {
|
||||
@@ -1199,27 +1243,30 @@ void AstPin::dump(std::ostream& str) const {
|
||||
if (svImplicit()) str << " [.SV]";
|
||||
}
|
||||
void AstPrintTimeScale::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
|
||||
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
void AstTime::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTermop::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
void AstTimeD::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTermop::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
void AstTimeImport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeUniop::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
void AstTypedef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (attrPublic()) str << " [PUBLIC]";
|
||||
}
|
||||
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstRange::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeRange::dump(str);
|
||||
if (littleEndian()) str << " [LITTLE]";
|
||||
}
|
||||
void AstRefDType::dump(std::ostream& str) const {
|
||||
@@ -1316,15 +1363,16 @@ void AstPackageImport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << packagep();
|
||||
}
|
||||
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
void AstSel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTriop::dump(str);
|
||||
if (declRange().ranged()) {
|
||||
str << " decl" << declRange() << "]";
|
||||
if (declElWidth() != 1) str << "/" << declElWidth();
|
||||
}
|
||||
}
|
||||
void AstSliceSel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTriop::dump(str);
|
||||
if (declRange().ranged()) str << " decl" << declRange();
|
||||
}
|
||||
void AstMTaskBody::dump(std::ostream& str) const {
|
||||
@@ -1392,10 +1440,11 @@ void AstVarScope::dump(std::ostream& str) const {
|
||||
str << " ->UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
void AstVarXRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeVarRef::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (lvalue()) {
|
||||
if (access().isWrite()) {
|
||||
str << " [LV] => ";
|
||||
} else {
|
||||
str << " [RV] <- ";
|
||||
@@ -1411,9 +1460,9 @@ void AstVarXRef::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstVarRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeVarRef::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (lvalue()) {
|
||||
if (access().isWrite()) {
|
||||
str << " [LV] => ";
|
||||
} else {
|
||||
str << " [RV] <- ";
|
||||
@@ -1462,19 +1511,19 @@ void AstParseRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [" << expect().ascii() << "]";
|
||||
}
|
||||
void AstPackageRef::dump(std::ostream& str) const {
|
||||
void AstClassOrPackageRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (classOrPackagep()) { str << " cpkg=" << nodeAddr(classOrPackagep()); }
|
||||
str << " -> ";
|
||||
if (packagep()) {
|
||||
packagep()->dump(str);
|
||||
if (classOrPackagep()) {
|
||||
classOrPackagep()->dump(str);
|
||||
} else {
|
||||
str << "UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstDot::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (colon()) str << "[::]";
|
||||
if (colon()) str << " [::]";
|
||||
}
|
||||
void AstActive::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
@@ -1486,7 +1535,7 @@ void AstActive::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
str << " -> ";
|
||||
if (dotted() != "") { str << ".=" << dotted() << " "; }
|
||||
@@ -1518,7 +1567,7 @@ void AstBegin::dump(std::ostream& str) const {
|
||||
if (implied()) str << " [IMPLIED]";
|
||||
}
|
||||
void AstCoverDecl::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (!page().empty()) str << " page=" << page();
|
||||
if (!linescov().empty()) str << " lc=" << linescov();
|
||||
if (this->dataDeclNullp()) {
|
||||
@@ -1529,7 +1578,7 @@ void AstCoverDecl::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstCoverInc::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (declp()) {
|
||||
declp()->dump(str);
|
||||
@@ -1542,7 +1591,7 @@ void AstFork::dump(std::ostream& str) const {
|
||||
if (!joinType().join()) str << " [" << joinType() << "]";
|
||||
}
|
||||
void AstTraceInc::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (declp()) {
|
||||
declp()->dump(str);
|
||||
@@ -1561,10 +1610,11 @@ void AstNodeText::dump(std::ostream& str) const {
|
||||
str << " \"" << out << "\"";
|
||||
}
|
||||
|
||||
void AstVFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
|
||||
|
||||
void AstCFile::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeFile::dump(str);
|
||||
if (source()) str << " [SRC]";
|
||||
if (slow()) str << " [SLOW]";
|
||||
}
|
||||
|
||||
+3017
-2677
File diff suppressed because it is too large
Load Diff
+31
-39
@@ -42,11 +42,10 @@ private:
|
||||
// Entire netlist:
|
||||
// AstNodeFTask::user1 -> bool, 1=processed
|
||||
AstUser1InUse m_inuser1;
|
||||
bool m_anyFuncInBegin;
|
||||
bool m_anyFuncInBegin = false;
|
||||
|
||||
public:
|
||||
BeginState()
|
||||
: m_anyFuncInBegin(false) {}
|
||||
BeginState() {}
|
||||
~BeginState() {}
|
||||
void userMarkChanged(AstNode* nodep) {
|
||||
nodep->user1(true);
|
||||
@@ -61,25 +60,24 @@ class BeginVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
BeginState* m_statep; // Current global state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_ifDepth; // Current if depth
|
||||
int m_ifDepth = 0; // Current if depth
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
UINFO(8, " " << nodep << endl);
|
||||
// Rename it
|
||||
if (m_unnamedScope != "") {
|
||||
@@ -92,19 +90,17 @@ private:
|
||||
// naming; so that any begin's inside the function will rename
|
||||
// inside the function.
|
||||
// Process children
|
||||
string oldScope = m_namedScope;
|
||||
string oldUnnamed = m_unnamedScope;
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
{
|
||||
m_namedScope = "";
|
||||
m_unnamedScope = "";
|
||||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_ftaskp = NULL;
|
||||
m_ftaskp = nullptr;
|
||||
}
|
||||
m_namedScope = oldScope;
|
||||
m_unnamedScope = oldUnnamed;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBegin* nodep) override {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8, " " << nodep << endl);
|
||||
string oldScope = m_namedScope;
|
||||
@@ -147,7 +143,7 @@ private:
|
||||
m_unnamedScope = oldUnnamed;
|
||||
|
||||
// Cleanup
|
||||
AstNode* addsp = NULL;
|
||||
AstNode* addsp = nullptr;
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
if (addsp) {
|
||||
@@ -163,7 +159,7 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
@@ -177,7 +173,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTypedef* nodep) override {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
@@ -192,7 +188,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
UINFO(8, " CELL " << nodep << endl);
|
||||
if (m_namedScope != "") {
|
||||
m_statep->userMarkChanged(nodep);
|
||||
@@ -205,14 +201,14 @@ private:
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarXRef* nodep) override {
|
||||
UINFO(9, " VARXREF " << nodep << endl);
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "") {
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) {
|
||||
nodep->inlinedDots(m_namedScope);
|
||||
UINFO(9, " rescope to " << nodep << endl);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScopeName* nodep) override {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Inline
|
||||
if (nodep->user1SetOnce()) return; // Don't double-add text's
|
||||
@@ -225,15 +221,15 @@ private:
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverDecl* nodep) override {
|
||||
// Don't need to fix path in coverage statements, they're not under
|
||||
// any BEGINs, but V3Coverage adds them all under the module itself.
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
// VISITORS - LINT CHECK
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE { // not AstNodeIf; other types not covered
|
||||
virtual void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered
|
||||
// Check IFDEPTH warning - could be in other transform files if desire
|
||||
int prevIfDepth = m_ifDepth;
|
||||
VL_RESTORER(m_ifDepth);
|
||||
if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off
|
||||
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
|
||||
m_ifDepth = -1;
|
||||
@@ -244,20 +240,16 @@ private:
|
||||
m_ifDepth = -1;
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
m_ifDepth = prevIfDepth;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
BeginVisitor(AstNetlist* nodep, BeginState* statep) {
|
||||
m_statep = statep;
|
||||
m_modp = NULL;
|
||||
m_ftaskp = NULL;
|
||||
m_ifDepth = 0;
|
||||
BeginVisitor(AstNetlist* nodep, BeginState* statep)
|
||||
: m_statep{statep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~BeginVisitor() {}
|
||||
virtual ~BeginVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -270,21 +262,21 @@ private:
|
||||
// AstNodeFTask::user1p // Node replaced, rename it
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) override {
|
||||
if (nodep->taskp()->user1()) { // It was converted
|
||||
UINFO(9, " relinkFTask " << nodep << endl);
|
||||
nodep->name(nodep->taskp()->name());
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (nodep->varp()->user1()) { // It was converted
|
||||
UINFO(9, " relinVarRef " << nodep << endl);
|
||||
nodep->name(nodep->varp()->name());
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstIfaceRefDType* nodep) override {
|
||||
// May have changed cell names
|
||||
// TypeTable is always after all modules, so names are stable
|
||||
UINFO(8, " IFACEREFDTYPE " << nodep << endl);
|
||||
@@ -293,12 +285,12 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
|
||||
virtual ~BeginRelinkVisitor() {}
|
||||
virtual ~BeginRelinkVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+8
-11
@@ -65,10 +65,10 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeIf* nodep) override {
|
||||
UINFO(4, " IF: " << nodep << endl);
|
||||
int lastLikely = m_likely;
|
||||
int lastUnlikely = m_unlikely;
|
||||
VL_RESTORER(m_likely);
|
||||
VL_RESTORER(m_unlikely);
|
||||
{
|
||||
// Do if
|
||||
reset();
|
||||
@@ -88,28 +88,25 @@ private:
|
||||
nodep->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
} // else leave unknown
|
||||
}
|
||||
m_likely = lastLikely;
|
||||
m_unlikely = lastUnlikely;
|
||||
}
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCCall* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
nodep->funcp()->user1Inc();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
m_cfuncsp.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
void calc_tasks() {
|
||||
for (CFuncVec::iterator it = m_cfuncsp.begin(); it != m_cfuncsp.end(); ++it) {
|
||||
AstCFunc* nodep = *it;
|
||||
for (AstCFunc* nodep : m_cfuncsp) {
|
||||
if (!nodep->dontInline()) nodep->isInline(true);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +118,7 @@ public:
|
||||
iterateChildren(nodep);
|
||||
calc_tasks();
|
||||
}
|
||||
virtual ~BranchVisitor() {}
|
||||
virtual ~BranchVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+19
-19
@@ -32,7 +32,7 @@
|
||||
#include "V3AstConstOnly.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -41,7 +41,7 @@ class BrokenTable : public AstNVisitor {
|
||||
private:
|
||||
// MEMBERS
|
||||
// For each node, we keep if it exists or not.
|
||||
typedef vl_unordered_map<const AstNode*, int> NodeMap; // Performance matters (when --debug)
|
||||
typedef std::unordered_map<const AstNode*, int> NodeMap; // Performance matters (when --debug)
|
||||
static NodeMap s_nodes; // Set of all nodes that exist
|
||||
// BITMASK
|
||||
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
|
||||
@@ -49,12 +49,13 @@ private:
|
||||
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
|
||||
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
|
||||
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
static void deleted(const AstNode* nodep) {
|
||||
// Called by operator delete on any node - only if VL_LEAK_CHECKS
|
||||
if (debug() >= 9) cout << "-nodeDel: " << cvtToHex(nodep) << endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
UASSERT_OBJ(!(iter == s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
|
||||
reinterpret_cast<const AstNode*>(nodep),
|
||||
"Deleting AstNode object that was never tracked or already deleted");
|
||||
@@ -67,7 +68,7 @@ public:
|
||||
static void addNewed(const AstNode* nodep) {
|
||||
// Called by operator new on any node - only if VL_LEAK_CHECKS
|
||||
if (debug() >= 9) cout << "-nodeNew: " << cvtToHex(nodep) << endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
UASSERT_OBJ(!(iter != s_nodes.end() && (iter->second & FLAG_ALLOCATED)), nodep,
|
||||
"Newing AstNode object that is already allocated");
|
||||
if (iter == s_nodes.end()) {
|
||||
@@ -78,7 +79,7 @@ public:
|
||||
static void setUnder(const AstNode* nodep, bool flag) {
|
||||
// Called by BrokenCheckVisitor when each node entered/exited
|
||||
if (!okIfLinkedTo(nodep)) return;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
if (iter != s_nodes.end()) {
|
||||
iter->second &= ~FLAG_UNDER_NOW;
|
||||
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||
@@ -89,7 +90,7 @@ public:
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (!linkable) return; // save some time, else the map will get huge!
|
||||
#endif
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
if (VL_UNCOVERABLE(iter == s_nodes.end())) {
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
|
||||
@@ -113,7 +114,7 @@ public:
|
||||
// Some generic node has a pointer to this node. Is it allocated?
|
||||
// Use this when might not be in tree; otherwise use okIfLinkedTo().
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) return false;
|
||||
if (!(iter->second & FLAG_ALLOCATED)) return false;
|
||||
#endif
|
||||
@@ -121,7 +122,7 @@ public:
|
||||
}
|
||||
static bool okIfLinkedTo(const AstNode* nodep) {
|
||||
// Some node in tree has a pointer to this node. Is it kosher?
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) return false;
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
if (!(iter->second & FLAG_ALLOCATED)) return false;
|
||||
@@ -133,7 +134,7 @@ public:
|
||||
static bool okIfAbove(const AstNode* nodep) {
|
||||
// Must be linked to and below current node
|
||||
if (!okIfLinkedTo(nodep)) return false;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) return false;
|
||||
if ((iter->second & FLAG_UNDER_NOW)) return false;
|
||||
return true;
|
||||
@@ -141,7 +142,7 @@ public:
|
||||
static bool okIfBelow(const AstNode* nodep) {
|
||||
// Must be linked to and below current node
|
||||
if (!okIfLinkedTo(nodep)) return false;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
const auto iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) return false;
|
||||
if (!(iter->second & FLAG_UNDER_NOW)) return false;
|
||||
return true;
|
||||
@@ -188,10 +189,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
BrokenTable() {}
|
||||
virtual ~BrokenTable() {}
|
||||
virtual ~BrokenTable() override {}
|
||||
};
|
||||
|
||||
BrokenTable::NodeMap BrokenTable::s_nodes;
|
||||
@@ -223,7 +223,7 @@ private:
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
// Process not just iterate
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~BrokenMarkVisitor() {}
|
||||
virtual ~BrokenMarkVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -239,7 +239,7 @@ public:
|
||||
|
||||
class BrokenCheckVisitor : public AstNVisitor {
|
||||
private:
|
||||
void checkWidthMin(const AstNode* nodep) {
|
||||
static void checkWidthMin(const AstNode* nodep) {
|
||||
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|
||||
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
|
||||
nodep, "Width != WidthMin");
|
||||
@@ -271,14 +271,14 @@ private:
|
||||
iterateChildrenConst(nodep);
|
||||
BrokenTable::setUnder(nodep, false);
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
processAndIterate(nodep);
|
||||
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
|
||||
&& VN_IS(nodep->lhsp(), NodeVarRef)
|
||||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
|
||||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWrite()),
|
||||
nodep, "Assignment LHS is not an lvalue");
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
// Process not just iterate
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
@@ -286,7 +286,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~BrokenCheckVisitor() {}
|
||||
virtual ~BrokenCheckVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+12
-9
@@ -48,11 +48,11 @@ private:
|
||||
public:
|
||||
void add(AstNode* nodep) {
|
||||
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||
m_funcp = NULL;
|
||||
m_funcp = nullptr;
|
||||
}
|
||||
if (!m_funcp) {
|
||||
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum),
|
||||
NULL, "void");
|
||||
nullptr, "void");
|
||||
m_funcp->isStatic(false);
|
||||
m_funcp->declPrivate(true);
|
||||
m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
m_modp = nodep;
|
||||
m_numStmts = 0;
|
||||
m_funcNum = 0;
|
||||
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void");
|
||||
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void");
|
||||
m_tlFuncp->declPrivate(true);
|
||||
m_tlFuncp->isStatic(false);
|
||||
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
|
||||
@@ -97,7 +97,7 @@ private:
|
||||
|
||||
void V3CCtors::evalAsserts() {
|
||||
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module wrapper
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", NULL, "void");
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", nullptr, "void");
|
||||
funcp->declPrivate(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->slow(false);
|
||||
@@ -111,7 +111,7 @@ void V3CCtors::evalAsserts() {
|
||||
int lastWordWidth = varp->width() % storedWidth;
|
||||
if (lastWordWidth != 0) {
|
||||
// if (signal & CONST(upper_non_clean_mask)) { fail; }
|
||||
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
|
||||
AstNode* newp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
|
||||
if (varp->isWide()) {
|
||||
newp = new AstWordSel(
|
||||
varp->fileline(), newp,
|
||||
@@ -151,8 +151,9 @@ void V3CCtors::cctorsAll() {
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(np, Var)) {
|
||||
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
|
||||
var_reset.add(new AstCReset(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true)));
|
||||
var_reset.add(
|
||||
new AstCReset(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, VAccess::WRITE)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,10 +171,12 @@ void V3CCtors::cctorsAll() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VN_IS(modp, Class)) {
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", NULL, "");
|
||||
if (AstClass* classp = VN_CAST(modp, Class)) {
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", nullptr, "");
|
||||
funcp->isDestructor(true);
|
||||
funcp->isStatic(false);
|
||||
// If can be referred to by base pointer, need virtual delete
|
||||
funcp->isVirtual(classp->isExtended());
|
||||
funcp->slow(false);
|
||||
modp->addStmtp(funcp);
|
||||
}
|
||||
|
||||
+25
-19
@@ -32,7 +32,7 @@
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit CUseState(AstNodeModule* nodep)
|
||||
: m_modInsertp(nodep) {}
|
||||
: m_modInsertp{nodep} {}
|
||||
virtual ~CUseState() {}
|
||||
VL_UNCOPYABLE(CUseState);
|
||||
};
|
||||
@@ -78,27 +78,26 @@ public:
|
||||
class CUseDTypeVisitor : public AstNVisitor {
|
||||
// MEMBERS
|
||||
CUseState& m_stater; // State for inserter
|
||||
bool m_impOnly; // In details needed only for implementation
|
||||
bool m_impOnly = false; // In details needed only for implementation
|
||||
// METHODS
|
||||
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstClassRefDType* nodep) override {
|
||||
if (nodep->user2SetOnce()) return; // Process once
|
||||
if (!m_impOnly) m_stater.newUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
|
||||
// No class.h, it's inside the class package's h file
|
||||
m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->packagep()->name());
|
||||
// Need to include extends() when we implement, but no need for pointers to know
|
||||
bool oldImpOnly = m_impOnly;
|
||||
VL_RESTORER(m_impOnly);
|
||||
{
|
||||
m_impOnly = true;
|
||||
iterateChildren(nodep->classp()); // This also gets all extend classes
|
||||
}
|
||||
m_impOnly = oldImpOnly;
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeDType* nodep) override {
|
||||
if (nodep->user2SetOnce()) return; // Process once
|
||||
if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep());
|
||||
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
if (nodep->user2SetOnce()) return; // Process once
|
||||
if (nodep->dtypep() && !nodep->dtypep()->user2()) iterate(nodep->dtypep());
|
||||
iterateChildren(nodep);
|
||||
@@ -107,11 +106,10 @@ class CUseDTypeVisitor : public AstNVisitor {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CUseDTypeVisitor(AstNodeModule* nodep, CUseState& stater)
|
||||
: m_stater(stater)
|
||||
, m_impOnly(false) {
|
||||
: m_stater(stater) { // Need () or GCC 4.8 false warning
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CUseDTypeVisitor() {}
|
||||
virtual ~CUseDTypeVisitor() override {}
|
||||
VL_UNCOPYABLE(CUseDTypeVisitor);
|
||||
};
|
||||
|
||||
@@ -132,7 +130,7 @@ class CUseVisitor : public AstNVisitor {
|
||||
}
|
||||
}
|
||||
void makeVlToString(AstClass* nodep) {
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "VL_TO_STRING", NULL, "std::string");
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "VL_TO_STRING", nullptr, "std::string");
|
||||
funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep)
|
||||
+ ">& obj");
|
||||
funcp->isMethod(false);
|
||||
@@ -145,7 +143,7 @@ class CUseVisitor : public AstNVisitor {
|
||||
nodep->addStmtp(funcp);
|
||||
}
|
||||
void makeToString(AstClass* nodep) {
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string", NULL, "std::string");
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string", nullptr, "std::string");
|
||||
funcp->isConst(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
@@ -156,7 +154,8 @@ class CUseVisitor : public AstNVisitor {
|
||||
nodep->addStmtp(funcp);
|
||||
}
|
||||
void makeToStringMiddle(AstClass* nodep) {
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string_middle", NULL, "std::string");
|
||||
AstCFunc* funcp
|
||||
= new AstCFunc(nodep->fileline(), "to_string_middle", nullptr, "std::string");
|
||||
funcp->isConst(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
@@ -168,7 +167,14 @@ class CUseVisitor : public AstNVisitor {
|
||||
stmt += comma;
|
||||
comma = ", ";
|
||||
stmt += itemp->origNameProtect();
|
||||
stmt += ":\" + VL_TO_STRING(";
|
||||
stmt += ":\" + ";
|
||||
if (itemp->isWide()) {
|
||||
stmt += "VL_TO_STRING_W(";
|
||||
stmt += cvtToStr(itemp->widthWords());
|
||||
stmt += ", ";
|
||||
} else {
|
||||
stmt += "VL_TO_STRING(";
|
||||
}
|
||||
stmt += itemp->nameProtect();
|
||||
stmt += ");\n";
|
||||
nodep->user1(true); // So what we extend dumps this
|
||||
@@ -189,7 +195,7 @@ class CUseVisitor : public AstNVisitor {
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
if (v3Global.opt.trace()) {
|
||||
AstCUse* usep
|
||||
= m_state.newUse(nodep, VUseType::INT_FWD_CLASS, v3Global.opt.traceClassBase());
|
||||
@@ -203,15 +209,15 @@ class CUseVisitor : public AstNVisitor {
|
||||
makeToStringMiddle(classp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode*) VL_OVERRIDE {} // All in AstNodeModule
|
||||
virtual void visit(AstNode*) override {} // All in AstNodeModule
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CUseVisitor(AstNodeModule* nodep)
|
||||
: m_state(nodep) {
|
||||
: m_state{nodep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CUseVisitor() {}
|
||||
virtual ~CUseVisitor() override {}
|
||||
VL_UNCOPYABLE(CUseVisitor);
|
||||
};
|
||||
|
||||
|
||||
+29
-33
@@ -52,12 +52,13 @@
|
||||
|
||||
class CaseLintVisitor : public AstNVisitor {
|
||||
private:
|
||||
AstNodeCase* m_caseExprp; // Under a CASE value node, if so the relevant case statement
|
||||
AstNodeCase* m_caseExprp
|
||||
= nullptr; // Under a CASE value node, if so the relevant case statement
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCase* nodep) override {
|
||||
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
|
||||
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
|
||||
}
|
||||
@@ -81,10 +82,10 @@ private:
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
iterateAndNextNull(itemp->condsp());
|
||||
}
|
||||
m_caseExprp = NULL;
|
||||
m_caseExprp = nullptr;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConst* nodep) override {
|
||||
// See also neverItem
|
||||
if (m_caseExprp && nodep->num().isFourState()) {
|
||||
if (VN_IS(m_caseExprp, GenCase)) {
|
||||
@@ -105,15 +106,12 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) {
|
||||
m_caseExprp = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CaseLintVisitor() {}
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
|
||||
virtual ~CaseLintVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -131,9 +129,9 @@ private:
|
||||
VDouble0 m_statCaseSlow; // Statistic tracking
|
||||
|
||||
// Per-CASE
|
||||
int m_caseWidth; // Width of valueItems
|
||||
int m_caseItems; // Number of caseItem unique values
|
||||
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
int m_caseWidth = 0; // Width of valueItems
|
||||
int m_caseItems = 0; // Number of caseItem unique values
|
||||
bool m_caseNoOverlapsAllCovered = false; // Proven to be synopsys parallel_case compliant
|
||||
// For each possible value, the case branch we need
|
||||
AstNode* m_valueItem[1 << CASE_OVERLAP_WIDTH];
|
||||
|
||||
@@ -161,7 +159,7 @@ private:
|
||||
}
|
||||
UINFO(8, "Simple case statement: " << nodep << endl);
|
||||
// Zero list of items for each value
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) m_valueItem[i] = NULL;
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) m_valueItem[i] = nullptr;
|
||||
// Now pick up the values for each assignment
|
||||
// We can cheat and use uint32_t's because we only support narrow case's
|
||||
bool bitched = false;
|
||||
@@ -218,7 +216,7 @@ private:
|
||||
}
|
||||
|
||||
// Convert valueItem from AstCaseItem* to the expression
|
||||
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
|
||||
// Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
|
||||
}
|
||||
@@ -324,13 +322,13 @@ private:
|
||||
hadDefault = true;
|
||||
} else {
|
||||
// Expressioned clause
|
||||
AstNode* icondNextp = NULL;
|
||||
AstNode* ifexprp = NULL; // If expression to test
|
||||
AstNode* icondNextp = nullptr;
|
||||
AstNode* ifexprp = nullptr; // If expression to test
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondNextp) {
|
||||
icondNextp = icondp->nextp();
|
||||
icondp->unlinkFrBack();
|
||||
|
||||
AstNode* condp = NULL; // Default is to use and1p/and2p
|
||||
AstNode* condp = nullptr; // Default is to use and1p/and2p
|
||||
AstConst* iconstp = VN_CAST(icondp, Const);
|
||||
if (iconstp && neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
@@ -377,8 +375,9 @@ private:
|
||||
if (!hadDefault) {
|
||||
// If there was no default, add a empty one, this greatly simplifies below code
|
||||
// and constant propagation will just eliminate it for us later.
|
||||
nodep->addItemsp(new AstCaseItem(
|
||||
nodep->fileline(), new AstConst(nodep->fileline(), AstConst::LogicTrue()), NULL));
|
||||
nodep->addItemsp(
|
||||
new AstCaseItem(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()), nullptr));
|
||||
}
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: ");
|
||||
// Now build the IF statement tree
|
||||
@@ -388,9 +387,9 @@ private:
|
||||
// should pull out the most common item from here and instead make
|
||||
// it the first IF branch.
|
||||
int depth = 0;
|
||||
AstNode* grouprootp = NULL;
|
||||
AstIf* groupnextp = NULL;
|
||||
AstIf* itemnextp = NULL;
|
||||
AstNode* grouprootp = nullptr;
|
||||
AstIf* groupnextp = nullptr;
|
||||
AstIf* itemnextp = nullptr;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
|
||||
@@ -400,9 +399,9 @@ private:
|
||||
{ // Prepare for next group
|
||||
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
|
||||
if (depth == 1) { // First group or starting new group
|
||||
itemnextp = NULL;
|
||||
itemnextp = nullptr;
|
||||
AstIf* newp
|
||||
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL);
|
||||
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), nullptr, nullptr);
|
||||
if (groupnextp) {
|
||||
groupnextp->addElsesp(newp);
|
||||
} else {
|
||||
@@ -422,7 +421,7 @@ private:
|
||||
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
|
||||
if (itemnextp) {
|
||||
itemnextp->addElsesp(newp);
|
||||
} else {
|
||||
@@ -467,7 +466,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCase* nodep) override {
|
||||
V3Case::caseLint(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " case_old: ");
|
||||
@@ -482,18 +481,15 @@ private:
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseVisitor(AstNetlist* nodep) {
|
||||
m_caseWidth = 0;
|
||||
m_caseItems = 0;
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = NULL;
|
||||
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CaseVisitor() {
|
||||
virtual ~CaseVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
|
||||
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
|
||||
}
|
||||
|
||||
+17
-17
@@ -109,25 +109,25 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeUniop* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeBiop* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeTriop* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeQuadop* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
|
||||
| nodep->fhsp()->user1());
|
||||
@@ -136,12 +136,12 @@ private:
|
||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
||||
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
|
||||
}
|
||||
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCCast* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureLower32Cast(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNegate* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->lhsp()->widthMin() == 1) {
|
||||
@@ -153,17 +153,17 @@ private:
|
||||
ensureCast(nodep->lhsp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
|
||||
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
|
||||
&& castSize(nodep) != castSize(nodep->varp())) {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (nodep->access().isRead() && !VN_IS(nodep->backp(), CCast)
|
||||
&& VN_IS(nodep->backp(), NodeMath) && !VN_IS(nodep->backp(), ArraySel)
|
||||
&& nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) {
|
||||
// Cast vars to IData first, else below has upper bits wrongly set
|
||||
// CData x=3; out = (QData)(x<<30);
|
||||
insertCast(nodep, castSize(nodep));
|
||||
}
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConst* nodep) override {
|
||||
// Constants are of unknown size if smaller than 33 bits, because
|
||||
// we're too lazy to wrap every constant in the universe in
|
||||
// ((IData)#).
|
||||
@@ -171,29 +171,29 @@ private:
|
||||
}
|
||||
|
||||
// Null dereference protection
|
||||
virtual void visit(AstNullCheck* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNullCheck* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
}
|
||||
virtual void visit(AstCMethodCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCMethodCall* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureNullChecked(nodep->fromp());
|
||||
}
|
||||
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstMemberSel* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureNullChecked(nodep->fromp());
|
||||
}
|
||||
|
||||
// NOPs
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstVar*) override {}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CastVisitor() {}
|
||||
virtual ~CastVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+87
-112
@@ -37,7 +37,7 @@
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
|
||||
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
||||
constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -52,25 +52,23 @@ public:
|
||||
class CdcEitherVertex : public V3GraphVertex {
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstSenTree* m_srcDomainp;
|
||||
AstSenTree* m_dstDomainp;
|
||||
AstSenTree* m_srcDomainp = nullptr;
|
||||
AstSenTree* m_dstDomainp = nullptr;
|
||||
bool m_srcDomainSet : 1;
|
||||
bool m_dstDomainSet : 1;
|
||||
bool m_asyncPath : 1;
|
||||
|
||||
public:
|
||||
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
|
||||
: V3GraphVertex(graphp)
|
||||
, m_scopep(scopep)
|
||||
, m_nodep(nodep)
|
||||
, m_srcDomainp(NULL)
|
||||
, m_dstDomainp(NULL)
|
||||
, m_srcDomainSet(false)
|
||||
, m_dstDomainSet(false)
|
||||
, m_asyncPath(false) {}
|
||||
virtual ~CdcEitherVertex() {}
|
||||
: V3GraphVertex{graphp}
|
||||
, m_scopep{scopep}
|
||||
, m_nodep{nodep}
|
||||
, m_srcDomainSet{false}
|
||||
, m_dstDomainSet{false}
|
||||
, m_asyncPath{false} {}
|
||||
virtual ~CdcEitherVertex() override {}
|
||||
// ACCESSORS
|
||||
virtual FileLine* fileline() const { return nodep()->fileline(); }
|
||||
virtual FileLine* fileline() const override { return nodep()->fileline(); }
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
AstSenTree* srcDomainp() const { return m_srcDomainp; }
|
||||
@@ -87,20 +85,18 @@ public:
|
||||
|
||||
class CdcVarVertex : public CdcEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
int m_cntAsyncRst;
|
||||
bool m_fromFlop;
|
||||
int m_cntAsyncRst = 0;
|
||||
bool m_fromFlop = false;
|
||||
|
||||
public:
|
||||
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: CdcEitherVertex(graphp, scopep, varScp)
|
||||
, m_varScp(varScp)
|
||||
, m_cntAsyncRst(0)
|
||||
, m_fromFlop(false) {}
|
||||
virtual ~CdcVarVertex() {}
|
||||
: CdcEitherVertex{graphp, scopep, varScp}
|
||||
, m_varScp{varScp} {}
|
||||
virtual ~CdcVarVertex() override {}
|
||||
// ACCESSORS
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
virtual string dotColor() const {
|
||||
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
virtual string dotColor() const override {
|
||||
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
|
||||
}
|
||||
int cntAsyncRst() const { return m_cntAsyncRst; }
|
||||
@@ -115,16 +111,18 @@ class CdcLogicVertex : public CdcEitherVertex {
|
||||
|
||||
public:
|
||||
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
|
||||
: CdcEitherVertex(graphp, scopep, nodep)
|
||||
, m_hazard(false)
|
||||
, m_isFlop(false) {
|
||||
: CdcEitherVertex{graphp, scopep, nodep}
|
||||
, m_hazard{false}
|
||||
, m_isFlop{false} {
|
||||
srcDomainp(sensenodep);
|
||||
dstDomainp(sensenodep);
|
||||
}
|
||||
virtual ~CdcLogicVertex() {}
|
||||
virtual ~CdcLogicVertex() override {}
|
||||
// ACCESSORS
|
||||
virtual string name() const { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
|
||||
virtual string dotColor() const { return hazard() ? "black" : "yellow"; }
|
||||
virtual string name() const override {
|
||||
return (cvtToHex(nodep()) + "@" + scopep()->prettyName());
|
||||
}
|
||||
virtual string dotColor() const override { return hazard() ? "black" : "yellow"; }
|
||||
bool hazard() const { return m_hazard; }
|
||||
void setHazard(AstNode* nodep) {
|
||||
m_hazard = true;
|
||||
@@ -145,7 +143,7 @@ private:
|
||||
std::ofstream* m_ofp; // Output file
|
||||
string m_prefix;
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
*m_ofp << m_prefix;
|
||||
if (nodep->user3()) {
|
||||
*m_ofp << " %%";
|
||||
@@ -167,22 +165,22 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix) {
|
||||
m_ofp = ofp;
|
||||
m_prefix = prefix;
|
||||
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix)
|
||||
: m_ofp{ofp}
|
||||
, m_prefix{prefix} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CdcDumpVisitor() {}
|
||||
virtual ~CdcDumpVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcWidthVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
int m_maxLineno;
|
||||
size_t m_maxFilenameLen;
|
||||
int m_maxLineno = 0;
|
||||
size_t m_maxFilenameLen = 0;
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Keeping line+filename lengths separate is much faster than calling ascii().length()
|
||||
if (nodep->fileline()->lineno() >= m_maxLineno) {
|
||||
@@ -195,14 +193,10 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CdcWidthVisitor(AstNode* nodep) {
|
||||
m_maxLineno = 0;
|
||||
m_maxFilenameLen = 0;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CdcWidthVisitor() {}
|
||||
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~CdcWidthVisitor() override {}
|
||||
// ACCESSORS
|
||||
int maxWidth() {
|
||||
int maxWidth() const {
|
||||
size_t width = 1;
|
||||
width += m_maxFilenameLen;
|
||||
width += 1; // The :
|
||||
@@ -229,16 +223,16 @@ private:
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
|
||||
AstScope* m_scopep; // Current scope being processed
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstSenTree* m_domainp; // Current sentree
|
||||
bool m_inDly; // In delayed assign
|
||||
int m_inSenItem; // Number of senitems
|
||||
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
|
||||
AstScope* m_scopep = nullptr; // Current scope being processed
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstSenTree* m_domainp = nullptr; // Current sentree
|
||||
bool m_inDly = false; // In delayed assign
|
||||
int m_inSenItem = 0; // Number of senitems
|
||||
string m_ofFilename; // Output filename
|
||||
std::ofstream* m_ofp; // Output file
|
||||
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth; // Characters in longest fileline
|
||||
uint32_t m_userGeneration = 0; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth = 0; // Characters in longest fileline
|
||||
|
||||
// METHODS
|
||||
void iterateNewStmt(AstNode* nodep) {
|
||||
@@ -253,7 +247,7 @@ private:
|
||||
m_logicVertexp->dstDomainSet(true);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
m_logicVertexp = NULL;
|
||||
m_logicVertexp = nullptr;
|
||||
|
||||
if (false && debug() >= 9) {
|
||||
UINFO(9, "Trace Logic:\n");
|
||||
@@ -273,7 +267,7 @@ private:
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are
|
||||
// now This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* ioVertexp
|
||||
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
|
||||
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), nullptr);
|
||||
if (varscp->varp()->isWritable()) {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
} else {
|
||||
@@ -364,7 +358,7 @@ private:
|
||||
UINFO(8, " Trace One async: " << vvertexp << endl);
|
||||
// Twice, as we need to detect, then propagate
|
||||
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
|
||||
if (markp) { // Mark is non-NULL if something bad on this path
|
||||
if (markp) { // Mark is non-nullptr if something bad on this path
|
||||
UINFO(9, " Trace One bad! " << vvertexp << endl);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
traceAsyncRecurse(vvertexp, true);
|
||||
@@ -377,12 +371,12 @@ private:
|
||||
}
|
||||
|
||||
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
|
||||
// First pass: Return vertex of any hazardous stuff attached, or NULL if OK
|
||||
// First pass: Return vertex of any hazardous stuff attached, or nullptr if OK
|
||||
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
|
||||
if (vertexp->user() >= m_userGeneration) return NULL; // Processed - prevent loop
|
||||
if (vertexp->user() >= m_userGeneration) return nullptr; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
CdcEitherVertex* mark_outp = NULL;
|
||||
CdcEitherVertex* mark_outp = nullptr;
|
||||
UINFO(9, " Trace: " << vertexp << endl);
|
||||
|
||||
// Clear out in prep for marking next path
|
||||
@@ -401,7 +395,7 @@ private:
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
// Also ok if from flop, but partially trace the flop so more obvious to users
|
||||
if (vvertexp->fromFlop()) {
|
||||
@@ -409,7 +403,7 @@ private:
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +508,7 @@ private:
|
||||
}
|
||||
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
|
||||
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatal("Can't write " << filename);
|
||||
*ofp << "Edge Report for " << v3Global.opt.prefix() << endl;
|
||||
|
||||
@@ -549,9 +543,7 @@ private:
|
||||
}
|
||||
}
|
||||
stable_sort(report.begin(), report.end());
|
||||
for (std::deque<string>::iterator it = report.begin(); it != report.end(); ++it) {
|
||||
*ofp << *it;
|
||||
}
|
||||
for (const auto& line : report) *ofp << line;
|
||||
}
|
||||
|
||||
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
||||
@@ -594,7 +586,7 @@ private:
|
||||
}
|
||||
|
||||
// Convert list of senses into one sense node
|
||||
AstSenTree* senoutp = NULL;
|
||||
AstSenTree* senoutp = nullptr;
|
||||
bool senedited = false;
|
||||
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
|
||||
if (!senoutp) {
|
||||
@@ -633,22 +625,21 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
m_logicVertexp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4, " BLOCK " << nodep << endl);
|
||||
AstNode::user2ClearTree();
|
||||
@@ -657,10 +648,10 @@ private:
|
||||
|| m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
m_domainp = NULL;
|
||||
m_domainp = nullptr;
|
||||
AstNode::user2ClearTree();
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
@@ -670,7 +661,7 @@ private:
|
||||
// We use weight of one for normal edges,
|
||||
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
|
||||
// When simplify we'll take the MAX weight
|
||||
if (nodep->lvalue()) {
|
||||
if (nodep->access().isWrite()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
if (m_inDly) {
|
||||
varvertexp->fromFlop(true);
|
||||
@@ -688,71 +679,55 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignDly* nodep) override {
|
||||
m_inDly = true;
|
||||
iterateChildren(nodep);
|
||||
m_inDly = false;
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
// Note we look at only AstSenItems, not AstSenGate's
|
||||
// The gating term of a AstSenGate is normal logic
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
m_inSenItem = true;
|
||||
iterateChildren(nodep);
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAlwaysPublic* nodep) override {
|
||||
// CDC doesn't care about public variables
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is dealt with as logic
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); }
|
||||
|
||||
// Math that shouldn't cause us to clear hazard
|
||||
virtual void visit(AstConst*) VL_OVERRIDE {}
|
||||
virtual void visit(AstReplicate* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNot* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConst*) override {}
|
||||
virtual void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstConcat* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstNot* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstSel* nodep) override {
|
||||
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeSel* nodep) override {
|
||||
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Ignores
|
||||
virtual void visit(AstInitial*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
|
||||
virtual void visit(AstCoverToggle*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeDType*) VL_OVERRIDE {}
|
||||
virtual void visit(AstInitial*) override {}
|
||||
virtual void visit(AstTraceDecl*) override {}
|
||||
virtual void visit(AstCoverToggle*) override {}
|
||||
virtual void visit(AstNodeDType*) override {}
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeMath* nodep) override {
|
||||
setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CdcVisitor(AstNode* nodep) {
|
||||
m_logicVertexp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_modp = NULL;
|
||||
m_domainp = NULL;
|
||||
m_inDly = false;
|
||||
m_inSenItem = 0;
|
||||
m_userGeneration = 0;
|
||||
m_filelineWidth = 0;
|
||||
|
||||
// Make report of all signal names and what clock edges they have
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt";
|
||||
m_ofp = V3File::new_ofstream(filename);
|
||||
@@ -770,12 +745,12 @@ public:
|
||||
if (debug() >= 1) edgeReport(); // Not useful to users at the moment
|
||||
if (false) {
|
||||
*m_ofp << "\nDBG-test-dumper\n";
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, NULL, true);
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true);
|
||||
*m_ofp << endl;
|
||||
}
|
||||
}
|
||||
virtual ~CdcVisitor() {
|
||||
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
|
||||
virtual ~CdcVisitor() override {
|
||||
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+40
-47
@@ -41,21 +41,14 @@
|
||||
class ChangedState {
|
||||
public:
|
||||
// STATE
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp; // Change function we're building
|
||||
AstCFunc* m_tlChgFuncp; // Top level change function we're building
|
||||
int m_numStmts; // Number of statements added to m_chgFuncp
|
||||
int m_funcNum; // Number of change functions emitted
|
||||
AstNodeModule* m_topModp = nullptr; // Top module
|
||||
AstScope* m_scopetopp = nullptr; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp = nullptr; // Change function we're building
|
||||
AstCFunc* m_tlChgFuncp = nullptr; // Top level change function we're building
|
||||
int m_numStmts = 0; // Number of statements added to m_chgFuncp
|
||||
int m_funcNum = 0; // Number of change functions emitted
|
||||
|
||||
ChangedState() {
|
||||
m_topModp = NULL;
|
||||
m_chgFuncp = NULL;
|
||||
m_scopetopp = NULL;
|
||||
m_tlChgFuncp = NULL;
|
||||
m_numStmts = 0;
|
||||
m_funcNum = 0;
|
||||
}
|
||||
ChangedState() {}
|
||||
~ChangedState() {}
|
||||
|
||||
void maybeCreateChgFuncp() {
|
||||
@@ -142,34 +135,33 @@ private:
|
||||
m_statep->m_numStmts += visitor.count();
|
||||
}
|
||||
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { //
|
||||
virtual void visit(AstBasicDType*) override { //
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE { //
|
||||
virtual void visit(AstPackArrayDType*) override { //
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUnpackArrayDType* nodep) override {
|
||||
for (int index = 0; index < nodep->elementsConst(); ++index) {
|
||||
AstNode* origVEp = m_varEqnp;
|
||||
AstNode* origNLEp = m_newLvEqnp;
|
||||
AstNode* origNREp = m_newRvEqnp;
|
||||
VL_RESTORER(m_varEqnp);
|
||||
VL_RESTORER(m_newLvEqnp);
|
||||
VL_RESTORER(m_newRvEqnp);
|
||||
{
|
||||
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
|
||||
m_newLvEqnp
|
||||
= new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
|
||||
m_newRvEqnp
|
||||
= new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
|
||||
|
||||
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
|
||||
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
|
||||
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
|
||||
iterate(nodep->subDTypep()->skipRefp());
|
||||
|
||||
iterate(nodep->subDTypep()->skipRefp());
|
||||
|
||||
m_varEqnp->deleteTree();
|
||||
m_newLvEqnp->deleteTree();
|
||||
m_newRvEqnp->deleteTree();
|
||||
|
||||
m_varEqnp = origVEp;
|
||||
m_newLvEqnp = origNLEp;
|
||||
m_newRvEqnp = origNREp;
|
||||
m_varEqnp->deleteTree();
|
||||
m_newLvEqnp->deleteTree();
|
||||
m_newRvEqnp->deleteTree();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) override {
|
||||
if (nodep->packedUnsup()) {
|
||||
newChangeDet();
|
||||
} else {
|
||||
@@ -179,7 +171,7 @@ private:
|
||||
<< m_vscp->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
|
||||
@@ -207,16 +199,16 @@ public:
|
||||
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
|
||||
m_statep->m_scopetopp->addVarp(m_newvscp);
|
||||
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
|
||||
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
|
||||
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, VAccess::READ);
|
||||
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::WRITE);
|
||||
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::READ);
|
||||
}
|
||||
iterate(vscp->dtypep()->skipRefp());
|
||||
m_varEqnp->deleteTree();
|
||||
m_newLvEqnp->deleteTree();
|
||||
m_newRvEqnp->deleteTree();
|
||||
}
|
||||
virtual ~ChangedInsertVisitor() {}
|
||||
virtual ~ChangedInsertVisitor() override {}
|
||||
VL_UNCOPYABLE(ChangedInsertVisitor);
|
||||
};
|
||||
|
||||
@@ -242,13 +234,13 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
if (nodep->isTop()) m_statep->m_topModp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
UINFO(4, " TS " << nodep << endl);
|
||||
// Clearing
|
||||
AstNode::user1ClearTree();
|
||||
@@ -267,27 +259,28 @@ private:
|
||||
// Each change detection function needs at least one AstChangeDet
|
||||
// to ensure that V3EmitC outputs the necessary code.
|
||||
m_statep->maybeCreateChgFuncp();
|
||||
m_statep->m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false));
|
||||
m_statep->m_chgFuncp->addStmtsp(
|
||||
new AstChangeDet(nodep->fileline(), nullptr, nullptr, false));
|
||||
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
if (nodep->isCircular()) {
|
||||
UINFO(8, " CIRC " << nodep << endl);
|
||||
if (!nodep->user1SetOnce()) genChangeDet(nodep);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ChangedVisitor(AstNetlist* nodep, ChangedState* statep) {
|
||||
m_statep = statep;
|
||||
ChangedVisitor(AstNetlist* nodep, ChangedState* statep)
|
||||
: m_statep{statep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ChangedVisitor() {}
|
||||
virtual ~ChangedVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+16
-21
@@ -34,8 +34,8 @@ private:
|
||||
// MEMBERS
|
||||
AstUser1InUse m_inuser1;
|
||||
string m_prefix; // String prefix to add to name based on hier
|
||||
AstScope* m_classScopep; // Package moving scopes into
|
||||
typedef std::vector<std::pair<AstNode*, AstScope*> > MoveVector;
|
||||
AstScope* m_classScopep = nullptr; // Package moving scopes into
|
||||
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
|
||||
MoveVector m_moves;
|
||||
|
||||
// NODE STATE
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
virtual void visit(AstClass* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstClass* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
// Move this class
|
||||
nodep->name(m_prefix + nodep->name());
|
||||
@@ -59,12 +59,12 @@ private:
|
||||
v3Global.rootp()->addModulep(packagep);
|
||||
// Add package to hierarchy
|
||||
AstCell* cellp = new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
|
||||
packagep->name(), NULL, NULL, NULL);
|
||||
packagep->name(), nullptr, nullptr, nullptr);
|
||||
cellp->modp(packagep);
|
||||
v3Global.rootp()->topModulep()->addStmtp(cellp);
|
||||
// Find class's scope
|
||||
// Alternative would be to move this and related to V3Scope
|
||||
AstScope* classScopep = NULL;
|
||||
AstScope* classScopep = nullptr;
|
||||
for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) {
|
||||
if ((classScopep = VN_CAST(itp, Scope))) break;
|
||||
}
|
||||
@@ -75,25 +75,23 @@ private:
|
||||
classScopep->aboveScopep(), classScopep->aboveCellp());
|
||||
packagep->addStmtp(scopep);
|
||||
// Iterate
|
||||
string prevPrefix = m_prefix;
|
||||
VL_RESTORER(m_prefix);
|
||||
{
|
||||
m_classScopep = classScopep;
|
||||
m_prefix = nodep->name() + "__02e"; // .
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_prefix = prevPrefix;
|
||||
m_classScopep = NULL;
|
||||
m_classScopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstPackage* nodep) VL_OVERRIDE {
|
||||
string prevPrefix = m_prefix;
|
||||
virtual void visit(AstPackage* nodep) override {
|
||||
VL_RESTORER(m_prefix);
|
||||
{
|
||||
m_prefix = nodep->name() + "__03a__03a"; // ::
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_prefix = prevPrefix;
|
||||
}
|
||||
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Don't move now, or wouldn't keep interating the class
|
||||
// TODO move class statics only
|
||||
@@ -101,7 +99,7 @@ private:
|
||||
// m_moves.push_back(make_pair(nodep, m_classScopep));
|
||||
//}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Don't move now, or wouldn't keep interating the class
|
||||
// TODO move function statics only
|
||||
@@ -110,17 +108,14 @@ private:
|
||||
//}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Short circuit
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {} // Short circuit
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath* nodep) override {} // Short circuit
|
||||
virtual void visit(AstNodeStmt* nodep) override {} // Short circuit
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ClassVisitor(AstNetlist* nodep)
|
||||
: m_classScopep(NULL) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ClassVisitor() {
|
||||
explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ClassVisitor() override {
|
||||
for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) {
|
||||
it->second->addVarp(it->first->unlinkFrBack());
|
||||
}
|
||||
|
||||
+32
-36
@@ -47,10 +47,10 @@ private:
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// TYPES
|
||||
enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
||||
enum CleanState : uint8_t { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp;
|
||||
AstNodeModule* m_modp = nullptr;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -170,65 +170,64 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeUniop* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeBiop* nodep) override {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstAnd* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAnd* nodep) override {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstXor* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstXor* nodep) override {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstOr* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstOr* nodep) override {
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeQuadop* nodep) override {
|
||||
operandQuadop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeMath* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstText* nodep) VL_OVERRIDE { //
|
||||
virtual void visit(AstText* nodep) override { //
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE { //
|
||||
virtual void visit(AstScopeName* nodep) override { //
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCNew* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSel* nodep) override {
|
||||
operandTriop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
setClean(nodep, false);
|
||||
@@ -236,75 +235,72 @@ private:
|
||||
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
|
||||
ensureCleanAndNext(nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTraceDecl* nodep) override {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTraceInc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->valuep());
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTypedef* nodep) override {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstParamTypeDType* nodep) override {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Control flow operators
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCond* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureClean(nodep->condp());
|
||||
setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p()));
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstWhile* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeIf* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSFormatF* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->exprsp());
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUCStmt* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCCall* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->argsp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstCMethodHard* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCMethodHard* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->pinsp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstIntfRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstIntfRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CleanVisitor(AstNetlist* nodep) {
|
||||
m_modp = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CleanVisitor() {}
|
||||
explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CleanVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+110
-88
@@ -48,16 +48,16 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstTopScope* m_topScopep; // Current top scope
|
||||
AstScope* m_scopep; // Current scope
|
||||
AstCFunc* m_evalFuncp; // Top eval function we are creating
|
||||
AstCFunc* m_initFuncp; // Top initial function we are creating
|
||||
AstCFunc* m_finalFuncp; // Top final function we are creating
|
||||
AstCFunc* m_settleFuncp; // Top settlement function we are creating
|
||||
AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates.
|
||||
AstIf* m_lastIfp; // Last sensitivity if active to add more under
|
||||
AstMTaskBody* m_mtaskBodyp; // Current mtask body
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstTopScope* m_topScopep = nullptr; // Current top scope
|
||||
AstScope* m_scopep = nullptr; // Current scope
|
||||
AstCFunc* m_evalFuncp = nullptr; // Top eval function we are creating
|
||||
AstCFunc* m_initFuncp = nullptr; // Top initial function we are creating
|
||||
AstCFunc* m_finalFuncp = nullptr; // Top final function we are creating
|
||||
AstCFunc* m_settleFuncp = nullptr; // Top settlement function we are creating
|
||||
AstSenTree* m_lastSenp = nullptr; // Last sensitivity match, so we can detect duplicates.
|
||||
AstIf* m_lastIfp = nullptr; // Last sensitivity if active to add more under
|
||||
AstMTaskBody* m_mtaskBodyp = nullptr; // Current mtask body
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -66,8 +66,8 @@ private:
|
||||
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
|
||||
AstVar* varp = vscp->varp();
|
||||
if (!varp->width1()) {
|
||||
varp->v3error(
|
||||
"Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ());
|
||||
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
|
||||
<< varp->prettyNameQ());
|
||||
}
|
||||
string newvarname
|
||||
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
|
||||
@@ -79,15 +79,15 @@ private:
|
||||
vscp->user1p(newvscp);
|
||||
m_scopep->addVarp(newvscp);
|
||||
// Add init
|
||||
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
|
||||
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
|
||||
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
|
||||
AstNode* newinitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp);
|
||||
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
|
||||
addToInitial(newinitp);
|
||||
// At bottom, assign them
|
||||
AstAssign* finalp
|
||||
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
AstAssign* finalp = new AstAssign(vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
m_evalFuncp->addFinalsp(finalp);
|
||||
//
|
||||
UINFO(4, "New Last: " << newvscp << endl);
|
||||
@@ -101,60 +101,49 @@ private:
|
||||
// BOTHEDGE: var ^ var_last
|
||||
// HIGHEDGE: var
|
||||
// LOWEDGE: ~var
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
nodep->v3error(
|
||||
"Unsupported: Complicated event expression in sensitive activity list");
|
||||
}
|
||||
return NULL;
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Complicated event expression in sensitive activity list");
|
||||
return nullptr;
|
||||
}
|
||||
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
||||
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
|
||||
new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false)));
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(),
|
||||
VAccess::READ)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstXor(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
|
||||
newp = new AstVarRef(nodep->fileline(), clkvscp, false);
|
||||
newp = new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ);
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
|
||||
newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false));
|
||||
newp = new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad edge type");
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
AstNode* createSenGateEquation(AstSenGate* nodep) {
|
||||
AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()),
|
||||
nodep->rhsp()->cloneTree(true));
|
||||
return newp;
|
||||
}
|
||||
AstNode* createSenseEquation(AstNodeSenItem* nodesp) {
|
||||
AstNode* createSenseEquation(AstSenItem* nodesp) {
|
||||
// Nodep may be a list of elements; we need to walk it
|
||||
AstNode* senEqnp = NULL;
|
||||
for (AstNodeSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
AstNode* senOnep = NULL;
|
||||
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
|
||||
senOnep = createSenItemEquation(itemp);
|
||||
} else if (AstSenGate* itemp = VN_CAST(senp, SenGate)) {
|
||||
senOnep = createSenGateEquation(itemp);
|
||||
} else {
|
||||
senp->v3fatalSrc("Strange node under sentree");
|
||||
}
|
||||
AstNode* senEqnp = nullptr;
|
||||
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
AstNode* const senOnep = createSenItemEquation(senp);
|
||||
if (senEqnp) {
|
||||
// Add new OR to the sensitivity list equation
|
||||
senEqnp = new AstOr(senp->fileline(), senEqnp, senOnep);
|
||||
@@ -167,16 +156,53 @@ private:
|
||||
AstIf* makeActiveIf(AstSenTree* sensesp) {
|
||||
AstNode* senEqnp = createSenseEquation(sensesp->sensesp());
|
||||
UASSERT_OBJ(senEqnp, sensesp, "No sense equation, shouldn't be in sequent activation.");
|
||||
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, NULL, NULL);
|
||||
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
|
||||
return newifp;
|
||||
}
|
||||
void clearLastSen() {
|
||||
m_lastSenp = NULL;
|
||||
m_lastIfp = NULL;
|
||||
m_lastSenp = nullptr;
|
||||
m_lastIfp = nullptr;
|
||||
}
|
||||
void splitCheck(AstCFunc* ofuncp) {
|
||||
if (!v3Global.opt.outputSplitCFuncs() || !ofuncp->stmtsp()) return;
|
||||
if (EmitCBaseCounterVisitor(ofuncp->stmtsp()).count() < v3Global.opt.outputSplitCFuncs())
|
||||
return;
|
||||
|
||||
int funcnum = 0;
|
||||
int func_stmts = 0;
|
||||
AstCFunc* funcp = nullptr;
|
||||
|
||||
// Unlink all statements, then add item by item to new sub-functions
|
||||
AstBegin* tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
|
||||
ofuncp->stmtsp()->unlinkFrBackWithNext()};
|
||||
if (ofuncp->finalsp()) tempp->addStmtsp(ofuncp->finalsp()->unlinkFrBackWithNext());
|
||||
while (tempp->stmtsp()) {
|
||||
AstNode* itemp = tempp->stmtsp()->unlinkFrBack();
|
||||
int stmts = EmitCBaseCounterVisitor(itemp).count();
|
||||
if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) {
|
||||
// Make a new function
|
||||
funcp = new AstCFunc{ofuncp->fileline(), ofuncp->name() + cvtToStr(++funcnum),
|
||||
m_topScopep->scopep()};
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->dontCombine(true);
|
||||
funcp->symProlog(true);
|
||||
funcp->isStatic(true);
|
||||
funcp->slow(ofuncp->slow());
|
||||
m_topScopep->scopep()->addActivep(funcp);
|
||||
//
|
||||
AstCCall* callp = new AstCCall{funcp->fileline(), funcp};
|
||||
callp->argTypes("vlSymsp");
|
||||
ofuncp->addStmtsp(callp);
|
||||
func_stmts = 0;
|
||||
}
|
||||
funcp->addStmtsp(itemp);
|
||||
func_stmts += stmts;
|
||||
}
|
||||
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
UINFO(4, " TOPSCOPE " << nodep << endl);
|
||||
m_topScopep = nodep;
|
||||
m_scopep = nodep->scopep();
|
||||
@@ -186,28 +212,29 @@ private:
|
||||
AstNode::user1ClearTree();
|
||||
// Make top functions
|
||||
{
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval", m_scopep);
|
||||
AstCFunc* funcp = new AstCFunc{nodep->fileline(), "_eval", m_topScopep->scopep()};
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->dontCombine(true);
|
||||
funcp->symProlog(true);
|
||||
funcp->isStatic(true);
|
||||
funcp->entryPoint(true);
|
||||
m_scopep->addActivep(funcp);
|
||||
m_topScopep->scopep()->addActivep(funcp);
|
||||
m_evalFuncp = funcp;
|
||||
}
|
||||
{
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_initial", m_scopep);
|
||||
AstCFunc* funcp
|
||||
= new AstCFunc{nodep->fileline(), "_eval_initial", m_topScopep->scopep()};
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->dontCombine(true);
|
||||
funcp->slow(true);
|
||||
funcp->symProlog(true);
|
||||
funcp->isStatic(true);
|
||||
funcp->entryPoint(true);
|
||||
m_scopep->addActivep(funcp);
|
||||
m_topScopep->scopep()->addActivep(funcp);
|
||||
m_initFuncp = funcp;
|
||||
}
|
||||
{
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "final", m_scopep);
|
||||
AstCFunc* funcp = new AstCFunc{nodep->fileline(), "final", m_topScopep->scopep()};
|
||||
funcp->skipDecl(true);
|
||||
funcp->dontCombine(true);
|
||||
funcp->slow(true);
|
||||
@@ -218,38 +245,44 @@ private:
|
||||
+ " = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
|
||||
m_scopep->addActivep(funcp);
|
||||
m_topScopep->scopep()->addActivep(funcp);
|
||||
m_finalFuncp = funcp;
|
||||
}
|
||||
{
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_settle", m_scopep);
|
||||
AstCFunc* funcp
|
||||
= new AstCFunc{nodep->fileline(), "_eval_settle", m_topScopep->scopep()};
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->dontCombine(true);
|
||||
funcp->slow(true);
|
||||
funcp->isStatic(true);
|
||||
funcp->symProlog(true);
|
||||
funcp->entryPoint(true);
|
||||
m_scopep->addActivep(funcp);
|
||||
m_topScopep->scopep()->addActivep(funcp);
|
||||
m_settleFuncp = funcp;
|
||||
}
|
||||
// Process the activates
|
||||
iterateChildren(nodep);
|
||||
UINFO(4, " TOPSCOPE iter done " << nodep << endl);
|
||||
// Split large functions
|
||||
splitCheck(m_evalFuncp);
|
||||
splitCheck(m_initFuncp);
|
||||
splitCheck(m_finalFuncp);
|
||||
splitCheck(m_settleFuncp);
|
||||
// Done, clear so we can detect errors
|
||||
UINFO(4, " TOPSCOPEDONE " << nodep << endl);
|
||||
clearLastSen();
|
||||
m_topScopep = NULL;
|
||||
m_scopep = NULL;
|
||||
m_topScopep = nullptr;
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// UINFO(4, " MOD " << nodep << endl);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
// UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
@@ -258,9 +291,9 @@ private:
|
||||
movep->unlinkFrBackWithNext();
|
||||
m_evalFuncp->addFinalsp(movep);
|
||||
}
|
||||
m_scopep = NULL;
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
@@ -269,7 +302,7 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPost* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlwaysPost* nodep) override {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
@@ -278,7 +311,7 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
// nodep->dumpTree(cout, "ct:");
|
||||
// COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
@@ -286,7 +319,7 @@ private:
|
||||
AstNode* origp = nodep->origp()->unlinkFrBack();
|
||||
AstNode* changep = nodep->changep()->unlinkFrBack();
|
||||
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changep),
|
||||
incp, NULL);
|
||||
incp, nullptr);
|
||||
// We could add another IF to detect posedges, and only increment if so.
|
||||
// It's another whole branch though versus a potential memory miss.
|
||||
// We'll go with the miss.
|
||||
@@ -295,7 +328,7 @@ private:
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstInitial* nodep) override {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
@@ -304,7 +337,7 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Link to global function
|
||||
if (nodep->formCallTree()) {
|
||||
@@ -314,7 +347,7 @@ private:
|
||||
m_finalFuncp->addStmtsp(callp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenTree* nodep) override {
|
||||
// Delete it later; Actives still pointing to it
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep);
|
||||
@@ -328,7 +361,7 @@ private:
|
||||
void addToInitial(AstNode* stmtsp) {
|
||||
m_initFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
// Careful if adding variables here, ACTIVES can be under other ACTIVES
|
||||
// Need to save and restore any member state in AstUntilStable block
|
||||
if (!m_topScopep || !nodep->stmtsp()) {
|
||||
@@ -396,7 +429,7 @@ private:
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstExecGraph* nodep) override {
|
||||
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
|
||||
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
|
||||
clearLastSen();
|
||||
@@ -411,28 +444,17 @@ private:
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ClockVisitor(AstNetlist* nodep) {
|
||||
m_modp = NULL;
|
||||
m_evalFuncp = NULL;
|
||||
m_initFuncp = NULL;
|
||||
m_finalFuncp = NULL;
|
||||
m_settleFuncp = NULL;
|
||||
m_topScopep = NULL;
|
||||
m_lastSenp = NULL;
|
||||
m_lastIfp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_mtaskBodyp = NULL;
|
||||
//
|
||||
iterate(nodep);
|
||||
// Allow downstream modules to find _eval()
|
||||
// easily without iterating through the tree.
|
||||
nodep->evalp(m_evalFuncp);
|
||||
}
|
||||
virtual ~ClockVisitor() {}
|
||||
virtual ~ClockVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+45
-50
@@ -45,7 +45,9 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
#define COMBINE_MIN_STATEMENTS 50 // Min # of statements to be worth making a function
|
||||
#ifdef VL_COMBINE_STATEMENTS
|
||||
constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth making a function
|
||||
#endif
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -54,7 +56,7 @@ protected:
|
||||
// STATE
|
||||
|
||||
// METHODS
|
||||
virtual ~CombBaseVisitor() {}
|
||||
virtual ~CombBaseVisitor() override {}
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
};
|
||||
|
||||
@@ -108,8 +110,8 @@ public:
|
||||
void deleteCall(AstCCall* nodep) {
|
||||
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
|
||||
= m_callMmap.equal_range(nodep->funcp());
|
||||
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
|
||||
CallMmap::iterator eqit = nextit++;
|
||||
for (auto nextit = eqrange.first; nextit != eqrange.second;) {
|
||||
const auto eqit = nextit++;
|
||||
AstCCall* callp = eqit->second;
|
||||
if (callp == nodep) {
|
||||
m_callMmap.erase(eqit);
|
||||
@@ -121,16 +123,16 @@ public:
|
||||
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE { addCall(nodep); }
|
||||
virtual void visit(AstCCall* nodep) override { addCall(nodep); }
|
||||
// Speed things up
|
||||
virtual void visit(AstNodeAssign*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeAssign*) override {}
|
||||
virtual void visit(AstNodeMath*) override {}
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CombCallVisitor() {}
|
||||
virtual ~CombCallVisitor() {}
|
||||
virtual ~CombCallVisitor() override {}
|
||||
void main(AstNetlist* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
@@ -143,7 +145,7 @@ private:
|
||||
// OUTPUT:
|
||||
// AstNode::user3() -> bool. True to indicate duplicated
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
nodep->user3(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
@@ -151,7 +153,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~CombMarkVisitor() {}
|
||||
virtual ~CombMarkVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -171,15 +173,17 @@ private:
|
||||
// AstUser4InUse part of V3Hashed
|
||||
|
||||
// STATE
|
||||
typedef enum { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState;
|
||||
typedef enum : uint8_t { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState;
|
||||
VDouble0 m_statCombs; // Statistic tracking
|
||||
CombineState m_state; // Major state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
CombineState m_state = STATE_IDLE; // Major state
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current function
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
int m_modNFuncs; // Number of functions made
|
||||
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
|
||||
AstNode* m_walkLast2p; // Final node that is the same in duplicate list
|
||||
int m_modNFuncs = 0; // Number of functions made
|
||||
#ifdef VL_COMBINE_STATEMENTS
|
||||
AstNode* m_walkLast1p = nullptr; // Final node that is the same in duplicate list
|
||||
#endif
|
||||
AstNode* m_walkLast2p = nullptr; // Final node that is the same in duplicate list
|
||||
V3Hashed m_hashed; // Hash for every node in module
|
||||
|
||||
// METHODS
|
||||
@@ -191,12 +195,11 @@ private:
|
||||
#ifdef VL_COMBINE_STATEMENTS
|
||||
void hashFunctions(AstCFunc* nodep) {
|
||||
// Compute hash of all statement trees in the function
|
||||
CombineState oldState = m_state;
|
||||
VL_RESTORER(m_state);
|
||||
{
|
||||
m_state = STATE_HASH;
|
||||
iterate(nodep);
|
||||
}
|
||||
m_state = oldState;
|
||||
}
|
||||
#endif
|
||||
void walkEmptyFuncs() {
|
||||
@@ -208,7 +211,7 @@ private:
|
||||
<< oldfuncp << endl);
|
||||
// Mark user3p on entire old tree, so we don't process it more
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, NULL);
|
||||
m_call.replaceFunc(oldfuncp, nullptr);
|
||||
oldfuncp->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
|
||||
}
|
||||
@@ -251,8 +254,8 @@ private:
|
||||
void replaceOnlyCallFunc(AstCCall* nodep) {
|
||||
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
|
||||
// oldfuncp->dumpTree(cout, "MAYDEL: ");
|
||||
if (nodep->nextp() == NULL && oldfuncp->initsp() == NULL && oldfuncp->stmtsp() == nodep
|
||||
&& oldfuncp->finalsp() == NULL) {
|
||||
if (nodep->nextp() == nullptr && oldfuncp->initsp() == nullptr
|
||||
&& oldfuncp->stmtsp() == nodep && oldfuncp->finalsp() == nullptr) {
|
||||
UINFO(9, " Function only has call " << oldfuncp << endl);
|
||||
m_call.deleteCall(nodep);
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
@@ -266,9 +269,9 @@ private:
|
||||
// UINFO(4," STMT " << hashval << " " << node1p << endl);
|
||||
//
|
||||
int bestDepth = 0; // Best substitution found in the search
|
||||
AstNode* bestNode2p = NULL;
|
||||
AstNode* bestLast1p = NULL;
|
||||
AstNode* bestLast2p = NULL;
|
||||
AstNode* bestNode2p = nullptr;
|
||||
AstNode* bestLast1p = nullptr;
|
||||
AstNode* bestLast2p = nullptr;
|
||||
//
|
||||
std::pair<V3Hashed::iterator, V3Hashed::iterator> eqrange
|
||||
= m_hashed.mmap().equal_range(hashval);
|
||||
@@ -279,8 +282,8 @@ private:
|
||||
// We need to mark iteration to prevent matching code inside
|
||||
// code (abab matching in ababab)
|
||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||
m_walkLast1p = NULL;
|
||||
m_walkLast2p = NULL;
|
||||
m_walkLast1p = nullptr;
|
||||
m_walkLast2p = nullptr;
|
||||
int depth = walkDupCodeNext(node1p, node2p, 1);
|
||||
if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) {
|
||||
bestDepth = depth;
|
||||
@@ -332,7 +335,7 @@ private:
|
||||
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
|
||||
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
|
||||
AstCFunc* newfuncp = new AstCFunc(node1p->fileline(),
|
||||
oldname + "_common" + cvtToStr(++m_modNFuncs), NULL);
|
||||
oldname + "_common" + cvtToStr(++m_modNFuncs), nullptr);
|
||||
m_modp->addStmtp(newfuncp);
|
||||
// Create calls
|
||||
AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp);
|
||||
@@ -381,7 +384,7 @@ private:
|
||||
#endif
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// Track all callers of each function
|
||||
m_call.main(nodep);
|
||||
//
|
||||
@@ -390,11 +393,11 @@ private:
|
||||
// Required so that a module instantiating another can benefit from collapsing.
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
m_modp = nodep;
|
||||
m_modNFuncs = 0;
|
||||
m_walkLast2p = NULL;
|
||||
m_walkLast2p = nullptr;
|
||||
m_hashed.clear();
|
||||
// Compute hash of all statement trees in the function
|
||||
m_state = STATE_HASH;
|
||||
@@ -417,9 +420,9 @@ private:
|
||||
m_state = STATE_IDLE;
|
||||
}
|
||||
#endif
|
||||
m_modp = NULL;
|
||||
m_modp = nullptr;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
m_funcp = nodep;
|
||||
if (!nodep->dontCombine()) {
|
||||
if (m_state == STATE_HASH) {
|
||||
@@ -431,9 +434,9 @@ private:
|
||||
}
|
||||
#endif
|
||||
}
|
||||
m_funcp = NULL;
|
||||
m_funcp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeStmt* nodep) override {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
@@ -450,23 +453,15 @@ private:
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {}
|
||||
virtual void visit(AstTraceDecl*) override {}
|
||||
virtual void visit(AstTraceInc*) override {}
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CombineVisitor(AstNetlist* nodep) {
|
||||
m_state = STATE_IDLE;
|
||||
m_modp = NULL;
|
||||
m_funcp = NULL;
|
||||
m_modNFuncs = 0;
|
||||
m_walkLast1p = NULL;
|
||||
m_walkLast2p = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CombineVisitor() { //
|
||||
explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CombineVisitor() override { //
|
||||
V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs);
|
||||
}
|
||||
};
|
||||
|
||||
+35
-36
@@ -60,10 +60,10 @@ public:
|
||||
// Access an entity and resolve wildcards that match it
|
||||
T* resolve(const string& name) {
|
||||
// Lookup if it was resolved before, typically not
|
||||
typename Map::iterator it = m_mapResolved.find(name);
|
||||
auto it = m_mapResolved.find(name);
|
||||
if (VL_UNLIKELY(it != m_mapResolved.end())) { return &it->second; }
|
||||
|
||||
T* newp = NULL;
|
||||
T* newp = nullptr;
|
||||
// Cannot be resolved, create if matched
|
||||
|
||||
// Update this entity with all matches in the wildcards
|
||||
@@ -87,8 +87,8 @@ public:
|
||||
AstAttrType m_type; // Type of attribute
|
||||
AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw
|
||||
V3ConfigVarAttr(AstAttrType type, AstSenTree* sentreep)
|
||||
: m_type(type)
|
||||
, m_sentreep(sentreep) {}
|
||||
: m_type{type}
|
||||
, m_sentreep{sentreep} {}
|
||||
};
|
||||
|
||||
// Overload vector with the required update function and to apply all entries
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
|
||||
varp->addAttrsp(newp);
|
||||
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
|
||||
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, NULL));
|
||||
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,15 +118,12 @@ typedef V3ConfigWildcardResolver<V3ConfigVar> V3ConfigVarResolver;
|
||||
|
||||
class V3ConfigFTask {
|
||||
V3ConfigVarResolver m_vars; // Variables in function/task
|
||||
bool m_isolate; // Isolate function return
|
||||
bool m_noinline; // Don't inline function/task
|
||||
bool m_public; // Public function/task
|
||||
bool m_isolate = false; // Isolate function return
|
||||
bool m_noinline = false; // Don't inline function/task
|
||||
bool m_public = false; // Public function/task
|
||||
|
||||
public:
|
||||
V3ConfigFTask()
|
||||
: m_isolate(false)
|
||||
, m_noinline(false)
|
||||
, m_public(false) {}
|
||||
V3ConfigFTask() {}
|
||||
void update(const V3ConfigFTask& f) {
|
||||
// Don't overwrite true with false
|
||||
if (f.m_isolate) m_isolate = true;
|
||||
@@ -141,7 +138,7 @@ public:
|
||||
void setNoInline(bool set) { m_noinline = set; }
|
||||
void setPublic(bool set) { m_public = set; }
|
||||
|
||||
void apply(AstNodeFTask* ftaskp) {
|
||||
void apply(AstNodeFTask* ftaskp) const {
|
||||
if (m_noinline)
|
||||
ftaskp->addStmtsp(new AstPragma(ftaskp->fileline(), AstPragmaType::NO_INLINE_TASK));
|
||||
if (m_public)
|
||||
@@ -157,33 +154,31 @@ typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
|
||||
// Modules have tasks, variables, named blocks and properties
|
||||
|
||||
class V3ConfigModule {
|
||||
typedef vl_unordered_set<string> StringSet;
|
||||
typedef std::unordered_set<string> StringSet;
|
||||
typedef std::set<AstPragmaType> PragmaSet;
|
||||
|
||||
V3ConfigFTaskResolver m_tasks; // Functions/tasks in module
|
||||
V3ConfigVarResolver m_vars; // Variables in module
|
||||
StringSet m_coverageOffBlocks; // List of block names for coverage_off
|
||||
bool m_inline; // Whether to force the inline
|
||||
bool m_inlineValue; // The inline value (on/off)
|
||||
bool m_public; // Public module
|
||||
PragmaSet m_modPragmas; // List of Pragmas for modules
|
||||
bool m_inline = false; // Whether to force the inline
|
||||
bool m_inlineValue = false; // The inline value (on/off)
|
||||
|
||||
public:
|
||||
V3ConfigModule()
|
||||
: m_inline(false)
|
||||
, m_inlineValue(false)
|
||||
, m_public(false) {}
|
||||
V3ConfigModule() {}
|
||||
|
||||
void update(const V3ConfigModule& m) {
|
||||
m_tasks.update(m.m_tasks);
|
||||
m_vars.update(m.m_vars);
|
||||
for (StringSet::const_iterator it = m.m_coverageOffBlocks.begin();
|
||||
it != m.m_coverageOffBlocks.end(); ++it) {
|
||||
m_coverageOffBlocks.insert(*it);
|
||||
}
|
||||
for (const string& i : m.m_coverageOffBlocks) m_coverageOffBlocks.insert(i);
|
||||
if (!m_inline) {
|
||||
m_inline = m.m_inline;
|
||||
m_inlineValue = m.m_inlineValue;
|
||||
}
|
||||
if (!m_public) m_public = m.m_public;
|
||||
for (PragmaSet::const_iterator it = m.m_modPragmas.begin(); it != m.m_modPragmas.end();
|
||||
++it) {
|
||||
m_modPragmas.insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
V3ConfigFTaskResolver& ftasks() { return m_tasks; }
|
||||
@@ -194,7 +189,7 @@ public:
|
||||
m_inline = true;
|
||||
m_inlineValue = set;
|
||||
}
|
||||
void setPublic(bool set) { m_public = set; }
|
||||
void addModulePragma(AstPragmaType pragma) { m_modPragmas.insert(pragma); }
|
||||
|
||||
void apply(AstNodeModule* modp) {
|
||||
if (m_inline) {
|
||||
@@ -203,8 +198,8 @@ public:
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), type);
|
||||
modp->addStmtp(nodep);
|
||||
}
|
||||
if (m_public) {
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), AstPragmaType::PUBLIC_MODULE);
|
||||
for (PragmaSet::const_iterator it = m_modPragmas.begin(); it != m_modPragmas.end(); ++it) {
|
||||
AstNode* nodep = new AstPragma(modp->fileline(), *it);
|
||||
modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
@@ -212,9 +207,8 @@ public:
|
||||
void applyBlock(AstNodeBlock* nodep) {
|
||||
AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF;
|
||||
if (!nodep->unnamed()) {
|
||||
for (StringSet::const_iterator it = m_coverageOffBlocks.begin();
|
||||
it != m_coverageOffBlocks.end(); ++it) {
|
||||
if (VString::wildmatch(nodep->name(), *it)) {
|
||||
for (const string& i : m_coverageOffBlocks) {
|
||||
if (VString::wildmatch(nodep->name(), i)) {
|
||||
nodep->addStmtsp(new AstPragma(nodep->fileline(), pragma));
|
||||
}
|
||||
}
|
||||
@@ -236,9 +230,9 @@ public:
|
||||
V3ErrorCode m_code; // Error code
|
||||
bool m_on; // True to enable message
|
||||
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
|
||||
: m_lineno(lineno)
|
||||
, m_code(code)
|
||||
, m_on(on) {}
|
||||
: m_lineno{lineno}
|
||||
, m_code{code}
|
||||
, m_on{on} {}
|
||||
~V3ConfigIgnoresLine() {}
|
||||
inline bool operator<(const V3ConfigIgnoresLine& rh) const {
|
||||
if (m_lineno < rh.m_lineno) return true;
|
||||
@@ -408,6 +402,10 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::addModulePragma(const string& module, AstPragmaType pragma) {
|
||||
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
|
||||
}
|
||||
|
||||
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
|
||||
if (ftask.empty()) {
|
||||
V3ConfigResolver::s().modules().at(module).setInline(on);
|
||||
@@ -439,7 +437,8 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
|
||||
} else if (attr == AstAttrType::VAR_PUBLIC) {
|
||||
if (ftask.empty()) {
|
||||
// public module, this is the only exception from var here
|
||||
V3ConfigResolver::s().modules().at(module).setPublic(true);
|
||||
V3ConfigResolver::s().modules().at(module).addModulePragma(
|
||||
AstPragmaType::PUBLIC_MODULE);
|
||||
} else {
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
static void addCoverageBlockOff(const string& module, const string& blockname);
|
||||
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
|
||||
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
|
||||
static void addModulePragma(const string& module, AstPragmaType pragma);
|
||||
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
|
||||
static void addVarAttr(FileLine* fl, const string& module, const string& ftask,
|
||||
const string& signal, AstAttrType type, AstSenTree* nodep);
|
||||
|
||||
+134
-199
@@ -41,10 +41,10 @@ class ConstVarMarkVisitor : public AstNVisitor {
|
||||
// AstVar::user4p -> bool, Var marked, 0=not set yet
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (nodep->varp()) nodep->varp()->user4(1);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
@@ -52,29 +52,26 @@ public:
|
||||
AstNode::user4ClearTree(); // Check marked InUse before we're called
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ConstVarMarkVisitor() {}
|
||||
virtual ~ConstVarMarkVisitor() override {}
|
||||
};
|
||||
|
||||
class ConstVarFindVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::user4p -> bool, input from ConstVarMarkVisitor
|
||||
// MEMBERS
|
||||
bool m_found;
|
||||
bool m_found = false;
|
||||
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (nodep->varp() && nodep->varp()->user4()) m_found = true;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ConstVarFindVisitor(AstNode* nodep) {
|
||||
m_found = false;
|
||||
iterateAndNextNull(nodep);
|
||||
}
|
||||
virtual ~ConstVarFindVisitor() {}
|
||||
explicit ConstVarFindVisitor(AstNode* nodep) { iterateAndNextNull(nodep); }
|
||||
virtual ~ConstVarFindVisitor() override {}
|
||||
// METHODS
|
||||
bool found() const { return m_found; }
|
||||
};
|
||||
@@ -92,20 +89,20 @@ private:
|
||||
// AstEnum::user4 -> bool. Recursing.
|
||||
|
||||
// STATE
|
||||
bool m_params; // If true, propagate parameterized and true numbers only
|
||||
bool m_required; // If true, must become a constant
|
||||
bool m_wremove; // Inside scope, no assignw removal
|
||||
bool m_warn; // Output warnings
|
||||
bool m_doExpensive; // Enable computationally expensive optimizations
|
||||
bool m_doNConst; // Enable non-constant-child simplifications
|
||||
bool m_doShort; // Remove expressions that short circuit
|
||||
bool m_doV; // Verilog, not C++ conversion
|
||||
bool m_doGenerate; // Postpone width checking inside generate
|
||||
bool m_hasJumpDelay; // JumpGo or Delay under this while
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstArraySel* m_selp; // Current select
|
||||
AstNode* m_scopep; // Current scope
|
||||
AstAttrOf* m_attrp; // Current attribute
|
||||
bool m_params = false; // If true, propagate parameterized and true numbers only
|
||||
bool m_required = false; // If true, must become a constant
|
||||
bool m_wremove = true; // Inside scope, no assignw removal
|
||||
bool m_warn = false; // Output warnings
|
||||
bool m_doExpensive = false; // Enable computationally expensive optimizations
|
||||
bool m_doNConst = false; // Enable non-constant-child simplifications
|
||||
bool m_doShort = true; // Remove expressions that short circuit
|
||||
bool m_doV = false; // Verilog, not C++ conversion
|
||||
bool m_doGenerate = false; // Postpone width checking inside generate
|
||||
bool m_hasJumpDelay = false; // JumpGo or Delay under this while
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstArraySel* m_selp = nullptr; // Current select
|
||||
AstNode* m_scopep = nullptr; // Current scope
|
||||
AstAttrOf* m_attrp = nullptr; // Current attribute
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -317,7 +314,7 @@ private:
|
||||
// It was an expression, then got constified. In reality, the WordSel
|
||||
// must be wrapped in a Cond, that will be false.
|
||||
return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef)
|
||||
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->lvalue()
|
||||
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isWrite()
|
||||
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
|
||||
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
|
||||
}
|
||||
@@ -588,6 +585,7 @@ private:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool operandsSameSize(AstNode* lhsp, AstNode* rhsp) { return lhsp->width() == rhsp->width(); }
|
||||
|
||||
//----------------------------------------
|
||||
// Constant Replacement functions.
|
||||
@@ -1114,7 +1112,7 @@ private:
|
||||
AstSel* sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2 - lsb2 + 1);
|
||||
// Make new assigns of same flavor as old one
|
||||
//*** Not cloneTree; just one node.
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
if (!need_temp) {
|
||||
AstNodeAssign* asn1ap = VN_CAST(nodep->cloneType(lc1p, sel1p), NodeAssign);
|
||||
AstNodeAssign* asn2ap = VN_CAST(nodep->cloneType(lc2p, sel2p), NodeAssign);
|
||||
@@ -1134,18 +1132,22 @@ private:
|
||||
VFlagLogicPacked(), msb2 - lsb2 + 1);
|
||||
m_modp->addStmtp(temp1p);
|
||||
m_modp->addStmtp(temp2p);
|
||||
AstNodeAssign* asn1ap = VN_CAST(
|
||||
nodep->cloneType(new AstVarRef(sel1p->fileline(), temp1p, true), sel1p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2ap = VN_CAST(
|
||||
nodep->cloneType(new AstVarRef(sel2p->fileline(), temp2p, true), sel2p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn1bp = VN_CAST(
|
||||
nodep->cloneType(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2bp = VN_CAST(
|
||||
nodep->cloneType(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn1ap
|
||||
= VN_CAST(nodep->cloneType(
|
||||
new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2ap
|
||||
= VN_CAST(nodep->cloneType(
|
||||
new AstVarRef(sel2p->fileline(), temp2p, VAccess::WRITE), sel2p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn1bp
|
||||
= VN_CAST(nodep->cloneType(
|
||||
lc1p, new AstVarRef(sel1p->fileline(), temp1p, VAccess::READ)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2bp
|
||||
= VN_CAST(nodep->cloneType(
|
||||
lc2p, new AstVarRef(sel2p->fileline(), temp2p, VAccess::READ)),
|
||||
NodeAssign);
|
||||
asn1ap->dtypeFrom(temp1p);
|
||||
asn1bp->dtypeFrom(temp1p);
|
||||
asn2ap->dtypeFrom(temp2p);
|
||||
@@ -1281,32 +1283,31 @@ private:
|
||||
//----------------------------------------
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// Iterate modules backwards, in bottom-up order. That's faster
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
// No ASSIGNW removals under funcs, we've long eliminated INITIALs
|
||||
// (We should perhaps rename the assignw's to just assigns)
|
||||
m_wremove = false;
|
||||
iterateChildren(nodep);
|
||||
m_wremove = true;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
// No ASSIGNW removals under scope, we've long eliminated INITIALs
|
||||
m_scopep = nodep;
|
||||
m_wremove = false;
|
||||
iterateChildren(nodep);
|
||||
m_wremove = true;
|
||||
m_scopep = NULL;
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
|
||||
void swapSides(AstNodeBiCom* nodep) {
|
||||
@@ -1372,16 +1373,16 @@ private:
|
||||
}
|
||||
|
||||
// Special cases
|
||||
virtual void visit(AstConst*) VL_OVERRIDE {} // Already constant
|
||||
virtual void visit(AstConst*) override {} // Already constant
|
||||
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
if (m_params) {
|
||||
iterateAndNextNull(nodep->paramsp());
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstPin* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
void replaceLogEq(AstLogEq* nodep) {
|
||||
// LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}}
|
||||
@@ -1562,14 +1563,15 @@ private:
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
|
||||
AstAttrOf* oldAttr = m_attrp;
|
||||
m_attrp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_attrp = oldAttr;
|
||||
virtual void visit(AstAttrOf* nodep) override {
|
||||
VL_RESTORER(m_attrp);
|
||||
{
|
||||
m_attrp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstArraySel* nodep) override {
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
if (VN_IS(nodep->bitp(), Const)
|
||||
&& VN_IS(nodep->fromp(), VarRef)
|
||||
@@ -1593,9 +1595,9 @@ private:
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
m_selp = NULL;
|
||||
m_selp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->varp(), nodep, "Not linked");
|
||||
bool did = false;
|
||||
@@ -1603,7 +1605,7 @@ private:
|
||||
// if (debug()) valuep->dumpTree(cout, " visitvaref: ");
|
||||
iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep()
|
||||
AstNode* valuep = nodep->varp()->valuep();
|
||||
if (!nodep->lvalue()
|
||||
if (!nodep->access().isWrite()
|
||||
&& ((!m_params // Can reduce constant wires into equations
|
||||
&& m_doNConst
|
||||
&& v3Global.opt.oConst()
|
||||
@@ -1649,7 +1651,7 @@ private:
|
||||
<< nodep->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstEnumItemRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
|
||||
bool did = false;
|
||||
@@ -1674,15 +1676,15 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// virtual void visit(AstCvtPackString* nodep) VL_OVERRIDE {
|
||||
// virtual void visit(AstCvtPackString* nodep) override {
|
||||
// Not constant propagated (for today) because AstNodeMath::isOpaque is set
|
||||
// Someday if lower is constant, convert to quoted "string".
|
||||
|
||||
bool onlySenItemInSenTree(AstNodeSenItem* nodep) {
|
||||
bool onlySenItemInSenTree(AstSenItem* nodep) {
|
||||
// Only one if it's not in a list
|
||||
return (!nodep->nextp() && nodep->backp()->nextp() != nodep);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst
|
||||
&& (VN_IS(nodep->sensp(), Const) || VN_IS(nodep->sensp(), EnumItemRef)
|
||||
@@ -1722,61 +1724,34 @@ private:
|
||||
"Null sensitivity variable");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) {
|
||||
if (constp->isZero()) {
|
||||
UINFO(4, "SENGATE(...,0)->NEVER" << endl);
|
||||
if (onlySenItemInSenTree(nodep)) {
|
||||
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
} else {
|
||||
UINFO(4, "SENGATE(SENITEM,0)->ALWAYS SENITEM" << endl);
|
||||
AstNode* senitemp = nodep->sensesp()->unlinkFrBack();
|
||||
nodep->replaceWith(senitemp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SenItemCmp {
|
||||
inline bool operator()(AstNodeSenItem* lhsp, AstNodeSenItem* rhsp) const {
|
||||
inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
|
||||
if (lhsp->type() < rhsp->type()) return true;
|
||||
if (lhsp->type() > rhsp->type()) return false;
|
||||
const AstSenItem* litemp = VN_CAST_CONST(lhsp, SenItem);
|
||||
const AstSenItem* ritemp = VN_CAST_CONST(rhsp, SenItem);
|
||||
if (litemp && ritemp) {
|
||||
// Looks visually better if we keep sorted by name
|
||||
if (!litemp->varrefp() && ritemp->varrefp()) return true;
|
||||
if (litemp->varrefp() && !ritemp->varrefp()) return false;
|
||||
if (litemp->varrefp() && ritemp->varrefp()) {
|
||||
if (litemp->varrefp()->name() < ritemp->varrefp()->name()) return true;
|
||||
if (litemp->varrefp()->name() > ritemp->varrefp()->name()) return false;
|
||||
// But might be same name with different scopes
|
||||
if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) {
|
||||
return true;
|
||||
}
|
||||
if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) {
|
||||
return false;
|
||||
}
|
||||
// Or rarely, different data types
|
||||
if (litemp->varrefp()->dtypep() < ritemp->varrefp()->dtypep()) return true;
|
||||
if (litemp->varrefp()->dtypep() > ritemp->varrefp()->dtypep()) return false;
|
||||
}
|
||||
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
|
||||
// note the SenTree optimizer requires this order (more
|
||||
// general first, less general last)
|
||||
if (litemp->edgeType() < ritemp->edgeType()) return true;
|
||||
if (litemp->edgeType() > ritemp->edgeType()) return false;
|
||||
// Looks visually better if we keep sorted by name
|
||||
if (!lhsp->varrefp() && rhsp->varrefp()) return true;
|
||||
if (lhsp->varrefp() && !rhsp->varrefp()) return false;
|
||||
if (lhsp->varrefp() && rhsp->varrefp()) {
|
||||
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
|
||||
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
|
||||
// But might be same name with different scopes
|
||||
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) { return true; }
|
||||
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) { return false; }
|
||||
// Or rarely, different data types
|
||||
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
|
||||
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
|
||||
}
|
||||
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
|
||||
// note the SenTree optimizer requires this order (more
|
||||
// general first, less general last)
|
||||
if (lhsp->edgeType() < rhsp->edgeType()) return true;
|
||||
if (lhsp->edgeType() > rhsp->edgeType()) return false;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenTree* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doExpensive) {
|
||||
// cout<<endl; nodep->dumpTree(cout, "ssin: ");
|
||||
@@ -1792,30 +1767,10 @@ private:
|
||||
{
|
||||
AstUser4InUse m_inuse4;
|
||||
// Mark x in SENITEM(x)
|
||||
for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
|
||||
senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
|
||||
if (itemp->varrefp() && itemp->varrefp()->varScopep()) {
|
||||
itemp->varrefp()->varScopep()->user4(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find x in SENTREE(SENITEM(x))
|
||||
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
|
||||
senp = nextp) {
|
||||
nextp = VN_CAST(senp->nextp(), NodeSenItem);
|
||||
if (AstSenGate* gatep = VN_CAST(senp, SenGate)) {
|
||||
if (AstSenItem* itemp = VN_CAST(gatep->sensesp(), SenItem)) {
|
||||
if (itemp->varrefp() && itemp->varrefp()->varScopep()) {
|
||||
if (itemp->varrefp()->varScopep()->user4()) {
|
||||
// Found, push this item up to the top
|
||||
itemp->unlinkFrBack();
|
||||
nodep->addSensesp(itemp);
|
||||
VL_DO_DANGLING(gatep->unlinkFrBack()->deleteTree(), gatep);
|
||||
VL_DANGLING(senp);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp;
|
||||
senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
if (senp->varrefp() && senp->varrefp()->varScopep()) {
|
||||
senp->varrefp()->varScopep()->user4(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1823,40 +1778,33 @@ private:
|
||||
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
|
||||
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
|
||||
// Make things a little faster; check first if we need a sort
|
||||
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
|
||||
for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp;
|
||||
senp = nextp) {
|
||||
nextp = VN_CAST(senp->nextp(), NodeSenItem);
|
||||
nextp = VN_CAST(senp->nextp(), SenItem);
|
||||
// cppcheck-suppress unassignedVariable // cppcheck bug
|
||||
SenItemCmp cmp;
|
||||
if (nextp && !cmp(senp, nextp)) {
|
||||
// Something's out of order, sort it
|
||||
senp = NULL;
|
||||
std::vector<AstNodeSenItem*> vec;
|
||||
for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
|
||||
senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
||||
senp = nullptr;
|
||||
std::vector<AstSenItem*> vec;
|
||||
for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp;
|
||||
senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||
vec.push_back(senp);
|
||||
}
|
||||
stable_sort(vec.begin(), vec.end(), SenItemCmp());
|
||||
for (std::vector<AstNodeSenItem*>::iterator it = vec.begin(); it != vec.end();
|
||||
++it) {
|
||||
(*it)->unlinkFrBack();
|
||||
}
|
||||
for (std::vector<AstNodeSenItem*>::iterator it = vec.begin(); it != vec.end();
|
||||
++it) {
|
||||
nodep->addSensesp(*it);
|
||||
}
|
||||
for (const auto& ip : vec) ip->unlinkFrBack();
|
||||
for (const auto& ip : vec) nodep->addSensesp(ip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass2, remove dup edges
|
||||
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
|
||||
for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp;
|
||||
senp = nextp) {
|
||||
nextp = VN_CAST(senp->nextp(), NodeSenItem);
|
||||
AstNodeSenItem* cmpp = nextp;
|
||||
AstSenItem* litemp = VN_CAST(senp, SenItem);
|
||||
AstSenItem* ritemp = VN_CAST(cmpp, SenItem);
|
||||
if (litemp && ritemp) {
|
||||
nextp = VN_CAST(senp->nextp(), SenItem);
|
||||
AstSenItem* const litemp = senp;
|
||||
AstSenItem* const ritemp = nextp;
|
||||
if (ritemp) {
|
||||
if ((litemp->varrefp() && ritemp->varrefp()
|
||||
&& litemp->varrefp()->sameGateTree(ritemp->varrefp()))
|
||||
|| (!litemp->varrefp() && !ritemp->varrefp())) {
|
||||
@@ -1876,7 +1824,7 @@ private:
|
||||
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
// Remove redundant node
|
||||
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
|
||||
VL_DANGLING(cmpp);
|
||||
VL_DANGLING(ritemp);
|
||||
// Try to collapse again
|
||||
nextp = litemp;
|
||||
}
|
||||
@@ -1889,17 +1837,17 @@ private:
|
||||
|
||||
//-----
|
||||
// Zero elimination
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst && replaceNodeAssign(nodep)) return;
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignAlias* nodep) override {
|
||||
// Don't perform any optimizations, keep the alias around
|
||||
}
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignVarScope* nodep) override {
|
||||
// Don't perform any optimizations, the node won't be linked yet
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignW* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst && replaceNodeAssign(nodep)) return;
|
||||
AstNodeVarRef* varrefp = VN_CAST(
|
||||
@@ -1926,17 +1874,20 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeIf* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst) {
|
||||
if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) {
|
||||
AstNode* keepp = NULL;
|
||||
AstNode* keepp = nullptr;
|
||||
if (constp->isZero()) {
|
||||
UINFO(4, "IF(0,{any},{x}) => {x}: " << nodep << endl);
|
||||
keepp = nodep->elsesp();
|
||||
} else {
|
||||
} else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog
|
||||
UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl);
|
||||
keepp = nodep->ifsp();
|
||||
} else {
|
||||
UINFO(4, "IF condition is X, retaining: " << nodep << endl);
|
||||
return;
|
||||
}
|
||||
if (keepp) {
|
||||
keepp->unlinkFrBackWithNext();
|
||||
@@ -1951,7 +1902,7 @@ private:
|
||||
// effects in the condition itself
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else if (!afterComment(nodep->ifsp())) {
|
||||
UINFO(4, "IF({x}) NULL {...} => IF(NOT{x}}: " << nodep << endl);
|
||||
UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl);
|
||||
AstNode* condp = nodep->condp();
|
||||
AstNode* elsesp = nodep->elsesp();
|
||||
condp->unlinkFrBackWithNext();
|
||||
@@ -2002,7 +1953,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDisplay* nodep) override {
|
||||
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
|
||||
iterateChildren(nodep);
|
||||
if (stmtDisplayDisplay(nodep)) return;
|
||||
@@ -2047,7 +1998,7 @@ private:
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSFormatF* nodep) override {
|
||||
// Substitute constants into displays. The main point of this is to
|
||||
// simplify assertion methodologies which call functions with display's.
|
||||
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
|
||||
@@ -2066,8 +2017,7 @@ private:
|
||||
bool inPct = false;
|
||||
AstNode* argp = nodep->exprsp();
|
||||
string text = nodep->text();
|
||||
for (string::const_iterator it = text.begin(); it != text.end(); ++it) {
|
||||
char ch = *it;
|
||||
for (const char ch : text) {
|
||||
if (!inPct && ch == '%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
@@ -2115,17 +2065,17 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstFuncRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFuncRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_params) { // Only parameters force us to do constant function call propagation
|
||||
replaceWithSimulation(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstArg* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstArg* nodep) override {
|
||||
// replaceWithSimulation on the Arg's parent FuncRef replaces these
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstWhile* nodep) override {
|
||||
bool oldHasJumpDelay = m_hasJumpDelay;
|
||||
m_hasJumpDelay = false;
|
||||
{ iterateChildren(nodep); }
|
||||
@@ -2151,22 +2101,22 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstInitItem* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstUnbounded* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstInitArray* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstUnbounded* nodep) override { iterateChildren(nodep); }
|
||||
// These are converted by V3Param. Don't constify as we don't want the
|
||||
// from() VARREF to disappear, if any.
|
||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||
virtual void visit(AstNodePreSel*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodePreSel*) override {}
|
||||
|
||||
// Ignored, can eliminate early
|
||||
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSysIgnore* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); }
|
||||
}
|
||||
|
||||
// Simplify
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBasicDType* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->cvtRangeConst();
|
||||
}
|
||||
@@ -2174,11 +2124,11 @@ private:
|
||||
//-----
|
||||
// Jump elimination
|
||||
|
||||
virtual void visit(AstDelay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDelay* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
m_hasJumpDelay = true;
|
||||
}
|
||||
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstJumpGo* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Jump to label where label immediately follows label is not useful
|
||||
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
||||
@@ -2209,7 +2159,7 @@ private:
|
||||
m_hasJumpDelay = true;
|
||||
}
|
||||
|
||||
virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstJumpBlock* nodep) override {
|
||||
// Because JumpLabels disable many optimizations,
|
||||
// remove JumpLabels that are not pointed to by any AstJumpGos
|
||||
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
|
||||
@@ -2217,7 +2167,7 @@ private:
|
||||
// AstJumpGo's below here that point to this node will set user4
|
||||
if (m_doExpensive && !nodep->user4()) {
|
||||
UINFO(4, "JUMPLABEL => unused " << nodep << endl);
|
||||
AstNode* underp = NULL;
|
||||
AstNode* underp = nullptr;
|
||||
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (underp) {
|
||||
nodep->replaceWith(underp);
|
||||
@@ -2263,8 +2213,8 @@ private:
|
||||
|
||||
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
|
||||
// Generic constants on both side. Do this first to avoid other replacements
|
||||
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque(), nodep->isPredictOptimizable()}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)");
|
||||
// Zero on one side or the other
|
||||
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
@@ -2322,7 +2272,7 @@ private:
|
||||
TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
|
||||
TREEOP ("AstMul {operandIsPowTwo($lhsp), operandsSameSize($lhsp,,$rhsp)}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
|
||||
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
|
||||
TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
|
||||
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
@@ -2563,7 +2513,7 @@ private:
|
||||
// Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
// Default: Just iterate
|
||||
if (m_required) {
|
||||
if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range)) {
|
||||
@@ -2581,7 +2531,7 @@ private:
|
||||
|
||||
public:
|
||||
// Processing Mode Enum
|
||||
enum ProcMode {
|
||||
enum ProcMode : uint8_t {
|
||||
PROC_PARAMS,
|
||||
PROC_GENERATE,
|
||||
PROC_LIVE,
|
||||
@@ -2593,21 +2543,6 @@ public:
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit ConstVisitor(ProcMode pmode) {
|
||||
m_params = false;
|
||||
m_required = false;
|
||||
m_doExpensive = false;
|
||||
m_doNConst = false;
|
||||
m_doShort = true; // Presently always done
|
||||
m_doV = false;
|
||||
m_doGenerate = false; // Inside generate conditionals
|
||||
m_hasJumpDelay = false;
|
||||
m_warn = false;
|
||||
m_wremove = true; // Overridden in visitors
|
||||
m_modp = NULL;
|
||||
m_selp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_attrp = NULL;
|
||||
//
|
||||
// clang-format off
|
||||
switch (pmode) {
|
||||
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true;
|
||||
@@ -2623,7 +2558,7 @@ public:
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
virtual ~ConstVisitor() {}
|
||||
virtual ~ConstVisitor() override {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
// Operate starting at a random place
|
||||
return iterateSubtreeReturnEdits(nodep);
|
||||
|
||||
+45
-62
@@ -32,7 +32,7 @@
|
||||
#include "V3Ast.h"
|
||||
|
||||
#include <map>
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
|
||||
//######################################################################
|
||||
// Coverage state, as a visitor of each AstNode
|
||||
@@ -40,41 +40,37 @@
|
||||
class CoverageVisitor : public AstNVisitor {
|
||||
private:
|
||||
// TYPES
|
||||
typedef vl_unordered_map<string, int> VarNameMap;
|
||||
typedef std::unordered_map<string, int> VarNameMap;
|
||||
typedef std::set<int> LinenoSet;
|
||||
typedef vl_unordered_map<int, LinenoSet> HandleLines;
|
||||
typedef std::unordered_map<int, LinenoSet> HandleLines;
|
||||
|
||||
struct ToggleEnt {
|
||||
string m_comment; // Comment for coverage dump
|
||||
AstNode* m_varRefp; // How to get to this element
|
||||
AstNode* m_chgRefp; // How to get to this element
|
||||
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
|
||||
: m_comment(comment)
|
||||
, m_varRefp(vp)
|
||||
, m_chgRefp(cp) {}
|
||||
: m_comment{comment}
|
||||
, m_varRefp{vp}
|
||||
, m_chgRefp{cp} {}
|
||||
~ToggleEnt() {}
|
||||
void cleanup() {
|
||||
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = NULL);
|
||||
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = NULL);
|
||||
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = nullptr);
|
||||
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct CheckState { // State save-restored on each new coverage scope/block
|
||||
bool m_on; // Should this block get covered?
|
||||
bool m_inModOff; // In module with no coverage
|
||||
int m_handle; // Opaque handle for index into line tracking
|
||||
const AstNode* m_nodep; // Node establishing this state
|
||||
CheckState()
|
||||
: m_on(false)
|
||||
, m_inModOff(false)
|
||||
, m_handle(0)
|
||||
, m_nodep(NULL) {}
|
||||
bool lineCoverageOn(const AstNode* nodep) {
|
||||
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
|
||||
const AstNode* m_nodep = nullptr; // Node establishing this state
|
||||
CheckState() {}
|
||||
bool lineCoverageOn(const AstNode* nodep) const {
|
||||
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
||||
&& v3Global.opt.coverageLine();
|
||||
}
|
||||
};
|
||||
int m_nextHandle;
|
||||
int m_nextHandle = 0;
|
||||
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -83,8 +79,8 @@ private:
|
||||
|
||||
// STATE
|
||||
CheckState m_state; // State save-restored on each new coverage scope/block
|
||||
AstNodeModule* m_modp; // Current module to add statement to
|
||||
bool m_inToggleOff; // In function/task etc
|
||||
AstNodeModule* m_modp = nullptr; // Current module to add statement to
|
||||
bool m_inToggleOff = false; // In function/task etc
|
||||
VarNameMap m_varnames; // Uniquification of inserted variable names
|
||||
string m_beginHier; // AstBegin hier name for user coverage points
|
||||
HandleLines m_handleLines; // All line numbers for a given m_stateHandle
|
||||
@@ -106,7 +102,7 @@ private:
|
||||
}
|
||||
// We allow this, though tracing doesn't
|
||||
// if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstCoverInc* newCoverInc(FileLine* fl, const string& hier, const string& page_prefix,
|
||||
@@ -134,8 +130,8 @@ private:
|
||||
m_modp->addStmtp(varp);
|
||||
UINFO(5, "New coverage trace: " << varp << endl);
|
||||
AstAssign* assp = new AstAssign(
|
||||
incp->fileline(), new AstVarRef(incp->fileline(), varp, true),
|
||||
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, false),
|
||||
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
|
||||
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
|
||||
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
|
||||
incp->addNext(assp);
|
||||
}
|
||||
@@ -144,7 +140,7 @@ private:
|
||||
string traceNameForLine(AstNode* nodep, const string& type) {
|
||||
string name = "vlCoverageLineTrace_" + nodep->fileline()->filebasenameNoExt() + "__"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + "_" + type;
|
||||
VarNameMap::iterator it = m_varnames.find(name);
|
||||
const auto it = m_varnames.find(name);
|
||||
if (it == m_varnames.end()) {
|
||||
m_varnames.insert(make_pair(name, 1));
|
||||
} else {
|
||||
@@ -212,9 +208,9 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS - BOTH
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
CheckState lastState = m_state;
|
||||
VL_RESTORER(m_state);
|
||||
{
|
||||
createHandle(nodep);
|
||||
m_modp = nodep;
|
||||
@@ -228,17 +224,16 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_state = lastState;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { iterateProcedure(nodep); }
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE { iterateProcedure(nodep); }
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
|
||||
virtual void visit(AstWhile* nodep) override { iterateProcedure(nodep); }
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
if (!nodep->dpiImport()) iterateProcedure(nodep);
|
||||
}
|
||||
void iterateProcedure(AstNode* nodep) {
|
||||
CheckState lastState = m_state;
|
||||
bool oldtog = m_inToggleOff;
|
||||
VL_RESTORER(m_state);
|
||||
VL_RESTORER(m_inToggleOff);
|
||||
{
|
||||
m_inToggleOff = true;
|
||||
createHandle(nodep);
|
||||
@@ -259,12 +254,10 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
m_state = lastState;
|
||||
m_inToggleOff = oldtog;
|
||||
}
|
||||
|
||||
// VISITORS - TOGGLE COVERAGE
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn()
|
||||
&& v3Global.opt.coverageToggle()) {
|
||||
@@ -295,8 +288,9 @@ private:
|
||||
// This is necessarily an O(n^2) expansion, which is why
|
||||
// we limit coverage to signals with < 256 bits.
|
||||
|
||||
ToggleEnt newvec(string(""), new AstVarRef(nodep->fileline(), nodep, false),
|
||||
new AstVarRef(nodep->fileline(), chgVarp, true));
|
||||
ToggleEnt newvec(string(""),
|
||||
new AstVarRef(nodep->fileline(), nodep, VAccess::READ),
|
||||
new AstVarRef(nodep->fileline(), chgVarp, VAccess::WRITE));
|
||||
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp);
|
||||
newvec.cleanup();
|
||||
}
|
||||
@@ -387,7 +381,7 @@ private:
|
||||
|
||||
// VISITORS - LINE COVERAGE
|
||||
// Note not AstNodeIf; other types don't get covered
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstIf* nodep) override {
|
||||
UINFO(4, " IF: " << nodep << endl);
|
||||
if (m_state.m_on) {
|
||||
// An else-if. When we iterate the if, use "elsif" marking
|
||||
@@ -463,12 +457,12 @@ private:
|
||||
}
|
||||
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
|
||||
}
|
||||
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCaseItem* nodep) override {
|
||||
// We don't add an explicit "default" coverage if not provided,
|
||||
// as we already have a warning when there is no default.
|
||||
UINFO(4, " CASEI: " << nodep << endl);
|
||||
if (m_state.lineCoverageOn(nodep)) {
|
||||
CheckState lastState = m_state;
|
||||
VL_RESTORER(m_state);
|
||||
{
|
||||
createHandle(nodep);
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
@@ -480,12 +474,11 @@ private:
|
||||
traceNameForLine(nodep, "case")));
|
||||
}
|
||||
}
|
||||
m_state = lastState;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCover* nodep) override {
|
||||
UINFO(4, " COVER: " << nodep << endl);
|
||||
CheckState lastState = m_state;
|
||||
VL_RESTORER(m_state);
|
||||
{
|
||||
m_state.m_on = true; // Always do cover blocks, even if there's a $stop
|
||||
createHandle(nodep);
|
||||
@@ -498,13 +491,12 @@ private:
|
||||
m_beginHier + "_vlCoverageUserTrace"));
|
||||
}
|
||||
}
|
||||
m_state = lastState;
|
||||
}
|
||||
virtual void visit(AstStop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstStop* nodep) override {
|
||||
UINFO(4, " STOP: " << nodep << endl);
|
||||
m_state.m_on = false;
|
||||
}
|
||||
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPragma* nodep) override {
|
||||
if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
|
||||
// Skip all NEXT nodes under this block, and skip this if/case branch
|
||||
UINFO(4, " OFF: h" << m_state.m_handle << " " << nodep << endl);
|
||||
@@ -515,14 +507,14 @@ private:
|
||||
lineTrack(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBegin* nodep) override {
|
||||
// Record the hierarchy of any named begins, so we can apply to user
|
||||
// coverage points. This is because there may be cov points inside
|
||||
// generate blocks; each point should get separate consideration.
|
||||
// (Currently ignored for line coverage, since any generate iteration
|
||||
// covers the code in that line.)
|
||||
string oldHier = m_beginHier;
|
||||
bool oldtog = m_inToggleOff;
|
||||
VL_RESTORER(m_beginHier);
|
||||
VL_RESTORER(m_inToggleOff);
|
||||
{
|
||||
m_inToggleOff = true;
|
||||
if (nodep->name() != "") {
|
||||
@@ -531,27 +523,18 @@ private:
|
||||
iterateChildren(nodep);
|
||||
lineTrack(nodep);
|
||||
}
|
||||
m_beginHier = oldHier;
|
||||
m_inToggleOff = oldtog;
|
||||
}
|
||||
|
||||
// VISITORS - BOTH
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
lineTrack(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CoverageVisitor(AstNetlist* rootp) {
|
||||
// Operate on all modules
|
||||
m_nextHandle = 0;
|
||||
m_modp = NULL;
|
||||
m_beginHier = "";
|
||||
m_inToggleOff = false;
|
||||
iterateChildren(rootp);
|
||||
}
|
||||
virtual ~CoverageVisitor() {}
|
||||
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }
|
||||
virtual ~CoverageVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+8
-12
@@ -54,20 +54,16 @@ private:
|
||||
// Note uses user4
|
||||
V3Hashed hashed; // Duplicate code detection
|
||||
// Hash all of the original signals we toggle cover
|
||||
for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) {
|
||||
AstCoverToggle* nodep = *it;
|
||||
hashed.hashAndInsert(nodep->origp());
|
||||
}
|
||||
for (AstCoverToggle* nodep : m_toggleps) hashed.hashAndInsert(nodep->origp());
|
||||
// Find if there are any duplicates
|
||||
for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) {
|
||||
AstCoverToggle* nodep = *it;
|
||||
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) {
|
||||
V3Hashed::iterator dupit = hashed.findDuplicate(nodep->origp());
|
||||
const auto dupit = hashed.findDuplicate(nodep->origp());
|
||||
if (dupit == hashed.end()) break;
|
||||
//
|
||||
AstNode* duporigp = hashed.iteratorNodep(dupit);
|
||||
@@ -97,24 +93,24 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// Find all Coverage's
|
||||
iterateChildren(nodep);
|
||||
// Simplify
|
||||
detectDuplicates();
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
m_toggleps.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CoverageJoinVisitor() {
|
||||
virtual ~CoverageJoinVisitor() override {
|
||||
V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins);
|
||||
}
|
||||
};
|
||||
|
||||
+47
-45
@@ -25,7 +25,7 @@
|
||||
// The following nodes have package pointers and are cleaned up here:
|
||||
// AstRefDType, AstEnumItemRef, AstNodeVarRef, AstNodeFTask
|
||||
// These have packagep but will not exist at this stage
|
||||
// AstPackageImport, AstDot, AstPackageRef
|
||||
// AstPackageImport, AstDot, AstClassOrPackageRef
|
||||
//
|
||||
// Note on packagep: After the V3Scope/V3LinkDotScoped stage, package links
|
||||
// are no longer used, but their presence prevents us from removing empty
|
||||
@@ -52,18 +52,18 @@ private:
|
||||
// NODE STATE
|
||||
// ** Shared with DeadVisitor **
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->modp()->user1Inc(-1);
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); }
|
||||
virtual ~DeadModVisitor() {}
|
||||
virtual ~DeadModVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -119,8 +119,8 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
if (!nodep->dead()) {
|
||||
@@ -135,14 +135,13 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->scopep()) nodep->scopep()->user1Inc();
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc();
|
||||
@@ -153,14 +152,14 @@ private:
|
||||
m_scopesp.push_back(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
m_cellsp.push_back(nodep);
|
||||
nodep->modp()->user1Inc();
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->varScopep()) {
|
||||
@@ -170,28 +169,28 @@ private:
|
||||
if (nodep->varp()) nodep->varp()->user1Inc();
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
nodep->packagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
nodep->packagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstMethodCall* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRefDType* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
@@ -199,49 +198,49 @@ private:
|
||||
"RefDType should point to data type before typedefs removed");
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
nodep->packagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstClassRefDType* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
nodep->packagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
if (nodep->classp()) nodep->classp()->user1Inc();
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeDType* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstEnumItemRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
nodep->packagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstMemberSel* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->varp()) nodep->varp()->user1Inc();
|
||||
if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstModport* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstModport* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_elimCells) {
|
||||
if (!nodep->varsp()) {
|
||||
@@ -251,7 +250,7 @@ private:
|
||||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTypedef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_elimCells && !nodep->attrPublic()) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
@@ -262,19 +261,19 @@ private:
|
||||
// Normal modules may disappear, e.g. if they are parameterized then removed
|
||||
if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->scopep()) nodep->scopep()->user1Inc();
|
||||
if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
|
||||
if (mightElimVar(nodep)) m_varsp.push_back(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
// See if simple assignments to variables may be eliminated because
|
||||
// that variable is never used.
|
||||
// Similar code in V3Life
|
||||
@@ -294,7 +293,7 @@ private:
|
||||
}
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
if (nodep->isOutputter()) m_sideEffect = true;
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
@@ -326,11 +325,16 @@ private:
|
||||
}
|
||||
}
|
||||
bool mightElimVar(AstVar* nodep) {
|
||||
return (!nodep->isSigPublic() // Can't elim publics!
|
||||
&& !nodep->isIO() && !nodep->isClassMember()
|
||||
&& ((nodep->isTemp() && !nodep->isTrace())
|
||||
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|
||||
|| m_elimUserVars)); // Post-Trace can kill most anything
|
||||
if (nodep->isSigPublic()) return false; // Can't elim publics!
|
||||
if (nodep->isIO() || nodep->isClassMember()) return false;
|
||||
if (nodep->isTemp() && !nodep->isTrace()) return true;
|
||||
if (nodep->isParam()) {
|
||||
const bool overriddenForHierBlock
|
||||
= m_modp && m_modp->hierBlock() && nodep->overriddenParam();
|
||||
if (!nodep->isTrace() && !overriddenForHierBlock && !v3Global.opt.xmlOnly())
|
||||
return true;
|
||||
}
|
||||
return m_elimUserVars; // Post-Trace can kill most anything
|
||||
}
|
||||
|
||||
void deadCheckScope() {
|
||||
@@ -345,7 +349,7 @@ private:
|
||||
scp->aboveScopep()->user1Inc(-1);
|
||||
if (scp->dtypep()) scp->dtypep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp);
|
||||
*it = NULL;
|
||||
*it = nullptr;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
@@ -353,8 +357,7 @@ private:
|
||||
}
|
||||
|
||||
void deadCheckCells() {
|
||||
for (std::vector<AstCell*>::iterator it = m_cellsp.begin(); it != m_cellsp.end(); ++it) {
|
||||
AstCell* cellp = *it;
|
||||
for (AstCell* cellp : m_cellsp) {
|
||||
if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) {
|
||||
cellp->modp()->user1Inc(-1);
|
||||
VL_DO_DANGLING(cellp->unlinkFrBack()->deleteTree(), cellp);
|
||||
@@ -366,12 +369,12 @@ private:
|
||||
retry = false;
|
||||
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
|
||||
++it) {
|
||||
if (AstClass* nodep = *it) { // NULL if deleted earlier
|
||||
if (AstClass* nodep = *it) { // nullptr if deleted earlier
|
||||
if (nodep->user1() == 0) {
|
||||
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
|
||||
if (nodep->packagep()) nodep->packagep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
*it = NULL;
|
||||
*it = nullptr;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
@@ -381,8 +384,7 @@ private:
|
||||
|
||||
void deadCheckVar() {
|
||||
// Delete any unused varscopes
|
||||
for (std::vector<AstVarScope*>::iterator it = m_vscsp.begin(); it != m_vscsp.end(); ++it) {
|
||||
AstVarScope* vscp = *it;
|
||||
for (AstVarScope* vscp : m_vscsp) {
|
||||
if (vscp->user1() == 0) {
|
||||
UINFO(4, " Dead " << vscp << endl);
|
||||
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
|
||||
@@ -407,7 +409,7 @@ private:
|
||||
UINFO(4, " Dead " << varp << endl);
|
||||
if (varp->dtypep()) varp->dtypep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
|
||||
*it = NULL;
|
||||
*it = nullptr;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
@@ -438,7 +440,7 @@ public:
|
||||
// CONSTRUCTORS
|
||||
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
|
||||
bool elimCells) {
|
||||
m_modp = NULL;
|
||||
m_modp = nullptr;
|
||||
m_elimCells = elimCells;
|
||||
m_elimUserVars = elimUserVars;
|
||||
m_elimDTypes = elimDTypes;
|
||||
@@ -460,7 +462,7 @@ public:
|
||||
// We may have removed some datatypes, cleanup
|
||||
nodep->typeTablep()->repairCache();
|
||||
}
|
||||
virtual ~DeadVisitor() {}
|
||||
virtual ~DeadVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+77
-75
@@ -86,15 +86,15 @@ private:
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
|
||||
enum VarUsage { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 };
|
||||
enum VarUsage : uint8_t { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 };
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Current activate
|
||||
AstCFunc* m_cfuncp; // Current public C Function
|
||||
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
|
||||
bool m_inDly; // True in delayed assignments
|
||||
bool m_inLoop; // True in for loops
|
||||
bool m_inInitial; // True in initial blocks
|
||||
AstActive* m_activep = nullptr; // Current activate
|
||||
AstCFunc* m_cfuncp = nullptr; // Current public C Function
|
||||
AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments
|
||||
bool m_inDly = false; // True in delayed assignments
|
||||
bool m_inLoop = false; // True in for loops
|
||||
bool m_inInitial = false; // True in initial blocks
|
||||
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
|
||||
VarMap m_modVarMap; // Table of new var names created under module
|
||||
VDouble0 m_statSharedSet; // Statistic tracking
|
||||
@@ -120,7 +120,7 @@ private:
|
||||
AstVar* varp;
|
||||
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
|
||||
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
|
||||
VarMap::iterator it = m_modVarMap.find(make_pair(addmodp, name));
|
||||
const auto it = m_modVarMap.find(make_pair(addmodp, name));
|
||||
if (it != m_modVarMap.end()) {
|
||||
// Created module's AstVar earlier under some other scope
|
||||
varp = it->second;
|
||||
@@ -171,8 +171,8 @@ private:
|
||||
UINFO(4, " Act: " << m_activep << endl);
|
||||
UINFO(4, " Act: " << oldactivep << endl);
|
||||
// Make a new sensitivity list, which is the combination of both blocks
|
||||
AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena);
|
||||
if (senb) treep->addSensesp(senb);
|
||||
if (AstSenTree* storep = oldactivep->sensesStorep()) {
|
||||
@@ -189,9 +189,9 @@ private:
|
||||
// See top of this file for transformation
|
||||
// Return the new LHS for the assignment, Null = unlink
|
||||
// Find selects
|
||||
AstNode* newlhsp = NULL; // NULL = unlink old assign
|
||||
AstSel* bitselp = NULL;
|
||||
AstArraySel* arrayselp = NULL;
|
||||
AstNode* newlhsp = nullptr; // nullptr = unlink old assign
|
||||
AstSel* bitselp = nullptr;
|
||||
AstArraySel* arrayselp = nullptr;
|
||||
if (VN_IS(lhsp, Sel)) {
|
||||
bitselp = VN_CAST(lhsp, Sel);
|
||||
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
|
||||
@@ -226,16 +226,17 @@ private:
|
||||
string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
|
||||
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), NULL);
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp);
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
|
||||
dimp);
|
||||
nodep->addNextHere(bitassignp);
|
||||
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
|
||||
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ));
|
||||
}
|
||||
}
|
||||
//
|
||||
//=== Bitselect: __Vdlyvlsb__
|
||||
AstNode* bitreadp = NULL; // Code to read Vdlyvlsb
|
||||
AstNode* bitreadp = nullptr; // Code to read Vdlyvlsb
|
||||
if (bitselp) {
|
||||
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
|
||||
if (VN_IS(bitselp->fromp(), Const)) {
|
||||
@@ -245,11 +246,12 @@ private:
|
||||
string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
|
||||
+ cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), NULL);
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep);
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
|
||||
lsbvaluep);
|
||||
nodep->addNextHere(bitassignp);
|
||||
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
|
||||
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ);
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -263,13 +265,13 @@ private:
|
||||
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
AstVarScope* valvscp
|
||||
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
|
||||
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
|
||||
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
|
||||
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
|
||||
}
|
||||
//
|
||||
//=== Setting/not setting boolean: __Vdlyvset__
|
||||
AstVarScope* setvscp;
|
||||
AstAssignPre* setinitp = NULL;
|
||||
AstAssignPre* setinitp = nullptr;
|
||||
|
||||
if (nodep->user3p()) {
|
||||
// Simplistic optimization. If the previous statement in same scope was also a =>,
|
||||
@@ -281,13 +283,13 @@ private:
|
||||
} else { // Create new one
|
||||
string setvarname
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, NULL);
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
|
||||
setinitp = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
AstAssign* setassignp
|
||||
= new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
|
||||
AstAssign* setassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
|
||||
nodep->addNextHere(setassignp);
|
||||
}
|
||||
if (m_nextDlyp) { // Tell next assigndly it can share the variable
|
||||
@@ -316,7 +318,7 @@ private:
|
||||
checkActivePost(varrefp, oldactivep);
|
||||
if (setinitp) oldactivep->addStmtsp(setinitp);
|
||||
} else { // first time we've dealt with this memory
|
||||
finalp = new AstAlwaysPost(nodep->fileline(), NULL /*sens*/, NULL /*body*/);
|
||||
finalp = new AstAlwaysPost(nodep->fileline(), nullptr /*sens*/, nullptr /*body*/);
|
||||
UINFO(9, " Created " << finalp << endl);
|
||||
AstActive* newactp = createActivePost(varrefp);
|
||||
newactp->addStmtsp(finalp);
|
||||
@@ -333,7 +335,8 @@ private:
|
||||
"Delayed assignment misoptimized; prev var found w/o associated IF");
|
||||
} else {
|
||||
postLogicp = new AstIf(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, false), NULL, NULL);
|
||||
new AstVarRef(nodep->fileline(), setvscp, VAccess::READ),
|
||||
nullptr, nullptr);
|
||||
UINFO(9, " Created " << postLogicp << endl);
|
||||
finalp->addBodysp(postLogicp);
|
||||
finalp->user3p(setvscp); // Remember IF's vset variable
|
||||
@@ -344,36 +347,38 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// VV***** We reset all userp() on the netlist
|
||||
m_modVarMap.clear();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
AstNode::user3ClearTree();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_cfuncp = NULL;
|
||||
m_cfuncp = nullptr;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
m_activep = nodep;
|
||||
bool oldinit = m_inInitial;
|
||||
m_inInitial = nodep->hasInitial();
|
||||
AstNode::user3ClearTree(); // Two sets to same variable in different
|
||||
// actives must use different vars.
|
||||
iterateChildren(nodep);
|
||||
m_inInitial = oldinit;
|
||||
VL_RESTORER(m_inInitial);
|
||||
{
|
||||
m_inInitial = nodep->hasInitial();
|
||||
// Two sets to same variable in different actives must use different vars.
|
||||
AstNode::user3ClearTree();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignDly* nodep) override {
|
||||
m_inDly = true;
|
||||
m_nextDlyp
|
||||
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
|
||||
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe nullptr.
|
||||
if (m_cfuncp) {
|
||||
nodep->v3error("Unsupported: Delayed assignment inside public function/task");
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Delayed assignment inside public function/task");
|
||||
}
|
||||
if (VN_IS(nodep->lhsp(), ArraySel)
|
||||
|| (VN_IS(nodep->lhsp(), Sel)
|
||||
@@ -385,7 +390,9 @@ private:
|
||||
"loops (non-delayed is ok - see docs)");
|
||||
}
|
||||
AstBasicDType* basicp = lhsp->dtypep()->basicp();
|
||||
if (basicp && basicp->isEventValue()) nodep->v3error("Unsupported: event arrays");
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays");
|
||||
}
|
||||
if (newlhsp) {
|
||||
nodep->lhsp(newlhsp);
|
||||
} else {
|
||||
@@ -396,12 +403,12 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_inDly = false;
|
||||
m_nextDlyp = NULL;
|
||||
m_nextDlyp = nullptr;
|
||||
}
|
||||
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (!nodep->user2Inc()) { // Not done yet
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
if (m_inDly && nodep->access().isWrite()) {
|
||||
UINFO(4, "AssignDlyVar: " << nodep << endl);
|
||||
markVarUsage(nodep->varScopep(), VU_DLY);
|
||||
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
|
||||
@@ -418,22 +425,25 @@ private:
|
||||
}
|
||||
if (!dlyvscp) { // First use of this delayed variable
|
||||
string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL);
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
|
||||
AstNodeAssign* prep;
|
||||
AstBasicDType* basicp = oldvscp->dtypep()->basicp();
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
// Events go to zero on next timestep unless reactivated
|
||||
prep = new AstAssignPre(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
|
||||
} else {
|
||||
prep = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, false));
|
||||
prep = new AstAssignPre(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
|
||||
}
|
||||
AstNodeAssign* postp = new AstAssignPost(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, false));
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
|
||||
postp->lhsp()->user2(true); // Don't detect this assignment
|
||||
oldvscp->user1p(dlyvscp); // So we can find it later
|
||||
// Make new ACTIVE with identical sensitivity tree
|
||||
@@ -442,11 +452,11 @@ private:
|
||||
newactp->addStmtsp(prep); // Add to FRONT of statements
|
||||
newactp->addStmtsp(postp);
|
||||
}
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
|
||||
newrefp->user2(true); // No reason to do it again
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (!m_inDly && nodep->lvalue()) {
|
||||
} else if (!m_inDly && nodep->access().isWrite()) {
|
||||
// UINFO(9, "NBA " << nodep << endl);
|
||||
if (!m_inInitial) {
|
||||
UINFO(4, "AssignNDlyVar: " << nodep << endl);
|
||||
@@ -456,33 +466,25 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc(
|
||||
"For statements should have been converted to while statements in V3Begin");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
bool oldloop = m_inLoop;
|
||||
m_inLoop = true;
|
||||
iterateChildren(nodep);
|
||||
m_inLoop = oldloop;
|
||||
virtual void visit(AstWhile* nodep) override {
|
||||
VL_RESTORER(m_inLoop);
|
||||
{
|
||||
m_inLoop = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DelayedVisitor(AstNetlist* nodep) {
|
||||
m_inDly = false;
|
||||
m_activep = NULL;
|
||||
m_cfuncp = NULL;
|
||||
m_nextDlyp = NULL;
|
||||
m_inLoop = false;
|
||||
m_inInitial = false;
|
||||
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~DelayedVisitor() {
|
||||
explicit DelayedVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~DelayedVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Delayed shared-sets", m_statSharedSet);
|
||||
}
|
||||
};
|
||||
|
||||
+23
-32
@@ -39,11 +39,11 @@ private:
|
||||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current block
|
||||
AstNode* m_stmtp; // Current statement
|
||||
int m_depth; // How deep in an expression
|
||||
int m_maxdepth; // Maximum depth in an expression
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current block
|
||||
AstNode* m_stmtp = nullptr; // Current statement
|
||||
int m_depth = 0; // How deep in an expression
|
||||
int m_maxdepth = 0; // Maximum depth in an expression
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -64,11 +64,11 @@ private:
|
||||
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
|
||||
m_funcp->addInitsp(varp);
|
||||
// Replace node tree with reference to var
|
||||
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
|
||||
nodep->replaceWith(newp);
|
||||
// Put assignment before the referencing statement
|
||||
AstAssign* assp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, true), nodep);
|
||||
AstAssign* assp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep);
|
||||
AstNRelinker linker2;
|
||||
m_stmtp->unlinkFrBack(&linker2);
|
||||
assp->addNext(m_stmtp);
|
||||
@@ -76,31 +76,30 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_funcp = NULL;
|
||||
m_funcp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
m_funcp = nodep;
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
iterateChildren(nodep);
|
||||
m_funcp = NULL;
|
||||
m_funcp = nullptr;
|
||||
}
|
||||
void visitStmt(AstNodeStmt* nodep) {
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
m_stmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_stmtp = NULL;
|
||||
m_stmtp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeStmt* nodep) override {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
} else {
|
||||
@@ -108,8 +107,8 @@ private:
|
||||
}
|
||||
}
|
||||
// Operators
|
||||
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeTermop* nodep) override {}
|
||||
virtual void visit(AstNodeMath* nodep) override {
|
||||
// We have some operator defines that use 2 parens, so += 2.
|
||||
m_depth += 2;
|
||||
if (m_depth > m_maxdepth) m_maxdepth = m_depth;
|
||||
@@ -135,32 +134,24 @@ private:
|
||||
m_funcp->isStatic(false);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUCFunc* nodep) override {
|
||||
needNonStaticFunc(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUCStmt* nodep) override {
|
||||
needNonStaticFunc(nodep);
|
||||
visitStmt(nodep);
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DepthVisitor(AstNetlist* nodep) {
|
||||
m_modp = NULL;
|
||||
m_funcp = NULL;
|
||||
m_stmtp = NULL;
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
//
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~DepthVisitor() {}
|
||||
explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~DepthVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+16
-26
@@ -37,10 +37,10 @@ private:
|
||||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
int m_depth; // How deep in an expression
|
||||
int m_deepNum; // How many functions made
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current function
|
||||
int m_depth = 0; // How deep in an expression
|
||||
int m_deepNum = 0; // How many functions made
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -50,7 +50,7 @@ private:
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
// Create function
|
||||
string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum);
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL);
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr);
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->symProlog(true);
|
||||
funcp->slow(m_funcp->slow());
|
||||
@@ -66,27 +66,24 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_deepNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
// We recurse into this.
|
||||
int lastDepth = m_depth;
|
||||
AstCFunc* lastFuncp = m_funcp;
|
||||
VL_RESTORER(m_depth);
|
||||
VL_RESTORER(m_funcp);
|
||||
{
|
||||
m_depth = 0;
|
||||
m_funcp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_depth = lastDepth;
|
||||
m_funcp = lastFuncp;
|
||||
}
|
||||
void visitStmt(AstNodeStmt* nodep) {
|
||||
m_depth++;
|
||||
@@ -104,7 +101,7 @@ private:
|
||||
}
|
||||
m_depth--;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeStmt* nodep) override {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
} else {
|
||||
@@ -112,22 +109,15 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
//--------------------
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DepthBlockVisitor(AstNetlist* nodep) {
|
||||
m_modp = NULL;
|
||||
m_funcp = NULL;
|
||||
m_depth = 0;
|
||||
m_deepNum = 0;
|
||||
//
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~DepthBlockVisitor() {}
|
||||
explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~DepthBlockVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+28
-35
@@ -45,11 +45,11 @@ private:
|
||||
typedef std::multimap<string, AstCFunc*> FuncMmap;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope
|
||||
bool m_modSingleton; // m_modp is only instanced once
|
||||
bool m_allowThis; // Allow function non-static
|
||||
bool m_needThis; // Make function non-static
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstScope* m_scopep = nullptr; // Current scope
|
||||
bool m_modSingleton = false; // m_modp is only instanced once
|
||||
bool m_allowThis = false; // Allow function non-static
|
||||
bool m_needThis = false; // Make function non-static
|
||||
FuncMmap m_modFuncs; // Name of public functions added
|
||||
|
||||
// METHODS
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
// Sets 'hierThisr' true if the object is local to this scope
|
||||
// (and could be made into a function-local later in V3Localize),
|
||||
// false if the object is in another scope.
|
||||
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = NULL) {
|
||||
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = nullptr) {
|
||||
UASSERT(scopep, "Var/Func not scoped");
|
||||
hierThisr = (scopep == m_scopep);
|
||||
|
||||
@@ -148,7 +148,7 @@ private:
|
||||
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
|
||||
string name = it->first;
|
||||
AstCFunc* topFuncp = it->second;
|
||||
FuncMmap::iterator nextIt1 = it;
|
||||
auto nextIt1 = it;
|
||||
++nextIt1;
|
||||
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
|
||||
if (moreOfSame1) {
|
||||
@@ -171,7 +171,7 @@ private:
|
||||
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
|
||||
it = eachIt;
|
||||
AstCFunc* funcp = eachIt->second;
|
||||
FuncMmap::iterator nextIt2 = eachIt;
|
||||
auto nextIt2 = eachIt;
|
||||
++nextIt2;
|
||||
bool moreOfSame = (nextIt2 != m_modFuncs.end() && nextIt2->first == name);
|
||||
UASSERT_OBJ(funcp->scopep(), funcp, "Not scoped");
|
||||
@@ -180,12 +180,13 @@ private:
|
||||
UINFO(6,
|
||||
" at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl);
|
||||
funcp->declPrivate(true);
|
||||
AstNode* argsp = NULL;
|
||||
AstNode* argsp = nullptr;
|
||||
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
AstNode* newp
|
||||
= new AstVarRef(portp->fileline(), portp, portp->isWritable());
|
||||
AstNode* newp = new AstVarRef(portp->fileline(), portp,
|
||||
portp->isWritable() ? VAccess::WRITE
|
||||
: VAccess::READ);
|
||||
argsp = argsp ? argsp->addNextNull(newp) : newp;
|
||||
}
|
||||
}
|
||||
@@ -202,7 +203,7 @@ private:
|
||||
new AstCMath(funcp->fileline(),
|
||||
string("&(") + funcp->scopep()->nameVlSym() + ")",
|
||||
64)),
|
||||
returnp, NULL);
|
||||
returnp, nullptr);
|
||||
newfuncp->addStmtsp(ifp);
|
||||
} else {
|
||||
newfuncp->addStmtsp(returnp);
|
||||
@@ -213,7 +214,7 @@ private:
|
||||
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
|
||||
// AstDisplayType::DT_WARNING,
|
||||
// string("%%Error: ")+name+"() called with bad
|
||||
// scope", NULL));
|
||||
// scope", nullptr));
|
||||
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
||||
if (debug() >= 9) newfuncp->dumpTree(cout, " newfunc: ");
|
||||
} else {
|
||||
@@ -225,8 +226,8 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modFuncs.clear();
|
||||
@@ -234,19 +235,18 @@ private:
|
||||
iterateChildren(nodep);
|
||||
makePublicFuncWrappers();
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
// Delete the varscope when we're finished
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Convert the hierch name
|
||||
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
|
||||
@@ -254,9 +254,9 @@ private:
|
||||
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis /*ref*/,
|
||||
nodep->varScopep()->varp()));
|
||||
nodep->hierThis(hierThis);
|
||||
nodep->varScopep(NULL);
|
||||
nodep->varScopep(nullptr);
|
||||
}
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCCall* nodep) override {
|
||||
// UINFO(9, " " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
// Convert the hierch name
|
||||
@@ -265,9 +265,9 @@ private:
|
||||
bool hierThis;
|
||||
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis /*ref*/));
|
||||
// Can't do this, as we may have more calls later
|
||||
// nodep->funcp()->scopep(NULL);
|
||||
// nodep->funcp()->scopep(nullptr);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
if (!nodep->user1()) {
|
||||
m_needThis = false;
|
||||
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
|
||||
@@ -288,20 +288,13 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {}
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DescopeVisitor(AstNetlist* nodep)
|
||||
: m_modp(NULL)
|
||||
, m_scopep(NULL)
|
||||
, m_modSingleton(false)
|
||||
, m_allowThis(false)
|
||||
, m_needThis(false) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~DescopeVisitor() {}
|
||||
explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~DescopeVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+264
-266
File diff suppressed because it is too large
Load Diff
+8
-14
@@ -33,8 +33,8 @@
|
||||
class EmitCBaseVisitor : public AstNVisitor {
|
||||
public:
|
||||
// STATE
|
||||
V3OutCFile* m_ofp;
|
||||
bool m_trackText; // Always track AstText nodes
|
||||
V3OutCFile* m_ofp = nullptr;
|
||||
bool m_trackText = false; // Always track AstText nodes
|
||||
// METHODS
|
||||
V3OutCFile* ofp() const { return m_ofp; }
|
||||
void puts(const string& str) { ofp()->puts(str); }
|
||||
@@ -106,11 +106,8 @@ public:
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
EmitCBaseVisitor() {
|
||||
m_ofp = NULL;
|
||||
m_trackText = false;
|
||||
}
|
||||
virtual ~EmitCBaseVisitor() {}
|
||||
EmitCBaseVisitor() {}
|
||||
virtual ~EmitCBaseVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -119,20 +116,17 @@ public:
|
||||
class EmitCBaseCounterVisitor : public AstNVisitor {
|
||||
private:
|
||||
// MEMBERS
|
||||
int m_count; // Number of statements
|
||||
int m_count = 0; // Number of statements
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
m_count++;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit EmitCBaseCounterVisitor(AstNode* nodep) {
|
||||
m_count = 0;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitCBaseCounterVisitor() {}
|
||||
explicit EmitCBaseCounterVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~EmitCBaseCounterVisitor() override {}
|
||||
int count() const { return m_count; }
|
||||
};
|
||||
|
||||
|
||||
@@ -35,24 +35,24 @@ class EmitCInlines : EmitCBaseVisitor {
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstClass* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstClass* nodep) override {
|
||||
checkHeavy(nodep);
|
||||
v3Global.needC11(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCNew* nodep) override {
|
||||
checkHeavy(nodep);
|
||||
if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new");
|
||||
if (v3Global.opt.savable())
|
||||
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDumpCtl* nodep) override {
|
||||
checkHeavy(nodep);
|
||||
if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
checkHeavy(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,11 +31,11 @@ class EmitCMain : EmitCBaseVisitor {
|
||||
|
||||
// VISITORS
|
||||
// This visitor doesn't really iterate, but exist to appease base class
|
||||
virtual void visit(AstNode* nodep) { iterateChildren(nodep); } // LCOV_EXCL_LINE
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit EmitCMain(AstNetlist* nodep) { emitInt(); }
|
||||
explicit EmitCMain(AstNetlist*) { emitInt(); }
|
||||
|
||||
private:
|
||||
// MAIN METHOD
|
||||
|
||||
+64
-6
@@ -21,6 +21,7 @@
|
||||
#include "V3Os.h"
|
||||
#include "V3EmitCMake.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3HierBlock.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -39,11 +40,11 @@ class CMakeEmitter {
|
||||
string s;
|
||||
if (strs.begin() != strs.end()) {
|
||||
s.append("\"");
|
||||
s.append(*strs.begin());
|
||||
s.append(VString::quoteAny(*strs.begin(), '"', '\\'));
|
||||
s.append("\"");
|
||||
for (typename List::const_iterator it = ++strs.begin(); it != strs.end(); ++it) {
|
||||
s.append(" \"");
|
||||
s.append(*it);
|
||||
s.append(VString::quoteAny(*it, '"', '\\'));
|
||||
s.append("\"");
|
||||
}
|
||||
}
|
||||
@@ -77,7 +78,7 @@ class CMakeEmitter {
|
||||
}
|
||||
|
||||
static void emitOverallCMake() {
|
||||
const vl_unique_ptr<std::ofstream> of(
|
||||
const std::unique_ptr<std::ofstream> of(
|
||||
V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake"));
|
||||
string name = v3Global.opt.prefix();
|
||||
|
||||
@@ -124,7 +125,11 @@ class CMakeEmitter {
|
||||
: "0");
|
||||
|
||||
*of << "\n### Sources...\n";
|
||||
std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global;
|
||||
std::vector<string> classes_fast;
|
||||
std::vector<string> classes_slow;
|
||||
std::vector<string> support_fast;
|
||||
std::vector<string> support_slow;
|
||||
std::vector<string> global;
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(nodep, CFile);
|
||||
@@ -163,8 +168,9 @@ class CMakeEmitter {
|
||||
+ "_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
|
||||
v3error("Unsupported: This trace format is not supported in SystemC, "
|
||||
"use VCD format.");
|
||||
v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: This trace format is not supported in SystemC, "
|
||||
"use VCD format.");
|
||||
}
|
||||
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
|
||||
+ ".cpp");
|
||||
@@ -194,6 +200,58 @@ class CMakeEmitter {
|
||||
|
||||
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
|
||||
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
|
||||
if (const V3HierBlockPlan* planp = v3Global.hierPlanp()) {
|
||||
*of << "# Verilate hierarchical blocks\n";
|
||||
// Sorted hierarchical blocks in order of leaf-first.
|
||||
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
||||
*of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n";
|
||||
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
|
||||
it != hierBlocks.end(); ++it) {
|
||||
const V3HierBlock* hblockp = *it;
|
||||
const V3HierBlock::HierBlockSet& children = hblockp->children();
|
||||
const string prefix = hblockp->hierPrefix();
|
||||
*of << "add_library(" << prefix << " STATIC)\n";
|
||||
*of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
|
||||
if (!children.empty()) {
|
||||
*of << "target_link_libraries(" << prefix << " INTERFACE";
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
*of << " " << (*child)->hierPrefix();
|
||||
}
|
||||
*of << ")\n";
|
||||
}
|
||||
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
|
||||
<< hblockp->modp()->name() << " DIRECTORY "
|
||||
<< deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES ";
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
*of << " "
|
||||
<< deslash(v3Global.opt.makeDir() + "/" + (*child)->hierWrapper(true));
|
||||
}
|
||||
*of << " ";
|
||||
const string vFile = hblockp->vFileIfNecessary();
|
||||
if (!vFile.empty()) *of << vFile << " ";
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
|
||||
*of << " VERILATOR_ARGS ";
|
||||
*of << "-f " << deslash(hblockp->commandArgsFileName(true))
|
||||
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
|
||||
// with .so
|
||||
<< ")\n";
|
||||
}
|
||||
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
|
||||
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
|
||||
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
|
||||
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
|
||||
for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) {
|
||||
*of << " "
|
||||
<< deslash(v3Global.opt.makeDir() + "/" + it->second->hierWrapper(true));
|
||||
}
|
||||
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
|
||||
*of << " VERILATOR_ARGS ";
|
||||
*of << "-f " << deslash(planp->topCommandArgsFileName(true));
|
||||
*of << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
+73
-65
@@ -43,19 +43,19 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
string m_type;
|
||||
ScopeData(const string& symName, const string& prettyName, int timeunit,
|
||||
const string& type)
|
||||
: m_symName(symName)
|
||||
, m_prettyName(prettyName)
|
||||
, m_timeunit(timeunit)
|
||||
, m_type(type) {}
|
||||
: m_symName{symName}
|
||||
, m_prettyName{prettyName}
|
||||
, m_timeunit{timeunit}
|
||||
, m_type{type} {}
|
||||
};
|
||||
struct ScopeFuncData {
|
||||
AstScopeName* m_scopep;
|
||||
AstCFunc* m_funcp;
|
||||
AstNodeModule* m_modp;
|
||||
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
||||
: m_scopep(scopep)
|
||||
, m_funcp(funcp)
|
||||
, m_modp(modp) {}
|
||||
: m_scopep{scopep}
|
||||
, m_funcp{funcp}
|
||||
, m_modp{modp} {}
|
||||
};
|
||||
struct ScopeVarData {
|
||||
string m_scopeName;
|
||||
@@ -65,11 +65,11 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
AstScope* m_scopep;
|
||||
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp,
|
||||
AstNodeModule* modp, AstScope* scopep)
|
||||
: m_scopeName(scopeName)
|
||||
, m_varBasePretty(varBasePretty)
|
||||
, m_varp(varp)
|
||||
, m_modp(modp)
|
||||
, m_scopep(scopep) {}
|
||||
: m_scopeName{scopeName}
|
||||
, m_varBasePretty{varBasePretty}
|
||||
, m_varp{varp}
|
||||
, m_modp{modp}
|
||||
, m_scopep{scopep} {}
|
||||
};
|
||||
typedef std::map<string, ScopeFuncData> ScopeFuncs;
|
||||
typedef std::map<string, ScopeVarData> ScopeVars;
|
||||
@@ -94,8 +94,8 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
};
|
||||
|
||||
// STATE
|
||||
AstCFunc* m_funcp; // Current function
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current function
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
std::vector<ScopeModPair> m_scopes; // Every scope by module
|
||||
std::vector<AstCFunc*> m_dpis; // DPI functions
|
||||
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
|
||||
@@ -104,11 +104,11 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
ScopeVars m_scopeVars; // Each {scope,public-var}
|
||||
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
|
||||
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
|
||||
int m_coverBins; // Coverage bin number
|
||||
int m_coverBins = 0; // Coverage bin number
|
||||
bool m_dpiHdrOnly; // Only emit the DPI header
|
||||
int m_numStmts; // Number of statements output
|
||||
int m_funcNum; // CFunc split function number
|
||||
V3OutCFile* m_ofpBase; // Base (not split) C file
|
||||
int m_numStmts = 0; // Number of statements output
|
||||
int m_funcNum = 0; // CFunc split function number
|
||||
V3OutCFile* m_ofpBase = nullptr; // Base (not split) C file
|
||||
std::map<int, bool> m_usesVfinal; // Split method uses __Vfinal
|
||||
|
||||
// METHODS
|
||||
@@ -120,7 +120,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
void emitDpiHdr();
|
||||
void emitDpiImp();
|
||||
|
||||
void nameCheck(AstNode* nodep) {
|
||||
static void nameCheck(AstNode* nodep) {
|
||||
// Prevent GCC compile time error; name check all things that reach C++ code
|
||||
if (nodep->name() != ""
|
||||
&& !(VN_IS(nodep, CFunc)
|
||||
@@ -139,7 +139,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
string scopeSymString(const string& scpname) {
|
||||
static string scopeSymString(const string& scpname) {
|
||||
string out = scpname;
|
||||
string::size_type pos;
|
||||
while ((pos = out.find("__PVT__")) != string::npos) out.replace(pos, 7, "");
|
||||
@@ -150,7 +150,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
return out;
|
||||
}
|
||||
|
||||
string scopeDecodeIdentifier(const string& scpname) {
|
||||
static string scopeDecodeIdentifier(const string& scpname) {
|
||||
string out = scpname;
|
||||
// Remove hierarchy
|
||||
string::size_type pos = out.rfind('.');
|
||||
@@ -168,7 +168,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
|
||||
void varHierarchyScopes(string scp) {
|
||||
while (!scp.empty()) {
|
||||
ScopeNames::const_iterator scpit = m_vpiScopeCandidates.find(scp);
|
||||
const auto scpit = m_vpiScopeCandidates.find(scp);
|
||||
if ((scpit != m_vpiScopeCandidates.end())
|
||||
&& (m_scopeNames.find(scp) == m_scopeNames.end())) {
|
||||
m_scopeNames.insert(make_pair(scpit->second.m_symName, scpit->second));
|
||||
@@ -252,7 +252,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// Collect list of scopes
|
||||
iterateChildren(nodep);
|
||||
varsExpand();
|
||||
@@ -274,16 +274,15 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
if (!m_dpiHdrOnly) emitDpiImp();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
nameCheck(nodep);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCellInline* nodep) override {
|
||||
if (v3Global.opt.vpi()) {
|
||||
string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE";
|
||||
string name = nodep->scopep()->name() + "__DOT__" + nodep->name();
|
||||
@@ -293,7 +292,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type)));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
|
||||
nameCheck(nodep);
|
||||
|
||||
@@ -307,7 +306,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
timeunit, "SCOPE_MODULE")));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScopeName* nodep) override {
|
||||
string name = nodep->scopeSymName();
|
||||
// UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()
|
||||
// <<" ss"<<name<<endl);
|
||||
@@ -329,43 +328,32 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
nameCheck(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isSigUserRdPublic()
|
||||
// The VPI functions require a pointer to allow modification,
|
||||
// but parameters are constants
|
||||
&& !nodep->isParam()) {
|
||||
m_modVars.push_back(make_pair(m_modp, nodep));
|
||||
}
|
||||
if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); }
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverDecl* nodep) override {
|
||||
// Assign numbers to all bins, so we know how big of an array to use
|
||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||
nodep->binNum(m_coverBins++);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
nameCheck(nodep);
|
||||
if (nodep->dpiImport() || nodep->dpiExportWrapper()) m_dpis.push_back(nodep);
|
||||
m_funcp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_funcp = NULL;
|
||||
m_funcp = nullptr;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
virtual void visit(AstConst*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstConst*) override {}
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly)
|
||||
: m_dpiHdrOnly(dpiHdrOnly) {
|
||||
m_funcp = NULL;
|
||||
m_modp = NULL;
|
||||
m_coverBins = 0;
|
||||
m_numStmts = 0;
|
||||
m_funcNum = 0;
|
||||
m_ofpBase = NULL;
|
||||
: m_dpiHdrOnly{dpiHdrOnly} {
|
||||
iterate(nodep);
|
||||
}
|
||||
};
|
||||
@@ -501,14 +489,14 @@ void EmitCSyms::emitSymHdr() {
|
||||
puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n");
|
||||
|
||||
ofp()->putsEndGuard();
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
}
|
||||
|
||||
void EmitCSyms::closeSplit() {
|
||||
if (!m_ofp || m_ofp == m_ofpBase) return;
|
||||
|
||||
puts("}\n");
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
}
|
||||
|
||||
void EmitCSyms::checkSplit(bool usesVfinal) {
|
||||
@@ -622,7 +610,7 @@ void EmitCSyms::emitSymImp() {
|
||||
puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed
|
||||
if (v3Global.needTraceDumper()) {
|
||||
puts(" , __Vm_dumping(false)\n");
|
||||
puts(" , __Vm_dumperp(NULL)\n");
|
||||
puts(" , __Vm_dumperp(nullptr)\n");
|
||||
}
|
||||
if (v3Global.opt.trace()) {
|
||||
puts(" , __Vm_activity(false)\n");
|
||||
@@ -715,8 +703,8 @@ void EmitCSyms::emitSymImp() {
|
||||
++lit) {
|
||||
string fromname = scopeSymString(it->first);
|
||||
string toname = scopeSymString(*lit);
|
||||
ScopeNames::const_iterator from = m_scopeNames.find(fromname);
|
||||
ScopeNames::const_iterator to = m_scopeNames.find(toname);
|
||||
const auto from = vlstd::as_const(m_scopeNames).find(fromname);
|
||||
const auto to = vlstd::as_const(m_scopeNames).find(toname);
|
||||
UASSERT(from != m_scopeNames.end(), fromname + " not in m_scopeNames");
|
||||
UASSERT(to != m_scopeNames.end(), toname + " not in m_scopeNames");
|
||||
puts("__Vhier.add(");
|
||||
@@ -794,16 +782,38 @@ void EmitCSyms::emitSymImp() {
|
||||
}
|
||||
puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,");
|
||||
putsQuoted(protect(it->second.m_varBasePretty));
|
||||
puts(", &(");
|
||||
|
||||
std::string varName;
|
||||
if (modp->isTop()) {
|
||||
puts(protectIf(scopep->nameDotless() + "p", scopep->protect()));
|
||||
puts("->");
|
||||
varName += (protectIf(scopep->nameDotless() + "p", scopep->protect()) + "->");
|
||||
} else {
|
||||
puts(protectIf(scopep->nameDotless(), scopep->protect()));
|
||||
puts(".");
|
||||
varName += (protectIf(scopep->nameDotless(), scopep->protect()) + ".");
|
||||
}
|
||||
puts(varp->nameProtect());
|
||||
puts("), ");
|
||||
|
||||
if (varp->isParam()) {
|
||||
varName += protect("var_" + varp->name());
|
||||
} else {
|
||||
varName += protect(varp->name());
|
||||
}
|
||||
|
||||
if (varp->isParam()) {
|
||||
if (varp->vlEnumType() == "VLVT_STRING") {
|
||||
puts(", const_cast<void*>(static_cast<const void*>(");
|
||||
puts(varName);
|
||||
puts(".c_str())), ");
|
||||
} else {
|
||||
puts(", const_cast<void*>(static_cast<const void*>(&(");
|
||||
puts(varName);
|
||||
puts("))), ");
|
||||
}
|
||||
} else {
|
||||
puts(", &(");
|
||||
puts(varName);
|
||||
puts("), ");
|
||||
}
|
||||
|
||||
puts(varp->isParam() ? "true" : "false");
|
||||
puts(", ");
|
||||
puts(varp->vlEnumType()); // VLVT_UINT32 etc
|
||||
puts(",");
|
||||
puts(varp->vlEnumDir()); // VLVD_IN etc
|
||||
@@ -818,7 +828,7 @@ void EmitCSyms::emitSymImp() {
|
||||
|
||||
m_ofpBase->puts("}\n");
|
||||
closeSplit();
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
@@ -848,8 +858,7 @@ void EmitCSyms::emitDpiHdr() {
|
||||
|
||||
int firstExp = 0;
|
||||
int firstImp = 0;
|
||||
for (std::vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) {
|
||||
AstCFunc* nodep = *it;
|
||||
for (AstCFunc* nodep : m_dpis) {
|
||||
if (nodep->dpiExportWrapper()) {
|
||||
if (!firstExp++) puts("\n// DPI EXPORTS\n");
|
||||
puts("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n");
|
||||
@@ -898,8 +907,7 @@ void EmitCSyms::emitDpiImp() {
|
||||
puts("#include \"" + topClassName() + ".h\"\n");
|
||||
puts("\n");
|
||||
|
||||
for (std::vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) {
|
||||
AstCFunc* nodep = *it;
|
||||
for (AstCFunc* nodep : m_dpis) {
|
||||
if (nodep->dpiExportWrapper()) {
|
||||
puts("#ifndef _VL_DPIDECL_" + nodep->name() + "\n");
|
||||
puts("#define _VL_DPIDECL_" + nodep->name() + "\n");
|
||||
|
||||
+178
-31
@@ -18,6 +18,7 @@
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3HierBlock.h"
|
||||
#include "V3Os.h"
|
||||
#include "V3EmitMk.h"
|
||||
#include "V3EmitCBase.h"
|
||||
@@ -46,11 +47,8 @@ public:
|
||||
of.puts("# See " + v3Global.opt.prefix() + ".mk" + " for the caller.\n");
|
||||
|
||||
of.puts("\n### Switches...\n");
|
||||
of.puts("# C11 constructs required? 0/1 (from --threads, "
|
||||
"--trace-threads or use of classes)\n");
|
||||
of.puts("VM_C11 = ");
|
||||
of.puts(v3Global.needC11() || v3Global.opt.threads() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# C11 constructs required? 0/1 (always on now)\n");
|
||||
of.puts("VM_C11 = 1\n");
|
||||
of.puts("# Coverage output mode? 0/1 (from --coverage)\n");
|
||||
of.puts("VM_COVERAGE = ");
|
||||
of.puts(v3Global.opt.coverage() ? "1" : "0");
|
||||
@@ -67,6 +65,10 @@ public:
|
||||
of.puts("VM_TRACE = ");
|
||||
of.puts(v3Global.opt.trace() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n");
|
||||
of.puts("VM_TRACE_FST = ");
|
||||
of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n");
|
||||
of.puts("VM_TRACE_THREADS = ");
|
||||
of.puts(cvtToStr(v3Global.opt.trueTraceThreads()));
|
||||
@@ -94,7 +96,10 @@ public:
|
||||
of.puts(support == 2 ? "VM_GLOBAL" : support == 1 ? "VM_SUPPORT" : "VM_CLASSES");
|
||||
of.puts(slow ? "_SLOW" : "_FAST");
|
||||
of.puts(" += \\\n");
|
||||
if (support == 2 && !slow) {
|
||||
if (support == 2 && v3Global.opt.hierChild()) {
|
||||
// Do nothing because VM_GLOBAL is necessary per executable. Top module will
|
||||
// have them.
|
||||
} else if (support == 2 && !slow) {
|
||||
putMakeClassEntry(of, "verilated.cpp");
|
||||
if (v3Global.dpi()) { putMakeClassEntry(of, "verilated_dpi.cpp"); }
|
||||
if (v3Global.opt.vpi()) { putMakeClassEntry(of, "verilated_vpi.cpp"); }
|
||||
@@ -104,8 +109,9 @@ public:
|
||||
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
|
||||
v3error("Unsupported: This trace format is not supported "
|
||||
"in SystemC, use VCD format.");
|
||||
v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: This trace format is not supported "
|
||||
"in SystemC, use VCD format.");
|
||||
} else {
|
||||
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
|
||||
}
|
||||
@@ -188,25 +194,20 @@ public:
|
||||
of.puts("VM_USER_CFLAGS = \\\n");
|
||||
if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n");
|
||||
const V3StringList& cFlags = v3Global.opt.cFlags();
|
||||
for (V3StringList::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
|
||||
of.puts("\t" + *it + " \\\n");
|
||||
}
|
||||
for (const string& i : cFlags) of.puts("\t" + i + " \\\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("# User LDLIBS (from -LDFLAGS on Verilator command line)\n");
|
||||
of.puts("VM_USER_LDLIBS = \\\n");
|
||||
const V3StringList& ldLibs = v3Global.opt.ldLibs();
|
||||
for (V3StringList::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) {
|
||||
of.puts("\t" + *it + " \\\n");
|
||||
}
|
||||
for (const string& i : ldLibs) of.puts("\t" + i + " \\\n");
|
||||
of.puts("\n");
|
||||
|
||||
V3StringSet dirs;
|
||||
of.puts("# User .cpp files (from .cpp's on Verilator command line)\n");
|
||||
of.puts("VM_USER_CLASSES = \\\n");
|
||||
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
|
||||
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
|
||||
string cppfile = *it;
|
||||
for (const auto& cppfile : cppFiles) {
|
||||
of.puts("\t" + V3Os::filenameNonExt(cppfile) + " \\\n");
|
||||
string dir = V3Os::filenameDir(cppfile);
|
||||
dirs.insert(dir);
|
||||
@@ -215,14 +216,16 @@ public:
|
||||
|
||||
of.puts("# User .cpp directories (from .cpp's on Verilator command line)\n");
|
||||
of.puts("VM_USER_DIR = \\\n");
|
||||
for (V3StringSet::iterator it = dirs.begin(); it != dirs.end(); ++it) {
|
||||
of.puts("\t" + *it + " \\\n");
|
||||
}
|
||||
for (const auto& i : dirs) of.puts("\t" + i + " \\\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("\n### Default rules...\n");
|
||||
of.puts("# Include list of all generated classes\n");
|
||||
of.puts("include " + v3Global.opt.prefix() + "_classes.mk\n");
|
||||
if (v3Global.opt.hierTop()) {
|
||||
of.puts("# Include rules for hierarchical blocks\n");
|
||||
of.puts("include " + v3Global.opt.prefix() + "_hier.mk\n");
|
||||
}
|
||||
of.puts("# Include global rules\n");
|
||||
of.puts("include $(VERILATOR_ROOT)/include/verilated.mk\n");
|
||||
|
||||
@@ -230,8 +233,7 @@ public:
|
||||
of.puts("\n### Executable rules... (from --exe)\n");
|
||||
of.puts("VPATH += $(VM_USER_DIR)\n");
|
||||
of.puts("\n");
|
||||
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
|
||||
string cppfile = *it;
|
||||
for (const string& cppfile : cppFiles) {
|
||||
string basename = V3Os::filenameNonExt(cppfile);
|
||||
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
||||
of.puts(basename + ".o: " + cppfile + "\n");
|
||||
@@ -240,24 +242,39 @@ public:
|
||||
|
||||
of.puts("\n### Link rules... (from --exe)\n");
|
||||
of.puts(v3Global.opt.exeName()
|
||||
+ ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n");
|
||||
+ ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a $(VM_HIER_LIBS)\n");
|
||||
of.puts("\t$(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) $(LIBS) $(SC_LIBS) -o $@\n");
|
||||
of.puts("\n");
|
||||
}
|
||||
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
const string protectLibDeps
|
||||
= "$(VK_OBJS) $(VK_GLOBAL_OBJS) " + v3Global.opt.protectLib() + ".o";
|
||||
const string protectLibDeps = "$(VK_OBJS) $(VK_GLOBAL_OBJS) "
|
||||
+ v3Global.opt.protectLib() + ".o $(VM_HIER_LIBS)";
|
||||
of.puts("\n### Library rules from --protect-lib\n");
|
||||
// The rule to create .a is defined in verilated.mk, so just define dependency here.
|
||||
of.puts(v3Global.opt.protectLibName(false) + ": " + protectLibDeps + "\n");
|
||||
of.puts("\tar rc $@ $^\n");
|
||||
of.puts("\n");
|
||||
of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("lib" + v3Global.opt.protectLib() + ": " + v3Global.opt.protectLibName(false)
|
||||
+ " " + v3Global.opt.protectLibName(true) + "\n");
|
||||
if (v3Global.opt.hierChild()) {
|
||||
// Hierarchical child does not need .so because hierTop() will create .so from .a
|
||||
of.puts("lib" + v3Global.opt.protectLib() + ": "
|
||||
+ v3Global.opt.protectLibName(false) + "\n");
|
||||
} else {
|
||||
of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n");
|
||||
// Linker on mac emits an error if all symbols are not found here,
|
||||
// but some symbols that are referred as "DPI-C" can not be found at this moment.
|
||||
// So add dynamic_lookup
|
||||
of.puts("ifeq ($(shell uname -s),Darwin)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -undefined "
|
||||
"dynamic_lookup -shared -flat_namespace -o $@ $^\n");
|
||||
of.puts("else\n");
|
||||
of.puts(
|
||||
"\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n");
|
||||
of.puts("endif\n");
|
||||
of.puts("\n");
|
||||
of.puts("lib" + v3Global.opt.protectLib() + ": "
|
||||
+ v3Global.opt.protectLibName(false) + " "
|
||||
+ v3Global.opt.protectLibName(true) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
of.puts("\n");
|
||||
@@ -272,6 +289,131 @@ public:
|
||||
virtual ~EmitMk() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
class EmitMkHierVerilation {
|
||||
const V3HierBlockPlan* const m_planp;
|
||||
const string m_makefile; // path of this makefile
|
||||
void emitCommonOpts(V3OutMkFile& of) const {
|
||||
const string cwd = V3Os::filenameRealPath(".");
|
||||
of.puts("# Verilation of hierarchical blocks are executed in this directory\n");
|
||||
of.puts("VM_HIER_RUN_DIR := " + cwd + "\n");
|
||||
of.puts("# Common options for hierarchical blocks\n");
|
||||
const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.bin());
|
||||
const string perl_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
|
||||
of.puts("VM_HIER_VERILATOR := " + perl_wrapper + "\n");
|
||||
of.puts("VM_HIER_INPUT_FILES := \\\n");
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) of.puts("\t" + V3Os::filenameRealPath(i) + " \\\n");
|
||||
of.puts("\n");
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
of.puts("VM_HIER_VERILOG_LIBS := \\\n");
|
||||
for (const string& i : libraryFiles) {
|
||||
of.puts("\t" + V3Os::filenameRealPath(i) + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
}
|
||||
void emitOpts(V3OutMkFile& of, const V3StringList& opts) const {
|
||||
for (const string& i : opts) { of.puts("\t\t" + i + " \\\n"); }
|
||||
}
|
||||
void emitLaunchVerilator(V3OutMkFile& of, const string& argsFile) const {
|
||||
of.puts("\t@$(MAKE) -C $(VM_HIER_RUN_DIR) -f " + m_makefile
|
||||
+ " hier_launch_verilator \\\n");
|
||||
of.puts("\t\tVM_HIER_LAUNCH_VERILATOR_ARGSFILE=\"" + argsFile + "\"\n");
|
||||
}
|
||||
void emit(V3OutMkFile& of) const {
|
||||
of.puts("# Hierarchical Verilation -*- Makefile -*-\n");
|
||||
of.puts("# DESCR"
|
||||
"IPTION: Verilator output: Makefile for hierarchical verilatrion\n");
|
||||
of.puts("#\n");
|
||||
of.puts("# The main makefile " + v3Global.opt.prefix() + ".mk calls this makefile\n");
|
||||
of.puts("\n");
|
||||
of.puts("ifndef VM_HIER_VERILATION_INCLUDED\n");
|
||||
of.puts("VM_HIER_VERILATION_INCLUDED = 1\n\n");
|
||||
|
||||
of.puts(".SUFFIXES:\n");
|
||||
of.puts(".PHONY: hier_build hier_verilation hier_launch_verilator\n");
|
||||
|
||||
of.puts("# Libraries of hierarchical blocks\n");
|
||||
of.puts("VM_HIER_LIBS := \\\n");
|
||||
const V3HierBlockPlan::HierVector blocks
|
||||
= m_planp->hierBlocksSorted(); // leaf comes first
|
||||
// List in order of leaf-last order so that linker can resolve dependency
|
||||
for (auto it = blocks.rbegin(); it != blocks.rend(); ++it) {
|
||||
of.puts("\t" + (*it)->hierLib(true) + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
|
||||
// Build hierarchical libraries as soon as possible to get maximum parallelism
|
||||
of.puts("hier_build: $(VM_HIER_LIBS) " + v3Global.opt.prefix() + ".mk\n");
|
||||
of.puts("\t$(MAKE) -f " + v3Global.opt.prefix() + ".mk\n");
|
||||
of.puts("hier_verilation: " + v3Global.opt.prefix() + ".mk\n");
|
||||
emitCommonOpts(of);
|
||||
|
||||
// Instead of direct execute of "cd $(VM_HIER_RUN_DIR) && $(VM_HIER_VERILATOR)",
|
||||
// call via make to get message of "Entering directory" and "Leaving directory".
|
||||
// This will make some editors and IDEs happy when viewing a logfile.
|
||||
of.puts("# VM_HIER_LAUNCH_VERILATOR_ARGSFILE must be passed as a command argument\n");
|
||||
of.puts("hier_launch_verilator:\n");
|
||||
of.puts("\t$(VM_HIER_VERILATOR) -f $(VM_HIER_LAUNCH_VERILATOR_ARGSFILE)\n");
|
||||
|
||||
// Top level module
|
||||
{
|
||||
const string argsFile = v3Global.hierPlanp()->topCommandArgsFileName(false);
|
||||
of.puts("\n# Verilate the top module\n");
|
||||
of.puts(v3Global.opt.prefix()
|
||||
+ ".mk: $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
|
||||
of.puts(V3Os::filenameNonDir(argsFile) + " ");
|
||||
for (V3HierBlockPlan::const_iterator it = m_planp->begin(); it != m_planp->end();
|
||||
++it) {
|
||||
of.puts(it->second->hierWrapper(true) + " ");
|
||||
}
|
||||
of.puts("\n");
|
||||
emitLaunchVerilator(of, argsFile);
|
||||
}
|
||||
|
||||
// Rules to process hierarchical blocks
|
||||
of.puts("\n# Verilate hierarchical blocks\n");
|
||||
for (V3HierBlockPlan::const_iterator it = m_planp->begin(); it != m_planp->end(); ++it) {
|
||||
const string prefix = it->second->hierPrefix();
|
||||
const string argsFile = it->second->commandArgsFileName(false);
|
||||
of.puts(it->second->hierGenerated(true));
|
||||
of.puts(": $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
|
||||
of.puts(V3Os::filenameNonDir(argsFile) + " ");
|
||||
const V3HierBlock::HierBlockSet& children = it->second->children();
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
of.puts((*child)->hierWrapper(true) + " ");
|
||||
}
|
||||
of.puts("\n");
|
||||
emitLaunchVerilator(of, argsFile);
|
||||
|
||||
// Rule to build lib*.a
|
||||
of.puts(it->second->hierLib(true));
|
||||
of.puts(": ");
|
||||
of.puts(it->second->hierMk(true));
|
||||
of.puts(" ");
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
of.puts((*child)->hierLib(true));
|
||||
of.puts(" ");
|
||||
}
|
||||
of.puts("\n\t$(MAKE) -f " + it->second->hierMk(false) + " -C " + prefix);
|
||||
of.puts(" VM_PREFIX=" + prefix);
|
||||
of.puts("\n\n");
|
||||
}
|
||||
of.puts("endif # Guard\n");
|
||||
}
|
||||
|
||||
public:
|
||||
explicit EmitMkHierVerilation(const V3HierBlockPlan* planp)
|
||||
: m_planp{planp}
|
||||
, m_makefile{v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_hier.mk"} {
|
||||
V3OutMkFile of(m_makefile);
|
||||
emit(of);
|
||||
}
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Gate class functions
|
||||
|
||||
@@ -279,3 +421,8 @@ void V3EmitMk::emitmk() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
EmitMk emitter;
|
||||
}
|
||||
|
||||
void V3EmitMk::emitHierVerilation(const V3HierBlockPlan* planp) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
EmitMkHierVerilation emitter(planp);
|
||||
}
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
class V3HierBlockPlan;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3EmitMk {
|
||||
public:
|
||||
static void emitmk();
|
||||
static void emitHierVerilation(const V3HierBlockPlan* planp);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+165
-161
@@ -30,8 +30,9 @@
|
||||
|
||||
class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
// MEMBERS
|
||||
bool m_suppressSemi;
|
||||
AstSenTree* m_sensesp;
|
||||
bool m_suppressSemi = false;
|
||||
bool m_suppressUnknown = false;
|
||||
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -51,13 +52,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); }
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPort* nodep) override {}
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
putfs(nodep, nodep->isFunction() ? "function" : "task");
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
@@ -68,7 +70,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBegin* nodep) override {
|
||||
if (nodep->name() == "") {
|
||||
putbs("begin\n");
|
||||
} else {
|
||||
@@ -77,7 +79,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateChildren(nodep);
|
||||
puts("end\n");
|
||||
}
|
||||
virtual void visit(AstFork* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFork* nodep) override {
|
||||
if (nodep->name() == "") {
|
||||
putbs("fork\n");
|
||||
} else {
|
||||
@@ -87,17 +89,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts(nodep->joinType().verilogKwd());
|
||||
puts("\n");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFinal* nodep) override {
|
||||
putfs(nodep, "final begin\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstInitial* nodep) override {
|
||||
putfs(nodep, "initial begin\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
putfs(nodep, "always ");
|
||||
if (m_sensesp) {
|
||||
iterateAndNextNull(m_sensesp);
|
||||
@@ -109,7 +111,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlwaysPublic* nodep) override {
|
||||
putfs(nodep, "/*verilator public_flat_rw ");
|
||||
if (m_sensesp) {
|
||||
iterateAndNextNull(m_sensesp);
|
||||
@@ -121,37 +123,37 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "*/\n");
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " " + nodep->verilogKwd() + " ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignDly* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " <= ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignAlias* nodep) override {
|
||||
putbs("alias ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " = ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignW* nodep) override {
|
||||
putfs(nodep, "assign ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putbs(" = ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBreak*) override {
|
||||
putbs("break");
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenTree* nodep) override {
|
||||
// AstSenItem is called for dumping in isolation by V3Order
|
||||
putfs(nodep, "@(");
|
||||
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
|
||||
@@ -160,16 +162,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
putfs(nodep, "");
|
||||
puts(nodep->edgeType().verilogKwd());
|
||||
if (nodep->sensp()) puts(" ");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCase* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (const AstCase* casep = VN_CAST(nodep, Case)) {
|
||||
if (casep->priorityPragma()) puts("priority ");
|
||||
@@ -190,7 +189,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->itemsp());
|
||||
putqs(nodep, "endcase\n");
|
||||
}
|
||||
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCaseItem* nodep) override {
|
||||
if (nodep->condsp()) {
|
||||
iterateAndNextNull(nodep->condsp());
|
||||
} else {
|
||||
@@ -200,118 +199,116 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstComment* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstComment* nodep) override {
|
||||
puts(string("// ") + nodep->name() + "\n");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstContinue*) override {
|
||||
putbs("continue");
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstCoverDecl*) VL_OVERRIDE {} // N/A
|
||||
virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A
|
||||
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A
|
||||
virtual void visit(AstCoverDecl*) override {} // N/A
|
||||
virtual void visit(AstCoverInc*) override {} // N/A
|
||||
virtual void visit(AstCoverToggle*) override {} // N/A
|
||||
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
|
||||
AstNode* exprsp) {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (fileOrStrgp) {
|
||||
iterateAndNextNull(fileOrStrgp);
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
}
|
||||
putsQuoted(text);
|
||||
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
|
||||
puts(",");
|
||||
puts(", ");
|
||||
iterateAndNextNull(expp);
|
||||
}
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
|
||||
putbs("disable " + nodep->name() + ";\n");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); }
|
||||
virtual void visit(AstDisplay* nodep) override {
|
||||
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, NULL, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
virtual void visit(AstElabDisplay* nodep) override {
|
||||
visitNodeDisplay(nodep, nullptr, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFScanF* nodep) override {
|
||||
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstSScanF* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSScanF* nodep) override {
|
||||
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSFormat* nodep) override {
|
||||
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
|
||||
virtual void visit(AstSFormatF* nodep) override {
|
||||
visitNodeDisplay(nodep, nullptr, nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFOpen* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->modep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFOpenMcd* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFOpenMcd* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFClose* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFClose* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFFlush* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFFlush* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstJumpBlock* nodep) override {
|
||||
putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n");
|
||||
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
|
||||
puts("end\n");
|
||||
}
|
||||
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstJumpGo* nodep) override {
|
||||
putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
|
||||
}
|
||||
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstJumpLabel* nodep) override {
|
||||
putbs("// " + cvtToStr(nodep->blockp()) + ":\n");
|
||||
}
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
if (nodep->memp()) iterateAndNextNull(nodep->memp());
|
||||
if (nodep->lsbp()) {
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
}
|
||||
if (nodep->msbp()) {
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->msbp());
|
||||
}
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSysFuncAsTask* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSysIgnore* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeFor* nodep) override {
|
||||
putfs(nodep, "for (");
|
||||
m_suppressSemi = true;
|
||||
iterateAndNextNull(nodep->initsp());
|
||||
@@ -324,14 +321,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRepeat* nodep) override {
|
||||
putfs(nodep, "repeat (");
|
||||
iterateAndNextNull(nodep->countp());
|
||||
puts(") begin\n");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putfs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstWhile* nodep) override {
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
putfs(nodep, "while (");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
@@ -341,7 +338,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
putfs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeIf* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (const AstIf* ifp = VN_CAST(nodep, If)) {
|
||||
if (ifp->priorityPragma()) puts("priority ");
|
||||
@@ -359,62 +356,62 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPast* nodep) override {
|
||||
putfs(nodep, "$past(");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
if (nodep->ticksp()) {
|
||||
puts(",");
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->ticksp());
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstReturn* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstReturn* nodep) override {
|
||||
putfs(nodep, "return ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstStop* nodep) VL_OVERRIDE { putfs(nodep, "$stop;\n"); }
|
||||
virtual void visit(AstFinish* nodep) VL_OVERRIDE { putfs(nodep, "$finish;\n"); }
|
||||
virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); }
|
||||
virtual void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); }
|
||||
virtual void visit(AstNodeSimpleText* nodep) override {
|
||||
if (nodep->tracking() || m_trackText) {
|
||||
puts(nodep->text());
|
||||
} else {
|
||||
putsNoTracking(nodep->text());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTextBlock* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTextBlock* nodep) override {
|
||||
visit(VN_CAST(nodep, NodeSimpleText));
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterate(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstCStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScopeName* nodep) override {}
|
||||
virtual void visit(AstCStmt* nodep) override {
|
||||
putfs(nodep, "$_CSTMT(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstCMath* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCMath* nodep) override {
|
||||
putfs(nodep, "$_CMATH(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUCStmt* nodep) override {
|
||||
putfs(nodep, "$c(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstUCFunc* nodep) override {
|
||||
putfs(nodep, "$c(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
puts(")");
|
||||
}
|
||||
|
||||
// Operators
|
||||
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = NULL,
|
||||
AstNode* rhsp = NULL, AstNode* thsp = NULL,
|
||||
AstNode* fhsp = NULL) {
|
||||
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr,
|
||||
AstNode* rhsp = nullptr, AstNode* thsp = nullptr,
|
||||
AstNode* fhsp = nullptr) {
|
||||
// Look at emitVerilog() format for term/uni/dual/triops,
|
||||
// and write out appropriate text.
|
||||
// %f Potential fileline-if-change and line break
|
||||
@@ -426,16 +423,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
// %k Potential line break
|
||||
bool inPct = false;
|
||||
putbs("");
|
||||
for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
|
||||
if (pos[0] == '%') {
|
||||
for (const char c : format) {
|
||||
if (c == '%') {
|
||||
inPct = true;
|
||||
} else if (!inPct) { // Normal text
|
||||
string s;
|
||||
s += pos[0];
|
||||
s += c;
|
||||
puts(s);
|
||||
} else { // Format character
|
||||
inPct = false;
|
||||
switch (*pos) {
|
||||
switch (c) {
|
||||
case '%': puts("%"); break;
|
||||
case 'f': putfs(nodep, ""); break;
|
||||
case 'k': putbs(""); break;
|
||||
@@ -464,35 +461,35 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->dtypep());
|
||||
break;
|
||||
}
|
||||
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << pos[0]); break;
|
||||
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << c); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeTermop* nodep) override {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog());
|
||||
}
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeUniop* nodep) override {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeBiop* nodep) override {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeTriop* nodep) override {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(),
|
||||
nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAttrOf* nodep) override {
|
||||
putfs(nodep, "$_ATTROF(");
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
if (nodep->dimp()) {
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->dimp());
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstInitArray* nodep) override {
|
||||
putfs(nodep, "`{");
|
||||
int comma = 0;
|
||||
const AstInitArray::KeyItemMap& mapr = nodep->map();
|
||||
@@ -505,7 +502,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCond* nodep) override {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
putfs(nodep, " ? ");
|
||||
@@ -514,7 +511,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->expr2p());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstRange* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRange* nodep) override {
|
||||
puts("[");
|
||||
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
|
||||
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
|
||||
@@ -529,7 +526,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts("]");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
puts("[");
|
||||
if (VN_IS(nodep->lsbp(), Const)) {
|
||||
@@ -553,18 +550,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
puts("]");
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSliceSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
puts(cvtToStr(nodep->declRange()));
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTypedef* nodep) override {
|
||||
putfs(nodep, "typedef ");
|
||||
iterateAndNextNull(nodep->dtypep());
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBasicDType* nodep) override {
|
||||
if (nodep->isSigned()) putfs(nodep, "signed ");
|
||||
putfs(nodep, nodep->prettyName());
|
||||
if (nodep->rangep()) {
|
||||
@@ -577,28 +574,28 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts(":0] ");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConstDType* nodep) override {
|
||||
putfs(nodep, "const ");
|
||||
iterate(nodep->subDTypep());
|
||||
}
|
||||
virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeArrayDType* nodep) override {
|
||||
iterate(nodep->subDTypep());
|
||||
iterateAndNextNull(nodep->rangep());
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) override {
|
||||
puts(nodep->verilogKwd() + " ");
|
||||
if (nodep->packed()) puts("packed ");
|
||||
puts("\n");
|
||||
iterateAndNextNull(nodep->membersp());
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstMemberDType* nodep) override {
|
||||
iterate(nodep->subDTypep());
|
||||
puts(" ");
|
||||
puts(nodep->name());
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeFTaskRef* nodep) override {
|
||||
if (nodep->dotted() != "") {
|
||||
putfs(nodep, nodep->dotted());
|
||||
puts(".");
|
||||
@@ -610,9 +607,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(nodep->pinsp());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstArg* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->exprp()); }
|
||||
virtual void visit(AstArg* nodep) override { iterateAndNextNull(nodep->exprp()); }
|
||||
// Terminals
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (nodep->varScopep()) {
|
||||
putfs(nodep, nodep->varScopep()->prettyName());
|
||||
} else {
|
||||
@@ -620,19 +617,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts(nodep->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarXRef* nodep) override {
|
||||
putfs(nodep, nodep->dotted());
|
||||
puts(".");
|
||||
puts(nodep->varp()->prettyName());
|
||||
}
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->num().ascii(true, true));
|
||||
}
|
||||
virtual void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); }
|
||||
|
||||
// Just iterate
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstScope* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
puts(" ");
|
||||
iterate(nodep->dtypep());
|
||||
@@ -644,35 +639,35 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts("\n");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
m_sensesp = nodep->sensesp();
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
m_sensesp = NULL;
|
||||
m_sensesp = nullptr;
|
||||
}
|
||||
virtual void visit(AstVarScope*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeText*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
|
||||
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
|
||||
virtual void visit(AstVarScope*) override {}
|
||||
virtual void visit(AstNodeText*) override {}
|
||||
virtual void visit(AstTraceDecl*) override {}
|
||||
virtual void visit(AstTraceInc*) override {}
|
||||
// NOPs
|
||||
virtual void visit(AstPragma*) VL_OVERRIDE {}
|
||||
virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class
|
||||
virtual void visit(AstPragma*) override {}
|
||||
virtual void visit(AstCell*) override {} // Handled outside the Visit class
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
|
||||
iterateChildren(nodep);
|
||||
// Not v3fatalSrc so we keep processing
|
||||
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
if (!m_suppressUnknown) {
|
||||
nodep->v3error(
|
||||
"Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(AstSenTree* domainp = NULL) {
|
||||
// Domain for printing one a ALWAYS under a ACTIVE
|
||||
m_suppressSemi = false;
|
||||
m_suppressVarSemi = false;
|
||||
m_sensesp = domainp;
|
||||
}
|
||||
virtual ~EmitVBaseVisitor() {}
|
||||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
|
||||
: m_suppressUnknown{suppressUnknown}
|
||||
, m_sensesp{domainp} {}
|
||||
virtual ~EmitVBaseVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -683,21 +678,22 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
|
||||
V3OutFile* m_ofp;
|
||||
// METHODS
|
||||
V3OutFile* ofp() const { return m_ofp; }
|
||||
virtual void puts(const string& str) { ofp()->puts(str); }
|
||||
virtual void putbs(const string& str) { ofp()->putbs(str); }
|
||||
virtual void putfs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
|
||||
virtual void puts(const string& str) override { ofp()->puts(str); }
|
||||
virtual void putbs(const string& str) override { ofp()->putbs(str); }
|
||||
virtual void putfs(AstNode*, const string& str) override { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||
virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
|
||||
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
|
||||
bool suppressVarSemi = false) {
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressVarSemi,
|
||||
bool suppressUnknown)
|
||||
: EmitVBaseVisitor{suppressUnknown, nullptr} {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
m_suppressVarSemi = suppressVarSemi;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitVFileVisitor() {}
|
||||
virtual ~EmitVFileVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -707,18 +703,19 @@ class EmitVStreamVisitor : public EmitVBaseVisitor {
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
// METHODS
|
||||
virtual void putsNoTracking(const string& str) { m_os << str; }
|
||||
virtual void puts(const string& str) { putsNoTracking(str); }
|
||||
virtual void putbs(const string& str) { puts(str); }
|
||||
virtual void putfs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putsNoTracking(const string& str) override { m_os << str; }
|
||||
virtual void puts(const string& str) override { putsNoTracking(str); }
|
||||
virtual void putbs(const string& str) override { puts(str); }
|
||||
virtual void putfs(AstNode*, const string& str) override { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||
|
||||
public:
|
||||
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
|
||||
: m_os(os) {
|
||||
: EmitVBaseVisitor{false, nullptr}
|
||||
, m_os(os) { // Need () or GCC 4.8 false warning
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitVStreamVisitor() {}
|
||||
virtual ~EmitVStreamVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -731,7 +728,7 @@ class EmitVPrefixedFormatter : public V3OutFormatter {
|
||||
int m_column; // Rough location; need just zero or non-zero
|
||||
FileLine* m_prefixFl;
|
||||
// METHODS
|
||||
virtual void putcOutput(char chr) {
|
||||
virtual void putcOutput(char chr) override {
|
||||
if (chr == '\n') {
|
||||
m_column = 0;
|
||||
m_os << chr;
|
||||
@@ -753,15 +750,15 @@ public:
|
||||
FileLine* prefixFl() const { return m_prefixFl; }
|
||||
int column() const { return m_column; }
|
||||
EmitVPrefixedFormatter(std::ostream& os, const string& prefix, int flWidth)
|
||||
: V3OutFormatter("__STREAM", V3OutFormatter::LA_VERILOG)
|
||||
, m_os(os)
|
||||
, m_prefix(prefix)
|
||||
, m_flWidth(flWidth) {
|
||||
: V3OutFormatter{"__STREAM", V3OutFormatter::LA_VERILOG}
|
||||
, m_os(os) // Need () or GCC 4.8 false warning
|
||||
, m_prefix{prefix}
|
||||
, m_flWidth{flWidth} {
|
||||
m_column = 0;
|
||||
m_prefixFl = v3Global.rootp()
|
||||
->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
|
||||
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
|
||||
// avoid nullptr checks
|
||||
}
|
||||
virtual ~EmitVPrefixedFormatter() {
|
||||
virtual ~EmitVPrefixedFormatter() override {
|
||||
if (m_column) puts("\n");
|
||||
}
|
||||
};
|
||||
@@ -771,13 +768,13 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
|
||||
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the
|
||||
// inheritance is another unused V3OutFormatter)
|
||||
// METHODS
|
||||
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
|
||||
virtual void puts(const string& str) { m_formatter.puts(str); }
|
||||
virtual void putsNoTracking(const string& str) override { m_formatter.putsNoTracking(str); }
|
||||
virtual void puts(const string& str) override { m_formatter.puts(str); }
|
||||
// We don't use m_formatter's putbs because the tokens will change filelines
|
||||
// and insert returns at the proper locations
|
||||
virtual void putbs(const string& str) { m_formatter.puts(str); }
|
||||
virtual void putfs(AstNode* nodep, const string& str) { putfsqs(nodep, str, false); }
|
||||
virtual void putqs(AstNode* nodep, const string& str) { putfsqs(nodep, str, true); }
|
||||
virtual void putbs(const string& str) override { m_formatter.puts(str); }
|
||||
virtual void putfs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, false); }
|
||||
virtual void putqs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, true); }
|
||||
void putfsqs(AstNode* nodep, const string& str, bool quiet) {
|
||||
if (m_formatter.prefixFl() != nodep->fileline()) {
|
||||
m_formatter.prefixFl(nodep->fileline());
|
||||
@@ -790,12 +787,12 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
|
||||
public:
|
||||
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
|
||||
AstSenTree* domainp, bool user3mark)
|
||||
: EmitVBaseVisitor(domainp)
|
||||
, m_formatter(os, prefix, flWidth) {
|
||||
: EmitVBaseVisitor{false, domainp}
|
||||
, m_formatter{os, prefix, flWidth} {
|
||||
if (user3mark) { AstUser3InUse::check(); }
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitVPrefixedVisitor() {}
|
||||
virtual ~EmitVPrefixedVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -817,7 +814,14 @@ void V3EmitV::emitvFiles() {
|
||||
V3OutVFile of(vfilep->name());
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated Verilog\n");
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3EmitV::debugEmitV(const string& stage) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
|
||||
V3OutVFile of(filename);
|
||||
EmitVFileVisitor visitor(v3Global.rootp(), &of, true, false, true);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
|
||||
int flWidth, AstSenTree* domainp, bool user3mark);
|
||||
static void emitvFiles();
|
||||
static void debugEmitV(const string& stage);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+40
-45
@@ -35,7 +35,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
|
||||
// MEMBERS
|
||||
V3OutFile* m_ofp;
|
||||
uint64_t m_id;
|
||||
uint64_t m_id = 0;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -100,11 +100,11 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignW* nodep) override {
|
||||
outputTag(nodep, "contassign"); // IEEE: vpiContAssign
|
||||
outputChildrenEnd(nodep, "contassign");
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
outputTag(nodep, "instance"); // IEEE: vpiInstance
|
||||
puts(" defName=");
|
||||
putsQuoted(nodep->modName()); // IEEE vpiDefName
|
||||
@@ -112,12 +112,12 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
putsQuoted(nodep->origName());
|
||||
outputChildrenEnd(nodep, "instance");
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
puts("<netlist>\n");
|
||||
iterateChildren(nodep);
|
||||
puts("</netlist>\n");
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" origName=");
|
||||
putsQuoted(nodep->origName());
|
||||
@@ -127,7 +127,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
if (nodep->modPublic()) puts(" public=\"true\"");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
AstVarType typ = nodep->varType();
|
||||
string kw = nodep->verilogKwd();
|
||||
string vt = nodep->dtypep()->name();
|
||||
@@ -144,25 +144,26 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
puts(" origName=");
|
||||
putsQuoted(nodep->origName());
|
||||
// Attributes
|
||||
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES)
|
||||
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
||||
puts(" clocker=\"true\"");
|
||||
else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO)
|
||||
} else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO) {
|
||||
puts(" clocker=\"false\"");
|
||||
}
|
||||
if (nodep->attrClockEn()) puts(" clock_enable=\"true\"");
|
||||
if (nodep->attrIsolateAssign()) puts(" isolate_assignments=\"true\"");
|
||||
if (nodep->isSigPublic()) puts(" public=\"true\"");
|
||||
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
|
||||
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
|
||||
if (nodep->isGParam())
|
||||
if (nodep->isGParam()) {
|
||||
puts(" param=\"true\"");
|
||||
else if (nodep->isParam())
|
||||
} else if (nodep->isParam()) {
|
||||
puts(" localparam=\"true\"");
|
||||
}
|
||||
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
|
||||
if (nodep->attrScClocked()) puts(" sc_clock=\"true\"");
|
||||
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPin* nodep) override {
|
||||
// What we call a pin in verilator is a port in the IEEE spec.
|
||||
outputTag(nodep, "port"); // IEEE: vpiPort
|
||||
if (nodep->modVarp()->isIO()) {
|
||||
@@ -172,12 +173,12 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
||||
outputChildrenEnd(nodep, "port");
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstModportVarRef* nodep) override {
|
||||
// Dump direction for Modport references
|
||||
string kw = nodep->direction().xmlKwd();
|
||||
outputTag(nodep, "");
|
||||
@@ -185,7 +186,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
putsQuoted(kw);
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarXRef* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" dotted=");
|
||||
putsQuoted(nodep->dotted());
|
||||
@@ -193,7 +194,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
}
|
||||
|
||||
// Data types
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBasicDType* nodep) override {
|
||||
outputTag(nodep, "basicdtype");
|
||||
if (nodep->isRanged()) {
|
||||
puts(" left=\"" + cvtToStr(nodep->left()) + "\"");
|
||||
@@ -201,7 +202,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
}
|
||||
puts("/>\n");
|
||||
}
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstIfaceRefDType* nodep) override {
|
||||
string mpn;
|
||||
outputTag(nodep, "");
|
||||
if (nodep->isModport()) mpn = nodep->modportName();
|
||||
@@ -209,19 +210,19 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
putsQuoted(mpn);
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDisplay* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" displaytype=");
|
||||
putsQuoted(nodep->verilogKwd());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstElabDisplay* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" displaytype=");
|
||||
putsQuoted(nodep->verilogKwd());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstExtend* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" width=");
|
||||
putsQuoted(cvtToStr(nodep->width()));
|
||||
@@ -229,7 +230,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstExtendS* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstExtendS* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
puts(" width=");
|
||||
putsQuoted(cvtToStr(nodep->width()));
|
||||
@@ -239,18 +240,17 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
}
|
||||
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
outputTag(nodep, "");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
|
||||
public:
|
||||
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) {
|
||||
m_ofp = ofp;
|
||||
m_id = 0;
|
||||
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp)
|
||||
: m_ofp{ofp} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitXmlFileVisitor() {}
|
||||
virtual ~EmitXmlFileVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -267,11 +267,11 @@ private:
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// Children are iterated backwards to ensure correct compilation order
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// Only list modules and interfaces
|
||||
// Assumes modules and interfaces list is already sorted level wise
|
||||
if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
|
||||
@@ -280,28 +280,25 @@ private:
|
||||
}
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNode*) VL_OVERRIDE {
|
||||
virtual void visit(AstNode*) override {
|
||||
// All modules are present at root so no need to iterate on children
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
||||
: m_os(os)
|
||||
, m_modulesCovered()
|
||||
, m_nodeModules() {
|
||||
: m_os(os) { // Need () or GCC 4.8 false warning
|
||||
// Operate on whole netlist
|
||||
nodep->accept(*this);
|
||||
// Xml output
|
||||
m_os << "<module_files>\n";
|
||||
for (std::deque<FileLine*>::iterator it = m_nodeModules.begin(); it != m_nodeModules.end();
|
||||
++it) {
|
||||
m_os << "<file id=\"" << (*it)->filenameLetters() << "\" filename=\""
|
||||
<< (*it)->filename() << "\" language=\"" << (*it)->language().ascii() << "\"/>\n";
|
||||
for (const FileLine* ifp : m_nodeModules) {
|
||||
m_os << "<file id=\"" << ifp->filenameLetters() << "\" filename=\"" << ifp->filename()
|
||||
<< "\" language=\"" << ifp->language().ascii() << "\"/>\n";
|
||||
}
|
||||
m_os << "</module_files>\n";
|
||||
}
|
||||
virtual ~ModuleFilesXmlVisitor() {}
|
||||
virtual ~ModuleFilesXmlVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -312,13 +309,13 @@ private:
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
std::string m_hier;
|
||||
bool m_hasChildren;
|
||||
bool m_hasChildren = false;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
if (nodep->level() >= 0
|
||||
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
|
||||
m_os << "<cells>\n";
|
||||
@@ -337,7 +334,7 @@ private:
|
||||
m_os << "</cells>\n";
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
if (nodep->modp()->dead()) { return; }
|
||||
if (!m_hasChildren) m_os << ">\n";
|
||||
m_os << "<cell " << nodep->fileline()->xml() << " "
|
||||
@@ -357,18 +354,16 @@ private:
|
||||
m_hasChildren = true;
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
||||
: m_os(os)
|
||||
, m_hier("")
|
||||
, m_hasChildren(false) {
|
||||
: m_os(os) { // Need () or GCC 4.8 false warning
|
||||
// Operate on whole netlist
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~HierCellsXmlVisitor() {}
|
||||
virtual ~HierCellsXmlVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+4
-6
@@ -40,7 +40,7 @@ bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX];
|
||||
bool V3Error::s_describedWarnings = false;
|
||||
bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX];
|
||||
V3Error::MessagesSet V3Error::s_messages;
|
||||
V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
|
||||
V3Error::ErrorExitCb V3Error::s_errorExitCb = nullptr;
|
||||
|
||||
struct v3errorIniter {
|
||||
v3errorIniter() { V3Error::init(); }
|
||||
@@ -174,12 +174,10 @@ void V3Error::vlAbort() {
|
||||
// Global Functions
|
||||
|
||||
void V3Error::suppressThisWarning() {
|
||||
if (s_errorCode >= V3ErrorCode::EC_MIN) {
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1);
|
||||
V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1);
|
||||
#endif
|
||||
s_errorSuppressed = true;
|
||||
}
|
||||
s_errorSuppressed = true;
|
||||
}
|
||||
|
||||
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
|
||||
@@ -212,7 +210,7 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
||||
s_messages.insert(msg);
|
||||
if (!locationStr.empty()) {
|
||||
string locationMsg = warnMore() + locationStr + "\n";
|
||||
size_t pos = msg.find("\n");
|
||||
size_t pos = msg.find('\n');
|
||||
msg.insert(pos + 1, locationMsg);
|
||||
}
|
||||
// Output
|
||||
|
||||
+17
-11
@@ -35,7 +35,7 @@
|
||||
class V3ErrorCode {
|
||||
public:
|
||||
// clang-format off
|
||||
enum en {
|
||||
enum en: uint8_t {
|
||||
EC_MIN=0, // Keep first
|
||||
//
|
||||
EC_INFO, // General information out
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
EC_FATALSRC, // Kill the program, for internal source errors
|
||||
EC_ERROR, // General error out, can't suppress
|
||||
// Boolean information we track per-line, but aren't errors
|
||||
I_CELLDEFINE, // Inside cell define from `celldefine/`endcelldefine
|
||||
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
|
||||
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
|
||||
I_LINT, // All lint messages
|
||||
@@ -51,6 +52,7 @@ public:
|
||||
// Error codes:
|
||||
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
|
||||
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
|
||||
E_UNSUPPORTED, // Error: Unsupported (generally)
|
||||
E_TASKNSVAR, // Error: Task I/O not simple
|
||||
//
|
||||
// Warning codes:
|
||||
@@ -78,6 +80,7 @@ public:
|
||||
DEPRECATED, // Feature will be deprecated
|
||||
ENDLABEL, // End lable name mismatch
|
||||
GENCLK, // Generated Clock
|
||||
HIERBLOCK, // Ignored hierarchical block setting
|
||||
IFDEPTH, // If statements too deep
|
||||
IGNOREDRETURN, // Ignoring return value (function as task)
|
||||
IMPERFECTSCH, // Imperfect schedule (disabled by default)
|
||||
@@ -95,6 +98,7 @@ public:
|
||||
PINMISSING, // Cell pin not specified
|
||||
PINNOCONNECT, // Cell pin not connected
|
||||
PINCONNECTEMPTY,// Cell pin connected by name with empty reference
|
||||
PKGNODECL, // Error: Package/class needs to be predeclared
|
||||
PROCASSWIRE, // Procedural assignment on wire
|
||||
REALCVT, // Real conversion
|
||||
REDEFMACRO, // Redefining existing define macro
|
||||
@@ -126,13 +130,13 @@ public:
|
||||
// clang-format on
|
||||
enum en m_e;
|
||||
inline V3ErrorCode()
|
||||
: m_e(EC_MIN) {}
|
||||
: m_e{EC_MIN} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline V3ErrorCode(en _e)
|
||||
: m_e(_e) {}
|
||||
: m_e{_e} {}
|
||||
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
|
||||
explicit inline V3ErrorCode(int _e)
|
||||
: m_e(static_cast<en>(_e)) {}
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
// clang-format off
|
||||
@@ -140,9 +144,9 @@ public:
|
||||
// Leading spaces indicate it can't be disabled.
|
||||
" MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR",
|
||||
// Boolean
|
||||
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
||||
" I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
||||
// Errors
|
||||
"DETECTARRAY", "PORTSHORT", "TASKNSVAR",
|
||||
"DETECTARRAY", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN",
|
||||
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
|
||||
@@ -150,13 +154,13 @@ public:
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CLKDATA",
|
||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
|
||||
"DEFPARAM", "DECLFILENAME", "DEPRECATED",
|
||||
"ENDLABEL", "GENCLK",
|
||||
"ENDLABEL", "GENCLK", "HIERBLOCK",
|
||||
"IFDEPTH", "IGNOREDRETURN",
|
||||
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
|
||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
||||
"LITENDIAN", "MODDUP",
|
||||
"MULTIDRIVEN", "MULTITOP",
|
||||
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
|
||||
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PKGNODECL", "PROCASSWIRE",
|
||||
"REALCVT", "REDEFMACRO",
|
||||
"SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"TICKCOUNT", "TIMESCALEMOD",
|
||||
@@ -170,14 +174,16 @@ public:
|
||||
return names[m_e];
|
||||
}
|
||||
// Warnings that default to off
|
||||
bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); }
|
||||
bool defaultsOff() const {
|
||||
return (m_e == IMPERFECTSCH || m_e == I_CELLDEFINE || styleError());
|
||||
}
|
||||
// Warnings that warn about nasty side effects
|
||||
bool dangerous() const { return (m_e == COMBDLY); }
|
||||
// Warnings we'll present to the user as errors
|
||||
// Later -Werror- options may make more of these.
|
||||
bool pretendError() const {
|
||||
return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG
|
||||
|| m_e == IMPURE || m_e == PROCASSWIRE //
|
||||
|| m_e == IMPURE || m_e == PKGNODECL || m_e == PROCASSWIRE //
|
||||
|| m_e == TIMESCALEMOD); // Says IEEE
|
||||
}
|
||||
// Warnings to mention manual
|
||||
@@ -234,7 +240,7 @@ private:
|
||||
static MessagesSet s_messages; // What errors we've outputted
|
||||
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
|
||||
|
||||
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
|
||||
static constexpr unsigned MAX_ERRORS = 50; // Fatal after this may errors
|
||||
|
||||
V3Error() {
|
||||
std::cerr << ("Static class");
|
||||
|
||||
+34
-37
@@ -44,7 +44,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNode* m_stmtp; // Current statement
|
||||
AstNode* m_stmtp = nullptr; // Current statement
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -94,7 +94,7 @@ private:
|
||||
void fixCloneLvalue(AstNode* nodep) {
|
||||
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
|
||||
// but are now being used on the RHS of the assignment
|
||||
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->lvalue(false);
|
||||
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ);
|
||||
// Iterate
|
||||
if (nodep->op1p()) fixCloneLvalue(nodep->op1p());
|
||||
if (nodep->op2p()) fixCloneLvalue(nodep->op2p());
|
||||
@@ -206,8 +206,8 @@ private:
|
||||
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
|
||||
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
|
||||
if (rhsp->num().isFourState()) {
|
||||
rhsp->v3error( // LCOV_EXCL_LINE // impossible?
|
||||
"Unsupported: 4-state numbers in this context");
|
||||
rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible?
|
||||
"Unsupported: 4-state numbers in this context");
|
||||
}
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(
|
||||
@@ -292,7 +292,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstExtend* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isWide()) {
|
||||
@@ -318,7 +318,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSel* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
||||
@@ -341,7 +341,7 @@ private:
|
||||
AstNode* lowp = new AstShiftR(nodep->fileline(), lowwordp, newSelBitBit(nodep->lsbp()),
|
||||
nodep->width());
|
||||
// If > 1 bit, we might be crossing the word boundary
|
||||
AstNode* midp = NULL;
|
||||
AstNode* midp = nullptr;
|
||||
V3Number zero(nodep, longOrQuadWidth(nodep));
|
||||
if (nodep->widthConst() > 1) {
|
||||
AstNode* midwordp = // SEL(from,[1+wordnum])
|
||||
@@ -378,7 +378,7 @@ private:
|
||||
}
|
||||
}
|
||||
// If > 32 bits, we might be crossing the second word boundary
|
||||
AstNode* hip = NULL;
|
||||
AstNode* hip = nullptr;
|
||||
if (nodep->widthConst() > VL_EDATASIZE) {
|
||||
AstNode* hiwordp = // SEL(from,[2+wordnum])
|
||||
newWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
|
||||
@@ -600,7 +600,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConcat* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isWide()) {
|
||||
@@ -642,7 +642,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstReplicate* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isWide()) {
|
||||
@@ -705,16 +705,16 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void visit(AstChangeXor* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstChangeXor* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
UINFO(8, " Wordize ChangeXor " << nodep << endl);
|
||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
|
||||
newAstWordSelClone(nodep->rhsp(), w));
|
||||
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == nullptr) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
@@ -725,11 +725,11 @@ private:
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
|
||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
|
||||
newAstWordSelClone(nodep->rhsp(), w));
|
||||
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == nullptr) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
if (VN_IS(nodep, Neq)) {
|
||||
newp
|
||||
@@ -742,19 +742,19 @@ private:
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
|
||||
virtual void visit(AstNeq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
|
||||
virtual void visit(AstEq* nodep) override { visitEqNeq(nodep); }
|
||||
virtual void visit(AstNeq* nodep) override { visitEqNeq(nodep); }
|
||||
|
||||
virtual void visit(AstRedOr* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRedOr* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8, " Wordize REDOR " << nodep << endl);
|
||||
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == nullptr) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstNeq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
|
||||
@@ -769,13 +769,13 @@ private:
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRedAnd* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRedAnd* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8, " Wordize REDAND " << nodep << endl);
|
||||
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
if (w == nodep->lhsp()->widthWords() - 1) {
|
||||
@@ -787,7 +787,7 @@ private:
|
||||
// cppcheck-suppress memleak
|
||||
eqp);
|
||||
}
|
||||
newp = (newp == NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == nullptr) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstEq(
|
||||
nodep->fileline(),
|
||||
@@ -802,16 +802,16 @@ private:
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRedXor* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRedXor* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8, " Wordize REDXOR " << nodep << endl);
|
||||
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
|
||||
AstNode* newp = NULL;
|
||||
AstNode* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
newp = (newp == NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == nullptr) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstRedXor(nodep->fileline(), newp);
|
||||
UINFO(8, " Wordize REDXORnew " << newp << endl);
|
||||
@@ -821,7 +821,7 @@ private:
|
||||
// which the inlined function does nicely.
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeStmt* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
@@ -829,9 +829,9 @@ private:
|
||||
}
|
||||
m_stmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_stmtp = NULL;
|
||||
m_stmtp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
m_stmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
@@ -869,20 +869,17 @@ private:
|
||||
}
|
||||
// Cleanup common code
|
||||
if (did) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
m_stmtp = NULL;
|
||||
m_stmtp = nullptr;
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ExpandVisitor(AstNetlist* nodep) {
|
||||
m_stmtp = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ExpandVisitor() {}
|
||||
explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ExpandVisitor() override {}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
+61
-79
@@ -56,8 +56,8 @@
|
||||
|
||||
// If change this code, run a test with the below size set very small
|
||||
//#define INFILTER_IPC_BUFSIZ 16
|
||||
#define INFILTER_IPC_BUFSIZ (64 * 1024) // For debug, try this as a small number
|
||||
#define INFILTER_CACHE_MAX (64 * 1024) // Maximum bytes to cache if same file read twice
|
||||
constexpr int INFILTER_IPC_BUFSIZ = (64 * 1024); // For debug, try this as a small number
|
||||
constexpr int INFILTER_CACHE_MAX = (64 * 1024); // Maximum bytes to cache if same file read twice
|
||||
|
||||
//######################################################################
|
||||
// V3File Internal state
|
||||
@@ -72,9 +72,9 @@ class V3FileDependImp {
|
||||
struct stat m_stat; // Stat information
|
||||
public:
|
||||
DependFile(const string& filename, bool target)
|
||||
: m_target(target)
|
||||
, m_exists(true)
|
||||
, m_filename(filename) {
|
||||
: m_target{target}
|
||||
, m_exists{true}
|
||||
, m_filename{filename} {
|
||||
m_stat.st_ctime = 0;
|
||||
m_stat.st_mtime = 0;
|
||||
}
|
||||
@@ -146,29 +146,26 @@ V3FileDependImp dependImp; // Depend implementation class
|
||||
// V3FileDependImp
|
||||
|
||||
inline void V3FileDependImp::writeDepend(const string& filename) {
|
||||
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatal("Can't write " << filename);
|
||||
|
||||
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
|
||||
iter != m_filenameList.end(); ++iter) {
|
||||
if (iter->target()) { *ofp << iter->filename() << " "; }
|
||||
for (const DependFile& i : m_filenameList) {
|
||||
if (i.target()) *ofp << i.filename() << " ";
|
||||
}
|
||||
*ofp << " : ";
|
||||
*ofp << v3Global.opt.bin();
|
||||
*ofp << " ";
|
||||
|
||||
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
|
||||
iter != m_filenameList.end(); ++iter) {
|
||||
if (!iter->target()) { *ofp << iter->filename() << " "; }
|
||||
for (const DependFile& i : m_filenameList) {
|
||||
if (!i.target()) *ofp << i.filename() << " ";
|
||||
}
|
||||
|
||||
*ofp << endl;
|
||||
|
||||
if (v3Global.opt.makePhony()) {
|
||||
*ofp << endl;
|
||||
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
|
||||
iter != m_filenameList.end(); ++iter) {
|
||||
if (!iter->target()) { *ofp << iter->filename() << ":" << endl; }
|
||||
for (const DependFile& i : m_filenameList) {
|
||||
if (!i.target()) *ofp << i.filename() << ":" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,7 +180,7 @@ inline std::vector<string> V3FileDependImp::getAllDeps() const {
|
||||
}
|
||||
|
||||
inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) {
|
||||
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatal("Can't write " << filename);
|
||||
|
||||
string cmdline = stripQuotes(cmdlineIn);
|
||||
@@ -219,7 +216,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
|
||||
}
|
||||
|
||||
inline bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) {
|
||||
const vl_unique_ptr<std::ifstream> ifp(V3File::new_ifstream_nodepend(filename));
|
||||
const std::unique_ptr<std::ifstream> ifp(V3File::new_ifstream_nodepend(filename));
|
||||
if (ifp->fail()) {
|
||||
UINFO(2, " --check-times failed: no input " << filename << endl);
|
||||
return false;
|
||||
@@ -326,6 +323,7 @@ void V3File::createMakeDir() {
|
||||
if (!created) {
|
||||
created = true;
|
||||
V3Os::createDir(v3Global.opt.makeDir());
|
||||
if (v3Global.opt.hierTop()) { V3Os::createDir(v3Global.opt.hierTopDataDir()); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,16 +335,16 @@ class VInFilterImp {
|
||||
typedef VInFilter::StrList StrList;
|
||||
|
||||
FileContentsMap m_contentsMap; // Cache of file contents
|
||||
bool m_readEof; // Received EOF on read
|
||||
bool m_readEof = false; // Received EOF on read
|
||||
#ifdef INFILTER_PIPE
|
||||
pid_t m_pid; // fork() process id
|
||||
pid_t m_pid = 0; // fork() process id
|
||||
#else
|
||||
int m_pid; // fork() process id - always zero as disabled
|
||||
int m_pid = 0; // fork() process id - always zero as disabled
|
||||
#endif
|
||||
bool m_pidExited;
|
||||
int m_pidStatus;
|
||||
int m_writeFd; // File descriptor TO filter
|
||||
int m_readFd; // File descriptor FROM filter
|
||||
bool m_pidExited = false;
|
||||
int m_pidStatus = 0;
|
||||
int m_writeFd = 0; // File descriptor TO filter
|
||||
int m_readFd = 0; // File descriptor FROM filter
|
||||
|
||||
private:
|
||||
// METHODS
|
||||
@@ -522,7 +520,7 @@ private:
|
||||
dup2(fd_stdout[P_WR], 1);
|
||||
// And stderr comes from parent
|
||||
|
||||
execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char*>(NULL));
|
||||
execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char*>(nullptr));
|
||||
// Don't use v3fatal, we don't share the common structures any more
|
||||
fprintf(stderr, "--pipe-filter: exec failed: %s\n", strerror(errno));
|
||||
_exit(1);
|
||||
@@ -575,7 +573,7 @@ protected:
|
||||
friend class VInFilter;
|
||||
// Read file contents and return it
|
||||
bool readWholefile(const string& filename, StrList& outl) {
|
||||
FileContentsMap::iterator it = m_contentsMap.find(filename);
|
||||
const auto it = m_contentsMap.find(filename);
|
||||
if (it != m_contentsMap.end()) {
|
||||
outl.push_back(it->second);
|
||||
return true;
|
||||
@@ -591,24 +589,16 @@ protected:
|
||||
}
|
||||
size_t listSize(StrList& sl) {
|
||||
size_t out = 0;
|
||||
for (StrList::iterator it = sl.begin(); it != sl.end(); ++it) out += it->length();
|
||||
for (const string& i : sl) out += i.length();
|
||||
return out;
|
||||
}
|
||||
string listString(StrList& sl) {
|
||||
string out;
|
||||
for (StrList::iterator it = sl.begin(); it != sl.end(); ++it) out += *it;
|
||||
for (const string& i : sl) out += i;
|
||||
return out;
|
||||
}
|
||||
// CONSTRUCTORS
|
||||
explicit VInFilterImp(const string& command) {
|
||||
m_readEof = false;
|
||||
m_pid = 0;
|
||||
m_pidExited = false;
|
||||
m_pidStatus = 0;
|
||||
m_writeFd = 0;
|
||||
m_readFd = 0;
|
||||
start(command);
|
||||
}
|
||||
explicit VInFilterImp(const string& command) { start(command); }
|
||||
~VInFilterImp() { stop(); }
|
||||
};
|
||||
|
||||
@@ -618,7 +608,7 @@ protected:
|
||||
|
||||
VInFilter::VInFilter(const string& command) { m_impp = new VInFilterImp(command); }
|
||||
VInFilter::~VInFilter() {
|
||||
if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = NULL);
|
||||
if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = nullptr);
|
||||
}
|
||||
|
||||
bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) {
|
||||
@@ -630,14 +620,8 @@ bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl)
|
||||
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
||||
|
||||
V3OutFormatter::V3OutFormatter(const string& filename, V3OutFormatter::Language lang)
|
||||
: m_filename(filename)
|
||||
, m_lang(lang)
|
||||
, m_lineno(1)
|
||||
, m_column(0)
|
||||
, m_nobreak(false)
|
||||
, m_prependIndent(true)
|
||||
, m_indentLevel(0)
|
||||
, m_bracketLevel(0) {
|
||||
: m_filename{filename}
|
||||
, m_lang{lang} {
|
||||
m_blockIndent = v3Global.opt.decoration() ? 4 : 1;
|
||||
m_commaWidth = v3Global.opt.decoration() ? 50 : 150;
|
||||
}
|
||||
@@ -844,14 +828,12 @@ void V3OutFormatter::putsQuoted(const string& strg) {
|
||||
// Don't use to quote a filename for #include - #include doesn't \ escape.
|
||||
putcNoTracking('"');
|
||||
string quoted = quoteNameControls(strg);
|
||||
for (string::const_iterator cp = quoted.begin(); cp != quoted.end(); ++cp) {
|
||||
putcNoTracking(*cp);
|
||||
}
|
||||
for (const char c : quoted) putcNoTracking(c);
|
||||
putcNoTracking('"');
|
||||
}
|
||||
void V3OutFormatter::putsNoTracking(const string& strg) {
|
||||
// Don't track {}'s, probably because it's a $display format string
|
||||
for (string::const_iterator cp = strg.begin(); cp != strg.end(); ++cp) putcNoTracking(*cp);
|
||||
for (const char c : strg) putcNoTracking(c);
|
||||
}
|
||||
|
||||
void V3OutFormatter::putcNoTracking(char chr) {
|
||||
@@ -880,43 +862,43 @@ string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::L
|
||||
string out;
|
||||
if (lang == LA_XML) {
|
||||
// Encode chars into XML string
|
||||
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
|
||||
if (pos[0] == '"') {
|
||||
for (const char c : namein) {
|
||||
if (c == '"') {
|
||||
out += string(""");
|
||||
} else if (pos[0] == '\'') {
|
||||
} else if (c == '\'') {
|
||||
out += string("'");
|
||||
} else if (pos[0] == '<') {
|
||||
} else if (c == '<') {
|
||||
out += string("<");
|
||||
} else if (pos[0] == '>') {
|
||||
} else if (c == '>') {
|
||||
out += string(">");
|
||||
} else if (pos[0] == '&') {
|
||||
} else if (c == '&') {
|
||||
out += string("&");
|
||||
} else if (isprint(pos[0])) {
|
||||
out += pos[0];
|
||||
} else if (isprint(c)) {
|
||||
out += c;
|
||||
} else {
|
||||
char decimal[10];
|
||||
sprintf(decimal, "&#%u;", (unsigned char)pos[0]);
|
||||
sprintf(decimal, "&#%u;", (unsigned char)c);
|
||||
out += decimal;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Encode control chars into C style escapes
|
||||
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
|
||||
if (pos[0] == '\\' || pos[0] == '"') {
|
||||
out += string("\\") + pos[0];
|
||||
} else if (pos[0] == '\n') {
|
||||
for (const char c : namein) {
|
||||
if (c == '\\' || c == '"') {
|
||||
out += string("\\") + c;
|
||||
} else if (c == '\n') {
|
||||
out += "\\n";
|
||||
} else if (pos[0] == '\r') {
|
||||
} else if (c == '\r') {
|
||||
out += "\\r";
|
||||
} else if (pos[0] == '\t') {
|
||||
} else if (c == '\t') {
|
||||
out += "\\t";
|
||||
} else if (isprint(pos[0])) {
|
||||
out += pos[0];
|
||||
} else if (isprint(c)) {
|
||||
out += c;
|
||||
} else {
|
||||
// This will also cover \a etc
|
||||
// Can't use %03o as messes up when signed
|
||||
char octal[10];
|
||||
sprintf(octal, "\\%o%o%o", (pos[0] >> 6) & 3, (pos[0] >> 3) & 7, pos[0] & 7);
|
||||
sprintf(octal, "\\%o%o%o", (c >> 6) & 3, (c >> 3) & 7, c & 7);
|
||||
out += octal;
|
||||
}
|
||||
}
|
||||
@@ -940,20 +922,20 @@ void V3OutFormatter::printf(const char* fmt...) {
|
||||
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
||||
|
||||
V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang)
|
||||
: V3OutFormatter(filename, lang) {
|
||||
if ((m_fp = V3File::new_fopen_w(filename)) == NULL) { v3fatal("Cannot write " << filename); }
|
||||
: V3OutFormatter{filename, lang} {
|
||||
if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) {
|
||||
v3fatal("Cannot write " << filename);
|
||||
}
|
||||
}
|
||||
|
||||
V3OutFile::~V3OutFile() {
|
||||
if (m_fp) fclose(m_fp);
|
||||
m_fp = NULL;
|
||||
m_fp = nullptr;
|
||||
}
|
||||
|
||||
void V3OutFile::putsForceIncs() {
|
||||
const V3StringList& forceIncs = v3Global.opt.forceIncs();
|
||||
for (V3StringList::const_iterator it = forceIncs.begin(); it != forceIncs.end(); ++it) {
|
||||
puts("#include \"" + *it + "\"\n");
|
||||
}
|
||||
for (const string& i : forceIncs) { puts("#include \"" + i + "\"\n"); }
|
||||
}
|
||||
|
||||
void V3OutCFile::putsGuard() {
|
||||
@@ -974,7 +956,7 @@ class VIdProtectImp {
|
||||
// MEMBERS
|
||||
typedef std::map<string, string> IdMap;
|
||||
IdMap m_nameMap; // Map of old name into new name
|
||||
typedef vl_unordered_set<std::string> IdSet;
|
||||
typedef std::unordered_set<std::string> IdSet;
|
||||
IdSet m_newIdSet; // Which new names exist
|
||||
protected:
|
||||
// CONSTRUCTORS
|
||||
@@ -995,7 +977,7 @@ public:
|
||||
// METHODS
|
||||
string passthru(const string& old) {
|
||||
if (!v3Global.opt.protectIds()) return old;
|
||||
IdMap::iterator it = m_nameMap.find(old);
|
||||
const auto it = m_nameMap.find(old);
|
||||
if (it != m_nameMap.end()) {
|
||||
// No way to go back and correct the older crypt name
|
||||
UASSERT(old == it->second,
|
||||
@@ -1008,10 +990,10 @@ public:
|
||||
}
|
||||
string protectIf(const string& old, bool doIt) {
|
||||
if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old;
|
||||
IdMap::iterator it = m_nameMap.find(old);
|
||||
if (it != m_nameMap.end())
|
||||
const auto it = m_nameMap.find(old);
|
||||
if (it != m_nameMap.end()) {
|
||||
return it->second;
|
||||
else {
|
||||
} else {
|
||||
string out;
|
||||
if (v3Global.opt.debugProtect()) {
|
||||
// This lets us see the symbol being protected to debug cases
|
||||
|
||||
+24
-25
@@ -101,10 +101,10 @@ public:
|
||||
|
||||
class V3OutFormatter {
|
||||
// TYPES
|
||||
enum MiscConsts { MAXSPACE = 80 }; // After this indent, stop indenting more
|
||||
static constexpr int MAXSPACE = 80; // After this indent, stop indenting more
|
||||
public:
|
||||
enum AlignClass { AL_AUTO = 0, AL_STATIC = 1 };
|
||||
enum Language {
|
||||
enum AlignClass : uint8_t { AL_AUTO = 0, AL_STATIC = 1 };
|
||||
enum Language : uint8_t {
|
||||
LA_C = 0,
|
||||
LA_VERILOG = 1,
|
||||
LA_MK = 2,
|
||||
@@ -117,13 +117,13 @@ private:
|
||||
Language m_lang; // Indenting Verilog code
|
||||
int m_blockIndent; // Characters per block indent
|
||||
int m_commaWidth; // Width after which to break at ,'s
|
||||
int m_lineno;
|
||||
int m_column;
|
||||
int m_nobreak; // Basic operator or begin paren, don't break next
|
||||
bool m_prependIndent;
|
||||
int m_indentLevel; // Current {} indentation
|
||||
int m_lineno = 1;
|
||||
int m_column = 0;
|
||||
int m_nobreak = false; // Basic operator or begin paren, don't break next
|
||||
bool m_prependIndent = true;
|
||||
int m_indentLevel = 0; // Current {} indentation
|
||||
std::stack<int> m_parenVec; // Stack of columns where last ( was
|
||||
int m_bracketLevel; // Intenting = { block, indicates number of {'s seen.
|
||||
int m_bracketLevel = 0; // Intenting = { block, indicates number of {'s seen.
|
||||
|
||||
int endLevels(const char* strg);
|
||||
void putcNoTracking(char chr);
|
||||
@@ -182,24 +182,23 @@ class V3OutFile : public V3OutFormatter {
|
||||
|
||||
public:
|
||||
V3OutFile(const string& filename, V3OutFormatter::Language lang);
|
||||
virtual ~V3OutFile();
|
||||
virtual ~V3OutFile() override;
|
||||
void putsForceIncs();
|
||||
|
||||
private:
|
||||
// CALLBACKS
|
||||
virtual void putcOutput(char chr) { fputc(chr, m_fp); }
|
||||
virtual void putcOutput(char chr) override { fputc(chr, m_fp); }
|
||||
};
|
||||
|
||||
class V3OutCFile : public V3OutFile {
|
||||
int m_guard; // Created header guard
|
||||
int m_guard = false; // Created header guard
|
||||
int m_private; // 1 = Most recently emitted private:, 2 = public:
|
||||
public:
|
||||
explicit V3OutCFile(const string& filename)
|
||||
: V3OutFile(filename, V3OutFormatter::LA_C)
|
||||
, m_guard(false) {
|
||||
: V3OutFile{filename, V3OutFormatter::LA_C} {
|
||||
resetPrivate();
|
||||
}
|
||||
virtual ~V3OutCFile() {}
|
||||
virtual ~V3OutCFile() override {}
|
||||
virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); }
|
||||
virtual void putsIntTopInclude() { putsForceIncs(); }
|
||||
virtual void putsGuard();
|
||||
@@ -222,10 +221,10 @@ public:
|
||||
class V3OutScFile : public V3OutCFile {
|
||||
public:
|
||||
explicit V3OutScFile(const string& filename)
|
||||
: V3OutCFile(filename) {}
|
||||
virtual ~V3OutScFile() {}
|
||||
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
|
||||
virtual void putsIntTopInclude() {
|
||||
: V3OutCFile{filename} {}
|
||||
virtual ~V3OutScFile() override {}
|
||||
virtual void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); }
|
||||
virtual void putsIntTopInclude() override {
|
||||
putsForceIncs();
|
||||
puts("#include \"systemc.h\"\n");
|
||||
puts("#include \"verilated_sc.h\"\n");
|
||||
@@ -235,26 +234,26 @@ public:
|
||||
class V3OutVFile : public V3OutFile {
|
||||
public:
|
||||
explicit V3OutVFile(const string& filename)
|
||||
: V3OutFile(filename, V3OutFormatter::LA_VERILOG) {}
|
||||
virtual ~V3OutVFile() {}
|
||||
: V3OutFile{filename, V3OutFormatter::LA_VERILOG} {}
|
||||
virtual ~V3OutVFile() override {}
|
||||
virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); }
|
||||
};
|
||||
|
||||
class V3OutXmlFile : public V3OutFile {
|
||||
public:
|
||||
explicit V3OutXmlFile(const string& filename)
|
||||
: V3OutFile(filename, V3OutFormatter::LA_XML) {
|
||||
: V3OutFile{filename, V3OutFormatter::LA_XML} {
|
||||
blockIndent(2);
|
||||
}
|
||||
virtual ~V3OutXmlFile() {}
|
||||
virtual ~V3OutXmlFile() override {}
|
||||
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
|
||||
};
|
||||
|
||||
class V3OutMkFile : public V3OutFile {
|
||||
public:
|
||||
explicit V3OutMkFile(const string& filename)
|
||||
: V3OutFile(filename, V3OutFormatter::LA_MK) {}
|
||||
virtual ~V3OutMkFile() {}
|
||||
: V3OutFile{filename, V3OutFormatter::LA_MK} {}
|
||||
virtual ~V3OutMkFile() override {}
|
||||
virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); }
|
||||
// No automatic indentation yet.
|
||||
void puts(const char* strg) { putsNoTracking(strg); }
|
||||
|
||||
+15
-20
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
#include <unordered_set>
|
||||
|
||||
//######################################################################
|
||||
// FileLineSingleton class functions
|
||||
@@ -58,7 +58,7 @@ string FileLineSingleton::filenameLetters(int fileno) {
|
||||
//! We associate a language with each source file, so we also set the default
|
||||
//! for this.
|
||||
int FileLineSingleton::nameToNumber(const string& filename) {
|
||||
FileNameNumMap::const_iterator it = m_namemap.find(filename);
|
||||
const auto it = vlstd::as_const(m_namemap).find(filename);
|
||||
if (VL_LIKELY(it != m_namemap.end())) return it->second;
|
||||
int num = m_names.size();
|
||||
m_names.push_back(filename);
|
||||
@@ -142,16 +142,16 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp) {
|
||||
//######################################################################
|
||||
// FileLine class functions
|
||||
|
||||
FileLine::FileLine(FileLine::EmptySecret) {
|
||||
// Sort of a singleton
|
||||
m_firstLineno = 0;
|
||||
m_lastLineno = 0;
|
||||
m_firstColumn = 0;
|
||||
m_lastColumn = 0;
|
||||
// Sort of a singleton
|
||||
FileLine::FileLine(FileLine::EmptySecret)
|
||||
: m_firstLineno{0}
|
||||
, m_firstColumn{0}
|
||||
, m_lastLineno{0}
|
||||
, m_lastColumn{0}
|
||||
, m_contentLineno{0}
|
||||
, m_contentp{nullptr}
|
||||
, m_parent{nullptr} {
|
||||
m_filenameno = singleton().nameToNumber(FileLine::builtInFilename());
|
||||
m_contentp = NULL;
|
||||
m_contentLineno = 0;
|
||||
m_parent = NULL;
|
||||
|
||||
m_warnOn = 0;
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
@@ -250,7 +250,7 @@ FileLine* FileLine::copyOrSameFileLine() {
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
V3Config::applyIgnores(this); // Toggle warnings based on global config file
|
||||
#endif
|
||||
static FileLine* lastNewp = NULL;
|
||||
static FileLine* lastNewp = nullptr;
|
||||
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
|
||||
return lastNewp;
|
||||
}
|
||||
@@ -310,11 +310,6 @@ bool FileLine::warnOff(const string& msg, bool flag) {
|
||||
V3ErrorCode code(msg.c_str());
|
||||
if (code < V3ErrorCode::EC_FIRST_WARN) {
|
||||
return false;
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
} else if (v3Global.opt.lintOnly() // Lint mode is allowed to suppress some errors
|
||||
&& code < V3ErrorCode::EC_MIN) {
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
warnOff(code, flag);
|
||||
return true;
|
||||
@@ -442,7 +437,7 @@ string FileLine::warnContext(bool secondary) const {
|
||||
}
|
||||
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
typedef vl_unordered_set<FileLine*> FileLineCheckSet;
|
||||
typedef std::unordered_set<FileLine*> FileLineCheckSet;
|
||||
FileLineCheckSet fileLineLeakChecks;
|
||||
|
||||
void* FileLine::operator new(size_t size) {
|
||||
@@ -454,7 +449,7 @@ void* FileLine::operator new(size_t size) {
|
||||
void FileLine::operator delete(void* objp, size_t size) {
|
||||
if (!objp) return;
|
||||
FileLine* flp = static_cast<FileLine*>(objp);
|
||||
FileLineCheckSet::iterator it = fileLineLeakChecks.find(flp);
|
||||
const auto it = fileLineLeakChecks.find(flp);
|
||||
if (it != fileLineLeakChecks.end()) {
|
||||
fileLineLeakChecks.erase(it);
|
||||
} else {
|
||||
@@ -470,7 +465,7 @@ void FileLine::deleteAllRemaining() {
|
||||
// that way. Unfortunately this makes our leak checking a big mess, so
|
||||
// only when leak checking we'll track them all and cleanup.
|
||||
while (true) {
|
||||
FileLineCheckSet::iterator it = fileLineLeakChecks.begin();
|
||||
const auto it = fileLineLeakChecks.begin();
|
||||
if (it == fileLineLeakChecks.end()) break;
|
||||
delete *it;
|
||||
// Operator delete will remove the iterated object from the list.
|
||||
|
||||
+38
-21
@@ -89,7 +89,7 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp);
|
||||
//! language is held in tables in the FileLineSingleton class.
|
||||
class FileLine {
|
||||
// CONSTANTS
|
||||
enum { SHOW_SOURCE_MAX_LENGTH = 400 }; // Don't show source lines > this long
|
||||
static constexpr unsigned SHOW_SOURCE_MAX_LENGTH = 400; // Don't show source lines > this long
|
||||
|
||||
// MEMBERS
|
||||
// Columns here means number of chars from beginning (i.e. tabs count as one)
|
||||
@@ -126,27 +126,27 @@ private:
|
||||
|
||||
public:
|
||||
explicit FileLine(const string& filename)
|
||||
: m_firstLineno(0)
|
||||
, m_firstColumn(0)
|
||||
, m_lastLineno(0)
|
||||
, m_lastColumn(0)
|
||||
, m_filenameno(singleton().nameToNumber(filename))
|
||||
, m_contentLineno(0)
|
||||
, m_contentp(NULL)
|
||||
, m_parent(NULL)
|
||||
, m_warnOn(defaultFileLine().m_warnOn)
|
||||
, m_waive(false) {}
|
||||
: m_firstLineno{0}
|
||||
, m_firstColumn{0}
|
||||
, m_lastLineno{0}
|
||||
, m_lastColumn{0}
|
||||
, m_filenameno{singleton().nameToNumber(filename)}
|
||||
, m_contentLineno{0}
|
||||
, m_contentp{nullptr}
|
||||
, m_parent{nullptr}
|
||||
, m_warnOn{defaultFileLine().m_warnOn}
|
||||
, m_waive{false} {}
|
||||
explicit FileLine(FileLine* fromp)
|
||||
: m_firstLineno(fromp->m_firstLineno)
|
||||
, m_firstColumn(fromp->m_firstColumn)
|
||||
, m_lastLineno(fromp->m_lastLineno)
|
||||
, m_lastColumn(fromp->m_lastColumn)
|
||||
, m_filenameno(fromp->m_filenameno)
|
||||
, m_contentLineno(fromp->m_contentLineno)
|
||||
, m_contentp(fromp->m_contentp)
|
||||
, m_parent(fromp->m_parent)
|
||||
, m_warnOn(fromp->m_warnOn)
|
||||
, m_waive(fromp->m_waive) {}
|
||||
: m_firstLineno{fromp->m_firstLineno}
|
||||
, m_firstColumn{fromp->m_firstColumn}
|
||||
, m_lastLineno{fromp->m_lastLineno}
|
||||
, m_lastColumn{fromp->m_lastColumn}
|
||||
, m_filenameno{fromp->m_filenameno}
|
||||
, m_contentLineno{fromp->m_contentLineno}
|
||||
, m_contentp{fromp->m_contentp}
|
||||
, m_parent{fromp->m_parent}
|
||||
, m_warnOn{fromp->m_warnOn}
|
||||
, m_waive{fromp->m_waive} {}
|
||||
struct EmptySecret {}; // Constructor selection
|
||||
explicit FileLine(EmptySecret);
|
||||
FileLine* copyOrSameFileLine();
|
||||
@@ -218,6 +218,8 @@ public:
|
||||
bool lastWarnWaived() { return m_waive; }
|
||||
|
||||
// Specific flag ACCESSORS/METHODS
|
||||
bool celldefineOn() const { return m_warnOn.test(V3ErrorCode::I_CELLDEFINE); }
|
||||
void celldefineOn(bool flag) { warnOn(V3ErrorCode::I_CELLDEFINE, flag); }
|
||||
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
|
||||
void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); }
|
||||
bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
|
||||
@@ -265,6 +267,21 @@ public:
|
||||
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
||||
&& m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn);
|
||||
}
|
||||
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
|
||||
// equivalent.
|
||||
int operatorCompare(const FileLine& rhs) const {
|
||||
if (m_filenameno != rhs.m_filenameno) return (m_filenameno < rhs.m_filenameno) ? -1 : 1;
|
||||
if (m_firstLineno != rhs.m_firstLineno)
|
||||
return (m_firstLineno < rhs.m_firstLineno) ? -1 : 1;
|
||||
if (m_firstColumn != rhs.m_firstColumn)
|
||||
return (m_firstColumn < rhs.m_firstColumn) ? -1 : 1;
|
||||
if (m_lastLineno != rhs.m_lastLineno) return (m_lastLineno < rhs.m_lastLineno) ? -1 : 1;
|
||||
if (m_lastColumn != rhs.m_lastColumn) return (m_lastColumn < rhs.m_lastColumn) ? -1 : 1;
|
||||
for (size_t i = 0; i < m_warnOn.size(); ++i) {
|
||||
if (m_warnOn[i] != rhs.m_warnOn[i]) return (m_warnOn[i] < rhs.m_warnOn[i]) ? -1 : 1;
|
||||
}
|
||||
return 0; // (*this) and rhs are equivalent
|
||||
}
|
||||
|
||||
private:
|
||||
string warnContext(bool secondary) const;
|
||||
|
||||
+173
-212
@@ -35,11 +35,11 @@
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
#include <unordered_set>
|
||||
|
||||
typedef std::list<AstNodeVarRef*> GateVarRefList;
|
||||
|
||||
#define GATE_DEDUP_MAX_DEPTH 20
|
||||
constexpr int GATE_DEDUP_MAX_DEPTH = 20;
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -56,7 +56,7 @@ class GateGraphBaseVisitor {
|
||||
public:
|
||||
V3Graph* m_graphp; // Graph this class is visiting
|
||||
explicit GateGraphBaseVisitor(V3Graph* graphp)
|
||||
: m_graphp(graphp) {}
|
||||
: m_graphp{graphp} {}
|
||||
virtual ~GateGraphBaseVisitor() {}
|
||||
virtual VNUser visit(GateLogicVertex* vertexp, VNUser vu = VNUser(0)) = 0;
|
||||
virtual VNUser visit(GateVarVertex* vertexp, VNUser vu = VNUser(0)) = 0;
|
||||
@@ -68,19 +68,16 @@ public:
|
||||
|
||||
class GateEitherVertex : public V3GraphVertex {
|
||||
AstScope* m_scopep; // Scope vertex refers to
|
||||
bool m_reducible; // True if this node should be able to be eliminated
|
||||
bool m_dedupable; // True if this node should be able to be deduped
|
||||
bool m_consumed; // Output goes to something meaningful
|
||||
bool m_reducible = true; // True if this node should be able to be eliminated
|
||||
bool m_dedupable = true; // True if this node should be able to be deduped
|
||||
bool m_consumed = false; // Output goes to something meaningful
|
||||
public:
|
||||
GateEitherVertex(V3Graph* graphp, AstScope* scopep)
|
||||
: V3GraphVertex(graphp)
|
||||
, m_scopep(scopep)
|
||||
, m_reducible(true)
|
||||
, m_dedupable(true)
|
||||
, m_consumed(false) {}
|
||||
virtual ~GateEitherVertex() {}
|
||||
: V3GraphVertex{graphp}
|
||||
, m_scopep{scopep} {}
|
||||
virtual ~GateEitherVertex() override {}
|
||||
// ACCESSORS
|
||||
virtual string dotStyle() const { return m_consumed ? "" : "dotted"; }
|
||||
virtual string dotStyle() const override { return m_consumed ? "" : "dotted"; }
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
bool reducible() const { return m_reducible; }
|
||||
bool dedupable() const { return m_dedupable; }
|
||||
@@ -116,7 +113,7 @@ public:
|
||||
// iterateInEdges() will stop traversing edges if one is deleted
|
||||
VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) {
|
||||
VNUser ret = VNUser(0);
|
||||
V3GraphEdge* next_edgep = NULL;
|
||||
V3GraphEdge* next_edgep = nullptr;
|
||||
for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) {
|
||||
// Need to find the next edge before visiting in case the edge is deleted
|
||||
next_edgep = edgep->outNextp();
|
||||
@@ -128,23 +125,19 @@ public:
|
||||
|
||||
class GateVarVertex : public GateEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
bool m_isTop;
|
||||
bool m_isClock;
|
||||
AstNode* m_rstSyncNodep; // Used as reset and not in SenItem, in clocked always
|
||||
AstNode* m_rstAsyncNodep; // Used as reset and in SenItem, in clocked always
|
||||
bool m_isTop = false;
|
||||
bool m_isClock = false;
|
||||
AstNode* m_rstSyncNodep = nullptr; // Used as reset and not in SenItem, in clocked always
|
||||
AstNode* m_rstAsyncNodep = nullptr; // Used as reset and in SenItem, in clocked always
|
||||
public:
|
||||
GateVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: GateEitherVertex(graphp, scopep)
|
||||
, m_varScp(varScp)
|
||||
, m_isTop(false)
|
||||
, m_isClock(false)
|
||||
, m_rstSyncNodep(NULL)
|
||||
, m_rstAsyncNodep(NULL) {}
|
||||
virtual ~GateVarVertex() {}
|
||||
: GateEitherVertex{graphp, scopep}
|
||||
, m_varScp{varScp} {}
|
||||
virtual ~GateVarVertex() override {}
|
||||
// ACCESSORS
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
virtual string dotColor() const { return "blue"; }
|
||||
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
virtual string dotColor() const override { return "blue"; }
|
||||
bool isTop() const { return m_isTop; }
|
||||
void setIsTop() { m_isTop = true; }
|
||||
bool isClock() const { return m_isClock; }
|
||||
@@ -165,29 +158,35 @@ public:
|
||||
setIsClock();
|
||||
}
|
||||
}
|
||||
VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { return v.visit(this, vu); }
|
||||
virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) override {
|
||||
return v.visit(this, vu);
|
||||
}
|
||||
};
|
||||
|
||||
class GateLogicVertex : public GateEitherVertex {
|
||||
AstNode* m_nodep;
|
||||
AstActive* m_activep; // Under what active; NULL is ok (under cfunc or such)
|
||||
AstActive* m_activep; // Under what active; nullptr is ok (under cfunc or such)
|
||||
bool m_slow; // In slow block
|
||||
public:
|
||||
GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep,
|
||||
bool slow)
|
||||
: GateEitherVertex(graphp, scopep)
|
||||
, m_nodep(nodep)
|
||||
, m_activep(activep)
|
||||
, m_slow(slow) {}
|
||||
virtual ~GateLogicVertex() {}
|
||||
: GateEitherVertex{graphp, scopep}
|
||||
, m_nodep{nodep}
|
||||
, m_activep{activep}
|
||||
, m_slow{slow} {}
|
||||
virtual ~GateLogicVertex() override {}
|
||||
// ACCESSORS
|
||||
virtual string name() const { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); }
|
||||
virtual string dotColor() const { return "purple"; }
|
||||
virtual FileLine* fileline() const { return nodep()->fileline(); }
|
||||
virtual string name() const override {
|
||||
return (cvtToHex(m_nodep) + "@" + scopep()->prettyName());
|
||||
}
|
||||
virtual string dotColor() const override { return "purple"; }
|
||||
virtual FileLine* fileline() const override { return nodep()->fileline(); }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
AstActive* activep() const { return m_activep; }
|
||||
bool slow() const { return m_slow; }
|
||||
VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { return v.visit(this, vu); }
|
||||
virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) override {
|
||||
return v.visit(this, vu);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -196,14 +195,14 @@ public:
|
||||
class GateOkVisitor : public GateBaseVisitor {
|
||||
private:
|
||||
// RETURN STATE
|
||||
bool m_isSimple; // Set false when we know it isn't simple
|
||||
bool m_isSimple = true; // Set false when we know it isn't simple
|
||||
GateVarRefList m_rhsVarRefs; // VarRefs on rhs of assignment
|
||||
AstNode* m_substTreep; // What to replace the variable with
|
||||
AstNode* m_substTreep = nullptr; // What to replace the variable with
|
||||
// STATE
|
||||
bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks)
|
||||
AstNodeVarRef* m_lhsVarRef; // VarRef on lhs of assignment (what we're replacing)
|
||||
AstNodeVarRef* m_lhsVarRef = nullptr; // VarRef on lhs of assignment (what we're replacing)
|
||||
bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable
|
||||
int m_ops; // Operation count
|
||||
int m_ops = 0; // Operation count
|
||||
|
||||
// METHODS
|
||||
void clearSimple(const char* because) {
|
||||
@@ -213,7 +212,7 @@ private:
|
||||
}
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
++m_ops;
|
||||
iterateChildren(nodep);
|
||||
// We only allow a LHS ref for the var being set, and a RHS ref for
|
||||
@@ -221,7 +220,7 @@ private:
|
||||
if (nodep->varScopep()->varp()->isSc()) {
|
||||
clearSimple("SystemC sig"); // Don't want to eliminate the VL_ASSIGN_SI's
|
||||
}
|
||||
if (nodep->lvalue()) {
|
||||
if (nodep->access().isWrite()) {
|
||||
if (m_lhsVarRef) clearSimple(">1 lhs varRefs");
|
||||
m_lhsVarRef = nodep;
|
||||
} else {
|
||||
@@ -237,7 +236,7 @@ private:
|
||||
m_rhsVarRefs.push_back(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
m_substTreep = nodep->rhsp();
|
||||
if (!VN_IS(nodep->lhsp(), NodeVarRef)) {
|
||||
clearSimple("ASSIGN(non-VARREF)");
|
||||
@@ -260,7 +259,7 @@ private:
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
// *** Special iterator
|
||||
if (!m_isSimple) return; // Fastpath
|
||||
if (++m_ops > v3Global.opt.gateStmts()) { clearSimple("--gate-stmts exceeded"); }
|
||||
@@ -276,12 +275,8 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GateOkVisitor(AstNode* nodep, bool buffersOnly, bool dedupe) {
|
||||
m_isSimple = true;
|
||||
m_substTreep = NULL;
|
||||
m_buffersOnly = buffersOnly;
|
||||
m_lhsVarRef = NULL;
|
||||
m_dedupe = dedupe;
|
||||
m_ops = 0;
|
||||
// Iterate
|
||||
iterate(nodep);
|
||||
// Check results
|
||||
@@ -294,7 +289,7 @@ public:
|
||||
}
|
||||
if (debug() >= 9 && !m_isSimple) nodep->dumpTree(cout, " gate!Ok: ");
|
||||
}
|
||||
virtual ~GateOkVisitor() {}
|
||||
virtual ~GateOkVisitor() override {}
|
||||
// PUBLIC METHODS
|
||||
bool isSimple() const { return m_isSimple; }
|
||||
AstNode* substTree() const { return m_substTreep; }
|
||||
@@ -318,13 +313,13 @@ private:
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
GateLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
|
||||
AstScope* m_scopep; // Current scope being processed
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstActive* m_activep; // Current active
|
||||
bool m_activeReducible; // Is activation block reducible?
|
||||
bool m_inSenItem; // Underneath AstSenItem; any varrefs are clocks
|
||||
bool m_inSlow; // Inside a slow structure
|
||||
GateLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
|
||||
AstScope* m_scopep = nullptr; // Current scope being processed
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstActive* m_activep = nullptr; // Current active
|
||||
bool m_activeReducible = true; // Is activation block reducible?
|
||||
bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks
|
||||
bool m_inSlow = false; // Inside a slow structure
|
||||
VDouble0 m_statSigs; // Statistic tracking
|
||||
VDouble0 m_statRefs; // Statistic tracking
|
||||
VDouble0 m_statDedupLogic; // Statistic tracking
|
||||
@@ -346,7 +341,7 @@ private:
|
||||
if (consumeReason) m_logicVertexp->setConsumed(consumeReason);
|
||||
if (VN_IS(nodep, SenItem)) m_logicVertexp->setConsumed("senItem");
|
||||
iterateChildren(nodep);
|
||||
m_logicVertexp = NULL;
|
||||
m_logicVertexp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +380,7 @@ private:
|
||||
void decomposeClkVectors();
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// if (debug() > 6) m_graph.dump();
|
||||
if (debug() > 6) m_graph.dumpDotFilePrefixed("gate_pre");
|
||||
@@ -416,23 +411,22 @@ private:
|
||||
consumedMove();
|
||||
replaceAssigns();
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_activeReducible = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
m_logicVertexp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4, " BLOCK " << nodep << endl);
|
||||
m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible
|
||||
@@ -440,10 +434,10 @@ private:
|
||||
AstNode::user2ClearTree();
|
||||
iterateChildren(nodep);
|
||||
AstNode::user2ClearTree();
|
||||
m_activep = NULL;
|
||||
m_activep = nullptr;
|
||||
m_activeReducible = true;
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
@@ -454,7 +448,7 @@ private:
|
||||
vvertexp->setIsClock();
|
||||
// For SYNCASYNCNET
|
||||
varscp->user2(true);
|
||||
} else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) {
|
||||
} else if (m_activep && m_activep->hasClocked() && !nodep->access().isWrite()) {
|
||||
if (varscp->user2()) {
|
||||
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
|
||||
} else {
|
||||
@@ -463,63 +457,60 @@ private:
|
||||
}
|
||||
// We use weight of one; if we ref the var more than once, when we simplify,
|
||||
// the weight will increase
|
||||
if (nodep->lvalue()) {
|
||||
if (nodep->access().isWrite()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1);
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? NULL : "Multiple Stmts"), NULL);
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"), nullptr);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "AlwaysPublic", NULL);
|
||||
m_inSlow = lastslow;
|
||||
virtual void visit(AstAlwaysPublic* nodep) override {
|
||||
VL_RESTORER(m_inSlow);
|
||||
{
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "AlwaysPublic", nullptr);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateNewStmt(nodep, "User C Function", "User C Function");
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
// Note we look at only AstSenItems, not AstSenGate's
|
||||
// The gating term of a AstSenGate is normal logic
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
m_inSenItem = true;
|
||||
if (m_logicVertexp) { // Already under logic; presumably a SenGate
|
||||
iterateChildren(nodep);
|
||||
} else { // Standalone item, probably right under a SenTree
|
||||
iterateNewStmt(nodep, NULL, NULL);
|
||||
iterateNewStmt(nodep, nullptr, nullptr);
|
||||
}
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is dealt with as logic
|
||||
iterateNewStmt(nodep, "Clock gater", "Clock gater");
|
||||
virtual void visit(AstInitial* nodep) override {
|
||||
VL_RESTORER(m_inSlow);
|
||||
{
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? NULL : "Multiple Stmts"), NULL);
|
||||
m_inSlow = lastslow;
|
||||
virtual void visit(AstAssignAlias* nodep) override { //
|
||||
iterateNewStmt(nodep, nullptr, nullptr);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { //
|
||||
iterateNewStmt(nodep, NULL, NULL);
|
||||
virtual void visit(AstAssignW* nodep) override { //
|
||||
iterateNewStmt(nodep, nullptr, nullptr);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { //
|
||||
iterateNewStmt(nodep, NULL, NULL);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
iterateNewStmt(nodep, "CoverToggle", "CoverToggle");
|
||||
}
|
||||
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
|
||||
const bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "Tracing", "Tracing");
|
||||
m_inSlow = lastslow;
|
||||
virtual void visit(AstTraceDecl* nodep) override {
|
||||
VL_RESTORER(m_inSlow);
|
||||
{
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "Tracing", "Tracing");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConcat* nodep) override {
|
||||
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)
|
||||
&& VN_CAST(nodep->backp(), NodeAssign)->lhsp() == nodep),
|
||||
nodep, "Concat on LHS of assignment; V3Const should have deleted it");
|
||||
@@ -527,25 +518,15 @@ private:
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isOutputter() && m_logicVertexp) m_logicVertexp->setConsumed("outputter");
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit GateVisitor(AstNode* nodep) {
|
||||
AstNode::user1ClearTree();
|
||||
m_logicVertexp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_modp = NULL;
|
||||
m_activep = NULL;
|
||||
m_activeReducible = true;
|
||||
m_inSenItem = false;
|
||||
m_inSlow = false;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~GateVisitor() {
|
||||
explicit GateVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~GateVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
|
||||
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
|
||||
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
|
||||
@@ -682,7 +663,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
||||
// optimize it further
|
||||
logicp->unlinkFrBack();
|
||||
vvertexp->varScp()->valuep(logicp);
|
||||
logicp = NULL;
|
||||
logicp = nullptr;
|
||||
// Mark the vertex so we don't mark it as being
|
||||
// unconsumed in the next step
|
||||
vvertexp->user(true);
|
||||
@@ -700,7 +681,7 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
|
||||
// Return true if can optimize
|
||||
// Return false if the consuming logic has an output signal that the
|
||||
// replacement logic has as an input
|
||||
typedef vl_unordered_set<AstVarScope*> VarScopeSet;
|
||||
typedef std::unordered_set<AstVarScope*> VarScopeSet;
|
||||
// Use map to find duplicates between two lists
|
||||
VarScopeSet varscopes;
|
||||
// Replacement logic usually has shorter input list, so faster to build list based on it
|
||||
@@ -794,7 +775,7 @@ void GateVisitor::consumedMove() {
|
||||
}
|
||||
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
|
||||
AstNode* nodep = lvertexp->nodep();
|
||||
AstActive* oldactp = lvertexp->activep(); // NULL under cfunc
|
||||
AstActive* oldactp = lvertexp->activep(); // nullptr under cfunc
|
||||
if (!lvertexp->consumed() && oldactp) {
|
||||
// Eventually: Move the statement to a new active block
|
||||
// with "tracing-on" sensitivity
|
||||
@@ -855,13 +836,13 @@ private:
|
||||
void hashReplace(AstNode* oldp, AstNode* newp);
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
if (nodep->varScopep() == m_elimVarScp) {
|
||||
// Substitute in the new tree
|
||||
// It's possible we substitute into something that will be reduced more later,
|
||||
// however, as we never delete the top Always/initial statement, all should be well.
|
||||
m_didReplace = true;
|
||||
UASSERT_OBJ(!nodep->lvalue(), nodep,
|
||||
UASSERT_OBJ(!nodep->access().isWrite(), nodep,
|
||||
"Can't replace lvalue assignments with const var");
|
||||
AstNode* substp = m_replaceTreep->cloneTree(false);
|
||||
UASSERT_OBJ(
|
||||
@@ -875,17 +856,18 @@ private:
|
||||
// to throw warnings that point to a PIN rather than where the pin us used.
|
||||
if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline());
|
||||
// Make the substp an rvalue like nodep. This facilitates the hashing in dedupe.
|
||||
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false);
|
||||
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef))
|
||||
varrefp->access(VAccess::READ);
|
||||
hashReplace(nodep, substp);
|
||||
nodep->replaceWith(substp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
virtual ~GateElimVisitor() {}
|
||||
virtual ~GateElimVisitor() override {}
|
||||
GateElimVisitor(AstNode* nodep, AstVarScope* varscp, AstNode* replaceTreep,
|
||||
GateDedupeVarVisitor* varVisp) {
|
||||
UINFO(9, " elimvisitor " << nodep << endl);
|
||||
@@ -902,7 +884,7 @@ public:
|
||||
|
||||
void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) {
|
||||
if (debug() >= 5) consumerp->dumpTree(cout, " elimUsePre: ");
|
||||
GateElimVisitor elimVisitor(consumerp, varscp, substp, NULL);
|
||||
GateElimVisitor elimVisitor(consumerp, varscp, substp, nullptr);
|
||||
if (elimVisitor.didReplace()) {
|
||||
if (debug() >= 9) consumerp->dumpTree(cout, " elimUseCns: ");
|
||||
// Caution: Can't let V3Const change our handle to consumerp, such as by
|
||||
@@ -927,9 +909,9 @@ private:
|
||||
// NODE STATE
|
||||
// Ast*::user2p -> parent AstNodeAssign* for this rhsp
|
||||
// Ast*::user3p -> AstActive* of assign, for isSame() in test for duplicate
|
||||
// Set to NULL if this assign's tree was later replaced
|
||||
// Set to nullptr if this assign's tree was later replaced
|
||||
// Ast*::user5p -> AstNode* of assign if condition, for isSame() in test for duplicate
|
||||
// Set to NULL if this assign's tree was later replaced
|
||||
// Set to nullptr if this assign's tree was later replaced
|
||||
// AstUser1InUse m_inuser1; (Allocated for use in GateVisitor)
|
||||
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
|
||||
AstUser3InUse m_inuser3;
|
||||
@@ -942,7 +924,7 @@ private:
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void hash(AstNode* nodep) {
|
||||
// !NULL && the object is hashable
|
||||
// !nullptr && the object is hashable
|
||||
if (nodep && !nodep->sameHash().isIllegal()) m_hashed.hash(nodep);
|
||||
}
|
||||
bool sameHash(AstNode* node1p, AstNode* node2p) {
|
||||
@@ -992,7 +974,8 @@ public:
|
||||
}
|
||||
|
||||
AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) {
|
||||
// Legal for extra1p/2p to be NULL, we'll compare with other assigns with extras also NULL
|
||||
// Legal for extra1p/2p to be nullptr, we'll compare with other assigns with extras also
|
||||
// nullptr
|
||||
AstNode* rhsp = assignp->rhsp();
|
||||
rhsp->user2p(assignp);
|
||||
rhsp->user3p(extra1p);
|
||||
@@ -1001,8 +984,8 @@ public:
|
||||
hash(extra1p);
|
||||
hash(extra2p);
|
||||
|
||||
V3Hashed::iterator inserted = m_hashed.hashAndInsert(rhsp);
|
||||
V3Hashed::iterator dupit = m_hashed.findDuplicate(rhsp, this);
|
||||
const auto inserted = m_hashed.hashAndInsert(rhsp);
|
||||
const auto dupit = m_hashed.findDuplicate(rhsp, this);
|
||||
// Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't
|
||||
// return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate)
|
||||
// So dupit is either a different, duplicate rhsp, or the end of the hash.
|
||||
@@ -1011,7 +994,7 @@ public:
|
||||
return VN_CAST(m_hashed.iteratorNodep(dupit)->user2p(), NodeAssign);
|
||||
}
|
||||
// Retain new inserted information
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void check() {
|
||||
@@ -1049,13 +1032,13 @@ class GateDedupeVarVisitor : public GateBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
GateDedupeHash m_ghash; // Hash used to find dupes of rhs of assign
|
||||
AstNodeAssign* m_assignp; // Assign found for dedupe
|
||||
AstNode* m_ifCondp; // IF condition that assign is under
|
||||
bool m_always; // Assign is under an always
|
||||
bool m_dedupable; // Determined the assign to be dedupable
|
||||
AstNodeAssign* m_assignp = nullptr; // Assign found for dedupe
|
||||
AstNode* m_ifCondp = nullptr; // IF condition that assign is under
|
||||
bool m_always = false; // Assign is under an always
|
||||
bool m_dedupable = true; // Determined the assign to be dedupable
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeAssign* assignp) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* assignp) override {
|
||||
if (m_dedupable) {
|
||||
// I think we could safely dedupe an always block with multiple
|
||||
// non-blocking statements, but erring on side of caution here
|
||||
@@ -1066,7 +1049,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* alwaysp) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* alwaysp) override {
|
||||
if (m_dedupable) {
|
||||
if (!m_always) {
|
||||
m_always = true;
|
||||
@@ -1080,7 +1063,7 @@ private:
|
||||
// always @(...)
|
||||
// if (...)
|
||||
// foo = ...; // or foo <= ...;
|
||||
virtual void visit(AstNodeIf* ifp) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeIf* ifp) override {
|
||||
if (m_dedupable) {
|
||||
if (m_always && !m_ifCondp && !ifp->elsesp()) {
|
||||
// we're under an always, this is the first IF, and there's no else
|
||||
@@ -1092,25 +1075,20 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstComment*) VL_OVERRIDE {} // NOP
|
||||
virtual void visit(AstComment*) override {} // NOP
|
||||
//--------------------
|
||||
virtual void visit(AstNode*) VL_OVERRIDE { //
|
||||
virtual void visit(AstNode*) override { //
|
||||
m_dedupable = false;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GateDedupeVarVisitor() {
|
||||
m_assignp = NULL;
|
||||
m_ifCondp = NULL;
|
||||
m_always = false;
|
||||
m_dedupable = true;
|
||||
}
|
||||
GateDedupeVarVisitor() {}
|
||||
~GateDedupeVarVisitor() {}
|
||||
// PUBLIC METHODS
|
||||
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
|
||||
m_assignp = NULL;
|
||||
m_ifCondp = NULL;
|
||||
m_assignp = nullptr;
|
||||
m_ifCondp = nullptr;
|
||||
m_always = false;
|
||||
m_dedupable = true;
|
||||
iterate(nodep);
|
||||
@@ -1125,7 +1103,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void hashReplace(AstNode* oldp, AstNode* newp) { m_ghash.hashReplace(oldp, newp); }
|
||||
};
|
||||
@@ -1147,9 +1125,9 @@ private:
|
||||
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
|
||||
VDouble0 m_numDeduped; // Statistic tracking
|
||||
GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic
|
||||
int m_depth; // Iteration depth
|
||||
int m_depth = 0; // Iteration depth
|
||||
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) {
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) override {
|
||||
// Check that we haven't been here before
|
||||
if (m_depth > GATE_DEDUP_MAX_DEPTH)
|
||||
return VNUser(0); // Break loops; before user2 set so hit this vertex later
|
||||
@@ -1164,7 +1142,7 @@ private:
|
||||
V3GraphEdge* edgep = vvertexp->inBeginp();
|
||||
GateLogicVertex* lvertexp = static_cast<GateLogicVertex*>(edgep->fromp());
|
||||
UASSERT_OBJ(vvertexp->dedupable(), vvertexp->varScp(),
|
||||
"GateLogicVertex* visit should have returned NULL "
|
||||
"GateLogicVertex* visit should have returned nullptr "
|
||||
"if consumer var vertex is not dedupable.");
|
||||
GateOkVisitor okVisitor(lvertexp->nodep(), false, true);
|
||||
if (okVisitor.isSimple()) {
|
||||
@@ -1204,7 +1182,7 @@ private:
|
||||
AstNode* lvertexNodep = lvertexp->nodep();
|
||||
lvertexNodep->unlinkFrBack();
|
||||
vvertexp->varScp()->valuep(lvertexNodep);
|
||||
lvertexNodep = NULL;
|
||||
lvertexNodep = nullptr;
|
||||
vvertexp->user(true);
|
||||
lvertexp->user(true);
|
||||
}
|
||||
@@ -1215,8 +1193,8 @@ private:
|
||||
}
|
||||
|
||||
// Given iterated logic, starting at vu which was consumer's GateVarVertex
|
||||
// Returns a varref that has the same logic input; or NULL if none
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) {
|
||||
// Returns a varref that has the same logic input; or nullptr if none
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
|
||||
lvertexp->iterateInEdges(*this);
|
||||
|
||||
GateVarVertex* consumerVvertexpp = static_cast<GateVarVertex*>(vu.toGraphVertex());
|
||||
@@ -1235,8 +1213,7 @@ private:
|
||||
|
||||
public:
|
||||
explicit GateDedupeGraphVisitor(V3Graph* graphp)
|
||||
: GateGraphBaseVisitor(graphp)
|
||||
, m_depth(0) {}
|
||||
: GateGraphBaseVisitor{graphp} {}
|
||||
void dedupeTree(GateVarVertex* vvertexp) { vvertexp->accept(*this); }
|
||||
VDouble0 numDeduped() { return m_numDeduped; }
|
||||
};
|
||||
@@ -1271,9 +1248,9 @@ void GateVisitor::dedupe() {
|
||||
class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
AstNodeAssign* m_assignp;
|
||||
AstActive* m_activep;
|
||||
GateLogicVertex* m_logicvp;
|
||||
AstNodeAssign* m_assignp = nullptr;
|
||||
AstActive* m_activep = nullptr;
|
||||
GateLogicVertex* m_logicvp = nullptr;
|
||||
VDouble0 m_numMergedAssigns; // Statistic tracking
|
||||
|
||||
// assemble two Sel into one if possible
|
||||
@@ -1281,22 +1258,22 @@ private:
|
||||
AstVarRef* preVarRefp = VN_CAST(pre->fromp(), VarRef);
|
||||
AstVarRef* curVarRefp = VN_CAST(cur->fromp(), VarRef);
|
||||
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) {
|
||||
return NULL; // not the same var
|
||||
return nullptr; // not the same var
|
||||
}
|
||||
const AstConst* pstart = VN_CAST(pre->lsbp(), Const);
|
||||
const AstConst* pwidth = VN_CAST(pre->widthp(), Const);
|
||||
const AstConst* cstart = VN_CAST(cur->lsbp(), Const);
|
||||
const AstConst* cwidth = VN_CAST(cur->widthp(), Const);
|
||||
if (!pstart || !pwidth || !cstart || !cwidth) return NULL; // too complicated
|
||||
if (!pstart || !pwidth || !cstart || !cwidth) return nullptr; // too complicated
|
||||
if (cur->lsbConst() + cur->widthConst() == pre->lsbConst()) {
|
||||
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false),
|
||||
cur->lsbConst(), pre->widthConst() + cur->widthConst());
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) {
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) override {
|
||||
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) {
|
||||
V3GraphEdge* oldedgep = edgep;
|
||||
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
|
||||
@@ -1369,18 +1346,14 @@ private:
|
||||
}
|
||||
return VNUser(0);
|
||||
}
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) { //
|
||||
virtual VNUser visit(GateLogicVertex*, VNUser vu) override { //
|
||||
return VNUser(0);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit GateMergeAssignsGraphVisitor(V3Graph* graphp)
|
||||
: GateGraphBaseVisitor(graphp) {
|
||||
m_assignp = NULL;
|
||||
m_activep = NULL;
|
||||
m_logicvp = NULL;
|
||||
m_numMergedAssigns = 0;
|
||||
m_graphp = graphp;
|
||||
: GateGraphBaseVisitor{graphp} {
|
||||
m_graphp = graphp; // In base
|
||||
}
|
||||
void mergeAssignsTree(GateVarVertex* vvertexp) { vvertexp->accept(*this); }
|
||||
VDouble0 numMergedAssigns() { return m_numMergedAssigns; }
|
||||
@@ -1405,13 +1378,13 @@ void GateVisitor::mergeAssigns() {
|
||||
class GateConcatVisitor : public GateBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVarScope* m_vscp; // Varscope we're trying to find
|
||||
int m_offset; // Current offset of varscope
|
||||
int m_found_offset; // Found offset of varscope
|
||||
bool m_found; // Offset found
|
||||
AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
|
||||
int m_offset = 0; // Current offset of varscope
|
||||
int m_found_offset = 0; // Found offset of varscope
|
||||
bool m_found = false; // Offset found
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
UINFO(9, "CLK DECOMP Concat search var (off = " << m_offset << ") - " << nodep << endl);
|
||||
if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) {
|
||||
// A concatenation may use the same var multiple times
|
||||
@@ -1423,23 +1396,18 @@ private:
|
||||
}
|
||||
m_offset += nodep->dtypep()->width();
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstConcat* nodep) override {
|
||||
UINFO(9, "CLK DECOMP Concat search (off = " << m_offset << ") - " << nodep << endl);
|
||||
iterate(nodep->rhsp());
|
||||
iterate(nodep->lhsp());
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GateConcatVisitor() {
|
||||
m_vscp = NULL;
|
||||
m_offset = 0;
|
||||
m_found_offset = 0;
|
||||
m_found = false;
|
||||
}
|
||||
virtual ~GateConcatVisitor() {}
|
||||
GateConcatVisitor() {}
|
||||
virtual ~GateConcatVisitor() override {}
|
||||
// PUBLIC METHODS
|
||||
bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) {
|
||||
m_vscp = vscp;
|
||||
@@ -1462,10 +1430,9 @@ class GateClkDecompState {
|
||||
public:
|
||||
int m_offset;
|
||||
AstVarScope* m_last_vsp;
|
||||
GateClkDecompState(int offset, AstVarScope* vsp) {
|
||||
m_offset = offset;
|
||||
m_last_vsp = vsp;
|
||||
}
|
||||
GateClkDecompState(int offset, AstVarScope* vsp)
|
||||
: m_offset{offset}
|
||||
, m_last_vsp{vsp} {}
|
||||
virtual ~GateClkDecompState() {}
|
||||
};
|
||||
|
||||
@@ -1473,14 +1440,14 @@ class GateClkDecompGraphVisitor : public GateGraphBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstVarScope::user2p -> bool: already visited
|
||||
int m_seen_clk_vectors;
|
||||
AstVarScope* m_clk_vsp;
|
||||
GateVarVertex* m_clk_vvertexp;
|
||||
int m_seen_clk_vectors = 0;
|
||||
AstVarScope* m_clk_vsp = nullptr;
|
||||
GateVarVertex* m_clk_vvertexp = nullptr;
|
||||
GateConcatVisitor m_concat_visitor;
|
||||
int m_total_seen_clk_vectors;
|
||||
int m_total_decomposed_clk_vectors;
|
||||
int m_total_seen_clk_vectors = 0;
|
||||
int m_total_decomposed_clk_vectors = 0;
|
||||
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) {
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) override {
|
||||
// Check that we haven't been here before
|
||||
AstVarScope* vsp = vvertexp->varScp();
|
||||
if (vsp->user2SetOnce()) return VNUser(0);
|
||||
@@ -1497,7 +1464,7 @@ private:
|
||||
return VNUser(0); // Unused
|
||||
}
|
||||
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) {
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
|
||||
GateClkDecompState* currState = reinterpret_cast<GateClkDecompState*>(vu.c());
|
||||
int clk_offset = currState->m_offset;
|
||||
if (const AstAssignW* assignp = VN_CAST(lvertexp->nodep(), AssignW)) {
|
||||
@@ -1545,7 +1512,7 @@ private:
|
||||
UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl);
|
||||
UINFO(9, " to - " << m_clk_vsp << endl);
|
||||
AstNode* rhsp = assignp->rhsp();
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ));
|
||||
while (V3GraphEdge* edgep = lvertexp->inBeginp()) {
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
@@ -1563,14 +1530,8 @@ private:
|
||||
|
||||
public:
|
||||
explicit GateClkDecompGraphVisitor(V3Graph* graphp)
|
||||
: GateGraphBaseVisitor(graphp) {
|
||||
m_seen_clk_vectors = 0;
|
||||
m_clk_vsp = NULL;
|
||||
m_clk_vvertexp = NULL;
|
||||
m_total_seen_clk_vectors = 0;
|
||||
m_total_decomposed_clk_vectors = 0;
|
||||
}
|
||||
virtual ~GateClkDecompGraphVisitor() {
|
||||
: GateGraphBaseVisitor{graphp} {}
|
||||
virtual ~GateClkDecompGraphVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors);
|
||||
V3Stats::addStat("Optimizations, Clocker decomposed vectors",
|
||||
m_total_decomposed_clk_vectors);
|
||||
@@ -1610,7 +1571,7 @@ void GateVisitor::decomposeClkVectors() {
|
||||
class GateDeassignVisitor : public GateBaseVisitor {
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
if (AstNodeAssign* assp = VN_CAST(nodep->valuep(), NodeAssign)) {
|
||||
UINFO(5, " Removeassign " << assp << endl);
|
||||
AstNode* valuep = assp->rhsp();
|
||||
@@ -1620,14 +1581,14 @@ private:
|
||||
}
|
||||
}
|
||||
// Speedups
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstActive*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {} // Accelerate
|
||||
virtual void visit(AstActive*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit GateDeassignVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~GateDeassignVisitor() {}
|
||||
virtual ~GateDeassignVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+33
-41
@@ -47,9 +47,9 @@ private:
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
AstActive* m_activep = nullptr; // Inside activate statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstScope* m_scopetopp = nullptr; // Scope under TOPSCOPE
|
||||
|
||||
// METHODS
|
||||
AstVarScope* genInpClk(AstVarScope* vscp) {
|
||||
@@ -67,9 +67,9 @@ private:
|
||||
m_topModp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
||||
m_scopetopp->addVarp(newvscp);
|
||||
AstAssign* asninitp
|
||||
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
AstAssign* asninitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
m_scopetopp->addFinalClkp(asninitp);
|
||||
//
|
||||
vscp->user2p(newvscp);
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
AstNode::user2ClearTree(); // user2p() used on entire tree
|
||||
|
||||
AstScope* scopep = nodep->scopep();
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//----
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
@@ -98,33 +98,31 @@ private:
|
||||
UINFO(8, " VarActReplace " << nodep << endl);
|
||||
// Replace with the new variable
|
||||
AstVarScope* newvscp = genInpClk(vscp);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
iterateChildren(nodep->sensesp()); // iterateAndNext?
|
||||
m_activep = NULL;
|
||||
m_activep = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GenClkRenameVisitor(AstTopScope* nodep, AstNodeModule* topModp) {
|
||||
m_topModp = topModp;
|
||||
m_scopetopp = NULL;
|
||||
m_activep = NULL;
|
||||
GenClkRenameVisitor(AstTopScope* nodep, AstNodeModule* topModp)
|
||||
: m_topModp{topModp} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~GenClkRenameVisitor() {}
|
||||
virtual ~GenClkRenameVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -138,13 +136,13 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
bool m_tracingCall; // Iterating into a call to a cfunc
|
||||
AstNodeAssign* m_assignp; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
bool m_tracingCall = false; // Iterating into a call to a cfunc
|
||||
AstActive* m_activep = nullptr; // Inside activate statement
|
||||
AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp = nullptr; // Top module
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||
iterateChildren(nodep);
|
||||
{
|
||||
@@ -153,14 +151,14 @@ private:
|
||||
GenClkRenameVisitor visitor(nodep, m_topModp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// Only track the top scopes, not lower level functions
|
||||
if (nodep->isTop()) {
|
||||
m_topModp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCCall* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->funcp()->entryPoint()) {
|
||||
// Enter the function and trace it
|
||||
@@ -168,7 +166,7 @@ private:
|
||||
iterate(nodep->funcp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
if (!m_tracingCall && !nodep->entryPoint()) {
|
||||
// Only consider logic within a CFunc when looking
|
||||
// at the call to it, and not when scanning whatever
|
||||
@@ -180,7 +178,7 @@ private:
|
||||
}
|
||||
//----
|
||||
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
// Consumption/generation of a variable,
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
@@ -188,42 +186,36 @@ private:
|
||||
UINFO(8, " VarAct " << nodep << endl);
|
||||
vscp->user1(true);
|
||||
}
|
||||
if (m_assignp && nodep->lvalue() && vscp->user1()) {
|
||||
if (m_assignp && nodep->access().isWrite() && vscp->user1()) {
|
||||
// Variable was previously used as a clock, and is now being set
|
||||
// Thus a unordered generated clock...
|
||||
UINFO(8, " VarSetAct " << nodep << endl);
|
||||
vscp->circular(true);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
// UINFO(8, "ASS " << nodep << endl);
|
||||
m_assignp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_assignp = NULL;
|
||||
m_assignp = nullptr;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
UINFO(8, "ACTIVE " << nodep << endl);
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
iterateChildren(nodep->sensesp()); // iterateAndNext?
|
||||
m_activep = NULL;
|
||||
m_activep = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
//-----
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar*) override {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit GenClkReadVisitor(AstNetlist* nodep)
|
||||
: m_activep(NULL)
|
||||
, m_tracingCall(false)
|
||||
, m_assignp(NULL)
|
||||
, m_topModp(NULL) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~GenClkReadVisitor() {}
|
||||
explicit GenClkReadVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~GenClkReadVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+15
-6
@@ -20,6 +20,7 @@
|
||||
#include "V3Global.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3File.h"
|
||||
#include "V3HierBlock.h"
|
||||
#include "V3LinkCells.h"
|
||||
#include "V3Parse.h"
|
||||
#include "V3ParseSym.h"
|
||||
@@ -34,7 +35,17 @@ AstNetlist* V3Global::makeNetlist() {
|
||||
return newp;
|
||||
}
|
||||
|
||||
void V3Global::checkTree() { rootp()->checkTree(); }
|
||||
void V3Global::clear() {
|
||||
#ifdef VL_LEAK_CHECK
|
||||
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void V3Global::shutdown() {
|
||||
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
|
||||
}
|
||||
|
||||
void V3Global::checkTree() const { rootp()->checkTree(); }
|
||||
|
||||
void V3Global::readFiles() {
|
||||
// NODE STATE
|
||||
@@ -47,8 +58,7 @@ void V3Global::readFiles() {
|
||||
V3Parse parser(v3Global.rootp(), &filter, &parseSyms);
|
||||
// Read top module
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (V3StringList::const_iterator it = vFiles.begin(); it != vFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
for (const string& filename : vFiles) {
|
||||
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, false,
|
||||
"Cannot find file containing module: ");
|
||||
}
|
||||
@@ -57,8 +67,7 @@ void V3Global::readFiles() {
|
||||
// To be compatible with other simulators,
|
||||
// this needs to be done after the top file is read
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
for (V3StringSet::const_iterator it = libraryFiles.begin(); it != libraryFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
for (const string& filename : libraryFiles) {
|
||||
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, true,
|
||||
"Cannot find file containing library module: ");
|
||||
}
|
||||
@@ -78,7 +87,7 @@ void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool
|
||||
}
|
||||
|
||||
const std::string& V3Global::ptrToId(const void* p) {
|
||||
PtrToIdMap::iterator it = m_ptrToId.find(p);
|
||||
auto it = m_ptrToId.find(p);
|
||||
if (it == m_ptrToId.end()) {
|
||||
std::ostringstream os;
|
||||
if (p) {
|
||||
|
||||
+48
-29
@@ -31,26 +31,47 @@
|
||||
#include "V3Options.h"
|
||||
|
||||
#include <string>
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
|
||||
class AstNetlist;
|
||||
class V3HierBlockPlan;
|
||||
|
||||
//======================================================================
|
||||
// Statics
|
||||
// Restorer
|
||||
|
||||
/// Save a given variable's value on the stack, restoring it at
|
||||
/// end-of-stope.
|
||||
// Object must be named, or it will not persist until end-of-scope.
|
||||
// Constructor needs () or GCC 4.8 false warning.
|
||||
#define VL_RESTORER(var) const VRestorer<decltype(var)> restorer_##var(var);
|
||||
|
||||
// Object used by VL_RESTORER. This object must be an auto variable, not
|
||||
// allocated on the heap or otherwise.
|
||||
template <typename T> class VRestorer {
|
||||
T& m_ref; // Reference to object we're saving and restoring
|
||||
const T m_saved; // Value saved, for later restore
|
||||
|
||||
public:
|
||||
VRestorer(T& permr)
|
||||
: m_ref(permr)
|
||||
, m_saved(permr) {}
|
||||
~VRestorer() { m_ref = m_saved; }
|
||||
VL_UNCOPYABLE(VRestorer);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VWidthMinUsage {
|
||||
public:
|
||||
enum en { LINT_WIDTH, MATCHES_WIDTH, VERILOG_WIDTH };
|
||||
enum en : uint8_t { LINT_WIDTH, MATCHES_WIDTH, VERILOG_WIDTH };
|
||||
enum en m_e;
|
||||
inline VWidthMinUsage()
|
||||
: m_e(LINT_WIDTH) {}
|
||||
: m_e{LINT_WIDTH} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline VWidthMinUsage(en _e)
|
||||
: m_e(_e) {}
|
||||
: m_e{_e} {}
|
||||
explicit inline VWidthMinUsage(int _e)
|
||||
: m_e(static_cast<en>(_e)) {}
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
operator en() const { return m_e; }
|
||||
};
|
||||
inline bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) {
|
||||
@@ -69,19 +90,19 @@ inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
|
||||
class V3Global {
|
||||
// Globals
|
||||
AstNetlist* m_rootp; // Root of entire netlist
|
||||
V3HierBlockPlan* m_hierPlanp; // Hierarchical verilation plan, nullptr unless hier_block
|
||||
VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
|
||||
|
||||
int m_debugFileNumber; // Number to append to debug files created
|
||||
bool m_assertDTypesResolved; // Tree should have dtypep()'s
|
||||
bool m_constRemoveXs; // Const needs to strip any Xs
|
||||
bool m_needC11; // Need C++11
|
||||
bool m_needHeavy; // Need verilated_heavy.h include
|
||||
bool m_needTraceDumper; // Need __Vm_dumperp in symbols
|
||||
bool m_dpi; // Need __Dpi include files
|
||||
bool m_useParallelBuild; // Use parallel build for model
|
||||
int m_debugFileNumber = 0; // Number to append to debug files created
|
||||
bool m_assertDTypesResolved = false; // Tree should have dtypep()'s
|
||||
bool m_constRemoveXs = false; // Const needs to strip any Xs
|
||||
bool m_needHeavy = false; // Need verilated_heavy.h include
|
||||
bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols
|
||||
bool m_dpi = false; // Need __Dpi include files
|
||||
bool m_useParallelBuild = false; // Use parallel build for model
|
||||
|
||||
// Memory address to short string mapping (for debug)
|
||||
typedef vl_unordered_map<const void*, std::string> PtrToIdMap; // The map type
|
||||
typedef std::unordered_map<const void*, std::string> PtrToIdMap; // The map type
|
||||
PtrToIdMap m_ptrToId; // The actual 'address' <=> 'short string' bijection
|
||||
|
||||
public:
|
||||
@@ -90,21 +111,16 @@ public:
|
||||
|
||||
// CONSTRUCTORS
|
||||
V3Global()
|
||||
: m_rootp(NULL) // created by makeInitNetlist() so static constructors run first
|
||||
, m_widthMinUsage(VWidthMinUsage::LINT_WIDTH)
|
||||
, m_debugFileNumber(0)
|
||||
, m_assertDTypesResolved(false)
|
||||
, m_constRemoveXs(false)
|
||||
, m_needC11(false)
|
||||
, m_needHeavy(false)
|
||||
, m_needTraceDumper(false)
|
||||
, m_dpi(false)
|
||||
, m_useParallelBuild(false) {}
|
||||
: m_rootp{nullptr} // created by makeInitNetlist(} so static constructors run first
|
||||
, m_hierPlanp{nullptr} // Set via hierPlanp(V3HierBlockPlan*} when use hier_block
|
||||
, m_widthMinUsage{VWidthMinUsage::LINT_WIDTH} {}
|
||||
AstNetlist* makeNetlist();
|
||||
void boot() {
|
||||
UASSERT(!m_rootp, "call once");
|
||||
m_rootp = makeNetlist();
|
||||
}
|
||||
void clear();
|
||||
void shutdown(); // Release allocated resorces
|
||||
// ACCESSORS (general)
|
||||
AstNetlist* rootp() const { return m_rootp; }
|
||||
VWidthMinUsage widthMinUsage() const { return m_widthMinUsage; }
|
||||
@@ -112,7 +128,7 @@ public:
|
||||
|
||||
// METHODS
|
||||
void readFiles();
|
||||
void checkTree();
|
||||
void checkTree() const;
|
||||
static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0,
|
||||
bool doDump = true);
|
||||
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
|
||||
@@ -124,16 +140,19 @@ public:
|
||||
if (newNumber) m_debugFileNumber = newNumber;
|
||||
char digits[100];
|
||||
sprintf(digits, "%03d", m_debugFileNumber);
|
||||
return opt.makeDir() + "/" + opt.prefix() + "_" + digits + "_" + nameComment;
|
||||
return opt.hierTopDataDir() + "/" + opt.prefix() + "_" + digits + "_" + nameComment;
|
||||
}
|
||||
bool needC11() const { return m_needC11; }
|
||||
void needC11(bool flag) { m_needC11 = flag; }
|
||||
bool needHeavy() const { return m_needHeavy; }
|
||||
void needHeavy(bool flag) { m_needHeavy = flag; }
|
||||
bool needTraceDumper() const { return m_needTraceDumper; }
|
||||
void needTraceDumper(bool flag) { m_needTraceDumper = flag; }
|
||||
bool dpi() const { return m_dpi; }
|
||||
void dpi(bool flag) { m_dpi = flag; }
|
||||
V3HierBlockPlan* hierPlanp() const { return m_hierPlanp; }
|
||||
void hierPlanp(V3HierBlockPlan* plan) {
|
||||
UASSERT(!m_hierPlanp, "call once");
|
||||
m_hierPlanp = plan;
|
||||
}
|
||||
void useParallelBuild(bool flag) { m_useParallelBuild = flag; }
|
||||
bool useParallelBuild() const { return m_useParallelBuild; }
|
||||
const std::string& ptrToId(const void* p);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user