mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b350b6a0ff | ||
|
|
80564a8f89 | ||
|
|
016611021d | ||
|
|
fa20614277 | ||
|
|
1e69167191 | ||
|
|
faa5edc068 | ||
|
|
e3c32adad4 | ||
|
|
b054d937cb | ||
|
|
212e8fb14b | ||
|
|
014e43f0ef | ||
|
|
d21b4e3fc7 | ||
|
|
0818d88113 | ||
|
|
77ec2dc875 | ||
|
|
665e8edaff | ||
|
|
67103d346b | ||
|
|
aebb54444e | ||
|
|
a54ac52a35 | ||
|
|
aa360052a8 | ||
|
|
e09f039a36 | ||
|
|
ff262fc4fb | ||
|
|
9a9931fb9d | ||
|
|
30686d8550 | ||
|
|
05f3fd7c6e | ||
|
|
e14319b401 | ||
|
|
1299b70945 | ||
|
|
cf2810db8b | ||
|
|
d77beecc6e | ||
|
|
0c6bd42da3 | ||
|
|
5091298fae | ||
|
|
cef7610b14 | ||
|
|
ed268805ce | ||
|
|
123d1af29d | ||
|
|
cc307626c0 | ||
|
|
963fd0664d | ||
|
|
4643d6e883 | ||
|
|
d89fc05da1 | ||
|
|
84d7380588 | ||
|
|
04febb1944 | ||
|
|
d56b923eaa | ||
|
|
a37866ee92 | ||
|
|
1a92a44c7d | ||
|
|
60a1d25a96 | ||
|
|
ad21f2e850 | ||
|
|
ffbae97a3d | ||
|
|
380137a402 | ||
|
|
ac2058c7ec | ||
|
|
de931d6a97 | ||
|
|
f2d8e45d72 | ||
|
|
085ef5fc05 | ||
|
|
6095efd84e | ||
|
|
114ab1378f | ||
|
|
8622c754b7 | ||
|
|
bf24fa9478 | ||
|
|
e1c45440fc | ||
|
|
b0cb43b2f2 | ||
|
|
dc1f44840d | ||
|
|
fd21a41acd | ||
|
|
cf09a9b6d2 | ||
|
|
dc306cf371 | ||
|
|
35374f09b4 | ||
|
|
e85a2e860e | ||
|
|
103ba1fb6d | ||
|
|
b684995292 | ||
|
|
c371a63d41 | ||
|
|
0102efd4ea | ||
|
|
abfee1270f | ||
|
|
5992d678be | ||
|
|
b6ded59c2b | ||
|
|
c0888c1b0f | ||
|
|
fa77141519 | ||
|
|
b3760911e7 | ||
|
|
b500e57991 | ||
|
|
19e4013ab5 | ||
|
|
82b2af3b83 | ||
|
|
e6f7510895 | ||
|
|
2f718b9ea0 | ||
|
|
899e7bacb2 | ||
|
|
5b3717b369 | ||
|
|
1e7c61b23e | ||
|
|
0e1e380a55 | ||
|
|
1b0a48ea02 | ||
|
|
70b3a599ce | ||
|
|
26c0e6ba00 | ||
|
|
efc6fb7fc3 | ||
|
|
b68038a73f | ||
|
|
f4ef4ad9f3 | ||
|
|
f6f7684ccd | ||
|
|
e74cc32f2d | ||
|
|
c64cc989f0 | ||
|
|
f94fcaa8e4 | ||
|
|
297b297bc7 | ||
|
|
02cb3d17a2 | ||
|
|
c3cfaf55ed | ||
|
|
3e7013af31 | ||
|
|
f7a5883205 | ||
|
|
5d3482734a | ||
|
|
e8c03650ae | ||
|
|
7eac788306 | ||
|
|
6a58e67699 | ||
|
|
b49be06a5a | ||
|
|
87b2adb6a1 | ||
|
|
5634a18f78 | ||
|
|
b84c9bb4c0 | ||
|
|
6dfce882a1 | ||
|
|
79d33bf1ee | ||
|
|
44eb362a18 | ||
|
|
8664aac225 | ||
|
|
6965e138aa | ||
|
|
fc52fb9093 | ||
|
|
cef7708f38 | ||
|
|
438fb01665 | ||
|
|
67d5b1a11a | ||
|
|
d78941885b | ||
|
|
6e7b07c794 | ||
|
|
9655e287ab | ||
|
|
917ca2bad7 | ||
|
|
c3f5dd7414 | ||
|
|
04c7fd1696 | ||
|
|
152689776d | ||
|
|
778f133118 | ||
|
|
ff5465308b | ||
|
|
602750b1ee | ||
|
|
2a24bb4759 | ||
|
|
7c4259bc0a | ||
|
|
1c2384cb3d | ||
|
|
75881754a9 | ||
|
|
0505816d31 | ||
|
|
48bcf66ac7 | ||
|
|
0145d9d514 | ||
|
|
2ce86eddfa | ||
|
|
b663d1a230 | ||
|
|
5821048df7 | ||
|
|
80284c437e | ||
|
|
2aedc91151 | ||
|
|
c1e8337fc1 | ||
|
|
1858cc8ff1 | ||
|
|
5e6aca59ab | ||
|
|
726e78fdda | ||
|
|
085e8454b8 | ||
|
|
85b05366bc | ||
|
|
e6b0479b80 | ||
|
|
3a53b32a32 | ||
|
|
cf7b5c091a | ||
|
|
51b0963e61 | ||
|
|
0c949ceba2 | ||
|
|
5c070558ae | ||
|
|
0c328b6eaf | ||
|
|
f670eccf8c | ||
|
|
23140aeff0 | ||
|
|
d44426b3f3 | ||
|
|
05ff96bea3 | ||
|
|
77ac9bfcc6 | ||
|
|
34b8ed4cf0 | ||
|
|
95d1272269 | ||
|
|
046c0a7aa1 | ||
|
|
835905bdae | ||
|
|
51d1235cda | ||
|
|
2f21b3385a | ||
|
|
9d0a7d5e70 | ||
|
|
4cec3ff2a0 | ||
|
|
25593c0ee2 | ||
|
|
5d3dd52f13 | ||
|
|
ec36d0d772 | ||
|
|
3d2503f9aa | ||
|
|
4576644591 | ||
|
|
d8df216a8d | ||
|
|
964dcd5b7c | ||
|
|
f62c070d06 | ||
|
|
a56e0a6e89 | ||
|
|
451e961e03 | ||
|
|
cb550e5357 | ||
|
|
829db3eefa | ||
|
|
44f938e507 | ||
|
|
4849c0530b | ||
|
|
f4ed367850 | ||
|
|
d4df94d866 | ||
|
|
5d8019f941 | ||
|
|
48597bebaf | ||
|
|
470859f929 | ||
|
|
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 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-modernize*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-default-arguments,-fuchsia-overloaded-operator,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance'
|
||||
Checks: '*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-modernize-use-auto,-modernize-use-trailing-return-type,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
FormatStyle: none
|
||||
|
||||
+5
-5
@@ -85,7 +85,7 @@ jobs:
|
||||
# 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: .}}}
|
||||
#- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
|
||||
############################################################################
|
||||
# Jobs in the 'test' stage
|
||||
############################################################################
|
||||
@@ -136,10 +136,10 @@ jobs:
|
||||
- {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}
|
||||
#- {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,95 @@ Revision history for Verilator
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
* Verilator 4.106 2020-12-02
|
||||
|
||||
** Change -sv option to select 1800-2017 instead of 1800-2005.
|
||||
|
||||
*** Check for proper 'local' and 'protected' (#2228).
|
||||
|
||||
*** Support $random and $urandom seeds.
|
||||
|
||||
*** Support $monitor and $strobe.
|
||||
|
||||
*** Support complex function arguments.
|
||||
|
||||
*** Support 'super'.
|
||||
|
||||
*** Support 'with item.index'.
|
||||
|
||||
**** Fix the default GNU Make executable name on FreeBSD (#2553). [Yuri Victorovich]
|
||||
|
||||
**** Fix trace signal names getting hashed (#2643). [Barbara Gigerl]
|
||||
|
||||
**** Fix unpacked array parameters near functions (#2639). [Anderson Ignacio da Silva]
|
||||
|
||||
**** Fix access to non-overridden base class variable (#2654). [Tobias Rosenkranz]
|
||||
|
||||
|
||||
* Verilator 4.104 2020-11-14
|
||||
|
||||
*** Support queue and associative array 'with' statements (#2616).
|
||||
|
||||
*** Support queue slicing (#2326).
|
||||
|
||||
*** Support associative array pattern assignments and defaults.
|
||||
|
||||
*** Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski]
|
||||
|
||||
**** Report error on typedef referencing self (#2539). [Cody Piersall]
|
||||
|
||||
**** With --debug, turn off address space layout randomization.
|
||||
|
||||
**** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett]
|
||||
|
||||
**** Fix cast width propagation (#2597). [flex-liu]
|
||||
|
||||
**** Fix return from callValueCbs (#2589) (#2605). [Marlon James]
|
||||
|
||||
**** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick]
|
||||
|
||||
**** Fix fault when $fgets, $sscanf, etc used with string (#2604). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Fix WIFEXITED missing from MinGW/MSYS2 (#2609). [Jean Berniolles]
|
||||
|
||||
**** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1]
|
||||
|
||||
**** Fix arrays of modport interfaces (#2614). [Thierry Tambe]
|
||||
|
||||
**** Fix split_var internal error (#2640) (#2641). [Yutetsu TAKATSUKASA]
|
||||
|
||||
|
||||
* 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.
|
||||
@@ -27,6 +116,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Add support for assume property. [Peter Monsson]
|
||||
|
||||
**** Add support for |=> inside properties (#1292). [Peter Monsson]
|
||||
|
||||
|
||||
* Verilator 4.040 2020-08-15
|
||||
|
||||
|
||||
@@ -66,4 +66,5 @@ ci/
|
||||
/csrc/
|
||||
obj_dir.*
|
||||
TAGS
|
||||
gmon.out
|
||||
.*~
|
||||
|
||||
+9
-5
@@ -170,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 \
|
||||
@@ -440,15 +442,16 @@ cppcheck: $(CPPCHECK_DEP)
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
|
||||
|
||||
CLANGTIDY = clang-tidy
|
||||
CLANGTIDY_FLAGS = -config=''
|
||||
CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables'
|
||||
CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \
|
||||
$(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP))
|
||||
CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_THREADED=1 -DVL_CPPCHECK=1
|
||||
|
||||
clangtidy: $(CLANGTIDY_DEP)
|
||||
clang-tidy: $(CLANGTIDY_DEP)
|
||||
%.cpp.tidy: %.cpp
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@
|
||||
%.h.tidy: %.h
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@
|
||||
|
||||
analyzer-src:
|
||||
-rm -rf src/obj_dbg
|
||||
@@ -460,11 +463,12 @@ analyzer-include:
|
||||
|
||||
CLANGFORMAT = clang-format
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c*
|
||||
|
||||
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) $(CPPCHECK_YL)
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||
|
||||
ftp: info
|
||||
|
||||
|
||||
+32
-19
@@ -76,7 +76,8 @@ if ($opt_gdbbt && !gdb_works()) {
|
||||
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
|
||||
if ($opt_gdb) {
|
||||
# Generic GDB interactive
|
||||
run (($ENV{VERILATOR_GDB}||"gdb")
|
||||
run (aslr_off()
|
||||
.($ENV{VERILATOR_GDB}||"gdb")
|
||||
." ".verilator_bin()
|
||||
# Note, uncomment to set breakpoints before running:
|
||||
# ." -ex 'break main'"
|
||||
@@ -91,16 +92,22 @@ if ($opt_gdb) {
|
||||
." -ex 'bt'");
|
||||
} elsif ($opt_rr) {
|
||||
# Record with rr
|
||||
run ("rr record ".verilator_bin()
|
||||
run (aslr_off()
|
||||
."rr record ".verilator_bin()
|
||||
." ".join(' ', @quoted_sw));
|
||||
} elsif ($opt_gdbbt && $Debug) {
|
||||
# Run under GDB to get gdbbt
|
||||
run ("gdb"
|
||||
run (aslr_off()
|
||||
."gdb"
|
||||
." ".verilator_bin()
|
||||
." --batch --quiet --return-child-result"
|
||||
." -ex \"run ".join(' ', @quoted_sw)."\""
|
||||
." -ex 'set width 0'"
|
||||
." -ex 'bt' -ex 'quit'");
|
||||
} elsif ($Debug) {
|
||||
# Debug
|
||||
run(aslr_off()
|
||||
.verilator_bin()." ".join(' ',@quoted_sw));
|
||||
} else {
|
||||
# Normal, non gdb
|
||||
run(verilator_bin()." ".join(' ',@quoted_sw));
|
||||
@@ -165,6 +172,15 @@ sub gdb_works {
|
||||
return $status==0;
|
||||
}
|
||||
|
||||
sub aslr_off {
|
||||
my $ok = `setarch --addr-no-randomize echo ok 2>/dev/null` || "";
|
||||
if ($ok =~ /ok/) {
|
||||
return "setarch --addr-no-randomize ";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
sub run {
|
||||
# Run command, check errors
|
||||
my $command = shift;
|
||||
@@ -1445,7 +1461,7 @@ future version of Verilator no longer always packs unpacked structures.
|
||||
=item -sv
|
||||
|
||||
Specifies SystemVerilog language features should be enabled; equivalent to
|
||||
"--language 1800-2005". This option is selected by default, it exists for
|
||||
"--language 1800-2017". This option is selected by default, it exists for
|
||||
compatibility with other simulators.
|
||||
|
||||
=item +systemverilogext+I<ext>
|
||||
@@ -1980,14 +1996,15 @@ section below for descriptions of some of the files that were created.
|
||||
|
||||
(Verilator included a default compile rule and link rule, since we used
|
||||
--exe and passed a .cpp file on the Verilator command line. Verilator also
|
||||
then used C<make> to build a final executable. You can also write your own
|
||||
compile rules, and run make yourself as we'll show in the SYSTEMC section.)
|
||||
then used C<make> to build a final executable, since we used --build. You
|
||||
can also write your own compile rules, and run make yourself as we'll show
|
||||
in the SYSTEMC section.
|
||||
|
||||
And now we run it
|
||||
And now we run it:
|
||||
|
||||
obj_dir/Vour
|
||||
|
||||
And we get as output
|
||||
And we get as output:
|
||||
|
||||
Hello World
|
||||
- our.v:2: Verilog $finish
|
||||
@@ -4075,9 +4092,10 @@ is ignored, only a single trace file may be active at once.
|
||||
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
|
||||
$dumplimit/$dumpportlimit are currently ignored.
|
||||
|
||||
=item $finish, $stop
|
||||
=item $exit, $finish, $stop
|
||||
|
||||
The rarely used optional parameter to $finish and $stop is ignored.
|
||||
The rarely used optional parameter to $finish and $stop is ignored. $exit
|
||||
is aliased to $finish.
|
||||
|
||||
=item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets,
|
||||
$fscanf, $fwrite, $fscanf, $sscanf
|
||||
@@ -4089,17 +4107,12 @@ $setup, $setuphold, $skew, $timeskew, $width
|
||||
|
||||
All specify blocks and timing checks are ignored.
|
||||
|
||||
=item $monitor, $strobe
|
||||
|
||||
Monitor and strobe are not supported, convert to always_comb $display or
|
||||
similar.
|
||||
|
||||
=item $random, $urandom, $urandom_range
|
||||
|
||||
$random and $urandom do not support the optional argument to set the seed.
|
||||
Use +verilator+seed argument to set the seed. There is one random seed per
|
||||
C thread, not per module for $random, nor per object for random stability
|
||||
of $urandom/$urandom_range.
|
||||
Use +verilator+seed argument to set the seed if there is no $random or
|
||||
$urandom optional argument to set the seed. There is one random seed per C
|
||||
thread, not per module for $random, nor per object for random stability of
|
||||
$urandom/$urandom_range.
|
||||
|
||||
=item $readmemb, $readmemh
|
||||
|
||||
|
||||
@@ -9,22 +9,6 @@ use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw($Debug);
|
||||
|
||||
#======================================================================
|
||||
|
||||
# Old version 1 dump nodes with no dtypep's
|
||||
our %Ver1_Non_Dtyped = map {$_ => 1} qw(
|
||||
ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM
|
||||
CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE
|
||||
COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT
|
||||
DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF
|
||||
IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST
|
||||
NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE
|
||||
PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR
|
||||
SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS
|
||||
SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT
|
||||
TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE
|
||||
UDPTABLELINE UNTILSTABLE VASSERT WHILE );
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
@@ -133,8 +117,6 @@ sub filter {
|
||||
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
||||
if ($verCvt) {
|
||||
next if $line =~ /^ NETLIST/;
|
||||
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
||||
# # Below Ver1_Non_Dtyped may replace above further
|
||||
if ($line =~ /: ([A-Z]+) /) {
|
||||
my $type = $1;
|
||||
next if $type =~ 'DTYPE';
|
||||
@@ -147,14 +129,7 @@ sub filter {
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($Ver1_Non_Dtyped{$type}) {
|
||||
$line =~ s! w[0-9]+!!g;
|
||||
}
|
||||
}
|
||||
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
||||
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
||||
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
||||
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
||||
}
|
||||
print $f2 $line;
|
||||
}
|
||||
|
||||
+88
-9
@@ -60,6 +60,7 @@ sub process {
|
||||
my $filename = shift;
|
||||
|
||||
read_data($filename);
|
||||
read_cpuinfo();
|
||||
report();
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ sub read_data {
|
||||
|
||||
%Global = (rdtsc_cycle_time => 0);
|
||||
|
||||
my $fh = IO::File->new ($filename) or die "%Error: $! $filename,";
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
|
||||
while (my $line = $fh->getline) {
|
||||
if ($line =~ m/VLPROF mtask\s(\d+)\sstart\s(\d+)\send\s(\d+)\selapsed\s(\d+)\spredict_time\s(\d+)\scpu\s(\d+)\son thread (\d+)/) {
|
||||
my $mtask = $1;
|
||||
@@ -113,6 +114,27 @@ sub read_data {
|
||||
}
|
||||
}
|
||||
|
||||
sub read_cpuinfo {
|
||||
my $filename = "/proc/cpuinfo";
|
||||
my $fh = IO::File->new("<$filename") or return;
|
||||
my $cpu;
|
||||
while (my $line = $fh->getline) {
|
||||
chomp $line;
|
||||
if ($line =~ m/^processor\s*:\s*(\d+)\s*$/) {
|
||||
$cpu = $1;
|
||||
}
|
||||
if ($cpu && $line =~ m/^([a-z_ ]+)\s*:\s*(.*)$/) {
|
||||
my ($term, $value) = ($1, $2);
|
||||
$term =~ s/\s+$//;
|
||||
$term =~ s/\s+/_/;
|
||||
$value =~ s/\s+$//;
|
||||
$Global{cpuinfo}{$cpu}{$term} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub report {
|
||||
print "Verilator Gantt report\n";
|
||||
|
||||
@@ -156,14 +178,15 @@ 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;
|
||||
printf " All-thread mtask time = %d rdtsc ticks\n", $mt_mtask_time;
|
||||
my $long_efficiency = $long_mtask_time/($Global{last_end});
|
||||
my $long_efficiency = $long_mtask_time/($Global{last_end} || 1);
|
||||
printf " Longest-thread efficiency = %0.1f%%\n", $long_efficiency*100;
|
||||
my $mt_efficiency = $mt_mtask_time/($Global{last_end}*$nthreads);
|
||||
my $mt_efficiency = $mt_mtask_time/($Global{last_end}*$nthreads || 1);
|
||||
printf " All-thread efficiency = %0.1f%%\n", $mt_efficiency*100;
|
||||
printf " All-thread speedup = %0.1f\n", $mt_efficiency*$nthreads;
|
||||
if ($Global{rdtsc_cycle_time} > 0) {
|
||||
@@ -197,17 +220,72 @@ sub report {
|
||||
}
|
||||
|
||||
print "\nStatistics:\n";
|
||||
print " min log(p2e) = $min_p2e from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict}, elapsed $Mtasks{$min_mtask}{elapsed})\n";
|
||||
print " max log(p2e) = $max_p2e from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict}, elapsed $Mtasks{$max_mtask}{elapsed})\n";
|
||||
printf " min log(p2e) = %0.3f", $min_p2e;
|
||||
print " from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict},";
|
||||
print " elapsed $Mtasks{$min_mtask}{elapsed})\n";
|
||||
printf " max log(p2e) = %0.3f", $max_p2e;
|
||||
print " from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict},";
|
||||
print " elapsed $Mtasks{$max_mtask}{elapsed})\n";
|
||||
|
||||
my $stddev = stddev(\@p2e_ratios);
|
||||
my $mean = mean(\@p2e_ratios);
|
||||
print " mean = " . ($mean) . "\n";
|
||||
print " stddev = " . ($stddev) . "\n";
|
||||
print " e ^ stddev = " . exp($stddev). "\n";
|
||||
printf " mean = %0.3f\n", $mean;
|
||||
printf " stddev = %0.3f\n", $stddev;
|
||||
printf " e ^ stddev = %0.3f\n", exp($stddev);
|
||||
|
||||
report_cpus();
|
||||
|
||||
if ($nthreads > $ncpus) {
|
||||
print "\n";
|
||||
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
|
||||
print " : See docs on use of numactl.\n";
|
||||
} else {
|
||||
if ($Global{cpu_socket_cores_warning}) {
|
||||
print "\n";
|
||||
print "%Warning: Multiple threads scheduled on same hyperthreaded core.\n";
|
||||
print " : See docs on use of numactl.\n";
|
||||
}
|
||||
if ($Global{cpu_sockets_warning}) {
|
||||
print "\n";
|
||||
print "%Warning: Threads scheduled on multiple sockets.\n";
|
||||
print " : See docs on use of numactl.\n";
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
sub report_cpus {
|
||||
print "\nCPUs:\n";
|
||||
# Test - show all cores
|
||||
# for (my $i=0; $i<73; ++$i) { $Global{cpus}{$i} ||= {cpu_time => 0}; }
|
||||
|
||||
$Global{cpu_sockets} ||= {};
|
||||
$Global{cpu_socket_cores} ||= {};
|
||||
|
||||
foreach my $cpu (sort {$a <=> $b} keys %{$Global{cpus}}) {
|
||||
printf " cpu %d: ", $cpu;
|
||||
printf "cpu_time=%d", $Global{cpus}{$cpu}{cpu_time};
|
||||
|
||||
my $socket = $Global{cpuinfo}{$cpu}{physical_id};
|
||||
$Global{cpu_sockets}{$socket}++ if defined $socket;
|
||||
printf " socket=%d", $socket if defined $socket;
|
||||
|
||||
my $core = $Global{cpuinfo}{$cpu}{core_id};
|
||||
$Global{cpu_socket_cores}{$socket."__".$core}++ if defined $socket && defined $core;
|
||||
printf " core=%d", $core if defined $core;
|
||||
|
||||
my $model = $Global{cpuinfo}{$cpu}{model_name};
|
||||
printf " %s", $model if defined $model;
|
||||
print "\n";
|
||||
}
|
||||
|
||||
$Global{cpu_sockets_warning} = 1
|
||||
if (scalar keys %{$Global{cpu_sockets}} > 1);
|
||||
foreach my $scn (values %{$Global{cpu_socket_cores}}) {
|
||||
$Global{cpu_socket_cores_warning} = 1 if $scn > 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub report_graph {
|
||||
my $time_per = $Opt_Time_Per_Char;
|
||||
if ($time_per == 0) {
|
||||
@@ -219,6 +297,7 @@ sub report_graph {
|
||||
}
|
||||
# One more step so we can fit more labels
|
||||
$time_per = int($time_per/2);
|
||||
$time_per ||= 1;
|
||||
}
|
||||
|
||||
my ($graph, $conflicts) = _make_graph($time_per);
|
||||
|
||||
@@ -40,7 +40,7 @@ RUN apt-get update \
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
|
||||
RUN cpan install -fi Unix::Processors Parallel::Forker
|
||||
|
||||
RUN git clone https://github.com/veripool/vcddiff.git && \
|
||||
make -C vcddiff && \
|
||||
|
||||
@@ -94,7 +94,6 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||
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
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.100 2020-09-07],
|
||||
AC_INIT([Verilator],[4.106 2020-12-02],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
|
||||
@@ -25,20 +25,26 @@ Iztok Jeras
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
Jamey Hicks
|
||||
James Pallister
|
||||
Jan Van Winkel
|
||||
Jean Berniolles
|
||||
Jeremy Bennett
|
||||
John Coiner
|
||||
John Demme
|
||||
Josh Redford
|
||||
Julien Margetts
|
||||
Kaleb Barrett
|
||||
Kanad Kanhere
|
||||
Kevin Kiningham
|
||||
Krzysztof Bieganski
|
||||
Kuba Ober
|
||||
Ludwig Rogiers
|
||||
Lukasz Dalek
|
||||
Maarten De Braekeleer
|
||||
Maciej Sobkowski
|
||||
Marco Widmer
|
||||
Markus Krause
|
||||
Marlon James
|
||||
Marshal Qiao
|
||||
Matthew Ballance
|
||||
Michael Killough
|
||||
@@ -52,6 +58,7 @@ Philipp Wagner
|
||||
Pieter Kapsenberg
|
||||
Piotr Binkowski
|
||||
Qingyao Sun
|
||||
Rafal Kapuscik
|
||||
Richard Myers
|
||||
Rupert Swarbrick
|
||||
Sean Cross
|
||||
@@ -65,6 +72,7 @@ Tobias Wölfel
|
||||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Tymoteusz Blazejczyk
|
||||
Victor Besyakov
|
||||
Vassilis Papaefstathiou
|
||||
Veripool API Bot
|
||||
Wilson Snyder
|
||||
|
||||
@@ -102,7 +102,6 @@ Those developing Verilator itself may also want these (see internals.adoc):
|
||||
cpan install Pod::Perldoc
|
||||
cpan install Unix::Processors
|
||||
cpan install Parallel::Forker
|
||||
cpan install Bit::Vector
|
||||
|
||||
==== Install SystemC
|
||||
|
||||
|
||||
+13
-6
@@ -586,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
|
||||
@@ -628,8 +628,6 @@ https://github.com/veripool/vcddiff
|
||||
|
||||
* Cmake for build paths that use it.
|
||||
|
||||
* Bit::Vector to test vgen.pl
|
||||
|
||||
=== Controlling the Test Driver
|
||||
|
||||
Test drivers are written in PERL. All invoke the main test driver script,
|
||||
@@ -672,7 +670,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,
|
||||
);
|
||||
@@ -758,6 +756,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
|
||||
@@ -950,9 +957,9 @@ Then, when the watch fires, to break at every following change to that node:
|
||||
To print a node:
|
||||
|
||||
pn nodep
|
||||
# or: call nodep->dumpGdb() # aliased to "pn" in src/.gdbinit
|
||||
# or: call dumpGdb(nodep) # aliased to "pn" in src/.gdbinit
|
||||
pnt nodep
|
||||
# or: call nodep->dumpTreeGdb() # aliased to "pnt" in src/.gdbinit
|
||||
# or: call dumpTreeGdb(nodep) # aliased to "pnt" in src/.gdbinit
|
||||
|
||||
When GDB halts, it is useful to understand that the backtrace will commonly
|
||||
show the iterator functions between each invocation of `visit` in the
|
||||
|
||||
+217
-182
@@ -61,7 +61,7 @@ typedef union {
|
||||
// Global variables
|
||||
|
||||
// Slow path variables
|
||||
VerilatedMutex Verilated::m_mutex;
|
||||
VerilatedMutex Verilated::s_mutex;
|
||||
|
||||
// Keep below together in one cache line
|
||||
Verilated::Serialized Verilated::s_s;
|
||||
@@ -75,7 +75,7 @@ VerilatedImp::VerilatedImpU VerilatedImp::s_s;
|
||||
struct VerilatedImpInitializer {
|
||||
VerilatedImpInitializer() { VerilatedImp::setup(); }
|
||||
~VerilatedImpInitializer() { VerilatedImp::teardown(); }
|
||||
} g_VerilatedImpInitializer;
|
||||
} s_VerilatedImpInitializer;
|
||||
|
||||
//===========================================================================
|
||||
// User definable functions
|
||||
@@ -256,6 +256,7 @@ Verilated::Serialized::Serialized() {
|
||||
s_errorLimit = 1;
|
||||
s_randReset = 0;
|
||||
s_randSeed = 0;
|
||||
s_randSeedEpoch = 1;
|
||||
s_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure
|
||||
s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure
|
||||
}
|
||||
@@ -279,6 +280,8 @@ void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.v.m_s
|
||||
static vluint32_t vl_sys_rand32() VL_MT_UNSAFE {
|
||||
// Return random 32-bits using system library.
|
||||
// Used only to construct seed for Verilator's PNRG.
|
||||
static VerilatedMutex s_mutex;
|
||||
const VerilatedLockGuard lock(s_mutex); // Otherwise rand is unsafe
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
// Windows doesn't have lrand48(), although Cygwin does.
|
||||
return (rand() << 16) ^ rand();
|
||||
@@ -288,29 +291,18 @@ static vluint32_t vl_sys_rand32() VL_MT_UNSAFE {
|
||||
}
|
||||
|
||||
vluint64_t vl_rand64() VL_MT_SAFE {
|
||||
static VerilatedMutex s_mutex;
|
||||
static VL_THREAD_LOCAL bool t_seeded = false;
|
||||
static VL_THREAD_LOCAL vluint32_t t_seedEpoch = 0;
|
||||
static VL_THREAD_LOCAL vluint64_t t_state[2];
|
||||
if (VL_UNLIKELY(!t_seeded)) {
|
||||
t_seeded = true;
|
||||
{
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
if (Verilated::randSeed() != 0) {
|
||||
t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
|
||||
^ (static_cast<vluint64_t>(Verilated::randSeed())));
|
||||
t_state[1] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
|
||||
^ (static_cast<vluint64_t>(Verilated::randSeed())));
|
||||
} else {
|
||||
t_state[0] = ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
|
||||
^ (static_cast<vluint64_t>(vl_sys_rand32())));
|
||||
t_state[1] = ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
|
||||
^ (static_cast<vluint64_t>(vl_sys_rand32())));
|
||||
}
|
||||
// Fix state as algorithm is slow to randomize if many zeros
|
||||
// This causes a loss of ~ 1 bit of seed entropy, no big deal
|
||||
if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0];
|
||||
if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1];
|
||||
}
|
||||
// For speed, we use a thread-local epoch number to know when to reseed
|
||||
if (VL_UNLIKELY(t_seedEpoch != Verilated::randSeedEpoch())) {
|
||||
// Set epoch before state, in case races with new seeding
|
||||
t_seedEpoch = Verilated::randSeedEpoch();
|
||||
t_state[0] = Verilated::randSeedDefault64();
|
||||
t_state[1] = t_state[0];
|
||||
// Fix state as algorithm is slow to randomize if many zeros
|
||||
// This causes a loss of ~ 1 bit of seed entropy, no big deal
|
||||
if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0];
|
||||
if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1];
|
||||
}
|
||||
// Xoroshiro128+ algorithm
|
||||
vluint64_t result = t_state[0] + t_state[1];
|
||||
@@ -334,6 +326,11 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE {
|
||||
Verilated::randSeed(static_cast<int>(seed));
|
||||
return VL_RANDOM_I(obits);
|
||||
}
|
||||
|
||||
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
||||
if (Verilated::randReset() == 0) return 0;
|
||||
IData data = ~0;
|
||||
@@ -556,7 +553,7 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W
|
||||
return owp;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return owp;
|
||||
}
|
||||
return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp);
|
||||
}
|
||||
@@ -688,7 +685,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
// Note uses a single buffer internally; presumes only one usage per printf
|
||||
// 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];
|
||||
static VL_THREAD_LOCAL char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
|
||||
const char* pctp = nullptr; // Most recent %##.##g format
|
||||
bool inPct = false;
|
||||
bool widthSet = false;
|
||||
@@ -766,11 +763,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
if (lbits) {} // UNUSED - always 64
|
||||
if (fmt == '^') { // Realtime
|
||||
if (!widthSet) width = VerilatedImp::timeFormatWidth();
|
||||
output += _vl_vsformat_time(tmp, d, left, width);
|
||||
output += _vl_vsformat_time(t_tmp, d, left, width);
|
||||
} else {
|
||||
std::string fmts(pctp, pos - pctp + 1);
|
||||
sprintf(tmp, fmts.c_str(), d);
|
||||
output += tmp;
|
||||
sprintf(t_tmp, fmts.c_str(), d);
|
||||
output += t_tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -814,9 +811,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
int digits = 0;
|
||||
std::string append;
|
||||
if (lbits <= VL_QUADSIZE) {
|
||||
digits = sprintf(tmp, "%" VL_PRI64 "d",
|
||||
digits = sprintf(t_tmp, "%" VL_PRI64 "d",
|
||||
static_cast<vlsint64_t>(VL_EXTENDS_QQ(lbits, lbits, ld)));
|
||||
append = tmp;
|
||||
append = t_tmp;
|
||||
} else {
|
||||
if (VL_SIGN_E(lbits, lwp[VL_WORDS_I(lbits) - 1])) {
|
||||
WData neg[VL_VALUE_STRING_MAX_WIDTH / 4 + 2];
|
||||
@@ -843,8 +840,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
int digits = 0;
|
||||
std::string append;
|
||||
if (lbits <= VL_QUADSIZE) {
|
||||
digits = sprintf(tmp, "%" VL_PRI64 "u", ld);
|
||||
append = tmp;
|
||||
digits = sprintf(t_tmp, "%" VL_PRI64 "u", ld);
|
||||
append = t_tmp;
|
||||
} else {
|
||||
append = VL_DECIMAL_NW(lbits, lwp);
|
||||
digits = append.length();
|
||||
@@ -863,7 +860,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
}
|
||||
case 't': { // Time
|
||||
if (!widthSet) width = VerilatedImp::timeFormatWidth();
|
||||
output += _vl_vsformat_time(tmp, static_cast<double>(ld), left, width);
|
||||
output += _vl_vsformat_time(t_tmp, static_cast<double>(ld), left, width);
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
@@ -913,10 +910,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
|
||||
@@ -1036,7 +1034,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
// Read a Verilog $sscanf/$fscanf style format into the output list
|
||||
// The format must be pre-processed (and lower cased) by Verilator
|
||||
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
|
||||
static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH];
|
||||
static VL_THREAD_LOCAL char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
|
||||
int floc = fbits - 1;
|
||||
IData got = 0;
|
||||
bool inPct = false;
|
||||
@@ -1044,7 +1042,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
const char* pos = formatp;
|
||||
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
|
||||
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
|
||||
// fromp, fstr)<<"'"<<endl);
|
||||
// fromp, fstr)<<"'\n");
|
||||
if (!inPct && pos[0] == '%') {
|
||||
inPct = true;
|
||||
inIgnore = false;
|
||||
@@ -1078,7 +1076,17 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
WData qowp[VL_WQ_WORDS_E];
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
WDataOutP owp = qowp;
|
||||
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
|
||||
if (obits == -1) { // string
|
||||
owp = nullptr;
|
||||
if (VL_UNCOVERABLE(fmt != 's')) {
|
||||
VL_FATAL_MT(
|
||||
__FILE__, __LINE__, "",
|
||||
"Internal: format other than %s is passed to string"); // LCOV_EXCL_LINE
|
||||
}
|
||||
} else if (obits > VL_QUADSIZE) {
|
||||
owp = va_arg(ap, WDataOutP);
|
||||
}
|
||||
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
switch (fmt) {
|
||||
case 'c': {
|
||||
@@ -1090,22 +1098,24 @@ 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, nullptr);
|
||||
if (!tmp[0]) goto done;
|
||||
int lpos = (static_cast<int>(strlen(tmp))) - 1;
|
||||
int lsb = 0;
|
||||
for (int i = 0; i < obits && lpos >= 0; --lpos) {
|
||||
_vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]);
|
||||
lsb += 8;
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, nullptr);
|
||||
if (!t_tmp[0]) goto done;
|
||||
if (owp) {
|
||||
int lpos = (static_cast<int>(strlen(t_tmp))) - 1;
|
||||
int lsb = 0;
|
||||
for (int i = 0; i < obits && lpos >= 0; --lpos) {
|
||||
_vl_vsss_setbit(owp, obits, lsb, 8, t_tmp[lpos]);
|
||||
lsb += 8;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'd': { // Signed decimal
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "0123456789+-xXzZ?_");
|
||||
if (!t_tmp[0]) goto done;
|
||||
vlsint64_t ld = 0;
|
||||
sscanf(tmp, "%30" VL_PRI64 "d", &ld);
|
||||
sscanf(t_tmp, "%30" VL_PRI64 "d", &ld);
|
||||
VL_SET_WQ(owp, ld);
|
||||
break;
|
||||
}
|
||||
@@ -1113,46 +1123,47 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
case 'e':
|
||||
case 'g': { // Real number
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
|
||||
if (!tmp[0]) goto done;
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "+-.0123456789eE");
|
||||
if (!t_tmp[0]) goto done;
|
||||
// cppcheck-suppress unusedStructMember // It's used
|
||||
union {
|
||||
double r;
|
||||
vlsint64_t ld;
|
||||
} u;
|
||||
u.r = strtod(tmp, nullptr);
|
||||
u.r = strtod(t_tmp, nullptr);
|
||||
VL_SET_WQ(owp, u.ld);
|
||||
break;
|
||||
}
|
||||
case 't': // FALLTHRU // Time
|
||||
case '#': { // Unsigned decimal
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "0123456789+-xXzZ?_");
|
||||
if (!t_tmp[0]) goto done;
|
||||
QData ld = 0;
|
||||
sscanf(tmp, "%30" VL_PRI64 "u", &ld);
|
||||
sscanf(t_tmp, "%30" VL_PRI64 "u", &ld);
|
||||
VL_SET_WQ(owp, ld);
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "01xXzZ?_");
|
||||
if (!t_tmp[0]) goto done;
|
||||
_vl_vsss_based(owp, obits, 1, t_tmp, 0, strlen(t_tmp));
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "01234567xXzZ?_");
|
||||
if (!t_tmp[0]) goto done;
|
||||
_vl_vsss_based(owp, obits, 3, t_tmp, 0, strlen(t_tmp));
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
|
||||
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp,
|
||||
"0123456789abcdefABCDEFxXzZ?_");
|
||||
if (!t_tmp[0]) goto done;
|
||||
_vl_vsss_based(owp, obits, 4, t_tmp, 0, strlen(t_tmp));
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
@@ -1182,15 +1193,20 @@ 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;
|
||||
// Reload data if non-wide (if wide, we put it in the right place directly)
|
||||
if (obits == 0) { // Due to inIgnore
|
||||
} else if (obits == -1) { // string
|
||||
std::string* p = va_arg(ap, std::string*);
|
||||
*p = t_tmp;
|
||||
} else if (obits <= VL_BYTESIZE) {
|
||||
CData* p = va_arg(ap, CData*);
|
||||
*p = owp[0];
|
||||
@@ -1249,36 +1265,44 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
|
||||
for (; i < bytes; ++i) { *op++ = 0; }
|
||||
}
|
||||
|
||||
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
|
||||
static IData getLine(std::string& str, IData fpi, size_t maxLen) VL_MT_SAFE {
|
||||
str.clear();
|
||||
|
||||
// While threadsafe, each thread can only access different file handles
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
|
||||
// The string needs to be padded with 0's in unused spaces in front of
|
||||
// any read data. This means we can't know in what location the first
|
||||
// character will finally live, so we need to copy. Yuk.
|
||||
IData bytes = VL_BYTES_I(obits);
|
||||
char buffer[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
|
||||
// We don't use fgets, as we must read \0s.
|
||||
while (str.size() < maxLen) {
|
||||
const int c = getc(fp); // getc() is threadsafe
|
||||
if (c == EOF) break;
|
||||
str.push_back(c);
|
||||
if (c == '\n') break;
|
||||
}
|
||||
return str.size();
|
||||
}
|
||||
|
||||
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
|
||||
std::string str;
|
||||
const IData bytes = VL_BYTES_I(obits);
|
||||
IData got = getLine(str, fpi, bytes);
|
||||
|
||||
if (VL_UNLIKELY(str.empty())) return 0;
|
||||
|
||||
// V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe
|
||||
if (VL_UNCOVERABLE(bytes > VL_TO_STRING_MAX_WORDS * VL_EDATASIZE)) {
|
||||
if (VL_UNCOVERABLE(bytes < str.size())) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun"); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// We don't use fgets, as we must read \0s.
|
||||
IData got = 0;
|
||||
char* cp = buffer;
|
||||
while (got < bytes) {
|
||||
int c = getc(fp); // getc() is threadsafe
|
||||
if (c == EOF) break;
|
||||
*cp++ = c;
|
||||
got++;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
|
||||
_VL_STRING_TO_VINT(obits, destp, got, buffer);
|
||||
_VL_STRING_TO_VINT(obits, destp, got, str.data());
|
||||
return got;
|
||||
}
|
||||
|
||||
// declared in verilated_heavy.h
|
||||
IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE {
|
||||
return getLine(dest, fpi, std::numeric_limits<size_t>::max());
|
||||
}
|
||||
|
||||
IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
|
||||
// We ignore lhs/fpi - IEEE says "most recent error" so probably good enough
|
||||
IData ret = errno;
|
||||
@@ -1306,58 +1330,58 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
|
||||
void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); }
|
||||
|
||||
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
|
||||
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
|
||||
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
|
||||
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
|
||||
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str());
|
||||
_VL_STRING_TO_VINT(obits, destp, t_output.length(), t_output.c_str());
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE {
|
||||
@@ -1370,38 +1394,38 @@ void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, .
|
||||
}
|
||||
|
||||
std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
return output;
|
||||
return t_output;
|
||||
}
|
||||
|
||||
void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
VL_PRINTF_MT("%s", output.c_str());
|
||||
VL_PRINTF_MT("%s", t_output.c_str());
|
||||
}
|
||||
|
||||
void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
|
||||
// While threadsafe, each thread can only access different file handles
|
||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||
output = "";
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
_vl_vsformat(t_output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
VerilatedImp::fdWrite(fpi, output);
|
||||
VerilatedImp::fdWrite(fpi, t_output);
|
||||
}
|
||||
|
||||
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
|
||||
@@ -1622,12 +1646,12 @@ 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];
|
||||
static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||
if (match.empty()) return nullptr;
|
||||
outstr[0] = '\0';
|
||||
strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+"
|
||||
t_outstr[0] = '\0';
|
||||
strncat(t_outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+"
|
||||
VL_VALUE_STRING_MAX_WIDTH - 1);
|
||||
return outstr;
|
||||
return t_outstr;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
@@ -1733,31 +1757,31 @@ 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 VL_THREAD_LOCAL char buf[32];
|
||||
static VL_THREAD_LOCAL char t_buf[32];
|
||||
switch ((nBits - 1) / 4) {
|
||||
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
|
||||
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
|
||||
case 2: VL_SNPRINTF(buf, 32, "%%03x"); break;
|
||||
case 3: VL_SNPRINTF(buf, 32, "%%04x"); break;
|
||||
case 4: VL_SNPRINTF(buf, 32, "%%05x"); break;
|
||||
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
|
||||
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
|
||||
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
|
||||
case 0: VL_SNPRINTF(t_buf, 32, "%%01x"); break;
|
||||
case 1: VL_SNPRINTF(t_buf, 32, "%%02x"); break;
|
||||
case 2: VL_SNPRINTF(t_buf, 32, "%%03x"); break;
|
||||
case 3: VL_SNPRINTF(t_buf, 32, "%%04x"); break;
|
||||
case 4: VL_SNPRINTF(t_buf, 32, "%%05x"); break;
|
||||
case 5: VL_SNPRINTF(t_buf, 32, "%%06x"); break;
|
||||
case 6: VL_SNPRINTF(t_buf, 32, "%%07x"); break;
|
||||
case 7: VL_SNPRINTF(t_buf, 32, "%%08x"); break;
|
||||
default: assert(false); break; // LCOV_EXCL_LINE
|
||||
}
|
||||
return buf;
|
||||
return t_buf;
|
||||
}
|
||||
|
||||
static const char* formatBinary(int nBits, vluint32_t bits) {
|
||||
assert((nBits >= 1) && (nBits <= 32));
|
||||
|
||||
static VL_THREAD_LOCAL char buf[64];
|
||||
static VL_THREAD_LOCAL char t_buf[64];
|
||||
for (int i = 0; i < nBits; i++) {
|
||||
bool isOne = bits & (1 << (nBits - 1 - i));
|
||||
buf[i] = (isOne ? '1' : '0');
|
||||
t_buf[i] = (isOne ? '1' : '0');
|
||||
}
|
||||
buf[nBits] = '\0';
|
||||
return buf;
|
||||
t_buf[nBits] = '\0';
|
||||
return t_buf;
|
||||
}
|
||||
|
||||
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
|
||||
@@ -2176,11 +2200,8 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
|
||||
//===========================================================================
|
||||
// Verilated:: Methods
|
||||
|
||||
Verilated::ThreadLocal::ThreadLocal() {}
|
||||
Verilated::ThreadLocal::~ThreadLocal() {}
|
||||
|
||||
void Verilated::debug(int level) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_debug = level;
|
||||
if (level) {
|
||||
#ifdef VL_DEBUG
|
||||
@@ -2194,49 +2215,65 @@ void Verilated::debug(int level) VL_MT_SAFE {
|
||||
}
|
||||
}
|
||||
void Verilated::randReset(int val) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_randReset = val;
|
||||
}
|
||||
void Verilated::randSeed(int val) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_randSeed = val;
|
||||
vluint64_t newEpoch = s_s.s_randSeedEpoch + 1;
|
||||
if (VL_UNLIKELY(newEpoch == 0)) newEpoch = 1;
|
||||
// Obververs must see new epoch AFTER seed updated
|
||||
#ifdef VL_THREADED
|
||||
std::atomic_signal_fence(std::memory_order_release);
|
||||
#endif
|
||||
s_s.s_randSeedEpoch = newEpoch;
|
||||
}
|
||||
vluint64_t Verilated::randSeedDefault64() VL_MT_SAFE {
|
||||
if (Verilated::randSeed() != 0) {
|
||||
return ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
|
||||
^ (static_cast<vluint64_t>(Verilated::randSeed())));
|
||||
} else {
|
||||
return ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
|
||||
^ (static_cast<vluint64_t>(vl_sys_rand32())));
|
||||
}
|
||||
}
|
||||
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_calcUnusedSigs = flag;
|
||||
}
|
||||
void Verilated::errorCount(int val) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_errorCount = val;
|
||||
}
|
||||
void Verilated::errorCountInc() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
++s_s.s_errorCount;
|
||||
}
|
||||
void Verilated::errorLimit(int val) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_errorLimit = val;
|
||||
}
|
||||
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_gotFinish = flag;
|
||||
}
|
||||
void Verilated::assertOn(bool flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_assertOn = flag;
|
||||
}
|
||||
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_fatalOnVpiError = flag;
|
||||
}
|
||||
void Verilated::timeunit(int value) VL_MT_SAFE {
|
||||
if (value < 0) value = -value; // Stored as 0..15
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_timeunit = value;
|
||||
}
|
||||
void Verilated::timeprecision(int value) VL_MT_SAFE {
|
||||
if (value < 0) value = -value; // Stored as 0..15
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_timeprecision = value;
|
||||
#ifdef SYSTEMC_VERSION
|
||||
sc_time sc_res = sc_get_time_resolution();
|
||||
@@ -2267,15 +2304,15 @@ void Verilated::timeprecision(int value) VL_MT_SAFE {
|
||||
#endif
|
||||
}
|
||||
void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_ns.s_profThreadsStart = flag;
|
||||
}
|
||||
void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_ns.s_profThreadsWindow = flag;
|
||||
}
|
||||
void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
if (s_ns.s_profThreadsFilenamep) free(const_cast<char*>(s_ns.s_profThreadsFilenamep));
|
||||
s_ns.s_profThreadsFilenamep = strdup(flagp);
|
||||
}
|
||||
@@ -2283,18 +2320,18 @@ 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 = nullptr;
|
||||
static VL_THREAD_LOCAL size_t len = 0;
|
||||
static VL_THREAD_LOCAL char* t_strp = nullptr;
|
||||
static VL_THREAD_LOCAL size_t t_len = 0;
|
||||
size_t newlen = strlen(n1) + strlen(n2) + strlen(delimiter) + 1;
|
||||
if (!strp || newlen > len) {
|
||||
if (strp) delete[] strp;
|
||||
strp = new char[newlen];
|
||||
len = newlen;
|
||||
if (!t_strp || newlen > t_len) {
|
||||
if (t_strp) delete[] t_strp;
|
||||
t_strp = new char[newlen];
|
||||
t_len = newlen;
|
||||
}
|
||||
strcpy(strp, n1);
|
||||
if (*n1) strcat(strp, delimiter);
|
||||
strcat(strp, n2);
|
||||
return strp;
|
||||
strcpy(t_strp, n1);
|
||||
if (*n1) strcat(t_strp, delimiter);
|
||||
strcat(t_strp, n2);
|
||||
return t_strp;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -2303,8 +2340,8 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
|
||||
// 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 VoidPCbList s_flushCbs;
|
||||
static VoidPCbList s_exitCbs;
|
||||
|
||||
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
|
||||
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
|
||||
@@ -2320,16 +2357,16 @@ static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE {
|
||||
}
|
||||
|
||||
void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
addCb(cb, datap, g_flushCbs);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
addCb(cb, datap, s_flushCbs);
|
||||
}
|
||||
void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
removeCb(cb, datap, g_flushCbs);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
removeCb(cb, datap, s_flushCbs);
|
||||
}
|
||||
void Verilated::runFlushCallbacks() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
runCallbacks(g_flushCbs);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
runCallbacks(s_flushCbs);
|
||||
fflush(stderr);
|
||||
fflush(stdout);
|
||||
// When running internal code coverage (gcc --coverage, as opposed to
|
||||
@@ -2339,16 +2376,16 @@ void Verilated::runFlushCallbacks() VL_MT_SAFE {
|
||||
}
|
||||
|
||||
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
addCb(cb, datap, g_exitCbs);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
addCb(cb, datap, s_exitCbs);
|
||||
}
|
||||
void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
removeCb(cb, datap, g_exitCbs);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
removeCb(cb, datap, s_exitCbs);
|
||||
}
|
||||
void Verilated::runExitCallbacks() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
runCallbacks(g_exitCbs);
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
runCallbacks(s_exitCbs);
|
||||
}
|
||||
|
||||
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
|
||||
@@ -2363,11 +2400,11 @@ void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
||||
|
||||
const char* Verilated::commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
|
||||
const std::string& match = VerilatedImp::argPlusMatch(prefixp);
|
||||
static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||
static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||
if (match.empty()) return "";
|
||||
outstr[0] = '\0';
|
||||
strncat(outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1);
|
||||
return outstr;
|
||||
t_outstr[0] = '\0';
|
||||
strncat(t_outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1);
|
||||
return t_outstr;
|
||||
}
|
||||
|
||||
void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE {
|
||||
@@ -2596,7 +2633,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;
|
||||
}
|
||||
@@ -2622,8 +2659,6 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
|
||||
//======================================================================
|
||||
// VerilatedScope:: Methods
|
||||
|
||||
VerilatedScope::VerilatedScope() {}
|
||||
|
||||
VerilatedScope::~VerilatedScope() {
|
||||
// Memory cleanup - not called during normal operation
|
||||
VerilatedImp::scopeErase(this);
|
||||
|
||||
+34
-27
@@ -129,12 +129,12 @@ extern vluint32_t VL_THREAD_ID() VL_MT_SAFE;
|
||||
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before relaxing
|
||||
|
||||
/// Mutex, wrapped to allow -fthread_safety checks
|
||||
class VL_CAPABILITY("mutex") VerilatedMutex {
|
||||
class VL_CAPABILITY("mutex") VerilatedMutex final {
|
||||
private:
|
||||
std::mutex m_mutex; // Mutex
|
||||
public:
|
||||
VerilatedMutex() {}
|
||||
~VerilatedMutex() {}
|
||||
VerilatedMutex() = default;
|
||||
~VerilatedMutex() = default;
|
||||
const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety
|
||||
/// Acquire/lock mutex
|
||||
void lock() VL_ACQUIRE() {
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
class VL_SCOPED_CAPABILITY VerilatedLockGuard {
|
||||
class VL_SCOPED_CAPABILITY VerilatedLockGuard final {
|
||||
VL_UNCOPYABLE(VerilatedLockGuard);
|
||||
|
||||
private:
|
||||
@@ -174,19 +174,19 @@ public:
|
||||
#else // !VL_THREADED
|
||||
|
||||
/// Empty non-threaded mutex to avoid #ifdefs in consuming code
|
||||
class VerilatedMutex {
|
||||
class VerilatedMutex final {
|
||||
public:
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
/// Empty non-threaded lock guard to avoid #ifdefs in consuming code
|
||||
class VerilatedLockGuard {
|
||||
class VerilatedLockGuard final {
|
||||
VL_UNCOPYABLE(VerilatedLockGuard);
|
||||
|
||||
public:
|
||||
explicit VerilatedLockGuard(VerilatedMutex&) {}
|
||||
~VerilatedLockGuard() {}
|
||||
~VerilatedLockGuard() = default;
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
#endif // VL_THREADED
|
||||
|
||||
/// Remember the calling thread at construction time, and make sure later calls use same thread
|
||||
class VerilatedAssertOneThread {
|
||||
class VerilatedAssertOneThread final {
|
||||
// MEMBERS
|
||||
#if defined(VL_THREADED) && defined(VL_DEBUG)
|
||||
vluint32_t m_threadid; /// Thread that is legal
|
||||
@@ -230,7 +230,7 @@ public:
|
||||
|
||||
class VerilatedScope;
|
||||
|
||||
class VerilatedModule {
|
||||
class VerilatedModule VL_NOT_FINAL {
|
||||
VL_UNCOPYABLE(VerilatedModule);
|
||||
|
||||
private:
|
||||
@@ -269,7 +269,8 @@ public:
|
||||
#define VL_CELL(instname, type) ///< Declare a cell, ala SP_CELL
|
||||
|
||||
/// Declare a module, ala SC_MODULE
|
||||
#define VL_MODULE(modname) class modname : public VerilatedModule
|
||||
#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule
|
||||
// Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical)
|
||||
|
||||
/// Constructor, ala SC_CTOR
|
||||
#define VL_CTOR(modname) modname(const char* __VCname = "")
|
||||
@@ -298,7 +299,7 @@ public:
|
||||
//===========================================================================
|
||||
/// Verilator symbol table base class
|
||||
|
||||
class VerilatedSyms {
|
||||
class VerilatedSyms VL_NOT_FINAL {
|
||||
public: // But for internal use only
|
||||
#ifdef VL_THREADED
|
||||
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
|
||||
@@ -311,7 +312,7 @@ public: // But for internal use only
|
||||
/// Verilator global class information class
|
||||
/// This class is initialized by main thread only. Reading post-init is thread safe.
|
||||
|
||||
class VerilatedScope {
|
||||
class VerilatedScope final {
|
||||
public:
|
||||
typedef enum : vluint8_t {
|
||||
SCOPE_MODULE,
|
||||
@@ -330,7 +331,7 @@ private:
|
||||
Type m_type = SCOPE_OTHER; ///< Type of the scope
|
||||
|
||||
public: // But internals only - called from VerilatedModule's
|
||||
VerilatedScope();
|
||||
VerilatedScope() = default;
|
||||
~VerilatedScope();
|
||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
|
||||
const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
|
||||
@@ -359,7 +360,7 @@ public: // But internals only - called from VerilatedModule's
|
||||
Type type() const { return m_type; }
|
||||
};
|
||||
|
||||
class VerilatedHierarchy {
|
||||
class VerilatedHierarchy final {
|
||||
public:
|
||||
static void add(VerilatedScope* fromp, VerilatedScope* top);
|
||||
};
|
||||
@@ -367,10 +368,10 @@ public:
|
||||
//===========================================================================
|
||||
/// Verilator global static information class
|
||||
|
||||
class Verilated {
|
||||
class Verilated final {
|
||||
// MEMBERS
|
||||
// Slow path variables
|
||||
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
|
||||
static VerilatedMutex s_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
|
||||
|
||||
static struct Serialized { // All these members serialized/deserialized
|
||||
// Fast path
|
||||
@@ -386,8 +387,9 @@ class Verilated {
|
||||
int s_errorLimit; ///< Stop on error number
|
||||
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||
int s_randSeed; ///< Random seed: 0=random
|
||||
int s_randSeedEpoch; ///< Number incrementing on each reseed, 0=illegal
|
||||
Serialized();
|
||||
~Serialized() {}
|
||||
~Serialized() = default;
|
||||
} s_s;
|
||||
|
||||
static struct NonSerialized { // Non-serialized information
|
||||
@@ -407,8 +409,8 @@ class Verilated {
|
||||
VerilatedMutex m_argMutex; ///< Mutex for s_args members, when VL_THREADED
|
||||
int argc = 0;
|
||||
const char** argv = nullptr;
|
||||
CommandArgValues() {}
|
||||
~CommandArgValues() {}
|
||||
CommandArgValues() = default;
|
||||
~CommandArgValues() = default;
|
||||
} s_args;
|
||||
|
||||
// Not covered by mutex, as per-thread
|
||||
@@ -422,8 +424,8 @@ class Verilated {
|
||||
const char* t_dpiFilename = nullptr; ///< DPI context filename
|
||||
int t_dpiLineno = 0; ///< DPI context line number
|
||||
|
||||
ThreadLocal();
|
||||
~ThreadLocal();
|
||||
ThreadLocal() = default;
|
||||
~ThreadLocal() = default;
|
||||
} t_s;
|
||||
|
||||
private:
|
||||
@@ -442,6 +444,9 @@ public:
|
||||
static int randReset() VL_MT_SAFE { return s_s.s_randReset; } ///< Return randReset value
|
||||
static void randSeed(int val) VL_MT_SAFE;
|
||||
static int randSeed() VL_MT_SAFE { return s_s.s_randSeed; } ///< Return randSeed value
|
||||
static vluint32_t randSeedEpoch() VL_MT_SAFE { return s_s.s_randSeedEpoch; }
|
||||
/// Random seed extended to 64 bits, and defaulted if user seed==0
|
||||
static vluint64_t randSeedDefault64() VL_MT_SAFE;
|
||||
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
@@ -452,7 +457,7 @@ public:
|
||||
static inline int debug() VL_MT_SAFE { return s_s.s_debug; }
|
||||
#else
|
||||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||
static inline int debug() VL_PURE { return 0; }
|
||||
static constexpr int debug() VL_PURE { return 0; }
|
||||
#endif
|
||||
/// Enable calculation of unused signals
|
||||
static void calcUnusedSigs(bool flag) VL_MT_SAFE;
|
||||
@@ -499,6 +504,7 @@ public:
|
||||
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;
|
||||
@@ -566,8 +572,8 @@ public:
|
||||
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
|
||||
static int exportFuncNum(const char* namep) VL_MT_SAFE;
|
||||
|
||||
static size_t serialized1Size() VL_PURE { return sizeof(s_s); }
|
||||
static void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only
|
||||
static constexpr size_t serialized1Size() VL_PURE { return sizeof(s_s); }
|
||||
static constexpr void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // For Serialize only
|
||||
static size_t serialized2Size() VL_PURE;
|
||||
static void* serialized2Ptr() VL_MT_UNSAFE;
|
||||
#ifdef VL_THREADED
|
||||
@@ -647,6 +653,7 @@ 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
|
||||
extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE;
|
||||
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
|
||||
vluint64_t rnd = vl_rand64();
|
||||
if (VL_LIKELY(hi > lo)) {
|
||||
@@ -752,9 +759,9 @@ static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE {
|
||||
u.q = lhs;
|
||||
return u.fp;
|
||||
}
|
||||
/// Return QData from void*
|
||||
static inline QData VL_CVT_VP_Q(void* fp) VL_PURE {
|
||||
union { void* fp; QData q; } u;
|
||||
/// Return QData from const void*
|
||||
static inline QData VL_CVT_VP_Q(const void* fp) VL_PURE {
|
||||
union { const void* fp; QData q; } u;
|
||||
u.q = 0;
|
||||
u.fp = fp;
|
||||
return u.q;
|
||||
|
||||
@@ -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
|
||||
|
||||
+17
-16
@@ -29,7 +29,7 @@
|
||||
// VerilatedCovImpBase
|
||||
/// Implementation base class for constants
|
||||
|
||||
struct VerilatedCovImpBase {
|
||||
struct VerilatedCovImpBase VL_NOT_FINAL {
|
||||
// TYPES
|
||||
enum { MAX_KEYS = 33 }; /// Maximum user arguments + filename+lineno
|
||||
enum { KEY_UNDEF = 0 }; /// Magic key # for unspecified values
|
||||
@@ -39,7 +39,7 @@ struct VerilatedCovImpBase {
|
||||
// VerilatedCovImpItem
|
||||
/// Implementation class for a VerilatedCov item
|
||||
|
||||
class VerilatedCovImpItem : VerilatedCovImpBase {
|
||||
class VerilatedCovImpItem VL_NOT_FINAL : VerilatedCovImpBase {
|
||||
public: // But only local to this file
|
||||
// MEMBERS
|
||||
int m_keys[MAX_KEYS]; ///< Key
|
||||
@@ -52,7 +52,7 @@ public: // But only local to this file
|
||||
m_vals[i] = 0;
|
||||
}
|
||||
}
|
||||
virtual ~VerilatedCovImpItem() {}
|
||||
virtual ~VerilatedCovImpItem() = default;
|
||||
virtual vluint64_t count() const = 0;
|
||||
virtual void zero() const = 0;
|
||||
};
|
||||
@@ -63,7 +63,7 @@ public: // But only local to this file
|
||||
/// This isn't in the header file for auto-magic conversion because it
|
||||
/// inlines to too much code and makes compilation too slow.
|
||||
|
||||
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
|
||||
template <class T> class VerilatedCoverItemSpec final : public VerilatedCovImpItem {
|
||||
private:
|
||||
// MEMBERS
|
||||
T* m_countp; ///< Count value
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
: m_countp{countp} {
|
||||
*m_countp = 0;
|
||||
}
|
||||
virtual ~VerilatedCoverItemSpec() override {}
|
||||
virtual ~VerilatedCoverItemSpec() override = default;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -87,10 +87,10 @@ public:
|
||||
/// All value and keys are indexed into a unique number. Thus we can greatly reduce
|
||||
/// the storage requirements for otherwise identical keys.
|
||||
|
||||
class VerilatedCovImp : VerilatedCovImpBase {
|
||||
class VerilatedCovImp final : VerilatedCovImpBase {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::map<std::string, int> ValueIndexMap;
|
||||
typedef std::map<const std::string, int> ValueIndexMap;
|
||||
typedef std::map<int, std::string> IndexValueMap;
|
||||
typedef std::deque<VerilatedCovImpItem*> ItemList;
|
||||
|
||||
@@ -99,13 +99,14 @@ private:
|
||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
|
||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for keys
|
||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||
int m_nextIndex VL_GUARDED_BY(m_mutex) = (KEY_UNDEF + 1); ///< Next insert value
|
||||
|
||||
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() {}
|
||||
VerilatedCovImp() = default;
|
||||
VL_UNCOPYABLE(VerilatedCovImp);
|
||||
|
||||
public:
|
||||
@@ -118,14 +119,13 @@ public:
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||
static int nextIndex = KEY_UNDEF + 1;
|
||||
const auto iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
nextIndex++;
|
||||
assert(nextIndex > 0); // Didn't rollover
|
||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||
return nextIndex;
|
||||
m_nextIndex++;
|
||||
assert(m_nextIndex > 0); // Didn't rollover
|
||||
m_valueIndexes.insert(std::make_pair(value, m_nextIndex));
|
||||
m_indexValues.insert(std::make_pair(m_nextIndex, value));
|
||||
return m_nextIndex;
|
||||
}
|
||||
static std::string dequote(const std::string& text) VL_PURE {
|
||||
// Quote any special characters
|
||||
@@ -235,6 +235,7 @@ private:
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
m_nextIndex = KEY_UNDEF + 1;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -350,7 +351,7 @@ 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<const std::string, std::pair<std::string, vluint64_t>> EventMap;
|
||||
EventMap eventCounts;
|
||||
for (const auto& itemp : m_items) {
|
||||
std::string name;
|
||||
@@ -399,7 +400,7 @@ public:
|
||||
os << i.first;
|
||||
if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first);
|
||||
os << "' " << i.second.second;
|
||||
os << std::endl;
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ template <class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||
/// Global class with methods affecting all coverage data.
|
||||
/// All public methods in this class are thread safe.
|
||||
|
||||
class VerilatedCov {
|
||||
class VerilatedCov final {
|
||||
VL_UNCOPYABLE(VerilatedCov);
|
||||
|
||||
public:
|
||||
|
||||
@@ -102,7 +102,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
|
||||
/// Verilator coverage global class.
|
||||
/// This class is thread safe.
|
||||
|
||||
class VerilatedCovKey {
|
||||
class VerilatedCovKey final {
|
||||
public:
|
||||
static std::string shortKey(const std::string& key) VL_PURE {
|
||||
// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
/// Base class to create a Verilator FST dump
|
||||
/// This is an internally used class - see VerilatedFstC for what to call from applications
|
||||
|
||||
class VerilatedFst : public VerilatedTrace<VerilatedFst> {
|
||||
class VerilatedFst final : public VerilatedTrace<VerilatedFst> {
|
||||
private:
|
||||
// Give the superclass access to private bits (to avoid virtual functions)
|
||||
friend class VerilatedTrace<VerilatedFst>;
|
||||
@@ -128,7 +128,7 @@ template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const std::st
|
||||
/// Also derived for use in SystemC simulations.
|
||||
/// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE
|
||||
|
||||
class VerilatedFstC {
|
||||
class VerilatedFstC final {
|
||||
VerilatedFst m_sptrace; ///< Trace file being created
|
||||
|
||||
// CONSTRUCTORS
|
||||
|
||||
+559
-142
@@ -26,10 +26,13 @@
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
//===================================================================
|
||||
// String formatters (required by below containers)
|
||||
@@ -41,10 +44,21 @@ extern std::string VL_TO_STRING(QData lhs);
|
||||
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
|
||||
extern std::string VL_TO_STRING_W(int words, WDataInP obj);
|
||||
|
||||
//===================================================================
|
||||
// Shuffle RNG
|
||||
|
||||
class VlURNG final {
|
||||
public:
|
||||
typedef size_t result_type;
|
||||
static constexpr size_t min() { return 0; }
|
||||
static constexpr size_t max() { return 1ULL << 31; }
|
||||
size_t operator()() { return VL_MASK_I(31) & VL_RANDOM_I(32); }
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Readmem/Writemem operation classes
|
||||
|
||||
class VlReadMem {
|
||||
class VlReadMem final {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
const std::string& m_filename; // Filename
|
||||
@@ -61,7 +75,7 @@ public:
|
||||
void setData(void* valuep, const std::string& rhs);
|
||||
};
|
||||
|
||||
class VlWriteMem {
|
||||
class VlWriteMem final {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
FILE* m_fp; // File handle for filename
|
||||
@@ -73,6 +87,363 @@ public:
|
||||
void print(QData addr, bool addrstamp, const void* valuep);
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Verilog queue and dynamic array container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
// be protected by other means
|
||||
//
|
||||
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
|
||||
// For dynamic arrays it is always zero
|
||||
template <class T_Value, size_t T_MaxSize = 0> class VlQueue final {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::deque<T_Value> Deque;
|
||||
|
||||
public:
|
||||
typedef typename Deque::const_iterator const_iterator;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
Deque m_deque; // State of the assoc array
|
||||
T_Value m_defaultValue; // Default value
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
// m_defaultValue isn't defaulted. Caller's constructor must do it.
|
||||
VlQueue() = default;
|
||||
~VlQueue() = default;
|
||||
VlQueue(const VlQueue&) = default;
|
||||
VlQueue(VlQueue&&) = default;
|
||||
VlQueue& operator=(const VlQueue&) = default;
|
||||
VlQueue& operator=(VlQueue&&) = default;
|
||||
|
||||
// Standard copy constructor works. Verilog: assoca = assocb
|
||||
// Also must allow conversion from a different T_MaxSize queue
|
||||
template <size_t U_MaxSize = 0> VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
|
||||
m_deque = rhs.privateDeque();
|
||||
if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static VlQueue cons(const T_Value& lhs) {
|
||||
VlQueue out;
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
|
||||
VlQueue out;
|
||||
out.push_back(rhs);
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
|
||||
VlQueue out = lhs;
|
||||
out.push_front(rhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
|
||||
VlQueue out = rhs;
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
|
||||
VlQueue out = rhs;
|
||||
for (const auto& i : lhs.m_deque) out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
T_Value& atDefault() { return m_defaultValue; }
|
||||
const T_Value& atDefault() const { return m_defaultValue; }
|
||||
const Deque& privateDeque() const { return m_deque; }
|
||||
|
||||
// Size. Verilog: function int size(), or int num()
|
||||
int size() const { return m_deque.size(); }
|
||||
// Clear array. Verilog: function void delete([input index])
|
||||
void clear() { m_deque.clear(); }
|
||||
void erase(vlsint32_t index) {
|
||||
if (VL_LIKELY(index >= 0 && index < m_deque.size()))
|
||||
m_deque.erase(m_deque.begin() + index);
|
||||
}
|
||||
|
||||
// Dynamic array new[] becomes a renew()
|
||||
void renew(size_t size) {
|
||||
clear();
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
// Dynamic array new[]() becomes a renew_copy()
|
||||
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
|
||||
if (size == 0) {
|
||||
clear();
|
||||
} else {
|
||||
*this = rhs;
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
}
|
||||
|
||||
// function void q.push_front(value)
|
||||
void push_front(const T_Value& value) {
|
||||
m_deque.push_front(value);
|
||||
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
|
||||
}
|
||||
// function void q.push_back(value)
|
||||
void push_back(const T_Value& value) {
|
||||
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
|
||||
}
|
||||
// function value_t q.pop_front();
|
||||
T_Value pop_front() {
|
||||
if (m_deque.empty()) return m_defaultValue;
|
||||
T_Value v = m_deque.front();
|
||||
m_deque.pop_front();
|
||||
return v;
|
||||
}
|
||||
// function value_t q.pop_back();
|
||||
T_Value pop_back() {
|
||||
if (m_deque.empty()) return m_defaultValue;
|
||||
T_Value v = m_deque.back();
|
||||
m_deque.pop_back();
|
||||
return v;
|
||||
}
|
||||
|
||||
// Setting. Verilog: assoc[index] = v
|
||||
// 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(vlsint32_t index) {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
s_throwAway = atDefault();
|
||||
return s_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(vlsint32_t index) const {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
return atDefault();
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// function void q.insert(index, value);
|
||||
void insert(vlsint32_t index, const T_Value& value) {
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
|
||||
m_deque.insert(m_deque.begin() + index, value);
|
||||
}
|
||||
|
||||
// Return slice q[lsb:msb]
|
||||
VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const {
|
||||
VlQueue out;
|
||||
if (VL_UNLIKELY(lsb < 0)) lsb = 0;
|
||||
if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1;
|
||||
if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1;
|
||||
for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
|
||||
return out;
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
const_iterator end() const { return m_deque.end(); }
|
||||
|
||||
// Methods
|
||||
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
|
||||
template <typename Func> void sort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) {
|
||||
// index number is meaninless with sort, as it changes
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
}
|
||||
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
|
||||
template <typename Func> void rsort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) {
|
||||
// index number is meaninless with sort, as it changes
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
}
|
||||
void reverse() { std::reverse(m_deque.begin(), m_deque.end()); }
|
||||
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); }
|
||||
VlQueue unique() const {
|
||||
VlQueue out;
|
||||
std::unordered_set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(i);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
VlQueue<IData> unique_index() const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
std::unordered_set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(index);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue find(Func with_func) const {
|
||||
VlQueue out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) out.push_back(i);
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_index(Func with_func) const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) out.push_back(index);
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue find_first(Func with_func) const {
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) return VlQueue::cons(i);
|
||||
++index;
|
||||
}
|
||||
return VlQueue{};
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_first_index(Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::cons(index);
|
||||
++index;
|
||||
}
|
||||
return VlQueue<IData>{};
|
||||
}
|
||||
template <typename Func> VlQueue find_last(Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) {
|
||||
if (with_func(index, *it)) return VlQueue::cons(*it);
|
||||
--index;
|
||||
}
|
||||
return VlQueue{};
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_last_index(Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) {
|
||||
if (with_func(index, *it)) return VlQueue<IData>::cons(index);
|
||||
--index;
|
||||
}
|
||||
return VlQueue<IData>{};
|
||||
}
|
||||
|
||||
// Reduction operators
|
||||
VlQueue min() const {
|
||||
if (m_deque.empty()) return VlQueue();
|
||||
const auto it = std::min_element(m_deque.begin(), m_deque.end());
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
VlQueue max() const {
|
||||
if (m_deque.empty()) return VlQueue();
|
||||
const auto it = std::max_element(m_deque.begin(), m_deque.end());
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out += i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out += with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.end(); ++it) out *= *it;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
IData index = 0;
|
||||
T_Value out{with_func(index, *it)};
|
||||
++it;
|
||||
++index;
|
||||
for (; it != m_deque.end(); ++it) out *= with_func(index++, *it);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.end(); ++it) out &= *it;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
IData index = 0;
|
||||
T_Value out{with_func(index, *it)};
|
||||
++it;
|
||||
++index;
|
||||
for (; it != m_deque.end(); ++it) out &= with_func(index, *it);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out |= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out |= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out ^= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
if (m_deque.empty()) return "'{}"; // No trailing space
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (const auto& i : m_deque) {
|
||||
out += comma + VL_TO_STRING(i);
|
||||
comma = ", ";
|
||||
}
|
||||
return out + "} ";
|
||||
}
|
||||
};
|
||||
|
||||
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||
return obj.to_string();
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog array container
|
||||
// Similar to std::array<WData, N>, but lighter weight, only methods needed
|
||||
@@ -81,13 +452,18 @@ public:
|
||||
// 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).
|
||||
|
||||
template <std::size_t T_Words> class VlWide {
|
||||
template <std::size_t T_Words> class VlWide final {
|
||||
WData m_storage[T_Words];
|
||||
|
||||
public:
|
||||
// cppcheck-suppress uninitVar
|
||||
VlWide() {}
|
||||
~VlWide() {}
|
||||
VlWide() = default;
|
||||
~VlWide() = default;
|
||||
VlWide(const VlWide&) = default;
|
||||
VlWide(VlWide&&) = default;
|
||||
VlWide& operator=(const VlWide&) = default;
|
||||
VlWide& operator=(VlWide&&) = default;
|
||||
// METHODS
|
||||
const WData& at(size_t index) const { return m_storage[index]; }
|
||||
WData& at(size_t index) { return m_storage[index]; }
|
||||
WData* data() { return &m_storage[0]; }
|
||||
@@ -112,7 +488,7 @@ template <std::size_t T_Words> std::string VL_TO_STRING(const VlWide<T_Words>& o
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
// be protected by other means
|
||||
//
|
||||
template <class T_Key, class T_Value> class VlAssocArray {
|
||||
template <class T_Key, class T_Value> class VlAssocArray final {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::map<T_Key, T_Value> Map;
|
||||
@@ -127,14 +503,17 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlAssocArray() {
|
||||
// m_defaultValue isn't defaulted. Caller's constructor must do it.
|
||||
}
|
||||
~VlAssocArray() {}
|
||||
// Standard copy constructor works. Verilog: assoca = assocb
|
||||
// m_defaultValue isn't defaulted. Caller's constructor must do it.
|
||||
VlAssocArray() = default;
|
||||
~VlAssocArray() = default;
|
||||
VlAssocArray(const VlAssocArray&) = default;
|
||||
VlAssocArray(VlAssocArray&&) = default;
|
||||
VlAssocArray& operator=(const VlAssocArray&) = default;
|
||||
VlAssocArray& operator=(VlAssocArray&&) = default;
|
||||
|
||||
// METHODS
|
||||
T_Value& atDefault() { return m_defaultValue; }
|
||||
const T_Value& atDefault() const { return m_defaultValue; }
|
||||
|
||||
// Size of array. Verilog: function int size(), or int num()
|
||||
int size() const { return m_map.size(); }
|
||||
@@ -196,12 +575,176 @@ public:
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
// Setting as a chained operation
|
||||
VlAssocArray& set(const T_Key& index, const T_Value& value) {
|
||||
at(index) = value;
|
||||
return *this;
|
||||
}
|
||||
VlAssocArray& setDefault(const T_Value& value) {
|
||||
atDefault() = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_map.begin(); }
|
||||
const_iterator end() const { return m_map.end(); }
|
||||
|
||||
// Methods
|
||||
VlQueue<T_Value> unique() const {
|
||||
VlQueue<T_Value> out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_map) {
|
||||
auto it = saw.find(i.second);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i.second);
|
||||
out.push_back(i.second);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
VlQueue<T_Key> unique_index() const {
|
||||
VlQueue<T_Key> out;
|
||||
std::set<T_Key> saw;
|
||||
for (const auto& i : m_map) {
|
||||
auto it = saw.find(i.second);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i.second);
|
||||
out.push_back(i.first);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find(Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.first, i.second)) out.push_back(i.second);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.first, i.second)) out.push_back(i.first);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
});
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
});
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
});
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
});
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
}
|
||||
|
||||
// Reduction operators
|
||||
VlQueue<T_Value> min() const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
const auto it = std::min_element(
|
||||
m_map.begin(), m_map.end(),
|
||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
VlQueue<T_Value> max() const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
const auto it = std::max_element(
|
||||
m_map.begin(), m_map.end(),
|
||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out += i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out *= it->second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_product(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out *= with_func(it->first, it->second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out &= it->second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_and(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out &= with_func(it->first, it->second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out |= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out |= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out ^= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
if (m_map.empty()) return "'{}"; // No trailing space
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (const auto& i : m_map) {
|
||||
@@ -245,133 +788,6 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog queue and dynamic array container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
// be protected by other means
|
||||
//
|
||||
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
|
||||
// For dynamic arrays it is always zero
|
||||
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::deque<T_Value> Deque;
|
||||
|
||||
public:
|
||||
typedef typename Deque::const_iterator const_iterator;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
Deque m_deque; // State of the assoc array
|
||||
T_Value m_defaultValue; // Default value
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlQueue() {
|
||||
// m_defaultValue isn't defaulted. Caller's constructor must do it.
|
||||
}
|
||||
~VlQueue() {}
|
||||
// Standard copy constructor works. Verilog: assoca = assocb
|
||||
|
||||
// METHODS
|
||||
T_Value& atDefault() { return m_defaultValue; }
|
||||
|
||||
// Size. Verilog: function int size(), or int num()
|
||||
int size() const { return m_deque.size(); }
|
||||
// Clear array. Verilog: function void delete([input index])
|
||||
void clear() { m_deque.clear(); }
|
||||
void erase(size_t index) {
|
||||
if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index);
|
||||
}
|
||||
|
||||
// Dynamic array new[] becomes a renew()
|
||||
void renew(size_t size) {
|
||||
clear();
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
// Dynamic array new[]() becomes a renew_copy()
|
||||
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
|
||||
if (size == 0) {
|
||||
clear();
|
||||
} else {
|
||||
*this = rhs;
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
}
|
||||
|
||||
// function void q.push_front(value)
|
||||
void push_front(const T_Value& value) {
|
||||
m_deque.push_front(value);
|
||||
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
|
||||
}
|
||||
// function void q.push_back(value)
|
||||
void push_back(const T_Value& value) {
|
||||
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
|
||||
}
|
||||
// function value_t q.pop_front();
|
||||
T_Value pop_front() {
|
||||
if (m_deque.empty()) return m_defaultValue;
|
||||
T_Value v = m_deque.front();
|
||||
m_deque.pop_front();
|
||||
return v;
|
||||
}
|
||||
// function value_t q.pop_back();
|
||||
T_Value pop_back() {
|
||||
if (m_deque.empty()) return m_defaultValue;
|
||||
T_Value v = m_deque.back();
|
||||
m_deque.pop_back();
|
||||
return v;
|
||||
}
|
||||
|
||||
// Setting. Verilog: assoc[index] = v
|
||||
// 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(size_t index) {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||
s_throwAway = atDefault();
|
||||
return s_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(size_t index) const {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||
return atDefault();
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// function void q.insert(index, value);
|
||||
void insert(size_t index, const T_Value& value) {
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) return;
|
||||
m_deque[index] = value;
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
const_iterator end() const { return m_deque.end(); }
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (const auto& i : m_deque) {
|
||||
out += comma + VL_TO_STRING(i);
|
||||
comma = ", ";
|
||||
}
|
||||
return out + "} ";
|
||||
}
|
||||
};
|
||||
|
||||
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||
return obj.to_string();
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog class reference container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
@@ -396,6 +812,7 @@ inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
|
||||
return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw);
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE { return lhs; }
|
||||
inline std::string& VL_CVT_PACK_STR_NN(std::string& lhs) VL_PURE { return lhs; }
|
||||
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
|
||||
WData lw[VL_WQ_WORDS_E];
|
||||
VL_SET_WI(lw, lhs);
|
||||
@@ -477,17 +894,17 @@ extern std::string VL_SUBSTR_N(const std::string& lhs, IData rhs, IData ths) VL_
|
||||
inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool ignoreCase) VL_PURE {
|
||||
// SystemVerilog does not allow a string variable to contain '\0'.
|
||||
// So C functions such as strcmp() can correctly compare strings.
|
||||
int result;
|
||||
if (ignoreCase) {
|
||||
result = VL_STRCASECMP(lhs.c_str(), rhs.c_str());
|
||||
return VL_STRCASECMP(lhs.c_str(), rhs.c_str());
|
||||
} else {
|
||||
result = std::strcmp(lhs.c_str(), rhs.c_str());
|
||||
return std::strcmp(lhs.c_str(), rhs.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
|
||||
|
||||
extern IData VL_FGETS_NI(std::string& dest, IData fpi);
|
||||
|
||||
//======================================================================
|
||||
// Dumping
|
||||
|
||||
|
||||
+18
-14
@@ -46,7 +46,7 @@ class VerilatedScope;
|
||||
|
||||
#ifdef VL_THREADED
|
||||
/// Message, enqueued on an mtask, and consumed on the main eval thread
|
||||
class VerilatedMsg {
|
||||
class VerilatedMsg final {
|
||||
public:
|
||||
// TYPES
|
||||
struct Cmp {
|
||||
@@ -64,7 +64,11 @@ public:
|
||||
VerilatedMsg(const std::function<void()>& cb)
|
||||
: m_mtaskId{Verilated::mtaskId()}
|
||||
, m_cb{cb} {}
|
||||
~VerilatedMsg() {}
|
||||
~VerilatedMsg() = default;
|
||||
VerilatedMsg(const VerilatedMsg&) = default;
|
||||
VerilatedMsg(VerilatedMsg&&) = default;
|
||||
VerilatedMsg& operator=(const VerilatedMsg&) = default;
|
||||
VerilatedMsg& operator=(VerilatedMsg&&) = default;
|
||||
// METHODS
|
||||
vluint32_t mtaskId() const { return m_mtaskId; }
|
||||
/// Execute the lambda function
|
||||
@@ -74,7 +78,7 @@ public:
|
||||
/// Each thread has a queue it pushes to
|
||||
/// This assumes no thread starts pushing the next tick until the previous has drained.
|
||||
/// If more aggressiveness is needed, a double-buffered scheme might work well.
|
||||
class VerilatedEvalMsgQueue {
|
||||
class VerilatedEvalMsgQueue final {
|
||||
typedef std::multiset<VerilatedMsg, VerilatedMsg::Cmp> VerilatedThreadQueue;
|
||||
|
||||
std::atomic<vluint64_t> m_depth; ///< Current depth of queue (see comments below)
|
||||
@@ -87,7 +91,7 @@ public:
|
||||
: m_depth{0} {
|
||||
assert(atomic_is_lock_free(&m_depth));
|
||||
}
|
||||
~VerilatedEvalMsgQueue() {}
|
||||
~VerilatedEvalMsgQueue() = default;
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
|
||||
@@ -126,7 +130,7 @@ public:
|
||||
};
|
||||
|
||||
/// Each thread has a local queue to build up messages until the end of the eval() call
|
||||
class VerilatedThreadMsgQueue {
|
||||
class VerilatedThreadMsgQueue final {
|
||||
std::queue<VerilatedMsg> m_queue;
|
||||
|
||||
public:
|
||||
@@ -170,7 +174,7 @@ public:
|
||||
#endif // VL_THREADED
|
||||
|
||||
// FILE* list constructed from a file-descriptor
|
||||
class VerilatedFpList {
|
||||
class VerilatedFpList final {
|
||||
FILE* m_fp[31];
|
||||
std::size_t m_sz = 0;
|
||||
|
||||
@@ -189,7 +193,7 @@ public:
|
||||
//======================================================================
|
||||
// VerilatedImp
|
||||
|
||||
class VerilatedImpData {
|
||||
class VerilatedImpData final {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
protected:
|
||||
friend class Verilated;
|
||||
@@ -207,8 +211,8 @@ protected:
|
||||
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() {}
|
||||
~Serialized() {}
|
||||
Serialized() = default;
|
||||
~Serialized() = default;
|
||||
} m_ser;
|
||||
|
||||
VerilatedMutex m_sergMutex; ///< Protect m_ser
|
||||
@@ -260,7 +264,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedImp {
|
||||
class VerilatedImp final {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
protected:
|
||||
friend class Verilated;
|
||||
@@ -268,15 +272,15 @@ protected:
|
||||
// MEMBERS
|
||||
union VerilatedImpU { ///< Enclose in an union to call ctor/dtor manually
|
||||
VerilatedImpData v;
|
||||
VerilatedImpU() {}
|
||||
~VerilatedImpU() {}
|
||||
VerilatedImpU() {} // Can't be = default;
|
||||
~VerilatedImpU() {} // Can't be = default;
|
||||
};
|
||||
static VerilatedImpU s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp() {}
|
||||
~VerilatedImp() {}
|
||||
VerilatedImp() = default;
|
||||
~VerilatedImp() = default;
|
||||
static void setup();
|
||||
static void teardown();
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -28,7 +28,7 @@
|
||||
// VerilatedSerialize - convert structures to a stream representation
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedSerialize {
|
||||
class VerilatedSerialize VL_NOT_FINAL {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
@@ -38,8 +38,8 @@ protected:
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
inline static size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16 * 1024; }
|
||||
static constexpr size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
|
||||
static constexpr size_t bufferInsertSize() { return 16 * 1024; }
|
||||
|
||||
void header() VL_MT_UNSAFE_ONE;
|
||||
void trailer() VL_MT_UNSAFE_ONE;
|
||||
@@ -87,7 +87,7 @@ private:
|
||||
// VerilatedDeserial - load structures from a stream representation
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedDeserialize {
|
||||
class VerilatedDeserialize VL_NOT_FINAL {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
@@ -98,8 +98,8 @@ protected:
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
inline static size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16 * 1024; }
|
||||
static constexpr size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
|
||||
static constexpr size_t bufferInsertSize() { return 16 * 1024; }
|
||||
|
||||
virtual void fill() = 0;
|
||||
void header() VL_MT_UNSAFE_ONE;
|
||||
@@ -154,13 +154,13 @@ private:
|
||||
// VerilatedSave - serialize to a file
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedSave : public VerilatedSerialize {
|
||||
class VerilatedSave final : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd = -1; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSave() {}
|
||||
VerilatedSave() = default;
|
||||
virtual ~VerilatedSave() override { close(); }
|
||||
// METHODS
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
@@ -174,13 +174,13 @@ public:
|
||||
// VerilatedRestore - deserialize from a file
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedRestore : public VerilatedDeserialize {
|
||||
class VerilatedRestore final : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd = -1; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedRestore() {}
|
||||
VerilatedRestore() = default;
|
||||
virtual ~VerilatedRestore() override { close(); }
|
||||
|
||||
// METHODS
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
// This class is thread safe (though most of SystemC is not).
|
||||
|
||||
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
|
||||
class VlScBvExposer : public sc_bv_base {
|
||||
class VlScBvExposer final : public sc_bv_base {
|
||||
public:
|
||||
static const vluint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp();
|
||||
|
||||
@@ -36,16 +36,14 @@
|
||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
||||
|
||||
// See also V3Ast::VNumRange
|
||||
class VerilatedRange {
|
||||
int m_left;
|
||||
int m_right;
|
||||
class VerilatedRange final {
|
||||
int m_left = 0;
|
||||
int m_right = 0;
|
||||
|
||||
protected:
|
||||
friend class VerilatedVarProps;
|
||||
friend class VerilatedScope;
|
||||
VerilatedRange()
|
||||
: m_left{0}
|
||||
, m_right{0} {}
|
||||
VerilatedRange() = default;
|
||||
VerilatedRange(int left, int right)
|
||||
: m_left{left}
|
||||
, m_right{right} {}
|
||||
@@ -55,7 +53,7 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
~VerilatedRange() {}
|
||||
~VerilatedRange() = default;
|
||||
int left() const { return m_left; }
|
||||
int right() const { return m_right; }
|
||||
int low() const { return (m_left < m_right) ? m_left : m_right; }
|
||||
@@ -70,7 +68,7 @@ public:
|
||||
/// Verilator variable
|
||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
||||
|
||||
class VerilatedVarProps {
|
||||
class VerilatedVarProps VL_NOT_FINAL {
|
||||
// TYPES
|
||||
enum { MAGIC = 0xddc4f829 };
|
||||
// MEMBERS
|
||||
@@ -138,7 +136,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
~VerilatedVarProps() {}
|
||||
~VerilatedVarProps() = default;
|
||||
// METHODS
|
||||
bool magicOk() const { return m_magic == MAGIC; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
@@ -189,7 +187,7 @@ public:
|
||||
//===========================================================================
|
||||
/// Verilator DPI open array variable
|
||||
|
||||
class VerilatedDpiOpenVar {
|
||||
class VerilatedDpiOpenVar final {
|
||||
// MEMBERS
|
||||
const VerilatedVarProps* m_propsp; // Variable properties
|
||||
void* m_datap; // Location of data (local to thread always, so safe)
|
||||
@@ -201,7 +199,7 @@ public:
|
||||
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap)
|
||||
: m_propsp{propsp}
|
||||
, m_datap{const_cast<void*>(datap)} {}
|
||||
~VerilatedDpiOpenVar() {}
|
||||
~VerilatedDpiOpenVar() = default;
|
||||
// METHODS
|
||||
void* datap() const { return m_datap; }
|
||||
// METHODS - from VerilatedVarProps
|
||||
@@ -227,7 +225,7 @@ public:
|
||||
/// Verilator variable
|
||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
||||
|
||||
class VerilatedVar : public VerilatedVarProps {
|
||||
class VerilatedVar final : public VerilatedVarProps {
|
||||
// MEMBERS
|
||||
void* m_datap; // Location of data
|
||||
const char* m_namep; // Name - slowpath
|
||||
@@ -243,7 +241,7 @@ protected:
|
||||
, m_isParam{isParam} {}
|
||||
|
||||
public:
|
||||
~VerilatedVar() {}
|
||||
~VerilatedVar() = default;
|
||||
// ACCESSORS
|
||||
void* datap() const { return m_datap; }
|
||||
const VerilatedRange& range() const { return packed(); } // Deprecated
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "verilated_sym_props.h"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
//======================================================================
|
||||
@@ -42,26 +43,27 @@ struct VerilatedCStrCmp {
|
||||
};
|
||||
|
||||
/// Map of sorted scope names to find associated scope class
|
||||
class VerilatedScopeNameMap
|
||||
class VerilatedScopeNameMap final
|
||||
: public std::map<const char*, const VerilatedScope*, VerilatedCStrCmp> {
|
||||
public:
|
||||
VerilatedScopeNameMap() {}
|
||||
~VerilatedScopeNameMap() {}
|
||||
VerilatedScopeNameMap() = default;
|
||||
~VerilatedScopeNameMap() = default;
|
||||
};
|
||||
|
||||
/// Map of sorted variable names to find associated variable class
|
||||
class VerilatedVarNameMap : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||
class VerilatedVarNameMap final : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||
public:
|
||||
VerilatedVarNameMap() {}
|
||||
~VerilatedVarNameMap() {}
|
||||
VerilatedVarNameMap() = default;
|
||||
~VerilatedVarNameMap() = default;
|
||||
};
|
||||
|
||||
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
|
||||
|
||||
class VerilatedHierarchyMap : public std::map<const VerilatedScope*, VerilatedScopeVector> {
|
||||
class VerilatedHierarchyMap final
|
||||
: public std::unordered_map<const VerilatedScope*, VerilatedScopeVector> {
|
||||
public:
|
||||
VerilatedHierarchyMap() {}
|
||||
~VerilatedHierarchyMap() {}
|
||||
VerilatedHierarchyMap() = default;
|
||||
~VerilatedHierarchyMap() = default;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -98,10 +98,8 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling)
|
||||
}
|
||||
|
||||
VlThreadPool::~VlThreadPool() {
|
||||
for (int i = 0; i < m_workers.size(); ++i) {
|
||||
// Each ~WorkerThread will wait for its thread to exit.
|
||||
delete m_workers[i];
|
||||
}
|
||||
// Each ~WorkerThread will wait for its thread to exit.
|
||||
for (auto& i : m_workers) delete i;
|
||||
if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread();
|
||||
}
|
||||
|
||||
@@ -139,7 +137,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
|
||||
|
||||
@@ -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>
|
||||
@@ -43,7 +52,7 @@ typedef void* VlThrSymTab;
|
||||
typedef void (*VlExecFnp)(bool, VlThrSymTab);
|
||||
|
||||
/// Track dependencies for a single MTask.
|
||||
class VlMTaskVertex {
|
||||
class VlMTaskVertex final {
|
||||
// MEMBERS
|
||||
static std::atomic<vluint64_t> s_yields; // Statistics
|
||||
|
||||
@@ -73,7 +82,7 @@ public:
|
||||
// that must notify this MTaskVertex before it will become ready
|
||||
// to run.
|
||||
explicit VlMTaskVertex(vluint32_t upstreamDepCount);
|
||||
~VlMTaskVertex() {}
|
||||
~VlMTaskVertex() = default;
|
||||
|
||||
static vluint64_t yields() { return s_yields; }
|
||||
static void yieldThread() {
|
||||
@@ -115,7 +124,7 @@ public:
|
||||
};
|
||||
|
||||
// Profiling support
|
||||
class VlProfileRec {
|
||||
class VlProfileRec final {
|
||||
protected:
|
||||
friend class VlThreadPool;
|
||||
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
|
||||
@@ -127,7 +136,7 @@ protected:
|
||||
unsigned m_cpu; // Execution CPU number (at start anyways)
|
||||
public:
|
||||
class Barrier {};
|
||||
VlProfileRec() {}
|
||||
VlProfileRec() = default;
|
||||
explicit VlProfileRec(Barrier) { m_cpu = getcpu(); }
|
||||
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
|
||||
m_type = VlProfileRec::TYPE_MTASK_RUN;
|
||||
@@ -159,7 +168,7 @@ public:
|
||||
|
||||
class VlThreadPool;
|
||||
|
||||
class VlWorkerThread {
|
||||
class VlWorkerThread final {
|
||||
private:
|
||||
// TYPES
|
||||
struct ExecRec {
|
||||
@@ -238,7 +247,7 @@ public:
|
||||
static void startWorker(VlWorkerThread* workerp);
|
||||
};
|
||||
|
||||
class VlThreadPool {
|
||||
class VlThreadPool final {
|
||||
// TYPES
|
||||
typedef std::vector<VlProfileRec> ProfileTrace;
|
||||
typedef std::set<ProfileTrace*> ProfileSet;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
// Threaded tracing
|
||||
|
||||
// A simple synchronized first in first out queue
|
||||
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
|
||||
template <class T> class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug
|
||||
private:
|
||||
VerilatedMutex m_mutex; // Protects m_queue
|
||||
std::condition_variable_any m_cv;
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
|
||||
// Commands used by thread tracing. Anonymous enum in class, as we want
|
||||
// it scoped, but we also want the automatic conversion to integer types.
|
||||
class VerilatedTraceCommand {
|
||||
class VerilatedTraceCommand final {
|
||||
public:
|
||||
// These must all fit in 4 bit at the moment, as the tracing routines
|
||||
// pack parameters in the top bits.
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
// VerilatedTrace uses F-bounded polymorphism to access duck-typed
|
||||
// implementations in the format specific derived class, which must be passed
|
||||
// as the type parameter T_Derived
|
||||
template <class T_Derived> class VerilatedTrace {
|
||||
template <class T_Derived> class VerilatedTrace VL_NOT_FINAL {
|
||||
public:
|
||||
//=========================================================================
|
||||
// Generic tracing internals
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef VL_CPPCHECK
|
||||
#ifndef VL_DERIVED_T
|
||||
# error "This file should be included in trace format implementations"
|
||||
#endif
|
||||
@@ -558,7 +559,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, doub
|
||||
// All of these take a destination pointer where the string will be emitted,
|
||||
// and a value to convert. There are a couple of variants for efficiency.
|
||||
|
||||
inline static void cvtCDataToStr(char* dstp, CData value) {
|
||||
static inline void cvtCDataToStr(char* dstp, CData value) {
|
||||
#ifdef VL_HAVE_SSE2
|
||||
// Similar to cvtSDataToStr but only the bottom 8 byte lanes are used
|
||||
const __m128i a = _mm_cvtsi32_si128(value);
|
||||
@@ -580,7 +581,7 @@ inline static void cvtCDataToStr(char* dstp, CData value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void cvtSDataToStr(char* dstp, SData value) {
|
||||
static inline void cvtSDataToStr(char* dstp, SData value) {
|
||||
#ifdef VL_HAVE_SSE2
|
||||
// We want each bit in the 16-bit input value to end up in a byte lane
|
||||
// within the 128-bit XMM register. Note that x86 is little-endian and we
|
||||
@@ -616,7 +617,7 @@ inline static void cvtSDataToStr(char* dstp, SData value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void cvtIDataToStr(char* dstp, IData value) {
|
||||
static inline void cvtIDataToStr(char* dstp, IData value) {
|
||||
#ifdef VL_HAVE_AVX2
|
||||
// Similar to cvtSDataToStr but the bottom 16-bits are processed in the
|
||||
// top half of the YMM registerss
|
||||
@@ -635,9 +636,11 @@ inline static void cvtIDataToStr(char* dstp, IData value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void cvtQDataToStr(char* dstp, QData value) {
|
||||
static inline void cvtQDataToStr(char* dstp, QData value) {
|
||||
cvtIDataToStr(dstp, value >> 32);
|
||||
cvtIDataToStr(dstp + 32, value);
|
||||
}
|
||||
|
||||
#define cvtEDataToStr cvtIDataToStr
|
||||
|
||||
#endif // VL_CPPCHECK
|
||||
|
||||
@@ -34,13 +34,13 @@ class VerilatedVcd;
|
||||
// VerilatedFile
|
||||
/// File handling routines, which can be overrode for e.g. socket I/O
|
||||
|
||||
class VerilatedVcdFile {
|
||||
class VerilatedVcdFile final {
|
||||
private:
|
||||
int m_fd = 0; ///< File descriptor we're writing to
|
||||
public:
|
||||
// METHODS
|
||||
VerilatedVcdFile() {}
|
||||
virtual ~VerilatedVcdFile() {}
|
||||
VerilatedVcdFile() = default;
|
||||
virtual ~VerilatedVcdFile() = default;
|
||||
virtual bool open(const std::string& name) VL_MT_UNSAFE;
|
||||
virtual void close() VL_MT_UNSAFE;
|
||||
virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
/// Base class to create a Verilator VCD dump
|
||||
/// This is an internally used class - see VerilatedVcdC for what to call from applications
|
||||
|
||||
class VerilatedVcd : public VerilatedTrace<VerilatedVcd> {
|
||||
class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace<VerilatedVcd> {
|
||||
private:
|
||||
// Give the superclass access to private bits (to avoid virtual functions)
|
||||
friend class VerilatedTrace<VerilatedVcd>;
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
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;
|
||||
typedef std::map<const std::string, const std::string> NameMap;
|
||||
NameMap* m_namemapp = nullptr; ///< List of names for the header
|
||||
|
||||
void bufferResize(vluint64_t minsize);
|
||||
@@ -329,7 +329,7 @@ template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::st
|
||||
/// Also derived for use in SystemC simulations.
|
||||
/// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE
|
||||
|
||||
class VerilatedVcdC {
|
||||
class VerilatedVcdC VL_NOT_FINAL {
|
||||
VerilatedVcd m_sptrace; ///< Trace file being created
|
||||
|
||||
// CONSTRUCTORS
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/// This class is passed to the SystemC simulation kernel, just like a
|
||||
/// documented SystemC trace format.
|
||||
|
||||
class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC {
|
||||
class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdSc);
|
||||
|
||||
|
||||
+166
-157
@@ -55,15 +55,15 @@ constexpr unsigned VL_VPI_LINE_SIZE = 8192;
|
||||
// Implementation
|
||||
|
||||
// Base VPI handled object
|
||||
class VerilatedVpio {
|
||||
class VerilatedVpio VL_NOT_FINAL {
|
||||
// MEM MANGLEMENT
|
||||
static VL_THREAD_LOCAL vluint8_t* t_freeHead;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedVpio() {}
|
||||
virtual ~VerilatedVpio() {}
|
||||
inline static void* operator new(size_t size) VL_MT_SAFE {
|
||||
VerilatedVpio() = default;
|
||||
virtual ~VerilatedVpio() = default;
|
||||
static void* operator new(size_t size) VL_MT_SAFE {
|
||||
// We new and delete tons of vpi structures, so keep them around
|
||||
// To simplify our free list, we use a size large enough for all derived types
|
||||
// We reserve word zero for the next pointer, as that's safer in case a
|
||||
@@ -79,13 +79,13 @@ public:
|
||||
vluint8_t* newp = reinterpret_cast<vluint8_t*>(::operator new(chunk + 8));
|
||||
return newp + 8;
|
||||
}
|
||||
inline static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE {
|
||||
static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE {
|
||||
vluint8_t* oldp = (static_cast<vluint8_t*>(obj)) - 8;
|
||||
*(reinterpret_cast<void**>(oldp)) = t_freeHead;
|
||||
t_freeHead = oldp;
|
||||
}
|
||||
// MEMBERS
|
||||
static inline VerilatedVpio* castp(vpiHandle h) {
|
||||
static VerilatedVpio* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
|
||||
@@ -96,12 +96,12 @@ public:
|
||||
virtual vluint32_t type() const { return 0; }
|
||||
virtual vluint32_t size() const { return 0; }
|
||||
virtual const VerilatedRange* rangep() const { return nullptr; }
|
||||
virtual vpiHandle dovpi_scan() { return 0; }
|
||||
virtual vpiHandle dovpi_scan() { return nullptr; }
|
||||
};
|
||||
|
||||
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*);
|
||||
|
||||
class VerilatedVpioCb : public VerilatedVpio {
|
||||
class VerilatedVpioCb final : public VerilatedVpio {
|
||||
t_cb_data m_cbData;
|
||||
s_vpi_value m_value;
|
||||
QData m_time;
|
||||
@@ -114,8 +114,8 @@ public:
|
||||
m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal;
|
||||
m_cbData.value = &m_value;
|
||||
}
|
||||
virtual ~VerilatedVpioCb() override {}
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioCb() override = default;
|
||||
static VerilatedVpioCb* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioCb*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiCallback; }
|
||||
@@ -125,21 +125,21 @@ public:
|
||||
QData time() const { return m_time; }
|
||||
};
|
||||
|
||||
class VerilatedVpioConst : public VerilatedVpio {
|
||||
class VerilatedVpioConst final : public VerilatedVpio {
|
||||
vlsint32_t m_num;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioConst(vlsint32_t num)
|
||||
: m_num{num} {}
|
||||
virtual ~VerilatedVpioConst() override {}
|
||||
static inline VerilatedVpioConst* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioConst() override = default;
|
||||
static VerilatedVpioConst* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiConstant; }
|
||||
vlsint32_t num() const { return m_num; }
|
||||
};
|
||||
|
||||
class VerilatedVpioParam : public VerilatedVpio {
|
||||
class VerilatedVpioParam final : public VerilatedVpio {
|
||||
const VerilatedVar* m_varp;
|
||||
const VerilatedScope* m_scopep;
|
||||
|
||||
@@ -148,9 +148,9 @@ public:
|
||||
: m_varp{varp}
|
||||
, m_scopep{scopep} {}
|
||||
|
||||
virtual ~VerilatedVpioParam() override {}
|
||||
virtual ~VerilatedVpioParam() override = default;
|
||||
|
||||
static inline VerilatedVpioParam* castp(vpiHandle h) {
|
||||
static VerilatedVpioParam* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioParam*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiParameter; }
|
||||
@@ -159,21 +159,21 @@ public:
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
virtual const char* name() const override { return m_varp->name(); }
|
||||
virtual const char* fullname() const override {
|
||||
static VL_THREAD_LOCAL std::string out;
|
||||
out = std::string(m_scopep->name()) + "." + name();
|
||||
return out.c_str();
|
||||
static VL_THREAD_LOCAL std::string t_out;
|
||||
t_out = std::string(m_scopep->name()) + "." + name();
|
||||
return t_out.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioRange : public VerilatedVpio {
|
||||
class VerilatedVpioRange final : public VerilatedVpio {
|
||||
const VerilatedRange* m_range;
|
||||
vlsint32_t m_iteration = 0;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioRange(const VerilatedRange* range)
|
||||
: m_range{range} {}
|
||||
virtual ~VerilatedVpioRange() override {}
|
||||
static inline VerilatedVpioRange* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioRange() override = default;
|
||||
static VerilatedVpioRange* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioRange*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiRange; }
|
||||
@@ -187,19 +187,19 @@ public:
|
||||
nextp->iterationInc();
|
||||
return ((nextp)->castVpiHandle());
|
||||
}
|
||||
return 0; // End of list - only one deep
|
||||
return nullptr; // End of list - only one deep
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioScope : public VerilatedVpio {
|
||||
class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio {
|
||||
protected:
|
||||
const VerilatedScope* m_scopep;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioScope(const VerilatedScope* scopep)
|
||||
: m_scopep{scopep} {}
|
||||
virtual ~VerilatedVpioScope() override {}
|
||||
static inline VerilatedVpioScope* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioScope() override = default;
|
||||
static VerilatedVpioScope* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioScope*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiScope; }
|
||||
@@ -208,10 +208,10 @@ public:
|
||||
virtual const char* fullname() const override { return m_scopep->name(); }
|
||||
};
|
||||
|
||||
class VerilatedVpioVar : public VerilatedVpio {
|
||||
class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpio {
|
||||
const VerilatedVar* m_varp;
|
||||
const VerilatedScope* m_scopep;
|
||||
vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange
|
||||
vluint8_t* m_prevDatap = nullptr; // Previous value of data, for cbValueChange
|
||||
union {
|
||||
vluint8_t u8[4];
|
||||
vluint32_t u32;
|
||||
@@ -219,7 +219,7 @@ class VerilatedVpioVar : public VerilatedVpio {
|
||||
vluint32_t m_entSize; // memoized variable size
|
||||
protected:
|
||||
void* m_varDatap; // varp()->datap() adjusted for array entries
|
||||
vlsint32_t m_index;
|
||||
vlsint32_t m_index = 0;
|
||||
const VerilatedRange& get_range() const {
|
||||
// Determine number of dimensions and return outermost
|
||||
return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed();
|
||||
@@ -228,9 +228,7 @@ protected:
|
||||
public:
|
||||
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
|
||||
: m_varp{varp}
|
||||
, m_scopep{scopep}
|
||||
, m_index{0} {
|
||||
m_prevDatap = nullptr;
|
||||
, m_scopep{scopep} {
|
||||
m_mask.u32 = VL_MASK_I(varp->packed().elements());
|
||||
m_entSize = varp->entSize();
|
||||
m_varDatap = varp->datap();
|
||||
@@ -238,7 +236,7 @@ public:
|
||||
virtual ~VerilatedVpioVar() override {
|
||||
if (m_prevDatap) VL_DO_CLEAR(delete[] m_prevDatap, m_prevDatap = nullptr);
|
||||
}
|
||||
static inline VerilatedVpioVar* castp(vpiHandle h) {
|
||||
static VerilatedVpioVar* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioVar*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
@@ -254,9 +252,9 @@ public:
|
||||
virtual const VerilatedRange* rangep() const override { return &get_range(); }
|
||||
virtual const char* name() const override { return m_varp->name(); }
|
||||
virtual const char* fullname() const override {
|
||||
static VL_THREAD_LOCAL std::string out;
|
||||
out = std::string(m_scopep->name()) + "." + name();
|
||||
return out.c_str();
|
||||
static VL_THREAD_LOCAL std::string t_out;
|
||||
t_out = std::string(m_scopep->name()) + "." + name();
|
||||
return t_out.c_str();
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
void* varDatap() const { return m_varDatap; }
|
||||
@@ -268,7 +266,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWord : public VerilatedVpioVar {
|
||||
class VerilatedVpioMemoryWord final : public VerilatedVpioVar {
|
||||
public:
|
||||
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep,
|
||||
vlsint32_t index, int offset)
|
||||
@@ -276,23 +274,23 @@ public:
|
||||
m_index = index;
|
||||
m_varDatap = (static_cast<vluint8_t*>(varp->datap())) + entSize() * offset;
|
||||
}
|
||||
virtual ~VerilatedVpioMemoryWord() override {}
|
||||
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioMemoryWord() override = default;
|
||||
static VerilatedVpioMemoryWord* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioMemoryWord*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiMemoryWord; }
|
||||
virtual vluint32_t size() const override { return varp()->packed().elements(); }
|
||||
virtual const VerilatedRange* rangep() const override { return &(varp()->packed()); }
|
||||
virtual const char* fullname() const override {
|
||||
static VL_THREAD_LOCAL std::string out;
|
||||
static VL_THREAD_LOCAL std::string t_out;
|
||||
char num[20];
|
||||
sprintf(num, "%d", m_index);
|
||||
out = std::string(scopep()->name()) + "." + name() + "[" + num + "]";
|
||||
return out.c_str();
|
||||
t_out = std::string(scopep()->name()) + "." + name() + "[" + num + "]";
|
||||
return t_out.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioVarIter : public VerilatedVpio {
|
||||
class VerilatedVpioVarIter final : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
VerilatedVarNameMap::const_iterator m_it;
|
||||
bool m_started = false;
|
||||
@@ -300,8 +298,8 @@ class VerilatedVpioVarIter : public VerilatedVpio {
|
||||
public:
|
||||
explicit VerilatedVpioVarIter(const VerilatedScope* scopep)
|
||||
: m_scopep{scopep} {}
|
||||
virtual ~VerilatedVpioVarIter() override {}
|
||||
static inline VerilatedVpioVarIter* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioVarIter() override = default;
|
||||
static VerilatedVpioVarIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioVarIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiIterator; }
|
||||
@@ -312,18 +310,18 @@ public:
|
||||
m_it = varsp->begin();
|
||||
m_started = true;
|
||||
} else if (VL_UNLIKELY(m_it == varsp->end())) {
|
||||
return 0;
|
||||
return nullptr;
|
||||
} else {
|
||||
++m_it;
|
||||
}
|
||||
if (m_it == varsp->end()) return 0;
|
||||
if (m_it == varsp->end()) return nullptr;
|
||||
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle());
|
||||
}
|
||||
return 0; // End of list - only one deep
|
||||
return nullptr; // End of list - only one deep
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWordIter : public VerilatedVpio {
|
||||
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
|
||||
const vpiHandle m_handle;
|
||||
const VerilatedVar* m_varp;
|
||||
vlsint32_t m_iteration;
|
||||
@@ -336,8 +334,8 @@ public:
|
||||
, m_varp{varp}
|
||||
, m_iteration{varp->unpacked().right()}
|
||||
, m_direction{VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) ? 1 : -1} {}
|
||||
virtual ~VerilatedVpioMemoryWordIter() override {}
|
||||
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioMemoryWordIter() override = default;
|
||||
static VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioMemoryWordIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiIterator; }
|
||||
@@ -346,14 +344,14 @@ public:
|
||||
}
|
||||
virtual vpiHandle dovpi_scan() override {
|
||||
vpiHandle result;
|
||||
if (m_done) return 0;
|
||||
if (m_done) return nullptr;
|
||||
result = vpi_handle_by_index(m_handle, m_iteration);
|
||||
iterationInc();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioModule : public VerilatedVpioScope {
|
||||
class VerilatedVpioModule final : public VerilatedVpioScope {
|
||||
const char* m_name;
|
||||
const char* m_fullname;
|
||||
|
||||
@@ -364,7 +362,7 @@ public:
|
||||
if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4;
|
||||
m_name = m_scopep->identifier();
|
||||
}
|
||||
static inline VerilatedVpioModule* castp(vpiHandle h) {
|
||||
static VerilatedVpioModule* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioModule*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiModule; }
|
||||
@@ -372,7 +370,7 @@ public:
|
||||
virtual const char* fullname() const override { return m_fullname; }
|
||||
};
|
||||
|
||||
class VerilatedVpioModuleIter : public VerilatedVpio {
|
||||
class VerilatedVpioModuleIter final : public VerilatedVpio {
|
||||
const std::vector<const VerilatedScope*>* m_vec;
|
||||
std::vector<const VerilatedScope*>::const_iterator m_it;
|
||||
|
||||
@@ -381,13 +379,13 @@ public:
|
||||
: m_vec{&vec} {
|
||||
m_it = m_vec->begin();
|
||||
}
|
||||
virtual ~VerilatedVpioModuleIter() override {}
|
||||
static inline VerilatedVpioModuleIter* castp(vpiHandle h) {
|
||||
virtual ~VerilatedVpioModuleIter() override = default;
|
||||
static VerilatedVpioModuleIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioModuleIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
virtual vluint32_t type() const override { return vpiIterator; }
|
||||
virtual vpiHandle dovpi_scan() override {
|
||||
if (m_it == m_vec->end()) return 0;
|
||||
if (m_it == m_vec->end()) return nullptr;
|
||||
const VerilatedScope* modp = *m_it++;
|
||||
return (new VerilatedVpioModule(modp))->castVpiHandle();
|
||||
}
|
||||
@@ -407,15 +405,11 @@ struct VerilatedVpiTimedCbsCmp {
|
||||
|
||||
class VerilatedVpiError;
|
||||
|
||||
class VerilatedVpiImp {
|
||||
class VerilatedVpiImp final {
|
||||
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maxium callback reason
|
||||
typedef std::list<VerilatedVpioCb*> VpioCbList;
|
||||
typedef std::set<std::pair<QData, VerilatedVpioCb*>, VerilatedVpiTimedCbsCmp> VpioTimedCbs;
|
||||
|
||||
struct product_info {
|
||||
PLI_BYTE8* product;
|
||||
};
|
||||
|
||||
VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
|
||||
VpioTimedCbs m_timedCbs; // Time based callbacks
|
||||
VerilatedVpiError* m_errorInfop = nullptr; // Container for vpi error info
|
||||
@@ -424,8 +418,8 @@ class VerilatedVpiImp {
|
||||
static VerilatedVpiImp s_s; // Singleton
|
||||
|
||||
public:
|
||||
VerilatedVpiImp() {}
|
||||
~VerilatedVpiImp() {}
|
||||
VerilatedVpiImp() = default;
|
||||
~VerilatedVpiImp() = default;
|
||||
static void assertOneCheck() { s_s.m_assertOne.check(); }
|
||||
static void cbReasonAdd(VerilatedVpioCb* vop) {
|
||||
if (vop->reason() == cbValueChange) {
|
||||
@@ -477,26 +471,38 @@ public:
|
||||
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
|
||||
bool called = false;
|
||||
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
|
||||
if (cbObjList.empty()) return called;
|
||||
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
||||
for (auto it = cbObjList.begin(); true;) {
|
||||
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
|
||||
bool was_last = it == last;
|
||||
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
if (was_last) break;
|
||||
continue;
|
||||
}
|
||||
VerilatedVpioCb* vop = *it++;
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback %d %p\n", reason, vop););
|
||||
(vop->cb_rtnp())(vop->cb_datap());
|
||||
called = true;
|
||||
if (was_last) break;
|
||||
}
|
||||
return called;
|
||||
}
|
||||
static void callValueCbs() VL_MT_UNSAFE_ONE {
|
||||
static bool callValueCbs() VL_MT_UNSAFE_ONE {
|
||||
assertOneCheck();
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
|
||||
typedef std::set<VerilatedVpioVar*> VpioVarSet;
|
||||
bool called = false;
|
||||
typedef std::unordered_set<VerilatedVpioVar*> VpioVarSet;
|
||||
VpioVarSet update; // set of objects to update after callbacks
|
||||
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
|
||||
if (cbObjList.empty()) return called;
|
||||
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
||||
for (auto it = cbObjList.begin(); true;) {
|
||||
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
|
||||
bool was_last = it == last;
|
||||
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
if (was_last) break;
|
||||
continue;
|
||||
}
|
||||
VerilatedVpioCb* vop = *it++;
|
||||
@@ -512,16 +518,19 @@ public:
|
||||
update.insert(varop);
|
||||
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
|
||||
(vop->cb_rtnp())(vop->cb_datap());
|
||||
called = true;
|
||||
}
|
||||
}
|
||||
if (was_last) break;
|
||||
}
|
||||
for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); }
|
||||
return called;
|
||||
}
|
||||
|
||||
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
|
||||
};
|
||||
|
||||
class VerilatedVpiError {
|
||||
class VerilatedVpiError final {
|
||||
//// Container for vpi error info
|
||||
|
||||
t_vpi_error_info m_errorInfo;
|
||||
@@ -550,7 +559,7 @@ public:
|
||||
m_buff[0] = '\0';
|
||||
m_errorInfo.product = const_cast<PLI_BYTE8*>(Verilated::productName());
|
||||
}
|
||||
~VerilatedVpiError() {}
|
||||
~VerilatedVpiError() = default;
|
||||
static void selfTest() VL_MT_UNSAFE_ONE;
|
||||
VerilatedVpiError* setMessage(PLI_INT32 level) {
|
||||
m_flag = true;
|
||||
@@ -559,14 +568,14 @@ public:
|
||||
}
|
||||
void setMessage(const std::string& file, PLI_INT32 line, const char* message, ...) {
|
||||
// message cannot be a const string& as va_start cannot use a reference
|
||||
static VL_THREAD_LOCAL std::string filehold;
|
||||
static VL_THREAD_LOCAL std::string t_filehold;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
VL_VSNPRINTF(m_buff, sizeof(m_buff), message, args);
|
||||
va_end(args);
|
||||
m_errorInfo.state = vpiPLI;
|
||||
filehold = file;
|
||||
setError((PLI_BYTE8*)m_buff, nullptr, const_cast<PLI_BYTE8*>(filehold.c_str()), line);
|
||||
t_filehold = file;
|
||||
setError((PLI_BYTE8*)m_buff, nullptr, const_cast<PLI_BYTE8*>(t_filehold.c_str()), line);
|
||||
}
|
||||
p_vpi_error_info getError() {
|
||||
if (m_flag) return &m_errorInfo;
|
||||
@@ -599,7 +608,7 @@ VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = nullptr;
|
||||
|
||||
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); }
|
||||
|
||||
void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callValueCbs(); }
|
||||
bool VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callValueCbs(); }
|
||||
|
||||
bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
return VerilatedVpiImp::callCbs(reason);
|
||||
@@ -1048,10 +1057,10 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
||||
}
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_remove_cb(vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", object););
|
||||
PLI_INT32 vpi_remove_cb(vpiHandle cb_obj) {
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", cb_obj););
|
||||
VerilatedVpiImp::assertOneCheck();
|
||||
VerilatedVpioCb* vop = VerilatedVpioCb::castp(object);
|
||||
VerilatedVpioCb* vop = VerilatedVpioCb::castp(cb_obj);
|
||||
_VL_VPI_ERROR_RESET();
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (vop->cb_datap()->reason == cbAfterDelay) {
|
||||
@@ -1065,7 +1074,7 @@ PLI_INT32 vpi_remove_cb(vpiHandle object) {
|
||||
void vpi_get_cb_info(vpiHandle /*object*/, p_cb_data /*cb_data_p*/) { _VL_VPI_UNIMP(); }
|
||||
vpiHandle vpi_register_systf(p_vpi_systf_data /*systf_data_p*/) {
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/) {
|
||||
_VL_VPI_UNIMP();
|
||||
@@ -1131,24 +1140,24 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
||||
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
|
||||
_VL_VPI_ERROR_RESET();
|
||||
if (VL_LIKELY(varop)) {
|
||||
if (varop->varp()->dims() < 2) return 0;
|
||||
if (varop->varp()->dims() < 2) return nullptr;
|
||||
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
|
||||
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|
||||
|| indx < varop->varp()->unpacked().right()))
|
||||
return 0;
|
||||
return nullptr;
|
||||
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->unpacked().right()))
|
||||
->castVpiHandle();
|
||||
}
|
||||
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|
||||
|| indx > varop->varp()->unpacked().right()))
|
||||
return 0;
|
||||
return nullptr;
|
||||
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->unpacked().left()))
|
||||
->castVpiHandle();
|
||||
}
|
||||
_VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC);
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// for traversing relationships
|
||||
@@ -1160,56 +1169,56 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
||||
switch (type) {
|
||||
case vpiLeftRange: {
|
||||
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
|
||||
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
|
||||
}
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__,
|
||||
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
|
||||
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
case vpiRightRange: {
|
||||
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
|
||||
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
|
||||
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
||||
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
||||
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
|
||||
}
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__,
|
||||
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
|
||||
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
case vpiIndex: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
|
||||
}
|
||||
case vpiScope: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
|
||||
}
|
||||
case vpiParent: {
|
||||
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
|
||||
}
|
||||
default:
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type));
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
vpiHandle vpi_handle_multi(PLI_INT32 /*type*/, vpiHandle /*refHandle1*/, vpiHandle /*refHandle2*/,
|
||||
...) {
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||
@@ -1219,8 +1228,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||
switch (type) {
|
||||
case vpiMemoryWord: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (vop->varp()->dims() < 2) return 0;
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
if (vop->varp()->dims() < 2) return nullptr;
|
||||
if (vop->varp()->dims() > 2) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__,
|
||||
"%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC,
|
||||
@@ -1231,8 +1240,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||
}
|
||||
case vpiRange: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (vop->varp()->dims() < 2) return 0;
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
if (vop->varp()->dims() < 2) return nullptr;
|
||||
// Unsupported is multidim list
|
||||
if (vop->varp()->dims() > 2) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__,
|
||||
@@ -1244,7 +1253,7 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||
}
|
||||
case vpiReg: {
|
||||
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle());
|
||||
}
|
||||
case vpiModule: {
|
||||
@@ -1252,13 +1261,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
|
||||
const VerilatedScope* mod = vop ? vop->scopep() : nullptr;
|
||||
const auto it = vlstd::as_const(map)->find(const_cast<VerilatedScope*>(mod));
|
||||
if (it == map->end()) return 0;
|
||||
if (it == map->end()) return nullptr;
|
||||
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
|
||||
}
|
||||
default:
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
vpiHandle vpi_scan(vpiHandle object) {
|
||||
@@ -1342,7 +1351,7 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
|
||||
default:
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1410,34 +1419,34 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
const char* fullname) {
|
||||
if (!vl_check_format(varp, valuep, fullname, true)) return;
|
||||
// Maximum required size is for binary string, one byte per bit plus null termination
|
||||
static VL_THREAD_LOCAL char outStr[1 + VL_MULS_MAX_WORDS * 32];
|
||||
static VL_THREAD_LOCAL char t_outStr[1 + VL_MULS_MAX_WORDS * 32];
|
||||
// cppcheck-suppress variableScope
|
||||
static VL_THREAD_LOCAL int outStrSz = sizeof(outStr) - 1;
|
||||
static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
|
||||
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||
// This may cause backward compatibility issues with older code.
|
||||
if (valuep->format == vpiVectorVal) {
|
||||
// Vector pointer must come from our memory pool
|
||||
// It only needs to persist until the next vpi_get_value
|
||||
static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS * 2];
|
||||
valuep->value.vector = out;
|
||||
static VL_THREAD_LOCAL t_vpi_vecval t_out[VL_MULS_MAX_WORDS * 2];
|
||||
valuep->value.vector = t_out;
|
||||
if (varp->vltype() == VLVT_UINT8) {
|
||||
out[0].aval = *(reinterpret_cast<CData*>(varDatap));
|
||||
out[0].bval = 0;
|
||||
t_out[0].aval = *(reinterpret_cast<CData*>(varDatap));
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT16) {
|
||||
out[0].aval = *(reinterpret_cast<SData*>(varDatap));
|
||||
out[0].bval = 0;
|
||||
t_out[0].aval = *(reinterpret_cast<SData*>(varDatap));
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT32) {
|
||||
out[0].aval = *(reinterpret_cast<IData*>(varDatap));
|
||||
out[0].bval = 0;
|
||||
t_out[0].aval = *(reinterpret_cast<IData*>(varDatap));
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
QData data = *(reinterpret_cast<QData*>(varDatap));
|
||||
out[1].aval = static_cast<IData>(data >> 32ULL);
|
||||
out[1].bval = 0;
|
||||
out[0].aval = static_cast<IData>(data);
|
||||
out[0].bval = 0;
|
||||
t_out[1].aval = static_cast<IData>(data >> 32ULL);
|
||||
t_out[1].bval = 0;
|
||||
t_out[0].aval = static_cast<IData>(data);
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_WDATA) {
|
||||
int words = VL_WORDS_I(varp->packed().elements());
|
||||
@@ -1448,47 +1457,47 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
}
|
||||
WDataInP datap = (reinterpret_cast<EData*>(varDatap));
|
||||
for (int i = 0; i < words; ++i) {
|
||||
out[i].aval = datap[i];
|
||||
out[i].bval = 0;
|
||||
t_out[i].aval = datap[i];
|
||||
t_out[i].bval = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (valuep->format == vpiBinStrVal) {
|
||||
valuep->value.str = outStr;
|
||||
valuep->value.str = t_outStr;
|
||||
int bits = varp->packed().elements();
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (bits > outStrSz) {
|
||||
if (bits > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
bits = outStrSz;
|
||||
bits = t_outStrSz;
|
||||
_VL_VPI_WARNING(
|
||||
__FILE__, __LINE__,
|
||||
"%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
||||
VL_MULS_MAX_WORDS, bits);
|
||||
}
|
||||
for (i = 0; i < bits; ++i) {
|
||||
char val = (datap[i >> 3] >> (i & 7)) & 1;
|
||||
outStr[bits - i - 1] = val ? '1' : '0';
|
||||
t_outStr[bits - i - 1] = val ? '1' : '0';
|
||||
}
|
||||
outStr[i] = '\0';
|
||||
t_outStr[i] = '\0';
|
||||
return;
|
||||
} else if (valuep->format == vpiOctStrVal) {
|
||||
valuep->value.str = outStr;
|
||||
valuep->value.str = t_outStr;
|
||||
int chars = (varp->packed().elements() + 2) / 3;
|
||||
int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (chars > outStrSz) {
|
||||
if (chars > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
_VL_VPI_WARNING(
|
||||
__FILE__, __LINE__,
|
||||
"%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
||||
VL_MULS_MAX_WORDS, chars);
|
||||
chars = outStrSz;
|
||||
chars = t_outStrSz;
|
||||
}
|
||||
for (i = 0; i < chars; ++i) {
|
||||
div_t idx = div(i * 3, 8);
|
||||
@@ -1509,44 +1518,44 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
val &= (1 << rem) - 1;
|
||||
}
|
||||
}
|
||||
outStr[chars - i - 1] = '0' + (val & 7);
|
||||
t_outStr[chars - i - 1] = '0' + (val & 7);
|
||||
}
|
||||
outStr[i] = '\0';
|
||||
t_outStr[i] = '\0';
|
||||
return;
|
||||
} else if (valuep->format == vpiDecStrVal) {
|
||||
valuep->value.str = outStr;
|
||||
valuep->value.str = t_outStr;
|
||||
// outStrSz does not include nullptr termination so add one
|
||||
if (varp->vltype() == VLVT_UINT8) {
|
||||
VL_SNPRINTF(outStr, outStrSz + 1, "%hhu",
|
||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hhu",
|
||||
static_cast<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT16) {
|
||||
VL_SNPRINTF(outStr, outStrSz + 1, "%hu",
|
||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hu",
|
||||
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT32) {
|
||||
VL_SNPRINTF(outStr, outStrSz + 1, "%u",
|
||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%u",
|
||||
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
VL_SNPRINTF(outStr, outStrSz + 1, "%llu",
|
||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%llu",
|
||||
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
||||
return;
|
||||
}
|
||||
} else if (valuep->format == vpiHexStrVal) {
|
||||
valuep->value.str = outStr;
|
||||
valuep->value.str = t_outStr;
|
||||
int chars = (varp->packed().elements() + 3) >> 2;
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (chars > outStrSz) {
|
||||
if (chars > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
_VL_VPI_WARNING(
|
||||
__FILE__, __LINE__,
|
||||
"%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
||||
VL_MULS_MAX_WORDS, chars);
|
||||
chars = outStrSz;
|
||||
chars = t_outStrSz;
|
||||
}
|
||||
for (i = 0; i < chars; ++i) {
|
||||
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
|
||||
@@ -1559,35 +1568,35 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
val &= (1 << rem) - 1;
|
||||
}
|
||||
}
|
||||
outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
|
||||
t_outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
|
||||
}
|
||||
outStr[i] = '\0';
|
||||
t_outStr[i] = '\0';
|
||||
return;
|
||||
} else if (valuep->format == vpiStringVal) {
|
||||
if (varp->vltype() == VLVT_STRING) {
|
||||
valuep->value.str = reinterpret_cast<char*>(varDatap);
|
||||
return;
|
||||
} else {
|
||||
valuep->value.str = outStr;
|
||||
valuep->value.str = t_outStr;
|
||||
int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
int i;
|
||||
if (bytes > outStrSz) {
|
||||
if (bytes > t_outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
_VL_VPI_WARNING(
|
||||
__FILE__, __LINE__,
|
||||
"%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
|
||||
VL_MULS_MAX_WORDS, bytes);
|
||||
bytes = outStrSz;
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname,
|
||||
t_outStrSz, VL_MULS_MAX_WORDS, bytes);
|
||||
bytes = t_outStrSz;
|
||||
}
|
||||
for (i = 0; i < bytes; ++i) {
|
||||
char val = datap[bytes - i - 1];
|
||||
// other simulators replace [leading?] zero chars with spaces, replicate here.
|
||||
outStr[i] = val ? val : ' ';
|
||||
t_outStr[i] = val ? val : ' ';
|
||||
}
|
||||
outStr[i] = '\0';
|
||||
t_outStr[i] = '\0';
|
||||
return;
|
||||
}
|
||||
} else if (valuep->format == vpiIntVal) {
|
||||
@@ -1639,7 +1648,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
_VL_VPI_ERROR_RESET();
|
||||
if (VL_UNLIKELY(!valuep)) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||
VL_DEBUG_IF_PLI(
|
||||
@@ -1652,9 +1661,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
"Ignoring vpi_put_value to signal marked read-only,"
|
||||
" use public_flat_rw instead: %s",
|
||||
vop->fullname());
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return 0;
|
||||
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr;
|
||||
if (valuep->format == vpiVectorVal) {
|
||||
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
|
||||
if (vop->varp()->vltype() == VLVT_UINT8) {
|
||||
@@ -1755,7 +1764,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
||||
VL_FUNC, valuep->value.str,
|
||||
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (success > 1) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__,
|
||||
@@ -1844,11 +1853,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
} else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s",
|
||||
VL_FUNC, vop->fullname());
|
||||
return 0;
|
||||
return nullptr;
|
||||
} else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s",
|
||||
VL_FUNC, vop->fullname());
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
|
||||
return nullptr;
|
||||
@@ -1910,7 +1919,7 @@ PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
||||
|
||||
PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) {
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) {
|
||||
@@ -2020,7 +2029,7 @@ PLI_INT32 vpi_put_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*num
|
||||
}
|
||||
void* vpi_get_userdata(vpiHandle /*obj*/) {
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
PLI_INT32 vpi_put_userdata(vpiHandle /*obj*/, void* /*userdata*/) {
|
||||
_VL_VPI_UNIMP();
|
||||
@@ -2051,5 +2060,5 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
|
||||
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
|
||||
PLI_INT32* /*index_array*/) {
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
|
||||
//======================================================================
|
||||
|
||||
class VerilatedVpi {
|
||||
class VerilatedVpi final {
|
||||
public:
|
||||
/// Call timed callbacks
|
||||
/// Users should call this from their main loops
|
||||
static void callTimedCbs() VL_MT_UNSAFE_ONE;
|
||||
/// Call value based callbacks
|
||||
/// Users should call this from their main loops
|
||||
static void callValueCbs() VL_MT_UNSAFE_ONE;
|
||||
static bool callValueCbs() VL_MT_UNSAFE_ONE;
|
||||
/// Call callbacks of arbitrary types
|
||||
/// Users can call this from their application code
|
||||
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE;
|
||||
|
||||
@@ -374,7 +374,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
//=========================================================================
|
||||
// Class definition helpers
|
||||
|
||||
// Used to declare a class as uncopyable; put after a private:
|
||||
/// Used to indicate a base class, e.g. cannot label "class final"
|
||||
#define VL_NOT_FINAL
|
||||
|
||||
/// Used to declare a class as uncopyable; put after a private:
|
||||
#define VL_UNCOPYABLE(Type) \
|
||||
Type(const Type& other) = delete; \
|
||||
Type& operator=(const Type&) = delete
|
||||
|
||||
+32
-32
@@ -83,28 +83,28 @@ sub test {
|
||||
require "./nodist/code_coverage.dat";
|
||||
|
||||
if ($Opt_Stages{1}) {
|
||||
travis_fold_start("configure");
|
||||
ci_fold_start("configure");
|
||||
print "Stage 1: configure (coverage on)\n";
|
||||
run("make distclean || true");
|
||||
run("autoconf");
|
||||
# Exceptions can pollute the branch coverage data
|
||||
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'");
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{2}) {
|
||||
travis_fold_start("build");
|
||||
ci_fold_start("build");
|
||||
print "Stage 2: build\n";
|
||||
my $nproc = Unix::Processors->new->max_online;
|
||||
run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1");
|
||||
# The optimized versions will not collect good coverage, overwrite them
|
||||
run("cp bin/verilator_bin_dbg bin/verilator_bin");
|
||||
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{3}) {
|
||||
travis_fold_start("test");
|
||||
ci_fold_start("test");
|
||||
print "Stage 3: make tests (with coverage on)\n";
|
||||
if ($#Opt_Tests < 0) {
|
||||
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
||||
@@ -121,12 +121,12 @@ sub test {
|
||||
run($test);
|
||||
}
|
||||
}
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
my $cc_dir = "nodist/obj_dir/coverage";
|
||||
if ($Opt_Stages{4}) {
|
||||
travis_fold_start("gcno");
|
||||
ci_fold_start("gcno");
|
||||
print "Stage 4: Create gcno files under $cc_dir\n";
|
||||
mkpath($cc_dir);
|
||||
mkpath("$cc_dir/info");
|
||||
@@ -165,11 +165,11 @@ sub test {
|
||||
}
|
||||
}
|
||||
}
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{5} && $Opt_Fastcov) {
|
||||
travis_fold_start("fastcov");
|
||||
ci_fold_start("fastcov");
|
||||
# Must run in root directory to find all files
|
||||
mkpath($cc_dir);
|
||||
#run("${RealBin}/fastcov.py -b -c src/obj_dbg -X".
|
||||
@@ -178,11 +178,11 @@ sub test {
|
||||
run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov".
|
||||
" --exclude /usr --exclude test_regress"
|
||||
." -o ${cc_dir}/app_total.info");
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{5} && !$Opt_Fastcov) {
|
||||
travis_fold_start("infos");
|
||||
ci_fold_start("infos");
|
||||
print "Stage 5: make infos\n";
|
||||
my $dats = `find . -print | grep .gcda`;
|
||||
my %dirs;
|
||||
@@ -199,20 +199,20 @@ sub test {
|
||||
})->run;
|
||||
}
|
||||
$Fork->wait_all;
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{6}) {
|
||||
travis_fold_start("clone");
|
||||
ci_fold_start("clone");
|
||||
# No control file to override single lines, so replicate the sources
|
||||
# Also lets us see the insertion markers in the HTML source res
|
||||
print "Stage 6: Clone sources under $cc_dir\n";
|
||||
clone_sources($cc_dir);
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{8} && !$Opt_Fastcov) {
|
||||
travis_fold_start("copy");
|
||||
ci_fold_start("copy");
|
||||
print "Stage 8: Copy .gcno files\n";
|
||||
my $dats = `find . -print | grep .gcno`;
|
||||
foreach my $dat (sort (split '\n', $dats)) {
|
||||
@@ -221,11 +221,11 @@ sub test {
|
||||
#print "cp $dat, $outdat);\n";
|
||||
cp($dat, $outdat);
|
||||
}
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{10} && !$Opt_Fastcov) {
|
||||
travis_fold_start("combine");
|
||||
ci_fold_start("combine");
|
||||
print "Stage 10: Combine data files\n";
|
||||
{
|
||||
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
||||
@@ -243,11 +243,11 @@ sub test {
|
||||
}
|
||||
}
|
||||
}
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{11}) {
|
||||
travis_fold_start("dirs");
|
||||
ci_fold_start("dirs");
|
||||
print "Stage 11: Cleanup paths\n";
|
||||
if ($Opt_Fastcov) {
|
||||
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||
@@ -255,11 +255,11 @@ sub test {
|
||||
} else {
|
||||
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||
}
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{12}) {
|
||||
travis_fold_start("filter");
|
||||
ci_fold_start("filter");
|
||||
print "Stage 12: Filter processed source files\n";
|
||||
my $inc = '';
|
||||
foreach my $glob (@Source_Globs) {
|
||||
@@ -282,24 +282,24 @@ sub test {
|
||||
} else {
|
||||
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
|
||||
}
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{17}) {
|
||||
travis_fold_start("report");
|
||||
ci_fold_start("report");
|
||||
print "Stage 17: Create HTML\n";
|
||||
run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp"
|
||||
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{18}) {
|
||||
travis_fold_start("upload");
|
||||
ci_fold_start("upload");
|
||||
print "Stage 18: Upload\n";
|
||||
my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info";
|
||||
print "print: Not running: export CODECOV_TOKEN=<hidden>\n";
|
||||
print "print: Not running: $cmd\n";
|
||||
travis_fold_end();
|
||||
ci_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{19}) {
|
||||
@@ -425,13 +425,13 @@ sub run {
|
||||
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
||||
}
|
||||
|
||||
our $_Travis_Action;
|
||||
sub travis_fold_start {
|
||||
$_Travis_Action = shift;
|
||||
print "travis_fold:start:$_Travis_Action\n";
|
||||
our $_Ci_Action;
|
||||
sub ci_fold_start {
|
||||
$_Ci_Action = shift;
|
||||
print "travis_fold:start:$_Ci_Action\n";
|
||||
}
|
||||
sub travis_fold_end {
|
||||
print "travis_fold:end:$_Travis_Action\n";
|
||||
sub ci_fold_end {
|
||||
print "travis_fold:end:$_Ci_Action\n";
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
@@ -46,14 +46,18 @@ 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\(\)
|
||||
|\bassert\(
|
||||
|\bBROKEN_RTK\(
|
||||
|\bSELF_CHECK)/x);
|
||||
|
||||
1;
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ use strict;
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add axiom-athdl`;
|
||||
exec('atsim',@ARGV);
|
||||
exec('atsim', @ARGV);
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
@@ -22,7 +22,7 @@ invoke_atsim - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_atsim {ncv arguments}
|
||||
invoke_atsim {arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ use strict;
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add cds-ius`;
|
||||
exec('iccr',@ARGV);
|
||||
exec('iccr', @ARGV);
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
@@ -22,7 +22,7 @@ invoke_iccr - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_iccr {ncv arguments}
|
||||
invoke_iccr {arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use strict;
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add cds-ius/latest`;
|
||||
exec('ncverilog',@ARGV);
|
||||
exec('ncverilog', @ARGV);
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
@@ -22,7 +22,7 @@ invoke_ncverilog - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_ncverilog {ncv arguments}
|
||||
invoke_ncverilog {arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ use strict;
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add synopsys-sim/latest`;
|
||||
exec('vcs',@ARGV);
|
||||
exec('vcs', @ARGV);
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
@@ -22,7 +22,7 @@ invoke_vcs - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_vcs {ncv arguments}
|
||||
invoke_vcs {arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
+3
-3
@@ -7,21 +7,21 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
define pn
|
||||
call $arg0->dumpGdb()
|
||||
call AstNode::dumpGdb($arg0)
|
||||
end
|
||||
document pn
|
||||
Verilator: Print single AstNode NODEP
|
||||
end
|
||||
|
||||
define pnt
|
||||
call $arg0->dumpTreeGdb()
|
||||
call AstNode::dumpTreeGdb($arg0)
|
||||
end
|
||||
document pnt
|
||||
Verilator: Print AstNode NODEP's tree
|
||||
end
|
||||
|
||||
define dtf
|
||||
call AstNode::dumpTreeFileGdb(0)
|
||||
call AstNode::dumpTreeFileGdb($arg0, 0)
|
||||
end
|
||||
document dtf
|
||||
Verilator: Dump AstNode tree to file
|
||||
|
||||
@@ -81,6 +81,10 @@ prefiles:: config_rev.h
|
||||
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
|
||||
# Human convenience
|
||||
clang-format:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_* *.log *.dmp *.vpd core
|
||||
|
||||
@@ -94,7 +94,6 @@ LIBS = $(CFG_LIBS) -lm
|
||||
|
||||
CPPFLAGS += -MMD
|
||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
||||
CPPFLAGS += -DYYDEBUG # Required to get nice error messages
|
||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGS += $(COPT)
|
||||
CPPFLAGS += -MP # Only works on recent GCC versions
|
||||
|
||||
+16
-8
@@ -43,12 +43,12 @@
|
||||
//######################################################################
|
||||
// Collect existing active names
|
||||
|
||||
class ActiveBaseVisitor : public AstNVisitor {
|
||||
class ActiveBaseVisitor VL_NOT_FINAL : public AstNVisitor {
|
||||
protected:
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
};
|
||||
|
||||
class ActiveNamer : public ActiveBaseVisitor {
|
||||
class ActiveNamer final : public ActiveBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstScope* m_scopep = nullptr; // Current scope to add statement to
|
||||
@@ -130,15 +130,15 @@ public:
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
ActiveNamer() {}
|
||||
virtual ~ActiveNamer() override {}
|
||||
ActiveNamer() = default;
|
||||
virtual ~ActiveNamer() override = default;
|
||||
void main(AstScope* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Active AssignDly replacement functions
|
||||
|
||||
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
||||
class ActiveDlyVisitor final : public ActiveBaseVisitor {
|
||||
public:
|
||||
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||
|
||||
@@ -205,13 +205,13 @@ public:
|
||||
, m_alwaysp{nodep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveDlyVisitor() override {}
|
||||
virtual ~ActiveDlyVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Active class functions
|
||||
|
||||
class ActiveVisitor : public ActiveBaseVisitor {
|
||||
class ActiveVisitor final : public ActiveBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Each call to V3Const::constify
|
||||
@@ -364,6 +364,14 @@ private:
|
||||
}
|
||||
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
|
||||
}
|
||||
virtual void visit(AstAlwaysPostponed* nodep) override {
|
||||
UINFO(4, " ALW " << nodep << endl);
|
||||
if (!nodep->bodysp()) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) override {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4, " ALWPub " << nodep << endl);
|
||||
@@ -406,7 +414,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ActiveVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ActiveVisitor() override {}
|
||||
virtual ~ActiveVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Active {
|
||||
class V3Active final {
|
||||
public:
|
||||
static void activeAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@
|
||||
//######################################################################
|
||||
// Active class functions
|
||||
|
||||
class ActiveTopVisitor : public AstNVisitor {
|
||||
class ActiveTopVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist
|
||||
@@ -128,7 +128,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ActiveTopVisitor() override {}
|
||||
virtual ~ActiveTopVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3ActiveTop {
|
||||
class V3ActiveTop final {
|
||||
public:
|
||||
static void activeTopAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+79
-9
@@ -26,7 +26,7 @@
|
||||
//######################################################################
|
||||
// Assert class functions
|
||||
|
||||
class AssertVisitor : public AstNVisitor {
|
||||
class AssertVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE/TYPES
|
||||
// Cleared on netlist
|
||||
@@ -36,7 +36,11 @@ private:
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Last module
|
||||
AstBegin* m_beginp = nullptr; // Last begin
|
||||
unsigned m_monitorNum = 0; // Global $monitor numbering (not per module)
|
||||
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
|
||||
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
|
||||
unsigned m_modPastNum = 0; // Module past numbering
|
||||
unsigned m_modStrobeNum = 0; // Module $strobe numbering
|
||||
VDouble0 m_statCover; // Statistic tracking
|
||||
VDouble0 m_statAsNotImm; // Statistic tracking
|
||||
VDouble0 m_statAsImm; // Statistic tracking
|
||||
@@ -62,7 +66,26 @@ private:
|
||||
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
|
||||
AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) {
|
||||
if (!m_monitorNumVarp) {
|
||||
m_monitorNumVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__VmonitorNum", nodep->findUInt64DType()};
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorNumVarp);
|
||||
}
|
||||
const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access);
|
||||
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
return varrefp;
|
||||
}
|
||||
AstVarRef* newMonitorOffVarRefp(AstNode* nodep, VAccess access) {
|
||||
if (!m_monitorOffVarp) {
|
||||
m_monitorOffVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__VmonitorOff", nodep->findBitDType()};
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorOffVarp);
|
||||
}
|
||||
const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access);
|
||||
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
return varrefp;
|
||||
}
|
||||
AstNode* newIfAssertOn(AstNode* nodep) {
|
||||
// Add a internal if to check assertions are on.
|
||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||
@@ -73,7 +96,7 @@ private:
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.assertOn()
|
||||
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
|
||||
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
|
||||
: static_cast<AstNode*>(new AstConst(fl, AstConst::BitFalse()))),
|
||||
nodep, nullptr);
|
||||
newp->user1(true); // Don't assert/cover this if
|
||||
return newp;
|
||||
@@ -207,7 +230,7 @@ private:
|
||||
bool allow_none = nodep->unique0Pragma();
|
||||
|
||||
// Empty case means no property
|
||||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
|
||||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
|
||||
|
||||
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
||||
// predicates evaluates to true.
|
||||
@@ -276,7 +299,7 @@ private:
|
||||
}
|
||||
}
|
||||
// Empty case means no property
|
||||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
|
||||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
|
||||
|
||||
bool allow_none = has_default || nodep->unique0Pragma();
|
||||
AstNode* ohot
|
||||
@@ -317,12 +340,12 @@ private:
|
||||
"_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);
|
||||
}
|
||||
@@ -342,9 +365,54 @@ private:
|
||||
} else if (nodep->displayType() == AstDisplayType::DT_ERROR
|
||||
|| nodep->displayType() == AstDisplayType::DT_FATAL) {
|
||||
replaceDisplay(nodep, "%%Error");
|
||||
} else if (nodep->displayType() == AstDisplayType::DT_MONITOR) {
|
||||
nodep->displayType(AstDisplayType::DT_DISPLAY);
|
||||
const auto fl = nodep->fileline();
|
||||
const auto monNum = ++m_monitorNum;
|
||||
// Where $monitor was we do "__VmonitorNum = N;"
|
||||
const auto newsetp = new AstAssign{fl, newMonitorNumVarRefp(nodep, VAccess::WRITE),
|
||||
new AstConst{fl, monNum}};
|
||||
nodep->replaceWith(newsetp);
|
||||
// Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);"
|
||||
AstNode* stmtsp = nodep;
|
||||
AstIf* ifp = new AstIf{
|
||||
fl,
|
||||
new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)},
|
||||
new AstEq{fl, new AstConst{fl, monNum},
|
||||
newMonitorNumVarRefp(nodep, VAccess::READ)}},
|
||||
stmtsp, nullptr};
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
|
||||
m_modp->addStmtp(newp);
|
||||
} else if (nodep->displayType() == AstDisplayType::DT_STROBE) {
|
||||
nodep->displayType(AstDisplayType::DT_DISPLAY);
|
||||
// Need one-shot
|
||||
const auto fl = nodep->fileline();
|
||||
const auto varp
|
||||
= new AstVar{fl, AstVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++),
|
||||
nodep->findBitDType()};
|
||||
m_modp->addStmtp(varp);
|
||||
// Where $strobe was we do "__Vstrobe = '1;"
|
||||
const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitTrue{}}};
|
||||
nodep->replaceWith(newsetp);
|
||||
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
|
||||
AstNode* stmtsp = nodep;
|
||||
AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
|
||||
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitFalse{}}});
|
||||
m_modp->addStmtp(newp);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstMonitorOff* nodep) override {
|
||||
const auto newp
|
||||
= new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off()));
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstAssert* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nodep->failsp());
|
||||
@@ -362,9 +430,11 @@ private:
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_modPastNum);
|
||||
VL_RESTORER(m_modStrobeNum);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
m_modStrobeNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Assert {
|
||||
class V3Assert final {
|
||||
public:
|
||||
static void assertAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+31
-8
@@ -26,7 +26,7 @@
|
||||
//######################################################################
|
||||
// Assert class functions
|
||||
|
||||
class AssertPreVisitor : public AstNVisitor {
|
||||
class AssertPreVisitor final : public AstNVisitor {
|
||||
// Removes clocks and other pre-optimizations
|
||||
// Eventually inlines calls to sequences, properties, etc.
|
||||
// We're not parsing the tree, or anything more complicated.
|
||||
@@ -39,6 +39,8 @@ private:
|
||||
AstSenItem* m_senip = nullptr; // Last sensitivity
|
||||
// Reset each always:
|
||||
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
|
||||
// Reset each assertion:
|
||||
AstNode* m_disablep = nullptr; // Last disable
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -58,7 +60,10 @@ private:
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
void clearAssertInfo() { m_senip = nullptr; }
|
||||
void clearAssertInfo() {
|
||||
m_senip = nullptr;
|
||||
m_disablep = nullptr;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
//========== Statements
|
||||
@@ -98,7 +103,7 @@ private:
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
|
||||
exprp->dtypeSetLogicBool();
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
@@ -117,7 +122,7 @@ private:
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
|
||||
exprp->dtypeSetLogicBool();
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
@@ -129,9 +134,26 @@ private:
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past,
|
||||
exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true)
|
||||
exprp->dtypeSetLogicBool();
|
||||
exprp = new AstEq(fl, past, exprp->cloneTree(false));
|
||||
exprp->dtypeSetBit();
|
||||
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->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
@@ -145,6 +167,7 @@ private:
|
||||
// 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(),
|
||||
@@ -174,7 +197,7 @@ public:
|
||||
// Process
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~AssertPreVisitor() override {}
|
||||
virtual ~AssertPreVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3AssertPre {
|
||||
class V3AssertPre final {
|
||||
public:
|
||||
static void assertPreAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+52
-30
@@ -58,9 +58,10 @@ 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 = nullptr;
|
||||
m_nextp = nullptr;
|
||||
m_backp = nullptr;
|
||||
m_headtailp = this; // When made, we're a list of only a single element
|
||||
@@ -126,8 +127,9 @@ string AstNode::encodeName(const string& namein) {
|
||||
}
|
||||
// Shorten names
|
||||
// TODO long term use VName in place of "string name"
|
||||
VName vname(out);
|
||||
out = vname.hashedName();
|
||||
// Then we also won't need to save the table of hased values
|
||||
VName vname{out};
|
||||
return vname.hashedName();
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -160,7 +162,8 @@ string AstNode::dedotName(const string& namein) {
|
||||
string AstNode::vcdName(const string& namein) {
|
||||
// VCD tracing expects space to separate hierarchy
|
||||
// Dots are reserved for dots the user put in the name
|
||||
string pretty = namein;
|
||||
// We earlier hashed all symbols, dehash them so user sees real name
|
||||
string pretty{VName::dehash(namein)};
|
||||
string::size_type pos;
|
||||
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " ");
|
||||
while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " ");
|
||||
@@ -393,6 +396,7 @@ void AstNode::setOp4p(AstNode* newp) {
|
||||
|
||||
void AstNode::addOp1p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp1p");
|
||||
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
|
||||
if (!m_op1p) {
|
||||
op1p(newp);
|
||||
} else {
|
||||
@@ -402,6 +406,7 @@ void AstNode::addOp1p(AstNode* newp) {
|
||||
|
||||
void AstNode::addOp2p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp2p");
|
||||
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
|
||||
if (!m_op2p) {
|
||||
op2p(newp);
|
||||
} else {
|
||||
@@ -411,6 +416,7 @@ void AstNode::addOp2p(AstNode* newp) {
|
||||
|
||||
void AstNode::addOp3p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp3p");
|
||||
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
|
||||
if (!m_op3p) {
|
||||
op3p(newp);
|
||||
} else {
|
||||
@@ -420,6 +426,7 @@ void AstNode::addOp3p(AstNode* newp) {
|
||||
|
||||
void AstNode::addOp4p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp4p");
|
||||
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
|
||||
if (!m_op4p) {
|
||||
op4p(newp);
|
||||
} else {
|
||||
@@ -1022,28 +1029,40 @@ void AstNode::checkTree() {
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
|
||||
dumpGdbHeader(); // LCOV_EXCL_LINE
|
||||
void AstNode::dumpGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_LINE
|
||||
if (!nodep) {
|
||||
cout << "<nullptr>" << endl;
|
||||
return;
|
||||
}
|
||||
nodep->dumpGdbHeader();
|
||||
cout << " ";
|
||||
dump(cout);
|
||||
cout << endl; // LCOV_EXCL_LINE
|
||||
}
|
||||
nodep->dump(cout);
|
||||
cout << endl;
|
||||
} // LCOV_EXCL_STOP
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
|
||||
dumpPtrs(cout); // LCOV_EXCL_LINE
|
||||
cout << " Fileline = " << fileline() << endl; // LCOV_EXCL_LINE
|
||||
}
|
||||
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_START
|
||||
dumpPtrs(cout);
|
||||
cout << " Fileline = " << fileline() << endl;
|
||||
} // LCOV_EXCL_STOP
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
|
||||
dumpGdbHeader(); // LCOV_EXCL_LINE
|
||||
dumpTree(cout); // LCOV_EXCL_LINE
|
||||
}
|
||||
void AstNode::dumpTreeGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_START
|
||||
if (!nodep) {
|
||||
cout << "<nullptr>" << endl;
|
||||
return;
|
||||
}
|
||||
nodep->dumpGdbHeader();
|
||||
nodep->dumpTree(cout);
|
||||
} // LCOV_EXCL_STOP
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
|
||||
string filename
|
||||
= filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
|
||||
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
|
||||
}
|
||||
void AstNode::dumpTreeFileGdb(const AstNode* nodep, // LCOV_EXCL_START
|
||||
const char* filenamep) { // For GDB only
|
||||
if (!nodep) {
|
||||
cout << "<nullptr>" << endl;
|
||||
return;
|
||||
}
|
||||
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98);
|
||||
v3Global.rootp()->dumpTreeFile(filename);
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::checkIter() const {
|
||||
@@ -1081,14 +1100,14 @@ void AstNode::dumpPtrs(std::ostream& os) const {
|
||||
|
||||
void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const {
|
||||
static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9
|
||||
os << indent << " " << this << endl;
|
||||
os << indent << " " << this << '\n';
|
||||
if (debug() > 8) {
|
||||
os << indent << " ";
|
||||
dumpPtrs(os);
|
||||
}
|
||||
if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); }
|
||||
if (maxDepth == 1) {
|
||||
if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; }
|
||||
if (op1p() || op2p() || op3p() || op4p()) os << indent << "1: ...(maxDepth)\n";
|
||||
} else {
|
||||
for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent + "1:", maxDepth - 1);
|
||||
@@ -1112,7 +1131,7 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, bool doCheck) {
|
||||
// Not const function as calls checkTree
|
||||
if (doDump) {
|
||||
{ // Write log & close
|
||||
@@ -1120,9 +1139,9 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
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;
|
||||
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
|
||||
if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) {
|
||||
*logsp << endl;
|
||||
*logsp << '\n';
|
||||
*logsp << "No changes since last dump!\n";
|
||||
} else {
|
||||
dumpTree(*logsp);
|
||||
@@ -1130,7 +1149,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) {
|
||||
if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) {
|
||||
// Error check
|
||||
checkTree();
|
||||
// Broken isn't part of check tree because it can munge iterp's
|
||||
@@ -1192,7 +1211,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
||||
std::ostringstream nsstr;
|
||||
nsstr << str.str();
|
||||
if (debug()) {
|
||||
nsstr << endl;
|
||||
nsstr << '\n';
|
||||
nsstr << "-node: ";
|
||||
const_cast<AstNode*>(this)->dump(nsstr);
|
||||
nsstr << endl;
|
||||
@@ -1260,6 +1279,9 @@ AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
||||
AstNodeDType* AstNode::findVoidDType() const {
|
||||
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
|
||||
}
|
||||
AstNodeDType* AstNode::findQueueIndexDType() const {
|
||||
return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline());
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// AstNVisitor
|
||||
|
||||
+222
-157
File diff suppressed because it is too large
Load Diff
+276
-170
@@ -54,7 +54,7 @@ void AstNodeVarRef::cloneRelink() {
|
||||
}
|
||||
|
||||
string AstNodeVarRef::hiernameProtect() const {
|
||||
return VIdProtect::protectWordsIf(hiername(), protect());
|
||||
return hiernameToUnprot() + VIdProtect::protectWordsIf(hiernameToProt(), protect());
|
||||
}
|
||||
|
||||
int AstNodeSel::bitConst() const {
|
||||
@@ -87,8 +87,10 @@ const char* AstNodeUOrStructDType::broken() const {
|
||||
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);
|
||||
@@ -105,7 +107,7 @@ const char* AstNodeCCall::broken() const {
|
||||
}
|
||||
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
|
||||
string AstNodeCCall::hiernameProtect() const {
|
||||
return VIdProtect::protectWordsIf(hiername(), protect());
|
||||
return hiernameToUnprot() + VIdProtect::protectWordsIf(hiernameToProt(), protect());
|
||||
}
|
||||
|
||||
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
|
||||
@@ -310,107 +312,22 @@ string AstVar::verilogKwd() const {
|
||||
}
|
||||
}
|
||||
|
||||
class AstVar::VlArgTypeRecursed {
|
||||
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) const {
|
||||
string out;
|
||||
out += m_type;
|
||||
out += " ";
|
||||
out += m_isRef ? "(&" + name + ")" : name;
|
||||
out += m_dims;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const {
|
||||
UASSERT_OBJ(!forReturn, this,
|
||||
"Internal data is never passed as return, but as first argument");
|
||||
string ostatic;
|
||||
if (isStatic() && namespc.empty()) ostatic = "static ";
|
||||
|
||||
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
|
||||
bool isRef = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
|
||||
|
||||
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
|
||||
|
||||
string oname;
|
||||
if (named) {
|
||||
if (!namespc.empty()) oname += namespc + "::";
|
||||
oname += VIdProtect::protectIf(name(), protect());
|
||||
}
|
||||
return ostatic + info.render(oname);
|
||||
}
|
||||
|
||||
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
|
||||
bool compound) const {
|
||||
VlArgTypeRecursed info;
|
||||
info.m_isRef
|
||||
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
|
||||
|
||||
dtypep = dtypep->skipRefp();
|
||||
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
|
||||
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
|
||||
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
|
||||
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
||||
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
|
||||
info.m_type = "VlQueue<" + sub.m_type + ">";
|
||||
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
||||
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
|
||||
info.m_type = "VlQueue<" + sub.m_type;
|
||||
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
||||
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
|
||||
info.m_type += ">";
|
||||
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
||||
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
||||
if (compound) {
|
||||
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
|
||||
}
|
||||
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
|
||||
info.m_type = sub.m_type;
|
||||
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
|
||||
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
|
||||
// We don't print msb()/lsb() as multidim packed would require recursion,
|
||||
// and may confuse users as C++ data is stored always with bit 0 used
|
||||
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
|
||||
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
|
||||
: "";
|
||||
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
|
||||
info.m_type = "const char*";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
|
||||
info.m_type = "const VerilatedScope*";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
|
||||
info.m_type = "double";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
|
||||
info.m_type = "float";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
|
||||
info.m_type = "std::string";
|
||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||
info.m_type = "CData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
info.m_type = "SData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
|
||||
info.m_type = "IData" + bitvec;
|
||||
} else if (dtypep->isQuad()) {
|
||||
info.m_type = "QData" + bitvec;
|
||||
} else if (dtypep->isWide()) {
|
||||
if (compound) {
|
||||
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
|
||||
} else {
|
||||
info.m_type += "WData" + bitvec; // []'s added later
|
||||
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
|
||||
}
|
||||
|
||||
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
|
||||
|
||||
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
|
||||
|
||||
return info;
|
||||
return ostatic + dtypep()->cType(oname, forFunc, isRef);
|
||||
}
|
||||
|
||||
string AstVar::vlEnumType() const {
|
||||
@@ -538,38 +455,99 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named = false;
|
||||
string arg;
|
||||
if (isDpiOpenArray()) {
|
||||
arg = "const svOpenArrayHandle";
|
||||
} else if (!basicp()) {
|
||||
arg = "UNKNOWN";
|
||||
} else if (basicp()->isDpiBitVec()) {
|
||||
if (forReturn) {
|
||||
arg = "svBitVecVal";
|
||||
} else if (isReadOnly()) {
|
||||
arg = "const svBitVecVal*";
|
||||
} else {
|
||||
arg = "svBitVecVal*";
|
||||
}
|
||||
} else if (basicp()->isDpiLogicVec()) {
|
||||
if (forReturn) {
|
||||
arg = "svLogicVecVal";
|
||||
} else if (isReadOnly()) {
|
||||
arg = "const svLogicVecVal*";
|
||||
} else {
|
||||
arg = "svLogicVecVal*";
|
||||
}
|
||||
} else {
|
||||
arg = basicp()->keyword().dpiType();
|
||||
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
|
||||
arg = "unsigned " + arg;
|
||||
}
|
||||
if (!forReturn && isWritable()) arg += "*";
|
||||
class dpiTypesToStringConverter VL_NOT_FINAL {
|
||||
public:
|
||||
virtual string openArray(const AstVar*) const { return "const svOpenArrayHandle"; }
|
||||
virtual string bitLogicVector(const AstVar* varp, bool isBit) const {
|
||||
return isBit ? "svBitVecVal" : "svLogicVecVal";
|
||||
}
|
||||
if (named) arg += " " + name();
|
||||
return arg;
|
||||
virtual string primitive(const AstVar* varp) const {
|
||||
string type;
|
||||
if (varp->basicp()->keyword().isDpiUnsignable() && !varp->basicp()->isSigned()) {
|
||||
type = "unsigned ";
|
||||
}
|
||||
type += varp->basicp()->keyword().dpiType();
|
||||
return type;
|
||||
}
|
||||
string convert(const AstVar* varp) const {
|
||||
if (varp->isDpiOpenArray()) {
|
||||
return openArray(varp);
|
||||
} else if (!varp->basicp()) {
|
||||
return "UNKNOWN";
|
||||
} else if (varp->basicp()->isDpiBitVec() || varp->basicp()->isDpiLogicVec()) {
|
||||
return bitLogicVector(varp, varp->basicp()->isDpiBitVec());
|
||||
} else {
|
||||
return primitive(varp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) {
|
||||
return dpiTypesToStringConverter{}.convert(this);
|
||||
} else {
|
||||
class converter final : public dpiTypesToStringConverter {
|
||||
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
||||
return string(varp->isReadOnly() ? "const " : "")
|
||||
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
||||
}
|
||||
virtual string primitive(const AstVar* varp) const override {
|
||||
string type = dpiTypesToStringConverter::primitive(varp);
|
||||
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
if (!varp->isWritable()
|
||||
&& varp->basicp()->keyword() != AstBasicDTypeKwd::STRING)
|
||||
type = "const " + type;
|
||||
type += "*";
|
||||
}
|
||||
return type;
|
||||
}
|
||||
};
|
||||
string arg = converter{}.convert(this);
|
||||
if (named) arg += " " + name();
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
string AstVar::dpiTmpVarType(const string& varName) const {
|
||||
class converter final : public dpiTypesToStringConverter {
|
||||
string m_name;
|
||||
string arraySuffix(const AstVar* varp, size_t n) const {
|
||||
if (AstUnpackArrayDType* unpackp
|
||||
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
// Convert multi dimensional unpacked array to 1D array
|
||||
if (n == 0) n = 1;
|
||||
n *= unpackp->arrayUnpackedElements();
|
||||
return '[' + cvtToStr(n) + ']';
|
||||
} else if (n > 0) {
|
||||
return '[' + cvtToStr(n) + ']';
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
virtual string openArray(const AstVar* varp) const override {
|
||||
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
|
||||
+ arraySuffix(varp, 0);
|
||||
}
|
||||
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
||||
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
|
||||
type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
|
||||
return type;
|
||||
}
|
||||
virtual string primitive(const AstVar* varp) const override {
|
||||
string type = dpiTypesToStringConverter::primitive(varp);
|
||||
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
if (!varp->isWritable() && varp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE)
|
||||
type = "const " + type;
|
||||
}
|
||||
type += ' ' + m_name + arraySuffix(varp, 0);
|
||||
return type;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit converter(const string& name)
|
||||
: m_name(name) {}
|
||||
};
|
||||
return converter{varName}.convert(this);
|
||||
}
|
||||
|
||||
string AstVar::scType() const {
|
||||
@@ -636,6 +614,90 @@ string AstVar::mtasksString() const {
|
||||
return os.str();
|
||||
}
|
||||
|
||||
class AstNodeDType::CTypeRecursed final {
|
||||
public:
|
||||
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, bool isRef) const {
|
||||
string out;
|
||||
out += m_type;
|
||||
if (name != "") out += " ";
|
||||
out += isRef ? "(&" + name + ")" : name;
|
||||
out += m_dims;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const {
|
||||
CTypeRecursed info = cTypeRecurse(false);
|
||||
return info.render(name, isRef);
|
||||
}
|
||||
|
||||
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
CTypeRecursed info;
|
||||
|
||||
const AstNodeDType* dtypep = this->skipRefp();
|
||||
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
|
||||
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
||||
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlQueue<" + sub.m_type + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlQueue<" + sub.m_type;
|
||||
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
||||
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
|
||||
info.m_type += ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
||||
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
||||
if (compound) {
|
||||
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
|
||||
}
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
||||
info.m_type = sub.m_type;
|
||||
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
|
||||
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
|
||||
// We don't print msb()/lsb() as multidim packed would require recursion,
|
||||
// and may confuse users as C++ data is stored always with bit 0 used
|
||||
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
|
||||
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
|
||||
: "";
|
||||
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
|
||||
info.m_type = "const char*";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
|
||||
info.m_type = "const VerilatedScope*";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
|
||||
info.m_type = "double";
|
||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
|
||||
info.m_type = "std::string";
|
||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||
info.m_type = "CData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
info.m_type = "SData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
|
||||
info.m_type = "IData" + bitvec;
|
||||
} else if (dtypep->isQuad()) {
|
||||
info.m_type = "QData" + bitvec;
|
||||
} else if (dtypep->isWide()) {
|
||||
if (compound) {
|
||||
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
|
||||
} else {
|
||||
info.m_type += "WData" + bitvec; // []'s added later
|
||||
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
|
||||
}
|
||||
|
||||
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
|
||||
// dimension passed from AstArraySel::dimension
|
||||
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
|
||||
@@ -843,9 +905,7 @@ bool AstSenTree::hasCombo() const {
|
||||
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] = nullptr;
|
||||
}
|
||||
for (auto& itr : m_basicps) itr = nullptr;
|
||||
m_detailedMap.clear();
|
||||
// Clear generic()'s so dead detection will work
|
||||
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
||||
@@ -872,6 +932,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
||||
return m_voidp;
|
||||
}
|
||||
|
||||
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
||||
if (VL_UNLIKELY(!m_queueIndexp)) {
|
||||
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
|
||||
addTypesp(newp);
|
||||
m_queueIndexp = newp;
|
||||
}
|
||||
return m_queueIndexp;
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
|
||||
if (m_basicps[kwd]) return m_basicps[kwd];
|
||||
//
|
||||
@@ -1035,8 +1104,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() << "]";
|
||||
}
|
||||
|
||||
@@ -1057,8 +1128,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 {
|
||||
@@ -1074,6 +1149,7 @@ void AstCell::dump(std::ostream& str) const {
|
||||
void AstCellInline::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << origModName();
|
||||
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
||||
}
|
||||
const char* AstClassPackage::broken() const {
|
||||
BROKEN_BASE_RTN(AstNodeModule::broken());
|
||||
@@ -1095,6 +1171,13 @@ void AstClass::repairCache() {
|
||||
clearCache();
|
||||
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); }
|
||||
}
|
||||
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
|
||||
// TAIL RECURSIVE
|
||||
if (!refClassp || !baseClassp) return false;
|
||||
if (refClassp == baseClassp) return true;
|
||||
if (!refClassp->extendsp()) return false;
|
||||
return isClassExtendedFrom(refClassp->extendsp()->classp(), baseClassp);
|
||||
}
|
||||
void AstClass::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isExtended()) str << " [EXT]";
|
||||
@@ -1102,6 +1185,9 @@ void AstClass::dump(std::ostream& str) const {
|
||||
}
|
||||
AstClass* AstClassExtends::classp() const {
|
||||
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
||||
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
||||
refp = VN_CAST(childDTypep(), ClassRefDType);
|
||||
}
|
||||
UASSERT_OBJ(refp, this, "class extends non-ref");
|
||||
return refp->classp();
|
||||
}
|
||||
@@ -1119,15 +1205,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);
|
||||
@@ -1158,16 +1244,16 @@ void AstInitArray::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
int n = 0;
|
||||
const AstInitArray::KeyItemMap& mapr = map();
|
||||
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
|
||||
for (const auto& itr : mapr) {
|
||||
if (n++ > 5) {
|
||||
str << " ...";
|
||||
break;
|
||||
}
|
||||
str << " [" << it->first << "]=" << (void*)it->second;
|
||||
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
|
||||
}
|
||||
}
|
||||
void AstJumpGo::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (labelp()) {
|
||||
labelp()->dump(str);
|
||||
@@ -1176,7 +1262,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);
|
||||
@@ -1185,7 +1271,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);
|
||||
@@ -1194,7 +1280,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()) {
|
||||
@@ -1235,27 +1321,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 {
|
||||
@@ -1327,6 +1416,18 @@ string AstUnpackArrayDType::prettyDTypeName() const {
|
||||
os << subp->prettyDTypeName() << "$" << ranges;
|
||||
return os.str();
|
||||
}
|
||||
std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
|
||||
std::vector<AstUnpackArrayDType*> dims;
|
||||
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
|
||||
dims.push_back(unpackp);
|
||||
if (AstNodeDType* subp = unpackp->subDTypep()) {
|
||||
unpackp = VN_CAST(subp, UnpackArrayDType);
|
||||
} else {
|
||||
unpackp = nullptr;
|
||||
}
|
||||
}
|
||||
return dims;
|
||||
}
|
||||
void AstNetlist::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
||||
@@ -1352,15 +1453,20 @@ void AstPackageImport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << packagep();
|
||||
}
|
||||
void AstSel::dump(std::ostream& str) const {
|
||||
void AstPatMember::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isDefault()) str << " [DEFAULT]";
|
||||
}
|
||||
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
void AstSel::dump(std::ostream& str) const {
|
||||
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 {
|
||||
@@ -1372,7 +1478,7 @@ void AstTypeTable::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
|
||||
if (AstBasicDType* subnodep = m_basicps[i]) {
|
||||
str << endl; // Newline from caller, so newline first
|
||||
str << '\n'; // Newline from caller, so newline first
|
||||
str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii();
|
||||
str << " -> ";
|
||||
subnodep->dump(str);
|
||||
@@ -1380,9 +1486,9 @@ void AstTypeTable::dump(std::ostream& str) const {
|
||||
}
|
||||
{
|
||||
const DetailedMap& mapr = m_detailedMap;
|
||||
for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
|
||||
AstBasicDType* dtypep = it->second;
|
||||
str << endl; // Newline from caller, so newline first
|
||||
for (const auto& itr : mapr) {
|
||||
AstBasicDType* dtypep = itr.second;
|
||||
str << '\n'; // Newline from caller, so newline first
|
||||
str << "\t\tdetailed -> ";
|
||||
dtypep->dump(str);
|
||||
}
|
||||
@@ -1391,7 +1497,7 @@ void AstTypeTable::dump(std::ostream& str) const {
|
||||
}
|
||||
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str << "[assoc-" << (void*)keyDTypep() << "]";
|
||||
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
|
||||
}
|
||||
string AstAssocArrayDType::prettyDTypeName() const {
|
||||
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
|
||||
@@ -1428,14 +1534,13 @@ void AstVarScope::dump(std::ostream& str) const {
|
||||
str << " ->UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstNodeVarRef::dump(std::ostream& str) const {
|
||||
this->AstNodeMath::dump(str);
|
||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||
str << " " << access().arrow() << " ";
|
||||
}
|
||||
void AstVarXRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (lvalue()) {
|
||||
str << " [LV] => ";
|
||||
} else {
|
||||
str << " [RV] <- ";
|
||||
}
|
||||
this->AstNodeVarRef::dump(str);
|
||||
str << ".=" << dotted() << " ";
|
||||
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
|
||||
if (varScopep()) {
|
||||
@@ -1447,13 +1552,7 @@ void AstVarXRef::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstVarRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (lvalue()) {
|
||||
str << " [LV] => ";
|
||||
} else {
|
||||
str << " [RV] <- ";
|
||||
}
|
||||
this->AstNodeVarRef::dump(str);
|
||||
if (varScopep()) {
|
||||
varScopep()->dump(str);
|
||||
} else if (varp()) {
|
||||
@@ -1486,6 +1585,12 @@ void AstVar::dump(std::ostream& str) const {
|
||||
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
|
||||
str << " " << varType();
|
||||
}
|
||||
void AstScope::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
|
||||
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
|
||||
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
|
||||
}
|
||||
void AstSenTree::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isMulti()) str << " [MULTI]";
|
||||
@@ -1522,8 +1627,8 @@ void AstActive::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||
str << " -> ";
|
||||
if (dotted() != "") { str << ".=" << dotted() << " "; }
|
||||
if (taskp()) {
|
||||
@@ -1554,7 +1659,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()) {
|
||||
@@ -1565,7 +1670,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);
|
||||
@@ -1578,7 +1683,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);
|
||||
@@ -1597,10 +1702,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]";
|
||||
}
|
||||
|
||||
+733
-481
File diff suppressed because it is too large
Load Diff
+36
-43
@@ -36,7 +36,7 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BeginState {
|
||||
class BeginState final {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -45,8 +45,8 @@ private:
|
||||
bool m_anyFuncInBegin = false;
|
||||
|
||||
public:
|
||||
BeginState() {}
|
||||
~BeginState() {}
|
||||
BeginState() = default;
|
||||
~BeginState() = default;
|
||||
void userMarkChanged(AstNode* nodep) {
|
||||
nodep->user1(true);
|
||||
m_anyFuncInBegin = true;
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BeginVisitor : public AstNVisitor {
|
||||
class BeginVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
BeginState* m_statep; // Current global state
|
||||
@@ -69,6 +69,11 @@ private:
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
string dot(const string& a, const string& b) {
|
||||
if (a == "") return b;
|
||||
return a + "__DOT__" + b;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
@@ -81,7 +86,7 @@ private:
|
||||
UINFO(8, " " << nodep << endl);
|
||||
// Rename it
|
||||
if (m_unnamedScope != "") {
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
nodep->name(dot(m_unnamedScope, nodep->name()));
|
||||
UINFO(8, " rename to " << nodep->name() << endl);
|
||||
m_statep->userMarkChanged(nodep);
|
||||
}
|
||||
@@ -103,8 +108,8 @@ private:
|
||||
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;
|
||||
string oldUnnamed = m_unnamedScope;
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
{
|
||||
UINFO(8, "nname " << m_namedScope << endl);
|
||||
if (nodep->name() != "") { // Else unneeded unnamed block
|
||||
@@ -114,18 +119,8 @@ private:
|
||||
while ((pos = dottedname.find("__DOT__")) != string::npos) {
|
||||
string ident = dottedname.substr(0, pos);
|
||||
dottedname = dottedname.substr(pos + strlen("__DOT__"));
|
||||
if (nodep->name() != "") {
|
||||
if (m_namedScope == "") {
|
||||
m_namedScope = ident;
|
||||
} else {
|
||||
m_namedScope = m_namedScope + "__DOT__" + ident;
|
||||
}
|
||||
}
|
||||
if (m_unnamedScope == "") {
|
||||
m_unnamedScope = ident;
|
||||
} else {
|
||||
m_unnamedScope = m_unnamedScope + "__DOT__" + ident;
|
||||
}
|
||||
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
|
||||
m_unnamedScope = dot(m_unnamedScope, ident);
|
||||
// Create CellInline for dotted var resolution
|
||||
if (!m_ftaskp) {
|
||||
AstCellInline* inlinep = new AstCellInline(
|
||||
@@ -138,31 +133,29 @@ private:
|
||||
// Remap var names and replace lower Begins
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
|
||||
}
|
||||
m_namedScope = oldScope;
|
||||
m_unnamedScope = oldUnnamed;
|
||||
|
||||
// Cleanup
|
||||
AstNode* addsp = nullptr;
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
if (addsp) {
|
||||
addsp = addsp->addNextNull(stmtsp);
|
||||
} else {
|
||||
addsp = stmtsp;
|
||||
// Cleanup
|
||||
AstNode* addsp = nullptr;
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
if (addsp) {
|
||||
addsp = addsp->addNextNull(stmtsp);
|
||||
} else {
|
||||
addsp = stmtsp;
|
||||
}
|
||||
}
|
||||
if (addsp) {
|
||||
nodep->replaceWith(addsp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
if (addsp) {
|
||||
nodep->replaceWith(addsp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
nodep->name(dot(m_unnamedScope, nodep->name()));
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
@@ -176,7 +169,7 @@ private:
|
||||
virtual void visit(AstTypedef* nodep) override {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
nodep->name(dot(m_unnamedScope, nodep->name()));
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
@@ -193,7 +186,7 @@ private:
|
||||
if (m_namedScope != "") {
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Rename it
|
||||
nodep->name(m_namedScope + "__DOT__" + nodep->name());
|
||||
nodep->name(dot(m_namedScope, nodep->name()));
|
||||
UINFO(8, " rename to " << nodep->name() << endl);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
@@ -203,7 +196,7 @@ private:
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -249,12 +242,12 @@ public:
|
||||
: m_statep{statep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~BeginVisitor() override {}
|
||||
virtual ~BeginVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BeginRelinkVisitor : public AstNVisitor {
|
||||
class BeginRelinkVisitor final : public AstNVisitor {
|
||||
// Replace tasks with new pointer
|
||||
private:
|
||||
// NODE STATE
|
||||
@@ -290,7 +283,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
|
||||
virtual ~BeginRelinkVisitor() override {}
|
||||
virtual ~BeginRelinkVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Begin {
|
||||
class V3Begin final {
|
||||
public:
|
||||
static void debeginAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@
|
||||
//######################################################################
|
||||
// Branch state, as a visitor of each AstNode
|
||||
|
||||
class BranchVisitor : public AstNVisitor {
|
||||
class BranchVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
iterateChildren(nodep);
|
||||
calc_tasks();
|
||||
}
|
||||
virtual ~BranchVisitor() override {}
|
||||
virtual ~BranchVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Branch {
|
||||
class V3Branch final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static void branchAll(AstNetlist* nodep);
|
||||
|
||||
+26
-8
@@ -36,7 +36,7 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BrokenTable : public AstNVisitor {
|
||||
class BrokenTable VL_NOT_FINAL : public AstNVisitor {
|
||||
// Table of brokenExists node pointers
|
||||
private:
|
||||
// MEMBERS
|
||||
@@ -190,8 +190,8 @@ public:
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
BrokenTable() {}
|
||||
virtual ~BrokenTable() override {}
|
||||
BrokenTable() = default;
|
||||
virtual ~BrokenTable() override = default;
|
||||
};
|
||||
|
||||
BrokenTable::NodeMap BrokenTable::s_nodes;
|
||||
@@ -211,7 +211,7 @@ bool AstNode::brokeExistsBelow() const {
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BrokenMarkVisitor : public AstNVisitor {
|
||||
class BrokenMarkVisitor final : public AstNVisitor {
|
||||
// Mark every node in the tree
|
||||
private:
|
||||
// NODE STATE
|
||||
@@ -231,13 +231,15 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~BrokenMarkVisitor() override {}
|
||||
virtual ~BrokenMarkVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Broken state, as a visitor of each AstNode
|
||||
|
||||
class BrokenCheckVisitor : public AstNVisitor {
|
||||
class BrokenCheckVisitor final : public AstNVisitor {
|
||||
bool m_inScope = false; // Under AstScope
|
||||
|
||||
private:
|
||||
static void checkWidthMin(const AstNode* nodep) {
|
||||
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|
||||
@@ -275,9 +277,25 @@ private:
|
||||
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().isWriteOrRW()),
|
||||
nodep, "Assignment LHS is not an lvalue");
|
||||
}
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
VL_RESTORER(m_inScope);
|
||||
{
|
||||
m_inScope = true;
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
processAndIterate(nodep);
|
||||
// m_inScope because some Vars have initial variable references without scopes
|
||||
// This might false fire with some debug flags, as not certain we don't have temporary
|
||||
// clear varScopep's during some an infrequent dump just before we re-LinkDot.
|
||||
UASSERT_OBJ(
|
||||
!(v3Global.assertScoped() && m_inScope && nodep->varp() && !nodep->varScopep()), nodep,
|
||||
"VarRef missing VarScope pointer");
|
||||
}
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
// Process not just iterate
|
||||
processAndIterate(nodep);
|
||||
@@ -286,7 +304,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~BrokenCheckVisitor() override {}
|
||||
virtual ~BrokenCheckVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Broken {
|
||||
class V3Broken final {
|
||||
public:
|
||||
static void brokenAll(AstNetlist* nodep);
|
||||
static void addNewed(AstNode* nodep);
|
||||
|
||||
+8
-9
@@ -34,7 +34,7 @@
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
class V3CCtorsVisitor {
|
||||
class V3CCtorsVisitor final {
|
||||
private:
|
||||
string m_basename;
|
||||
string m_argsp;
|
||||
@@ -42,8 +42,8 @@ private:
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_tlFuncp; // Top level function being built
|
||||
AstCFunc* m_funcp; // Current function
|
||||
int m_numStmts; // Number of statements output
|
||||
int m_funcNum; // Function number being built
|
||||
int m_numStmts = 0; // Number of statements output
|
||||
int m_funcNum = 0; // Function number being built
|
||||
|
||||
public:
|
||||
void add(AstNode* nodep) {
|
||||
@@ -76,8 +76,6 @@ public:
|
||||
m_argsp = argsp;
|
||||
m_callargsp = callargsp;
|
||||
m_modp = nodep;
|
||||
m_numStmts = 0;
|
||||
m_funcNum = 0;
|
||||
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void");
|
||||
m_tlFuncp->declPrivate(true);
|
||||
m_tlFuncp->isStatic(false);
|
||||
@@ -87,7 +85,7 @@ public:
|
||||
m_funcp = m_tlFuncp;
|
||||
m_modp->addStmtp(m_tlFuncp);
|
||||
}
|
||||
~V3CCtorsVisitor() {}
|
||||
~V3CCtorsVisitor() = default;
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(V3CCtorsVisitor);
|
||||
@@ -111,7 +109,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 +149,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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CCtors {
|
||||
class V3CCtors final {
|
||||
public:
|
||||
static void cctorsAll();
|
||||
|
||||
|
||||
+28
-19
@@ -36,12 +36,12 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CUseState {
|
||||
class CUseState final {
|
||||
private:
|
||||
// MEMBERS
|
||||
AstNodeModule* m_modInsertp; // Current module to insert AstCUse under
|
||||
typedef std::pair<VUseType, string> UseString;
|
||||
std::map<UseString, AstCUse*> m_didUse; // What we already used
|
||||
std::map<const UseString, AstCUse*> m_didUse; // What we already used
|
||||
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -68,14 +68,14 @@ public:
|
||||
// CONSTRUCTORS
|
||||
explicit CUseState(AstNodeModule* nodep)
|
||||
: m_modInsertp{nodep} {}
|
||||
virtual ~CUseState() {}
|
||||
virtual ~CUseState() = default;
|
||||
VL_UNCOPYABLE(CUseState);
|
||||
};
|
||||
|
||||
// Visit within a module all nodes and data types they reference, finding
|
||||
// any classes so we can make sure they are defined when Verilated code
|
||||
// compiles
|
||||
class CUseDTypeVisitor : public AstNVisitor {
|
||||
class CUseDTypeVisitor final : public AstNVisitor {
|
||||
// MEMBERS
|
||||
CUseState& m_stater; // State for inserter
|
||||
bool m_impOnly = false; // In details needed only for implementation
|
||||
@@ -84,7 +84,7 @@ class CUseDTypeVisitor : public AstNVisitor {
|
||||
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());
|
||||
m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->classOrPackagep()->name());
|
||||
// Need to include extends() when we implement, but no need for pointers to know
|
||||
VL_RESTORER(m_impOnly);
|
||||
{
|
||||
@@ -109,11 +109,11 @@ public:
|
||||
: m_stater(stater) { // Need () or GCC 4.8 false warning
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CUseDTypeVisitor() override {}
|
||||
virtual ~CUseDTypeVisitor() override = default;
|
||||
VL_UNCOPYABLE(CUseDTypeVisitor);
|
||||
};
|
||||
|
||||
class CUseVisitor : public AstNVisitor {
|
||||
class CUseVisitor final : public AstNVisitor {
|
||||
// MEMBERS
|
||||
CUseState m_state; // Inserter state
|
||||
|
||||
@@ -148,7 +148,7 @@ class CUseVisitor : public AstNVisitor {
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstNode* exprp = new AstCMath(nodep->fileline(),
|
||||
"std::string(\"`{\") + to_string_middle() + \"}\"", 0);
|
||||
R"(std::string("'{") + to_string_middle() + "}")", 0);
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp));
|
||||
nodep->addStmtp(funcp);
|
||||
@@ -162,16 +162,25 @@ class CUseVisitor : public AstNVisitor {
|
||||
funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n"));
|
||||
std::string comma;
|
||||
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
|
||||
if (VN_IS(itemp, Var)) {
|
||||
string stmt = "out += \"";
|
||||
stmt += comma;
|
||||
comma = ", ";
|
||||
stmt += itemp->origNameProtect();
|
||||
stmt += ":\" + VL_TO_STRING(";
|
||||
stmt += itemp->nameProtect();
|
||||
stmt += ");\n";
|
||||
nodep->user1(true); // So what we extend dumps this
|
||||
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
if (auto* varp = VN_CAST(itemp, Var)) {
|
||||
if (!varp->isParam()) {
|
||||
string stmt = "out += \"";
|
||||
stmt += comma;
|
||||
comma = ", ";
|
||||
stmt += itemp->origNameProtect();
|
||||
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
|
||||
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {
|
||||
@@ -210,7 +219,7 @@ public:
|
||||
: m_state{nodep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CUseVisitor() override {}
|
||||
virtual ~CUseVisitor() override = default;
|
||||
VL_UNCOPYABLE(CUseVisitor);
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CUse {
|
||||
class V3CUse final {
|
||||
public:
|
||||
static void cUseAll();
|
||||
};
|
||||
|
||||
+10
-11
@@ -50,7 +50,7 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CaseLintVisitor : public AstNVisitor {
|
||||
class CaseLintVisitor final : public AstNVisitor {
|
||||
private:
|
||||
AstNodeCase* m_caseExprp
|
||||
= nullptr; // Under a CASE value node, if so the relevant case statement
|
||||
@@ -111,13 +111,13 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
|
||||
virtual ~CaseLintVisitor() override {}
|
||||
virtual ~CaseLintVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Case state, as a visitor of each AstNode
|
||||
|
||||
class CaseVisitor : public AstNVisitor {
|
||||
class CaseVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared each Case
|
||||
@@ -133,7 +133,7 @@ private:
|
||||
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];
|
||||
std::array<AstNode*, 1 << CASE_OVERLAP_WIDTH> m_valueItem;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -318,7 +318,7 @@ private:
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->condsp()) {
|
||||
// Default clause. Just make true, we'll optimize it away later
|
||||
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
|
||||
itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue()));
|
||||
hadDefault = true;
|
||||
} else {
|
||||
// Expressioned clause
|
||||
@@ -336,7 +336,7 @@ private:
|
||||
VL_DANGLING(iconstp);
|
||||
// For simplicity, make expression that is not equal, and let later
|
||||
// optimizations remove it
|
||||
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
|
||||
condp = new AstConst(itemp->fileline(), AstConst::BitFalse());
|
||||
} else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) {
|
||||
// Similar logic in V3Width::visit(AstInside)
|
||||
condp = irangep->newAndFromInside(cexprp, irangep->lhsp()->unlinkFrBack(),
|
||||
@@ -375,9 +375,8 @@ 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()), nullptr));
|
||||
nodep->addItemsp(new AstCaseItem(
|
||||
nodep->fileline(), new AstConst(nodep->fileline(), AstConst::BitTrue()), nullptr));
|
||||
}
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: ");
|
||||
// Now build the IF statement tree
|
||||
@@ -419,7 +418,7 @@ private:
|
||||
VL_DANGLING(ifexprp);
|
||||
if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition
|
||||
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::BitTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
|
||||
if (itemnextp) {
|
||||
@@ -486,7 +485,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseVisitor(AstNetlist* nodep) {
|
||||
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr;
|
||||
for (auto& itr : m_valueItem) itr = nullptr;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CaseVisitor() override {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Case {
|
||||
class V3Case final {
|
||||
public:
|
||||
static void caseAll(AstNetlist* nodep);
|
||||
static void caseLint(AstNodeCase* nodep);
|
||||
|
||||
+6
-6
@@ -49,7 +49,7 @@
|
||||
//######################################################################
|
||||
// Cast state, as a visitor of each AstNode
|
||||
|
||||
class CastVisitor : public AstNVisitor {
|
||||
class CastVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
ensureLower32Cast(castp);
|
||||
nodep->user1(1); // Now must be of known size
|
||||
}
|
||||
int castSize(AstNode* nodep) {
|
||||
static int castSize(AstNode* nodep) {
|
||||
if (nodep->isQuad()) {
|
||||
return VL_QUADSIZE;
|
||||
} else if (nodep->width() <= 8) {
|
||||
@@ -154,9 +154,9 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) 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())) {
|
||||
if (nodep->access().isReadOnly() && !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));
|
||||
@@ -193,7 +193,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CastVisitor() override {}
|
||||
virtual ~CastVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Cast {
|
||||
class V3Cast final {
|
||||
public:
|
||||
static void castAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+25
-26
@@ -41,7 +41,7 @@ constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async lo
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcBaseVisitor : public AstNVisitor {
|
||||
class CdcBaseVisitor VL_NOT_FINAL : public AstNVisitor {
|
||||
public:
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
};
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
//######################################################################
|
||||
// Graph support classes
|
||||
|
||||
class CdcEitherVertex : public V3GraphVertex {
|
||||
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstSenTree* m_srcDomainp = nullptr;
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
, m_srcDomainSet{false}
|
||||
, m_dstDomainSet{false}
|
||||
, m_asyncPath{false} {}
|
||||
virtual ~CdcEitherVertex() override {}
|
||||
virtual ~CdcEitherVertex() override = default;
|
||||
// ACCESSORS
|
||||
virtual FileLine* fileline() const override { return nodep()->fileline(); }
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
void asyncPath(bool flag) { m_asyncPath = flag; }
|
||||
};
|
||||
|
||||
class CdcVarVertex : public CdcEitherVertex {
|
||||
class CdcVarVertex final : public CdcEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
int m_cntAsyncRst = 0;
|
||||
bool m_fromFlop = false;
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: CdcEitherVertex{graphp, scopep, varScp}
|
||||
, m_varScp{varScp} {}
|
||||
virtual ~CdcVarVertex() override {}
|
||||
virtual ~CdcVarVertex() override = default;
|
||||
// ACCESSORS
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
void fromFlop(bool flag) { m_fromFlop = flag; }
|
||||
};
|
||||
|
||||
class CdcLogicVertex : public CdcEitherVertex {
|
||||
class CdcLogicVertex final : public CdcEitherVertex {
|
||||
bool m_hazard : 1;
|
||||
bool m_isFlop : 1;
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
srcDomainp(sensenodep);
|
||||
dstDomainp(sensenodep);
|
||||
}
|
||||
virtual ~CdcLogicVertex() override {}
|
||||
virtual ~CdcLogicVertex() override = default;
|
||||
// ACCESSORS
|
||||
virtual string name() const override {
|
||||
return (cvtToHex(nodep()) + "@" + scopep()->prettyName());
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcDumpVisitor : public CdcBaseVisitor {
|
||||
class CdcDumpVisitor final : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -150,7 +150,7 @@ private:
|
||||
} else {
|
||||
*m_ofp << " ";
|
||||
}
|
||||
*m_ofp << nodep->prettyTypeName() << " " << endl;
|
||||
*m_ofp << nodep->prettyTypeName() << "\n";
|
||||
string lastPrefix = m_prefix;
|
||||
m_prefix = lastPrefix + "1:";
|
||||
iterateAndNextNull(nodep->op1p());
|
||||
@@ -170,12 +170,12 @@ public:
|
||||
, m_prefix{prefix} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CdcDumpVisitor() override {}
|
||||
virtual ~CdcDumpVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcWidthVisitor : public CdcBaseVisitor {
|
||||
class CdcWidthVisitor final : public CdcBaseVisitor {
|
||||
private:
|
||||
int m_maxLineno = 0;
|
||||
size_t m_maxFilenameLen = 0;
|
||||
@@ -194,7 +194,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~CdcWidthVisitor() override {}
|
||||
virtual ~CdcWidthVisitor() override = default;
|
||||
// ACCESSORS
|
||||
int maxWidth() const {
|
||||
size_t width = 1;
|
||||
@@ -209,7 +209,7 @@ public:
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
class CdcVisitor : public CdcBaseVisitor {
|
||||
class CdcVisitor final : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -292,7 +292,7 @@ private:
|
||||
told_file = true;
|
||||
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
|
||||
}
|
||||
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
|
||||
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << '\n';
|
||||
}
|
||||
|
||||
void setNodeHazard(AstNode* nodep) {
|
||||
@@ -311,13 +311,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
string spaces(int level) {
|
||||
static string spaces(int level) {
|
||||
string out;
|
||||
while (level--) out += " ";
|
||||
return out;
|
||||
} // LCOV_EXCL_LINE
|
||||
|
||||
string pad(unsigned column, const string& in) {
|
||||
static string pad(unsigned column, const string& in) {
|
||||
string out = in;
|
||||
while (out.length() < column) out += ' ';
|
||||
return out;
|
||||
@@ -463,7 +462,7 @@ private:
|
||||
string front
|
||||
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
|
||||
if (VN_IS(nodep, VarScope)) {
|
||||
*m_ofp << front << "Variable: " << nodep->prettyName() << endl;
|
||||
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
|
||||
} else {
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(),
|
||||
vertexp->srcDomainp(), true);
|
||||
@@ -510,7 +509,7 @@ private:
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
|
||||
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;
|
||||
*ofp << "Edge Report for " << v3Global.opt.prefix() << '\n';
|
||||
|
||||
std::deque<string> report; // Sort output by name
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
@@ -537,7 +536,7 @@ private:
|
||||
V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
|
||||
}
|
||||
os << std::setw(0);
|
||||
os << endl;
|
||||
os << '\n';
|
||||
report.push_back(os.str());
|
||||
}
|
||||
}
|
||||
@@ -588,15 +587,15 @@ private:
|
||||
// Convert list of senses into one sense node
|
||||
AstSenTree* senoutp = nullptr;
|
||||
bool senedited = false;
|
||||
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
|
||||
for (const auto& itr : senouts) {
|
||||
if (!senoutp) {
|
||||
senoutp = *it;
|
||||
senoutp = itr;
|
||||
} else {
|
||||
if (!senedited) {
|
||||
senedited = true;
|
||||
senoutp = senoutp->cloneTree(true);
|
||||
}
|
||||
senoutp->addSensesp((*it)->sensesp()->cloneTree(true));
|
||||
senoutp->addSensesp(itr->sensesp()->cloneTree(true));
|
||||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
@@ -661,7 +660,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().isWriteOrRW()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
if (m_inDly) {
|
||||
varvertexp->fromFlop(true);
|
||||
@@ -733,7 +732,7 @@ public:
|
||||
m_ofp = V3File::new_ofstream(filename);
|
||||
if (m_ofp->fail()) v3fatal("Can't write " << filename);
|
||||
m_ofFilename = filename;
|
||||
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << endl;
|
||||
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << '\n';
|
||||
*m_ofp
|
||||
<< "Each dump below traces logic from inputs/source flops to destination flop(s).\n";
|
||||
*m_ofp << "First source logic is listed, then a variable that logic generates,\n";
|
||||
@@ -746,7 +745,7 @@ public:
|
||||
if (false) {
|
||||
*m_ofp << "\nDBG-test-dumper\n";
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true);
|
||||
*m_ofp << endl;
|
||||
*m_ofp << '\n';
|
||||
}
|
||||
}
|
||||
virtual ~CdcVisitor() override {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Cdc {
|
||||
class V3Cdc final {
|
||||
public:
|
||||
static void cdcAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+12
-13
@@ -38,7 +38,7 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class ChangedState {
|
||||
class ChangedState final {
|
||||
public:
|
||||
// STATE
|
||||
AstNodeModule* m_topModp = nullptr; // Top module
|
||||
@@ -48,8 +48,8 @@ public:
|
||||
int m_numStmts = 0; // Number of statements added to m_chgFuncp
|
||||
int m_funcNum = 0; // Number of change functions emitted
|
||||
|
||||
ChangedState() {}
|
||||
~ChangedState() {}
|
||||
ChangedState() = default;
|
||||
~ChangedState() = default;
|
||||
|
||||
void maybeCreateChgFuncp() {
|
||||
// Don't create an extra function call if splitting is disabled
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
//######################################################################
|
||||
// Utility visitor to find elements to be compared
|
||||
|
||||
class ChangedInsertVisitor : public AstNVisitor {
|
||||
class ChangedInsertVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
@@ -117,10 +117,9 @@ private:
|
||||
"Unsupported: Can't detect more than "
|
||||
<< cvtToStr(DETECTARRAY_MAX_INDEXES)
|
||||
<< " array indexes (probably with UNOPTFLAT warning suppressed): "
|
||||
<< m_vscp->prettyName() << endl
|
||||
<< m_vscp->prettyName() << '\n'
|
||||
<< m_vscp->warnMore()
|
||||
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased"
|
||||
<< endl);
|
||||
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased");
|
||||
return;
|
||||
}
|
||||
m_statep->maybeCreateChgFuncp();
|
||||
@@ -199,23 +198,23 @@ 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() override {}
|
||||
virtual ~ChangedInsertVisitor() override = default;
|
||||
VL_UNCOPYABLE(ChangedInsertVisitor);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Changed state, as a visitor of each AstNode
|
||||
|
||||
class ChangedVisitor : public AstNVisitor {
|
||||
class ChangedVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -280,7 +279,7 @@ public:
|
||||
: m_statep{statep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ChangedVisitor() override {}
|
||||
virtual ~ChangedVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Changed {
|
||||
class V3Changed final {
|
||||
public:
|
||||
static void changedAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+37
-10
@@ -29,12 +29,14 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class ClassVisitor : public AstNVisitor {
|
||||
class ClassVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// MEMBERS
|
||||
AstUser1InUse m_inuser1;
|
||||
string m_prefix; // String prefix to add to name based on hier
|
||||
AstScope* m_classScopep = nullptr; // Package moving scopes into
|
||||
AstScope* m_packageScopep = nullptr; // Class package scope
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current task
|
||||
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
|
||||
MoveVector m_moves;
|
||||
|
||||
@@ -54,7 +56,7 @@ private:
|
||||
// Note origName is the same as the class origName so errors look correct
|
||||
AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName());
|
||||
packagep->name(nodep->name() + "__Vclpkg");
|
||||
nodep->packagep(packagep);
|
||||
nodep->classOrPackagep(packagep);
|
||||
packagep->classp(nodep);
|
||||
v3Global.rootp()->addModulep(packagep);
|
||||
// Add package to hierarchy
|
||||
@@ -76,14 +78,17 @@ private:
|
||||
packagep->addStmtp(scopep);
|
||||
// Iterate
|
||||
VL_RESTORER(m_prefix);
|
||||
VL_RESTORER(m_classScopep);
|
||||
VL_RESTORER(m_packageScopep);
|
||||
{
|
||||
m_classScopep = classScopep;
|
||||
m_packageScopep = scopep;
|
||||
m_prefix = nodep->name() + "__02e"; // .
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_classScopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstPackage* nodep) override {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
|
||||
VL_RESTORER(m_prefix);
|
||||
{
|
||||
m_prefix = nodep->name() + "__03a__03a"; // ::
|
||||
@@ -94,11 +99,28 @@ private:
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Don't move now, or wouldn't keep interating the class
|
||||
// TODO move class statics only
|
||||
// if (m_classScopep) {
|
||||
// m_moves.push_back(make_pair(nodep, m_classScopep));
|
||||
//}
|
||||
// TODO move class statics too
|
||||
if (m_packageScopep && m_ftaskp && m_ftaskp->lifetime().isStatic()) {
|
||||
m_moves.push_back(make_pair(nodep, m_packageScopep));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->varp()->user1p(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_ftaskp);
|
||||
{
|
||||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
if (m_packageScopep && nodep->lifetime().isStatic()) {
|
||||
m_moves.push_back(make_pair(nodep, m_packageScopep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Don't move now, or wouldn't keep interating the class
|
||||
@@ -116,8 +138,13 @@ public:
|
||||
// CONSTRUCTORS
|
||||
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());
|
||||
for (auto moved : m_moves) {
|
||||
if (VN_IS(moved.first, NodeFTask)) {
|
||||
moved.second->addActivep(moved.first->unlinkFrBack());
|
||||
} else if (VN_IS(moved.first, Var)) {
|
||||
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
|
||||
moved.second->addVarp(scopep->unlinkFrBack());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Class {
|
||||
class V3Class final {
|
||||
public:
|
||||
static void classAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+7
-2
@@ -35,7 +35,7 @@
|
||||
//######################################################################
|
||||
// Clean state, as a visitor of each AstNode
|
||||
|
||||
class CleanVisitor : public AstNVisitor {
|
||||
class CleanVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -285,6 +285,11 @@ private:
|
||||
ensureCleanAndNext(nodep->pinsp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstWith* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->exprp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstIntfRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
@@ -300,7 +305,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CleanVisitor() override {}
|
||||
virtual ~CleanVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Clean {
|
||||
class V3Clean final {
|
||||
public:
|
||||
static void cleanAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+28
-25
@@ -40,7 +40,7 @@
|
||||
//######################################################################
|
||||
// Clock state, as a visitor of each AstNode
|
||||
|
||||
class ClockVisitor : public AstNVisitor {
|
||||
class ClockVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared each Module:
|
||||
@@ -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);
|
||||
@@ -112,25 +112,28 @@ private:
|
||||
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");
|
||||
}
|
||||
@@ -290,7 +293,7 @@ private:
|
||||
}
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
virtual void visit(AstNodeProcedure* nodep) override {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
@@ -308,6 +311,15 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPostponed* nodep) override {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
// nodep->dumpTree(cout, "ct:");
|
||||
// COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
@@ -325,15 +337,6 @@ private:
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) override {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
nodep->replaceWith(cmtp);
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Link to global function
|
||||
@@ -451,7 +454,7 @@ public:
|
||||
// easily without iterating through the tree.
|
||||
nodep->evalp(m_evalFuncp);
|
||||
}
|
||||
virtual ~ClockVisitor() override {}
|
||||
virtual ~ClockVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Clock {
|
||||
class V3Clock final {
|
||||
public:
|
||||
static void clockAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+16
-16
@@ -51,19 +51,19 @@ constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth m
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CombBaseVisitor : public AstNVisitor {
|
||||
class CombBaseVisitor VL_NOT_FINAL : public AstNVisitor {
|
||||
protected:
|
||||
// STATE
|
||||
|
||||
// METHODS
|
||||
virtual ~CombBaseVisitor() override {}
|
||||
virtual ~CombBaseVisitor() override = default;
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Combine replacement function
|
||||
|
||||
class CombCallVisitor : CombBaseVisitor {
|
||||
class CombCallVisitor final : CombBaseVisitor {
|
||||
// Find all CCALLS of each CFUNC, so that we can later rename them
|
||||
private:
|
||||
// NODE STATE
|
||||
@@ -131,15 +131,15 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CombCallVisitor() {}
|
||||
virtual ~CombCallVisitor() override {}
|
||||
CombCallVisitor() = default;
|
||||
virtual ~CombCallVisitor() override = default;
|
||||
void main(AstNetlist* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Combine marking function
|
||||
|
||||
class CombMarkVisitor : CombBaseVisitor {
|
||||
class CombMarkVisitor final : CombBaseVisitor {
|
||||
// Mark all nodes under specified one.
|
||||
private:
|
||||
// OUTPUT:
|
||||
@@ -153,13 +153,13 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~CombMarkVisitor() override {}
|
||||
virtual ~CombMarkVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Combine state, as a visitor of each AstNode
|
||||
|
||||
class CombineVisitor : CombBaseVisitor {
|
||||
class CombineVisitor final : CombBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -177,7 +177,7 @@ private:
|
||||
VDouble0 m_statCombs; // Statistic tracking
|
||||
CombineState m_state = STATE_IDLE; // Major state
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current function
|
||||
AstCFunc* m_cfuncp = nullptr; // Current function
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
int m_modNFuncs = 0; // Number of functions made
|
||||
#ifdef VL_COMBINE_STATEMENTS
|
||||
@@ -203,8 +203,8 @@ private:
|
||||
}
|
||||
#endif
|
||||
void walkEmptyFuncs() {
|
||||
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
|
||||
AstNode* node1p = it->second;
|
||||
for (const auto& itr : m_hashed) {
|
||||
AstNode* node1p = itr.second;
|
||||
AstCFunc* oldfuncp = VN_CAST(node1p, CFunc);
|
||||
if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) {
|
||||
UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " "
|
||||
@@ -330,7 +330,7 @@ private:
|
||||
AstNode* last2p) { // Final node in linked list, maybe null if all statements
|
||||
// to be grabbed
|
||||
// Make new function
|
||||
string oldname = m_funcp->name();
|
||||
string oldname = m_cfuncp->name();
|
||||
string::size_type pos;
|
||||
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
|
||||
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
|
||||
@@ -423,7 +423,8 @@ private:
|
||||
m_modp = nullptr;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
m_funcp = nodep;
|
||||
VL_RESTORER(m_cfuncp);
|
||||
m_cfuncp = nodep;
|
||||
if (!nodep->dontCombine()) {
|
||||
if (m_state == STATE_HASH) {
|
||||
hashStatement(nodep); // Hash the entire function - it might be identical
|
||||
@@ -434,18 +435,17 @@ private:
|
||||
}
|
||||
#endif
|
||||
}
|
||||
m_funcp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) override {
|
||||
if (!nodep->isStatement()) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
if (m_state == STATE_HASH && m_funcp) {
|
||||
if (m_state == STATE_HASH && m_cfuncp) {
|
||||
hashStatement(nodep);
|
||||
}
|
||||
#ifdef VL_COMBINE_STATEMENTS
|
||||
else if (m_state == STATE_DUP && m_funcp) {
|
||||
else if (m_state == STATE_DUP && m_cfuncp) {
|
||||
walkDupCodeStart(nodep);
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Combine {
|
||||
class V3Combine final {
|
||||
public:
|
||||
static void combineAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+26
-33
@@ -33,13 +33,13 @@
|
||||
// cache of resolved entities. Entities stored in this container need an update
|
||||
// function that takes a reference of this type to join multiple entities into one.
|
||||
template <typename T> class V3ConfigWildcardResolver {
|
||||
typedef std::map<string, T> Map;
|
||||
typedef std::map<const string, T> Map;
|
||||
|
||||
Map m_mapWildcard; // Wildcard strings to entities
|
||||
Map m_mapResolved; // Resolved strings to converged entities
|
||||
public:
|
||||
V3ConfigWildcardResolver() {}
|
||||
~V3ConfigWildcardResolver() {}
|
||||
V3ConfigWildcardResolver() = default;
|
||||
~V3ConfigWildcardResolver() = default;
|
||||
|
||||
/// Update into maps from other
|
||||
void update(const V3ConfigWildcardResolver& other) {
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
};
|
||||
|
||||
// Only public_flat_rw has the sensitity tree
|
||||
class V3ConfigVarAttr {
|
||||
class V3ConfigVarAttr final {
|
||||
public:
|
||||
AstAttrType m_type; // Type of attribute
|
||||
AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
};
|
||||
|
||||
// Overload vector with the required update function and to apply all entries
|
||||
class V3ConfigVar : public std::vector<V3ConfigVarAttr> {
|
||||
class V3ConfigVar final : public std::vector<V3ConfigVarAttr> {
|
||||
public:
|
||||
// Update from other by copying all attributes
|
||||
void update(const V3ConfigVar& node) {
|
||||
@@ -116,14 +116,14 @@ typedef V3ConfigWildcardResolver<V3ConfigVar> V3ConfigVarResolver;
|
||||
//######################################################################
|
||||
// Function or task: Have variables and properties
|
||||
|
||||
class V3ConfigFTask {
|
||||
class V3ConfigFTask final {
|
||||
V3ConfigVarResolver m_vars; // Variables in 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() {}
|
||||
V3ConfigFTask() = default;
|
||||
void update(const V3ConfigFTask& f) {
|
||||
// Don't overwrite true with false
|
||||
if (f.m_isolate) m_isolate = true;
|
||||
@@ -153,7 +153,7 @@ typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
|
||||
//######################################################################
|
||||
// Modules have tasks, variables, named blocks and properties
|
||||
|
||||
class V3ConfigModule {
|
||||
class V3ConfigModule final {
|
||||
typedef std::unordered_set<string> StringSet;
|
||||
typedef std::set<AstPragmaType> PragmaSet;
|
||||
|
||||
@@ -165,7 +165,7 @@ class V3ConfigModule {
|
||||
bool m_inlineValue = false; // The inline value (on/off)
|
||||
|
||||
public:
|
||||
V3ConfigModule() {}
|
||||
V3ConfigModule() = default;
|
||||
|
||||
void update(const V3ConfigModule& m) {
|
||||
m_tasks.update(m.m_tasks);
|
||||
@@ -224,7 +224,7 @@ typedef V3ConfigWildcardResolver<V3ConfigModule> V3ConfigModuleResolver;
|
||||
// - Line attributes: Attributes attached to lines
|
||||
|
||||
// lint/coverage/tracing on/off
|
||||
class V3ConfigIgnoresLine {
|
||||
class V3ConfigIgnoresLine final {
|
||||
public:
|
||||
int m_lineno; // Line number to make change at
|
||||
V3ErrorCode m_code; // Error code
|
||||
@@ -233,8 +233,8 @@ public:
|
||||
: m_lineno{lineno}
|
||||
, m_code{code}
|
||||
, m_on{on} {}
|
||||
~V3ConfigIgnoresLine() {}
|
||||
inline bool operator<(const V3ConfigIgnoresLine& rh) const {
|
||||
~V3ConfigIgnoresLine() = default;
|
||||
bool operator<(const V3ConfigIgnoresLine& rh) const {
|
||||
if (m_lineno < rh.m_lineno) return true;
|
||||
if (m_lineno > rh.m_lineno) return false;
|
||||
if (m_code < rh.m_code) return true;
|
||||
@@ -253,7 +253,7 @@ std::ostream& operator<<(std::ostream& os, const V3ConfigIgnoresLine& rhs) {
|
||||
typedef std::bitset<AstPragmaType::ENUM_SIZE> V3ConfigLineAttribute;
|
||||
|
||||
// File entity
|
||||
class V3ConfigFile {
|
||||
class V3ConfigFile final {
|
||||
typedef std::map<int, V3ConfigLineAttribute> LineAttrMap; // Map line->bitset of attributes
|
||||
typedef std::multiset<V3ConfigIgnoresLine> IgnLines; // list of {line,code,on}
|
||||
typedef std::pair<V3ErrorCode, string> WaiverSetting; // Waive code if string matches
|
||||
@@ -282,15 +282,9 @@ public:
|
||||
}
|
||||
void update(const V3ConfigFile& file) {
|
||||
// Copy in all Attributes
|
||||
for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin();
|
||||
it != file.m_lineAttrs.end(); ++it) {
|
||||
m_lineAttrs[it->first] |= it->second;
|
||||
}
|
||||
for (const auto& itr : file.m_lineAttrs) { m_lineAttrs[itr.first] |= itr.second; }
|
||||
// Copy in all ignores
|
||||
for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end();
|
||||
++it) {
|
||||
m_ignLines.insert(*it);
|
||||
}
|
||||
for (const auto& ignLine : file.m_ignLines) m_ignLines.insert(ignLine);
|
||||
// Update the iterator after the list has changed
|
||||
m_lastIgnore.it = m_ignLines.begin();
|
||||
m_waivers.reserve(m_waivers.size() + file.m_waivers.size());
|
||||
@@ -338,9 +332,9 @@ public:
|
||||
}
|
||||
}
|
||||
bool waive(V3ErrorCode code, const string& match) {
|
||||
for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) {
|
||||
if (((it->first == code) || (it->first == V3ErrorCode::I_LINT))
|
||||
&& VString::wildmatch(match, it->second)) {
|
||||
for (const auto& itr : m_waivers) {
|
||||
if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT))
|
||||
&& VString::wildmatch(match, itr.second)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -353,16 +347,16 @@ typedef V3ConfigWildcardResolver<V3ConfigFile> V3ConfigFileResolver;
|
||||
//######################################################################
|
||||
// Resolve modules and files in the design
|
||||
|
||||
class V3ConfigResolver {
|
||||
class V3ConfigResolver final {
|
||||
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
|
||||
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
|
||||
|
||||
static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow)
|
||||
V3ConfigResolver() {}
|
||||
~V3ConfigResolver() {}
|
||||
V3ConfigResolver() = default;
|
||||
~V3ConfigResolver() = default;
|
||||
|
||||
public:
|
||||
inline static V3ConfigResolver& s() { return s_singleton; }
|
||||
static V3ConfigResolver& s() { return s_singleton; }
|
||||
|
||||
V3ConfigModuleResolver& modules() { return m_modules; }
|
||||
V3ConfigFileResolver& files() { return m_files; }
|
||||
@@ -411,7 +405,7 @@ void V3Config::addInline(FileLine* fl, const string& module, const string& ftask
|
||||
V3ConfigResolver::s().modules().at(module).setInline(on);
|
||||
} else {
|
||||
if (!on) {
|
||||
fl->v3error("no_inline not supported for tasks" << endl);
|
||||
fl->v3error("no_inline not supported for tasks");
|
||||
} else {
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setNoInline(on);
|
||||
}
|
||||
@@ -422,15 +416,14 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
|
||||
const string& var, AstAttrType attr, AstSenTree* sensep) {
|
||||
// Semantics: sensep only if public_flat_rw
|
||||
if ((attr != AstAttrType::VAR_PUBLIC_FLAT_RW) && sensep) {
|
||||
sensep->v3error("sensitivity not expected for attribute" << endl);
|
||||
sensep->v3error("sensitivity not expected for attribute");
|
||||
return;
|
||||
}
|
||||
// Semantics: Most of the attributes operate on signals
|
||||
if (var.empty()) {
|
||||
if (attr == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||
if (ftask.empty()) {
|
||||
fl->v3error("isolate_assignments only applies to signals or functions/tasks"
|
||||
<< endl);
|
||||
fl->v3error("isolate_assignments only applies to signals or functions/tasks");
|
||||
} else {
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setIsolate(true);
|
||||
}
|
||||
@@ -443,7 +436,7 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
|
||||
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
|
||||
}
|
||||
} else {
|
||||
fl->v3error("missing -signal" << endl);
|
||||
fl->v3error("missing -signal");
|
||||
}
|
||||
} else {
|
||||
V3ConfigModule& mod = V3ConfigResolver::s().modules().at(module);
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3Config {
|
||||
class V3Config final {
|
||||
public:
|
||||
static void addCaseFull(const string& file, int lineno);
|
||||
static void addCaseParallel(const string& file, int lineno);
|
||||
|
||||
+43
-33
@@ -36,7 +36,7 @@
|
||||
//######################################################################
|
||||
// Utilities
|
||||
|
||||
class ConstVarMarkVisitor : public AstNVisitor {
|
||||
class ConstVarMarkVisitor final : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::user4p -> bool, Var marked, 0=not set yet
|
||||
private:
|
||||
@@ -52,10 +52,10 @@ public:
|
||||
AstNode::user4ClearTree(); // Check marked InUse before we're called
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ConstVarMarkVisitor() override {}
|
||||
virtual ~ConstVarMarkVisitor() override = default;
|
||||
};
|
||||
|
||||
class ConstVarFindVisitor : public AstNVisitor {
|
||||
class ConstVarFindVisitor final : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::user4p -> bool, input from ConstVarMarkVisitor
|
||||
// MEMBERS
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ConstVarFindVisitor(AstNode* nodep) { iterateAndNextNull(nodep); }
|
||||
virtual ~ConstVarFindVisitor() override {}
|
||||
virtual ~ConstVarFindVisitor() override = default;
|
||||
// METHODS
|
||||
bool found() const { return m_found; }
|
||||
};
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
//######################################################################
|
||||
// Const state, as a visitor of each AstNode
|
||||
|
||||
class ConstVisitor : public AstNVisitor {
|
||||
class ConstVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// ** only when m_warn/m_doExpensive is set. If state is needed other times,
|
||||
@@ -314,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().isReadOnly()
|
||||
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
|
||||
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
|
||||
}
|
||||
@@ -1132,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);
|
||||
@@ -1258,7 +1262,7 @@ private:
|
||||
AstNode* errorp = simvis.whyNotNodep();
|
||||
if (!errorp) errorp = nodep;
|
||||
nodep->v3error("Expecting expression to be constant, but can't determine constant for "
|
||||
<< nodep->prettyTypeName() << endl
|
||||
<< nodep->prettyTypeName() << '\n'
|
||||
<< errorp->warnOther() << "... Location of non-constant "
|
||||
<< errorp->prettyTypeName() << ": " << simvis.whyNotMessage());
|
||||
VL_DO_DANGLING(replaceZero(nodep), nodep);
|
||||
@@ -1293,17 +1297,21 @@ private:
|
||||
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;
|
||||
VL_RESTORER(m_wremove);
|
||||
{
|
||||
m_wremove = false;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
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 = nullptr;
|
||||
VL_RESTORER(m_wremove);
|
||||
VL_RESTORER(m_scopep);
|
||||
{
|
||||
m_wremove = false;
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
void swapSides(AstNodeBiCom* nodep) {
|
||||
@@ -1601,7 +1609,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().isReadOnly()
|
||||
&& ((!m_params // Can reduce constant wires into equations
|
||||
&& m_doNConst
|
||||
&& v3Global.opt.oConst()
|
||||
@@ -1722,7 +1730,7 @@ private:
|
||||
}
|
||||
|
||||
struct SenItemCmp {
|
||||
inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
|
||||
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
|
||||
if (lhsp->type() < rhsp->type()) return true;
|
||||
if (lhsp->type() > rhsp->type()) return false;
|
||||
// Looks visually better if we keep sorted by name
|
||||
@@ -1922,8 +1930,9 @@ private:
|
||||
nodep->replaceWith(ifp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (ifSameAssign(nodep)) {
|
||||
UINFO(4, "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"
|
||||
<< endl);
|
||||
UINFO(
|
||||
4,
|
||||
"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})\n");
|
||||
AstNodeAssign* ifp = VN_CAST(nodep->ifsp(), NodeAssign);
|
||||
AstNodeAssign* elsep = VN_CAST(nodep->elsesp(), NodeAssign);
|
||||
ifp->unlinkFrBack();
|
||||
@@ -1933,7 +1942,8 @@ private:
|
||||
ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep));
|
||||
nodep->replaceWith(ifp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
|
||||
} else if (false // Disabled, as vpm assertions are faster
|
||||
// without due to short-circuiting
|
||||
&& operandIfIf(nodep)) {
|
||||
UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl);
|
||||
AstNodeIf* lowerIfp = VN_CAST(nodep->ifsp(), NodeIf);
|
||||
@@ -2554,7 +2564,7 @@ public:
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
virtual ~ConstVisitor() override {}
|
||||
virtual ~ConstVisitor() override = default;
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
// Operate starting at a random place
|
||||
return iterateSubtreeReturnEdits(nodep);
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Const {
|
||||
class V3Const final {
|
||||
public:
|
||||
static AstNode* constifyParamsEdit(AstNode* nodep);
|
||||
static AstNode* constifyGenerateParamsEdit(AstNode* nodep);
|
||||
|
||||
+13
-12
@@ -37,7 +37,7 @@
|
||||
//######################################################################
|
||||
// Coverage state, as a visitor of each AstNode
|
||||
|
||||
class CoverageVisitor : public AstNVisitor {
|
||||
class CoverageVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::unordered_map<string, int> VarNameMap;
|
||||
@@ -52,7 +52,7 @@ private:
|
||||
: m_comment{comment}
|
||||
, m_varRefp{vp}
|
||||
, m_chgRefp{cp} {}
|
||||
~ToggleEnt() {}
|
||||
~ToggleEnt() = default;
|
||||
void cleanup() {
|
||||
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = nullptr);
|
||||
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = nullptr);
|
||||
@@ -64,7 +64,7 @@ private:
|
||||
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() {}
|
||||
CheckState() = default;
|
||||
bool lineCoverageOn(const AstNode* nodep) const {
|
||||
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
||||
&& v3Global.opt.coverageLine();
|
||||
@@ -130,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);
|
||||
}
|
||||
@@ -188,15 +188,15 @@ private:
|
||||
const LinenoSet& lines = m_handleLines[state.m_handle];
|
||||
int first = 0;
|
||||
int last = 0;
|
||||
for (LinenoSet::iterator it = lines.begin(); it != lines.end(); ++it) {
|
||||
for (int linen : lines) {
|
||||
if (!first) {
|
||||
first = last = *it;
|
||||
} else if (*it == last + 1) {
|
||||
first = last = linen;
|
||||
} else if (linen == last + 1) {
|
||||
++last;
|
||||
} else {
|
||||
if (!out.empty()) out += ",";
|
||||
out += linesFirstLast(first, last);
|
||||
first = last = *it;
|
||||
first = last = linen;
|
||||
}
|
||||
}
|
||||
if (first) {
|
||||
@@ -288,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();
|
||||
}
|
||||
@@ -533,7 +534,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }
|
||||
virtual ~CoverageVisitor() override {}
|
||||
virtual ~CoverageVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Coverage {
|
||||
class V3Coverage final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static void coverage(AstNetlist* rootp);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
//######################################################################
|
||||
// CoverageJoin state, as a visitor of each AstNode
|
||||
|
||||
class CoverageJoinVisitor : public AstNVisitor {
|
||||
class CoverageJoinVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// V3Hashed
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CoverageJoin {
|
||||
class V3CoverageJoin final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static void coverageJoin(AstNetlist* rootp);
|
||||
|
||||
+54
-55
@@ -30,9 +30,8 @@
|
||||
// Note on packagep: After the V3Scope/V3LinkDotScoped stage, package links
|
||||
// are no longer used, but their presence prevents us from removing empty
|
||||
// packages. As the links as no longer used after V3Scope, we remove them
|
||||
// here after scoping to allow more dead node
|
||||
// removal.
|
||||
// *************************************************************************
|
||||
// here after scoping to allow more dead node removal.
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
@@ -46,7 +45,7 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class DeadModVisitor : public AstNVisitor {
|
||||
class DeadModVisitor final : public AstNVisitor {
|
||||
// In a module that is dead, cleanup the in-use counts of the modules
|
||||
private:
|
||||
// NODE STATE
|
||||
@@ -63,13 +62,13 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); }
|
||||
virtual ~DeadModVisitor() override {}
|
||||
virtual ~DeadModVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Dead state, as a visitor of each AstNode
|
||||
|
||||
class DeadVisitor : public AstNVisitor {
|
||||
class DeadVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire Netlist:
|
||||
@@ -83,7 +82,7 @@ private:
|
||||
typedef std::multimap<AstVarScope*, AstNodeAssign*> AssignMap;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
// List of all encountered to avoid another loop through tree
|
||||
std::vector<AstVar*> m_varsp;
|
||||
std::vector<AstNode*> m_dtypesp;
|
||||
@@ -93,10 +92,10 @@ private:
|
||||
std::vector<AstClass*> m_classesp;
|
||||
|
||||
AssignMap m_assignMap; // List of all simple assignments for each variable
|
||||
bool m_elimUserVars; // Allow removal of user's vars
|
||||
bool m_elimDTypes; // Allow removal of DTypes
|
||||
bool m_elimCells; // Allow removal of Cells
|
||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||
const bool m_elimUserVars; // Allow removal of user's vars
|
||||
const bool m_elimDTypes; // Allow removal of DTypes
|
||||
const bool m_elimCells; // Allow removal of Cells
|
||||
bool m_sideEffect = false; // Side effects discovered in assign RHS
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -107,6 +106,9 @@ private:
|
||||
}
|
||||
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
||||
}
|
||||
void checkVarRef(AstNodeVarRef* nodep) {
|
||||
if (nodep->classOrPackagep() && m_elimCells) nodep->classOrPackagep(nullptr);
|
||||
}
|
||||
void checkDType(AstNodeDType* nodep) {
|
||||
if (!nodep->generic() // Don't remove generic types
|
||||
&& m_elimDTypes // dtypes stick around until post-widthing
|
||||
@@ -120,6 +122,7 @@ private:
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
if (m_modp) m_modp->user1Inc(); // e.g. Class under Package
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
@@ -128,7 +131,7 @@ private:
|
||||
checkAll(nodep);
|
||||
if (AstClass* classp = VN_CAST(nodep, Class)) {
|
||||
if (classp->extendsp()) classp->extendsp()->user1Inc();
|
||||
if (classp->packagep()) classp->packagep()->user1Inc();
|
||||
if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc();
|
||||
m_classesp.push_back(classp);
|
||||
// TODO we don't reclaim dead classes yet - graph implementation instead?
|
||||
classp->user1Inc();
|
||||
@@ -160,29 +163,25 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeVarRef* nodep) override {
|
||||
// Note NodeAssign skips calling this in some cases
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
checkVarRef(nodep);
|
||||
if (nodep->varScopep()) {
|
||||
nodep->varScopep()->user1Inc();
|
||||
nodep->varScopep()->varp()->user1Inc();
|
||||
}
|
||||
if (nodep->varp()) nodep->varp()->user1Inc();
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc();
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (nodep->classOrPackagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(nullptr);
|
||||
nodep->classOrPackagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
nodep->classOrPackagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,11 +195,11 @@ private:
|
||||
checkAll(nodep);
|
||||
UASSERT_OBJ(!(m_elimCells && nodep->typedefp()), nodep,
|
||||
"RefDType should point to data type before typedefs removed");
|
||||
if (nodep->packagep()) {
|
||||
if (nodep->classOrPackagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(nullptr);
|
||||
nodep->classOrPackagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
nodep->classOrPackagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,11 +207,11 @@ private:
|
||||
iterateChildren(nodep);
|
||||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (nodep->classOrPackagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(nullptr);
|
||||
nodep->classOrPackagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
nodep->classOrPackagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
if (nodep->classp()) nodep->classp()->user1Inc();
|
||||
@@ -225,11 +224,11 @@ private:
|
||||
virtual void visit(AstEnumItemRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (nodep->classOrPackagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(nullptr);
|
||||
nodep->classOrPackagep(nullptr);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
nodep->classOrPackagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
checkAll(nodep);
|
||||
@@ -277,19 +276,22 @@ private:
|
||||
// See if simple assignments to variables may be eliminated because
|
||||
// that variable is never used.
|
||||
// Similar code in V3Life
|
||||
m_sideEffect = false;
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
checkAll(nodep);
|
||||
// Has to be direct assignment without any EXTRACTing.
|
||||
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
if (varrefp && !m_sideEffect
|
||||
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
|
||||
m_assignMap.insert(make_pair(varrefp->varScopep(), nodep));
|
||||
checkAll(varrefp); // Must track reference to dtype()
|
||||
} else { // Track like any other statement
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
VL_RESTORER(m_sideEffect);
|
||||
{
|
||||
m_sideEffect = false;
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
checkAll(nodep);
|
||||
// Has to be direct assignment without any EXTRACTing.
|
||||
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
if (varrefp && !m_sideEffect
|
||||
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
|
||||
m_assignMap.insert(make_pair(varrefp->varScopep(), nodep));
|
||||
checkAll(varrefp); // Must track reference to dtype()
|
||||
checkVarRef(varrefp);
|
||||
} else { // Track like any other statement
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
}
|
||||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
|
||||
//-----
|
||||
@@ -367,14 +369,13 @@ private:
|
||||
void deadCheckClasses() {
|
||||
for (bool retry = true; retry;) {
|
||||
retry = false;
|
||||
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
|
||||
++it) {
|
||||
if (AstClass* nodep = *it) { // nullptr if deleted earlier
|
||||
for (auto& itr : m_classesp) {
|
||||
if (AstClass* nodep = itr) { // nullptr if deleted earlier
|
||||
if (nodep->user1() == 0) {
|
||||
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
|
||||
if (nodep->packagep()) nodep->packagep()->user1Inc(-1);
|
||||
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
*it = nullptr;
|
||||
itr = nullptr;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
@@ -439,12 +440,10 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
|
||||
bool elimCells) {
|
||||
m_modp = nullptr;
|
||||
m_elimCells = elimCells;
|
||||
m_elimUserVars = elimUserVars;
|
||||
m_elimDTypes = elimDTypes;
|
||||
m_sideEffect = false;
|
||||
bool elimCells)
|
||||
: m_elimUserVars{elimUserVars}
|
||||
, m_elimDTypes{elimDTypes}
|
||||
, m_elimCells{elimCells} {
|
||||
// Prepare to remove some datatypes
|
||||
nodep->typeTablep()->clearCache();
|
||||
// Operate on whole netlist
|
||||
@@ -462,7 +461,7 @@ public:
|
||||
// We may have removed some datatypes, cleanup
|
||||
nodep->typeTablep()->repairCache();
|
||||
}
|
||||
virtual ~DeadVisitor() override {}
|
||||
virtual ~DeadVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Dead {
|
||||
class V3Dead final {
|
||||
public:
|
||||
// Modules, no vars/dtypes
|
||||
static void deadifyModules(AstNetlist* nodep);
|
||||
|
||||
+41
-33
@@ -63,7 +63,7 @@
|
||||
//######################################################################
|
||||
// Delayed state, as a visitor of each AstNode
|
||||
|
||||
class DelayedVisitor : public AstNVisitor {
|
||||
class DelayedVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared each module:
|
||||
@@ -95,10 +95,10 @@ private:
|
||||
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;
|
||||
typedef std::map<const std::pair<AstNodeModule*, string>, AstVar*> VarMap;
|
||||
VarMap m_modVarMap; // Table of new var names created under module
|
||||
VDouble0 m_statSharedSet; // Statistic tracking
|
||||
typedef std::map<AstVarScope*, int> ScopeVecMap;
|
||||
typedef std::unordered_map<const AstVarScope*, int> ScopeVecMap;
|
||||
ScopeVecMap m_scopeVecMap; // Next var number for each scope
|
||||
|
||||
// METHODS
|
||||
@@ -160,10 +160,10 @@ private:
|
||||
varrefp->varp()->v3warn(
|
||||
MULTIDRIVEN,
|
||||
"Signal has multiple driving blocks with different clocking: "
|
||||
<< varrefp->varp()->prettyNameQ() << endl
|
||||
<< varrefp->warnOther() << "... Location of first driving block" << endl
|
||||
<< varrefp->warnContextPrimary() << endl
|
||||
<< oldactivep->warnOther() << "... Location of other driving block" << endl
|
||||
<< varrefp->varp()->prettyNameQ() << '\n'
|
||||
<< varrefp->warnOther() << "... Location of first driving block\n"
|
||||
<< varrefp->warnContextPrimary() << '\n'
|
||||
<< oldactivep->warnOther() << "... Location of other driving block\n"
|
||||
<< oldactivep->warnContextSecondary());
|
||||
varrefp->varp()->user2(true);
|
||||
}
|
||||
@@ -228,9 +228,10 @@ private:
|
||||
AstVarScope* bitvscp
|
||||
= 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));
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -247,9 +248,10 @@ private:
|
||||
AstVarScope* bitvscp
|
||||
= 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,8 +265,8 @@ 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__
|
||||
@@ -283,11 +285,11 @@ private:
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
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::BitTrue()));
|
||||
nodep->addNextHere(setassignp);
|
||||
}
|
||||
if (m_nextDlyp) { // Tell next assigndly it can share the variable
|
||||
@@ -332,9 +334,9 @@ private:
|
||||
UASSERT_OBJ(postLogicp, nodep,
|
||||
"Delayed assignment misoptimized; prev var found w/o associated IF");
|
||||
} else {
|
||||
postLogicp
|
||||
= new AstIf(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, false),
|
||||
nullptr, nullptr);
|
||||
postLogicp = new AstIf(nodep->fileline(),
|
||||
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
|
||||
@@ -356,9 +358,11 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_cfuncp = nullptr;
|
||||
VL_RESTORER(m_cfuncp);
|
||||
{
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
m_activep = nodep;
|
||||
@@ -406,10 +410,11 @@ private:
|
||||
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (!nodep->user2Inc()) { // Not done yet
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
if (m_inDly && nodep->access().isWriteOrRW()) {
|
||||
UINFO(4, "AssignDlyVar: " << nodep << endl);
|
||||
markVarUsage(nodep->varScopep(), VU_DLY);
|
||||
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
|
||||
UASSERT_OBJ(!nodep->access().isRW(), nodep, "<= on read+write method");
|
||||
if (!m_activep->hasClocked()) {
|
||||
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
|
||||
"have converted in V3Active");
|
||||
@@ -429,16 +434,19 @@ private:
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
// Events go to zero on next timestep unless reactivated
|
||||
prep = new AstAssignPre(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::BitFalse()));
|
||||
} 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
|
||||
@@ -447,11 +455,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().isWriteOrRW()) {
|
||||
// UINFO(9, "NBA " << nodep << endl);
|
||||
if (!m_inInitial) {
|
||||
UINFO(4, "AssignNDlyVar: " << nodep << endl);
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Delayed {
|
||||
class V3Delayed final {
|
||||
public:
|
||||
static void delayedAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
+26
-22
@@ -34,13 +34,13 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class DepthVisitor : public AstNVisitor {
|
||||
class DepthVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current block
|
||||
AstCFunc* m_cfuncp = 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
|
||||
@@ -61,14 +61,14 @@ private:
|
||||
// bitmask instead of widths....)
|
||||
// See t_func_crc for an example test that requires this
|
||||
VFlagLogicPacked(), nodep->width());
|
||||
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
|
||||
m_funcp->addInitsp(varp);
|
||||
UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function");
|
||||
m_cfuncp->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);
|
||||
@@ -81,23 +81,27 @@ private:
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_funcp = nullptr;
|
||||
m_cfuncp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
m_funcp = nodep;
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
iterateChildren(nodep);
|
||||
m_funcp = nullptr;
|
||||
VL_RESTORER(m_cfuncp);
|
||||
{
|
||||
m_cfuncp = nodep;
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visitStmt(AstNodeStmt* nodep) {
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
m_stmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_stmtp = nullptr;
|
||||
VL_RESTORER(m_stmtp);
|
||||
{
|
||||
m_stmtp = nodep;
|
||||
m_depth = 0;
|
||||
m_maxdepth = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) override {
|
||||
if (!nodep->isStatement()) {
|
||||
@@ -128,10 +132,10 @@ private:
|
||||
// Marking of non-static functions (because they might need "this")
|
||||
// (Here instead of new visitor after V3Descope just to avoid another visitor)
|
||||
void needNonStaticFunc(AstNode* nodep) {
|
||||
UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function");
|
||||
if (m_funcp->isStatic().trueUnknown()) {
|
||||
UASSERT_OBJ(m_cfuncp, nodep, "Non-static accessor not under a function");
|
||||
if (m_cfuncp->isStatic().trueUnknown()) {
|
||||
UINFO(5, "Mark non-public due to " << nodep << endl);
|
||||
m_funcp->isStatic(false);
|
||||
m_cfuncp->isStatic(false);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) override {
|
||||
@@ -151,7 +155,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~DepthVisitor() override {}
|
||||
virtual ~DepthVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Depth {
|
||||
class V3Depth final {
|
||||
public:
|
||||
static void depthAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class DepthBlockVisitor : public AstNVisitor {
|
||||
class DepthBlockVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_funcp = nullptr; // Current function
|
||||
AstCFunc* m_cfuncp = nullptr; // Current function
|
||||
int m_depth = 0; // How deep in an expression
|
||||
int m_deepNum = 0; // How many functions made
|
||||
|
||||
@@ -49,11 +49,11 @@ private:
|
||||
AstNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
// Create function
|
||||
string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum);
|
||||
string name = m_cfuncp->name() + "__deep" + cvtToStr(++m_deepNum);
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr);
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->symProlog(true);
|
||||
funcp->slow(m_funcp->slow());
|
||||
funcp->slow(m_cfuncp->slow());
|
||||
funcp->addStmtsp(nodep);
|
||||
m_modp->addStmtp(funcp);
|
||||
// Call it at the point where the body was removed from
|
||||
@@ -78,10 +78,10 @@ private:
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
// We recurse into this.
|
||||
VL_RESTORER(m_depth);
|
||||
VL_RESTORER(m_funcp);
|
||||
VL_RESTORER(m_cfuncp);
|
||||
{
|
||||
m_depth = 0;
|
||||
m_funcp = nodep;
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~DepthBlockVisitor() override {}
|
||||
virtual ~DepthBlockVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3DepthBlock {
|
||||
class V3DepthBlock final {
|
||||
public:
|
||||
static void depthBlockAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user