mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 08:33:21 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d3a9eec7f | ||
|
|
3d21a79148 | ||
|
|
e15f5266a3 | ||
|
|
9130eb8b99 | ||
|
|
09e856d2f3 | ||
|
|
ee5c0a2902 | ||
|
|
621b7e63cf | ||
|
|
c6bf9fb89e | ||
|
|
f794180865 | ||
|
|
0e769d42a1 | ||
|
|
cbeb9d39ff | ||
|
|
5a98c1a3b1 | ||
|
|
cac634d39b | ||
|
|
08330bad0b | ||
|
|
84a46939b3 | ||
|
|
65a484e00b | ||
|
|
843fdd3e57 | ||
|
|
a10b51705f | ||
|
|
df86e39845 | ||
|
|
7f49b6c102 | ||
|
|
754a0b8320 | ||
|
|
7d3b3761b2 | ||
|
|
d1b80ffa29 | ||
|
|
f95ce886f1 | ||
|
|
fa16eff003 | ||
|
|
23f90b13f3 | ||
|
|
37e7b5dfc7 | ||
|
|
e1683afb31 | ||
|
|
e38b359d75 | ||
|
|
b6dcec2710 | ||
|
|
0307d59c1f | ||
|
|
3aa013c8db | ||
|
|
fc70876aa9 | ||
|
|
722ab9306a | ||
|
|
2ab34b5eeb | ||
|
|
e3bdae77a0 | ||
|
|
663d6a1c8d | ||
|
|
bf5cbb512e | ||
|
|
d4bb58630e | ||
|
|
fff0eb5d88 | ||
|
|
7ae0c5d546 | ||
|
|
114d93b212 | ||
|
|
13a87e5514 | ||
|
|
d67d75282c | ||
|
|
827cbf22c9 | ||
|
|
2530cda507 | ||
|
|
38000a3da0 | ||
|
|
6c21b21ecc | ||
|
|
8caf9be3e6 | ||
|
|
cdb61842d6 | ||
|
|
05660d1118 | ||
|
|
a3f9221a67 | ||
|
|
7e1980af7a | ||
|
|
921fd919b5 | ||
|
|
fc5a5ea53d | ||
|
|
86156dd05b | ||
|
|
3219ffddd4 | ||
|
|
3a01c32bf9 | ||
|
|
9ffd0a4e70 | ||
|
|
90e049c674 | ||
|
|
69121633cf | ||
|
|
28eadded87 | ||
|
|
93c598dd19 | ||
|
|
d012563ab1 | ||
|
|
0b96789e65 | ||
|
|
947402bc57 | ||
|
|
d4107dce52 | ||
|
|
990b19e048 | ||
|
|
2290e6ccf2 | ||
|
|
14c8f072f1 | ||
|
|
c55df02b1a | ||
|
|
5b86248b54 | ||
|
|
449ac44131 | ||
|
|
f439a7927f | ||
|
|
277bd67f72 | ||
|
|
5de8ccbf32 | ||
|
|
577e0700ba | ||
|
|
71a37484f5 | ||
|
|
daf157e6c0 | ||
|
|
2aa6a229ca | ||
|
|
9b869edd90 | ||
|
|
2b21697b86 | ||
|
|
895ab8789b | ||
|
|
5f02f95ce6 | ||
|
|
f2aac8c49a | ||
|
|
82e653a739 | ||
|
|
053f760e2a | ||
|
|
ba9e141fae | ||
|
|
d60a3e2b66 | ||
|
|
70c2d1eded | ||
|
|
80cbf81b3b | ||
|
|
798d7346cf | ||
|
|
d6c5d40f9b | ||
|
|
371b8310d9 | ||
|
|
1ac721af8f | ||
|
|
85fd88ace2 | ||
|
|
ed1e377bb1 | ||
|
|
4240c29f4b | ||
|
|
51ba4a1531 | ||
|
|
d1b55cb7aa | ||
|
|
bbf53bd5af | ||
|
|
b2ced6ff1d | ||
|
|
a9b07fe7d7 | ||
|
|
66e4656a8e | ||
|
|
8f4d4f07a4 | ||
|
|
8e55580cde | ||
|
|
8ae79066a2 | ||
|
|
36da6a3563 | ||
|
|
45690faea7 | ||
|
|
046fecbb35 | ||
|
|
0f6024ef3c | ||
|
|
2488b5a97f | ||
|
|
56de6f1a9f | ||
|
|
0fc5d37901 | ||
|
|
ea4cc4e076 | ||
|
|
9e25c21fed | ||
|
|
fc3fdcc71c | ||
|
|
80b7b8bbdb | ||
|
|
a8ce272e4a | ||
|
|
72963c4e20 | ||
|
|
4e5bd361e0 | ||
|
|
ed1a9309d4 | ||
|
|
1d0a06438c | ||
|
|
2c62714a30 | ||
|
|
f13e753b52 | ||
|
|
39a5bce8a6 | ||
|
|
ba953bfa94 | ||
|
|
1debd0405b | ||
|
|
1f1d9312d2 | ||
|
|
259201b352 | ||
|
|
bb45bd048e | ||
|
|
5489ec6eff | ||
|
|
e55e81bcd0 | ||
|
|
5c5c758718 | ||
|
|
b87669039e | ||
|
|
60a6ed2a20 | ||
|
|
81e8388c3f | ||
|
|
4532680e5f | ||
|
|
fc17ab280a | ||
|
|
621cd0f008 | ||
|
|
13c9877099 | ||
|
|
ff889fde18 | ||
|
|
f68c16a5e6 | ||
|
|
cc45f64280 | ||
|
|
725ec088ea | ||
|
|
87c3de5aab | ||
|
|
6d7c04a3de | ||
|
|
d0f5ce0cc4 | ||
|
|
cb89ef9885 | ||
|
|
90360d40fd | ||
|
|
15dcd326f8 | ||
|
|
ae1eb56695 | ||
|
|
a47fd07585 | ||
|
|
19bc257002 | ||
|
|
a1d4cd658e | ||
|
|
21093fd1bd | ||
|
|
329a933efd | ||
|
|
e21198cb2d | ||
|
|
ab502c5196 | ||
|
|
12728bc478 | ||
|
|
3fc684359a | ||
|
|
1e28387541 | ||
|
|
dd917d50eb | ||
|
|
0130c2bceb | ||
|
|
8a5804fc3a | ||
|
|
3df29085c8 | ||
|
|
976af0068b | ||
|
|
a85e6a9d8c | ||
|
|
463ea57b0a | ||
|
|
326a60d307 | ||
|
|
2c60c5f816 | ||
|
|
faf3804b9a | ||
|
|
08a433260c | ||
|
|
7fc278f6db | ||
|
|
b1a95f642f | ||
|
|
c6a569df49 | ||
|
|
06661ab676 | ||
|
|
d9a0e69597 | ||
|
|
a0997d0b98 | ||
|
|
a3ff375ce7 | ||
|
|
c03affa544 | ||
|
|
4703fc39be | ||
|
|
9bf0e54937 | ||
|
|
b039f246df | ||
|
|
a93b344096 | ||
|
|
191c71edea | ||
|
|
b4dd398af6 | ||
|
|
cfe0fdd5cc | ||
|
|
003a8cfe75 | ||
|
|
7559af5879 | ||
|
|
47a7e75841 | ||
|
|
adf1de45de | ||
|
|
45f955f175 | ||
|
|
063f9a7a4c | ||
|
|
c82a098f2e | ||
|
|
393b7714c4 | ||
|
|
43d8de4f80 | ||
|
|
026bbc306b | ||
|
|
f8b0e359b9 | ||
|
|
94ef1b76d0 | ||
|
|
50929e5d43 | ||
|
|
3f4b7af8a1 | ||
|
|
bc6a7787ed | ||
|
|
5064ec2806 | ||
|
|
4f19eeaffa | ||
|
|
10d0088f73 | ||
|
|
15d0ec317d | ||
|
|
260d58e47e | ||
|
|
d9c4d9316f | ||
|
|
e9441cff50 | ||
|
|
daa545774e | ||
|
|
dee2e45e27 | ||
|
|
4d29487e75 | ||
|
|
2bb2935924 | ||
|
|
aff3f7c4f6 | ||
|
|
5aa4f46101 | ||
|
|
8f87022496 | ||
|
|
d34aa10faf | ||
|
|
93d50c4499 | ||
|
|
4eb280601e | ||
|
|
b778784333 | ||
|
|
9121a81a74 | ||
|
|
d3cbb1e53f | ||
|
|
cf88700fc2 | ||
|
|
072d76fe8e | ||
|
|
3436d1780f | ||
|
|
1607225063 | ||
|
|
807e5b22a0 | ||
|
|
2c64b83c19 | ||
|
|
dfc98e77c0 | ||
|
|
936bb7b1ed | ||
|
|
88e5017564 | ||
|
|
508f6f7e5a | ||
|
|
70eceae3d8 | ||
|
|
eb5aad94f1 | ||
|
|
2d89c458f6 | ||
|
|
d33ded22f9 | ||
|
|
edc32ca82d | ||
|
|
dc9c81256d | ||
|
|
6908e471e7 | ||
|
|
e3558d9e1b | ||
|
|
11043aeb9b | ||
|
|
15c163c12e | ||
|
|
c7ed73e249 | ||
|
|
4aa3e72509 | ||
|
|
31130c4b4a | ||
|
|
00f0027c80 | ||
|
|
c8be50d40b | ||
|
|
e16e9b89cd | ||
|
|
80b291407b | ||
|
|
d2aff13402 | ||
|
|
82f450d838 | ||
|
|
f6d4f1ad02 | ||
|
|
645e1387e0 | ||
|
|
d3c14cc1ac | ||
|
|
33468fa0e7 | ||
|
|
0e955d503e | ||
|
|
18e317fb78 | ||
|
|
ef9f443532 | ||
|
|
6e3b957b30 | ||
|
|
aea1834ed8 | ||
|
|
7f3e178b68 | ||
|
|
87a7881d46 | ||
|
|
29f4821d78 | ||
|
|
9f9c84aa64 | ||
|
|
d80e0523cc | ||
|
|
164aa96953 | ||
|
|
6a12c4d02a | ||
|
|
6a7dfb7696 | ||
|
|
4208db7811 | ||
|
|
a19dddf05e | ||
|
|
7855a78a0f | ||
|
|
248bd173d3 | ||
|
|
8d2be855f5 | ||
|
|
ba8700f99d | ||
|
|
f20997a2f0 | ||
|
|
bea225e191 | ||
|
|
93517b8378 | ||
|
|
a39c7f7dac | ||
|
|
5125b94fd8 | ||
|
|
d118a739dc | ||
|
|
c2a8810eb1 | ||
|
|
91c44d7830 | ||
|
|
21aafe8f50 | ||
|
|
4a8cfe367d | ||
|
|
b56e7f6910 | ||
|
|
8a85cedaf5 | ||
|
|
be26e8da1b | ||
|
|
b2dd5de860 | ||
|
|
6ea725f479 | ||
|
|
665758a68b |
+6
-11
@@ -15,7 +15,7 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||
project(Verilator
|
||||
VERSION 5.003
|
||||
VERSION 5.010
|
||||
HOMEPAGE_URL https://verilator.org
|
||||
LANGUAGES CXX
|
||||
)
|
||||
@@ -23,7 +23,8 @@ project(Verilator
|
||||
option(DEBUG_AND_RELEASE_AND_COVERAGE
|
||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.")
|
||||
|
||||
set(PYTHON3 python)
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
set(PYTHON3 Python3::Interpreter)
|
||||
set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX})
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
@@ -44,15 +45,7 @@ if (MSVC)
|
||||
if (NOT WIN_FLEX_BISON)
|
||||
message(FATAL_ERROR "Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build.")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++20")
|
||||
else()
|
||||
if (NOT DEFINED ENV{FLEX_INCLUDE})
|
||||
message(FATAL_ERROR "Please set environment variable FLEX_INCLUDE to the directory containing FlexLexer.h")
|
||||
endif()
|
||||
set(WIN_FLEX_BISON "$ENV{FLEX_INCLUDE}")
|
||||
if (WIN32 AND NOT MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
endif()
|
||||
|
||||
find_package(BISON)
|
||||
@@ -99,6 +92,7 @@ configure_package_config_file(verilator-config-version.cmake.in verilator-config
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
foreach (program
|
||||
verilator
|
||||
verilator_gantt
|
||||
verilator_ccache_report
|
||||
verilator_difftree
|
||||
@@ -118,6 +112,7 @@ install(DIRECTORY include TYPE DATA FILES_MATCHING
|
||||
PATTERN "include/verilated.mk"
|
||||
PATTERN "include/*.[chv]"
|
||||
PATTERN "include/*.cpp"
|
||||
PATTERN "include/*.sv"
|
||||
PATTERN "include/gtkwave/*.[chv]*"
|
||||
PATTERN "include/vltstd/*.[chv]*"
|
||||
)
|
||||
|
||||
@@ -8,7 +8,131 @@ The changes in each Verilator version are described below. The
|
||||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 5.006 2022-01-22
|
||||
Verilator 5.010 2023-04-30
|
||||
==========================
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Add --public-depth to force public to a certain instance depth (#3952). [Andrew Nolte]
|
||||
* Add --public-params flag (#3990). [Andrew Nolte]
|
||||
* Add CONSTRAINTIGN warning when constraint ignored.
|
||||
* Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add error if class types don't match (#4064). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support class extends of package::class.
|
||||
* Support class srandom and class random stability.
|
||||
* Support class method calls without parenthesis (#3902) (#4082). [Srinivasan Venkataramanan]
|
||||
* Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support parameterized return types of methods (#4122). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support parameterized class references in extends statement (#4146). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support complicated IEEE 'for' assignments.
|
||||
* Support $fopen as an expression.
|
||||
* Support ++/-- on dotted member variables.
|
||||
* Optimize static trigger evaluation (#4142). [Geza Lore, X-EPIC]
|
||||
* Optimize more xor trees (#4071). [Yutetsu TAKATSUKASA]
|
||||
* Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras]
|
||||
* Change ZERODLY to a warning.
|
||||
* Fix random internal crashes (#666). [Dag Lem]
|
||||
* Fix install, standardization in cmake CMakeLists.txt (#3974). [Yu-Sheng Lin]
|
||||
* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker]
|
||||
* Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński]
|
||||
* Fix event controls reusing same variable (#4014). Kamil Rakoczy <[email protected]>
|
||||
* Fix push to dynamic queue in struct (#4015). [ezchi]
|
||||
* Fix names for blocks in do..while loop (#4019). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix randomize on null field (#4023). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix rand fields in base classes (#4025). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt]
|
||||
* Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan]
|
||||
* Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube]
|
||||
* Fix characters from DEFENV literals for Conda (#4035) (#4044). [Tim Snyder]
|
||||
* Fix info message prints under --assert (#4036) (#4053). [Srinivasan Venkataramanan]
|
||||
* Fix C++ compile errors when passing class refs as task argument (#4063). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix NBAs inside fork-joins (#4050). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Fix task calls as fork statements (#4055). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix _Vilp used before declaration (#4057) (#4062). [Josep Sans]
|
||||
* Fix incorrect optimization of bit op tree (#4059) (#4070). [Yutetsu TAKATSUKASA]
|
||||
* Fix parameters in a class body to be localparam (#4061). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix interface generate begin (#4065). [Srinivasan Venkataramanan]
|
||||
* Fix tracing with awaits at end of block (#4075) (#4076). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix sense expression variable naming (#4081). [Kamil Rakoczy]
|
||||
* Fix importing symbols from base class (#4084). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix false error on new const assignment (#4098). [Tudor Timi]
|
||||
* Fix unpacked structs under classes (#4102). [Tudor Timi]
|
||||
* Fix variables in class methods to be automatic (#4111) (#4137). [Peter Monsson]
|
||||
* Fix to use parallel build for projects with a lot of files (#4116). [Krzysztof Boroński]
|
||||
* Fix including __Syms header in generated C++ files (#4123). [Krzysztof Boroński]
|
||||
* Fix systemc namespace issues (#4126) (#4127). [Eyck Jentzsch]
|
||||
* Fix class param extends A=B (#4128). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix missing begin block hierarchy in --xml-only cells section (#4129) (#4133). [Risto Pejašinović]
|
||||
* Fix resolution of class lvalues after parameterization (#4131). [Krzysztof Boroński]
|
||||
* Fix DFG error on $countbits (#4101) (#4143). [Paul Donahue]
|
||||
* Fix duplicating parameter class types (#4115). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix class extend param references (#4136). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix -CFLAGS to allow overriding optimization levels (#4140). [Peter Monsson]
|
||||
* Fix DPI function type alias (#4148) (#4149). [Toru Niina]
|
||||
* Fix deleting unused parameterized classes (#4150). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix false ENUMVALUE on expressions and arrays.
|
||||
* Fix unnecessary verilated_std.sv waivers in --waiver-output.
|
||||
|
||||
|
||||
Verilator 5.008 2023-03-04
|
||||
==========================
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Add --annotate-points option, change multipoint on line reporting (#3876). [Nassim Corteggiani]
|
||||
* Add --verilate-jobs option (#3889). [Kamil Rakoczy, Antmicro Ltd]
|
||||
* Add WIDTHEXPAND and WIDTHTRUNC warnings to replace WIDTH (#3900). [Andrew Nolte]
|
||||
* Add SOURCE_DATE_EPOCH for docs/guide/conf.py (#3918). [Larry Doolittle]
|
||||
* Add /*verilator public[flat|flat_rd|flat_rw| ]*/ metacomments (#3894). [Joseph Nwabueze]
|
||||
* Add lint warning on always_comb multidriven (#3888) (#3939). [Adam Bagley]
|
||||
* Add warning on ++/-- over expressions with potential side effects (#3976). [Krzysztof Boroński]
|
||||
* Add error on mixing .name and by-port instantiations.
|
||||
* Removed deprecated --cdc option.
|
||||
* Support unpacked unions.
|
||||
* Support interface classes and class implements.
|
||||
* Support global clocking and $global_clock.
|
||||
* Support class parameters without initial values.
|
||||
* Support cast to numbers from strings.
|
||||
* Support struct I/O in --lib-create (#3378) (#3892). [Varun Koyyalagunta]
|
||||
* Support function calls without parenthesis (#3903) (#3902). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support class extending its parameter (#3904). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support static function variables (#3830). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support recursive methods (#3987). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix real parameters of infinity and NaN.
|
||||
* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal]
|
||||
* Fix single-element replication to dynarray/unpacked/queue (#3548). [Gustav Svensk]
|
||||
* Fix constant enum methods (#3621). [Todd Strader]
|
||||
* Fix inconsistent naming of generate scope arrays (#3840). [Andrew Nolte]
|
||||
* Fix namespace fallback resolution (#3863) (#3942). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Fix std:: to be parsed first (#3864) (#3928). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Fix cmake warning if multiple SOURCES w/o PREFIX (#3916) (#3927). [Yoda Lee]
|
||||
* Fix parameterized class function linkage (#3917). [Ryszard Rozak]
|
||||
* Fix static members of type aliases of a parameterized class (#3922). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix class extend parameter dot case (#3926). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix MsWin missing directory exception, and ::std (#3928) (#3933) (#3935). [Kritik Bhimani]
|
||||
* Fix very long VPI signal names (#3929). [Marlon James]
|
||||
* Fix VPI upper interface scopes not found (#3937). [David Stanford]
|
||||
* Fix virus detection false positive (#3944). [Stuart Morris]
|
||||
* Fix constant string function assignment (#3945). [Todd Strader]
|
||||
* Fix constant format field widths (#3946). [Todd Strader]
|
||||
* Fix class field linking when a super classes is a param (#3949). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix CMake bad C identifiers (#3948) (#3951). [Zixi Li]
|
||||
* Fix build on HP PA architecture (#3954). [John David Anglin]
|
||||
* Fix date on the front page of verilator.pdf (#3956) (#3957). [Larry Doolittle]
|
||||
* Fix associative arrays declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix missing error on negative replicate (#3963). [Benjamin Menküc]
|
||||
* Fix self references to parameterized classes (#3962). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix LITENDIAN warning is backwards (#3966) (#3967). [Cameron Kirk]
|
||||
* Fix subsequent parameter declarations (#3969). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix timing delays to not truncate below 64 bits (#3973) (#3982). [Felix Neumärker]
|
||||
* Fix cmake on MacOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker]
|
||||
* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker]
|
||||
* Fix coverage of class methods (#3998). [Tim Paine]
|
||||
* Fix packed array structure replication.
|
||||
* Fix enum.next(0) and enum.prev(0).
|
||||
|
||||
|
||||
Verilator 5.006 2023-01-22
|
||||
==========================
|
||||
|
||||
**Minor:**
|
||||
@@ -20,7 +144,8 @@ Verilator 5.006 2022-01-22
|
||||
* Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support import/export lists in modport (#3886). [Gökçe Aydos]
|
||||
* Support class queue equality (#3895). [Ilya Barkov]
|
||||
* Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support type case and type equality comparisons.
|
||||
* Add IMPLICITSTATIC warning when a task/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add VL_VALUE_STRING_MAX_WORDS override (#3869). [Andrew Nolte]
|
||||
* Optimize expansion of extend operators.
|
||||
* Internal multithreading tests. [Mariusz Glebocki, et al, Antmicro Ltd]
|
||||
@@ -34,7 +159,7 @@ Verilator 5.006 2022-01-22
|
||||
* Fix self references when param class instantiated (#3833). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix memory leak in V3Sched, etc. (#3834). [Geza Lore]
|
||||
* Fix compatibility with musl libc / Alpine Linux (#3845). [Sören Tempel]
|
||||
* Fix empty case items crash (#3851). [rporter]
|
||||
* Fix empty case items crash (#3851). [Rich Porter]
|
||||
* Fix VL_CPU_RELAX on MIPS/Armel/s390/sparc (#3843) (#3891). [Kamil Rakoczy]
|
||||
* Fix module parameter name collision (#3854) (#3855). [James Shi]
|
||||
* Fix unpacked array expansion (#3861). [Joey Liu]
|
||||
@@ -44,6 +169,8 @@ Verilator 5.006 2022-01-22
|
||||
* Fix foreach unnamedblk duplicate error (#3885). [Ilya Barkov]
|
||||
* Fix elaboration of member selected classes (#3890). [Ilya Barkov]
|
||||
* Fix mismatched widths in DFG (#3872). [Geza Lore, Yike Zhou]
|
||||
* Fix lint for non-integral types in packed structs.
|
||||
* Fix generate case with empty body statements.
|
||||
|
||||
|
||||
Verilator 5.004 2022-12-14
|
||||
|
||||
+7
-7
@@ -15,13 +15,13 @@
|
||||
#
|
||||
#****************************************************************************/
|
||||
#
|
||||
# make all to compile and build Verilator.
|
||||
# make install to install it.
|
||||
# make TAGS to update tags tables.
|
||||
# make all to compile and build Verilator.
|
||||
# make install to install it.
|
||||
# make TAGS to update tags tables.
|
||||
#
|
||||
# make clean or make mostlyclean
|
||||
# Delete all files from the current directory that are normally
|
||||
# created by building the program. Don't delete the files that
|
||||
# created by building the program. Don't delete the files that
|
||||
# record the configuration. Also preserve files that could be made
|
||||
# by building, but normally aren't because the distribution comes
|
||||
# with them.
|
||||
@@ -153,7 +153,7 @@ msg_test: all_nomsg
|
||||
@echo
|
||||
|
||||
.PHONY: test
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
test: smoke-test test_regress
|
||||
# examples is part of test_regress's test_regress/t/t_a2_examples.pl
|
||||
# (because that allows it to run in parallel with other test_regress's)
|
||||
@@ -462,7 +462,7 @@ config.status: configure
|
||||
./config.status --recheck
|
||||
|
||||
configure: configure.ac
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
autoconf --warnings=all
|
||||
else
|
||||
autoconf
|
||||
@@ -501,7 +501,7 @@ distclean maintainer-clean::
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
${srcdir}/*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
|
||||
.PHONY: doxygen
|
||||
|
||||
+4
-1
@@ -362,7 +362,7 @@ detailed descriptions of these arguments.
|
||||
+incdir+<dir> Directory to search for includes
|
||||
--inline-mult <value> Tune module inlining
|
||||
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
|
||||
-j <jobs> Parallelism for --build (alias to --build-jobs)
|
||||
-j <jobs> Parallelism for --build-jobs/--verilate-jobs
|
||||
--l2-name <value> Verilog scope name of the top module
|
||||
--language <lang> Default language standard to parse
|
||||
-LDFLAGS <flags> Linker pre-object arguments for makefile
|
||||
@@ -404,6 +404,7 @@ detailed descriptions of these arguments.
|
||||
--protect-key <key> Key for symbol protection
|
||||
--protect-lib <name> Create a DPI protected library
|
||||
--public Debugging; see docs
|
||||
--public-params Mark all parameters as public_flat
|
||||
--public-flat-rw Mark all variables, etc as public_flat_rw
|
||||
-pvalue+<name>=<value> Overwrite toplevel parameter
|
||||
--quiet-exit Don't print the command on failure
|
||||
@@ -416,6 +417,7 @@ detailed descriptions of these arguments.
|
||||
--no-skip-identical Disable skipping identical output
|
||||
--stats Create statistics file
|
||||
--stats-vars Provide statistics on variables
|
||||
--no-std Prevent parsing standard library
|
||||
--structs-packed Convert all unpacked structures to packed structures
|
||||
-sv Enable SystemVerilog parsing
|
||||
+systemverilogext+<ext> Synonym for +1800-2017ext+<ext>
|
||||
@@ -445,6 +447,7 @@ detailed descriptions of these arguments.
|
||||
--unused-regexp <regexp> Tune UNUSED lint signals
|
||||
-V Verbose version and config
|
||||
-v <filename> Verilog library
|
||||
--verilate-jobs Job threads for Verilation stage
|
||||
--no-verilate Skip Verilation and just compile previously Verilated code
|
||||
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
|
||||
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
|
||||
|
||||
@@ -169,6 +169,7 @@ L<https://verilator.org/guide/latest/exe_verilator_coverage.html>.
|
||||
--annotate <output_dir> Directory name for source annotation.
|
||||
--annotate-all All files should be shown.
|
||||
--annotate-min <count> Minimum occurrence count for uncovered.
|
||||
--annotate-points Annotates info from each coverage point.
|
||||
--help Displays this message and version and exits.
|
||||
--rank Compute relative importance of tests.
|
||||
--unlink With --write, unlink all inputs
|
||||
|
||||
@@ -42,8 +42,8 @@ def diff_dir(a, b):
|
||||
continue
|
||||
a = files[base]['a']
|
||||
b = files[base]['b']
|
||||
print("=" * 70)
|
||||
print("= %s <-> %s" % (a, b))
|
||||
print("=" * 70, flush=True)
|
||||
print("= %s <-> %s" % (a, b), flush=True)
|
||||
diff_file(a, b)
|
||||
anyfile = True
|
||||
if not anyfile:
|
||||
|
||||
@@ -4,12 +4,12 @@ if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../../../.ccache
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../../../.ccache
|
||||
cd ../..
|
||||
}
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../install
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../install
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ cd examples/cmake_tracing_c
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Release -j 3
|
||||
Release/example.exe
|
||||
cd ..
|
||||
Remove-Item -path build -recurse
|
||||
|
||||
+3
-3
@@ -5,12 +5,12 @@
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
# When releasing, also update header of Changes file
|
||||
# When releasing, also update header of Changes file,
|
||||
# and commit using "devel release" or "Version bump" message
|
||||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.006 2023-01-22],
|
||||
AC_INIT([Verilator],[5.010 2023-04-30],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
@@ -68,7 +68,7 @@ AC_MSG_CHECKING(whether to use -m32)
|
||||
AC_ARG_ENABLE([m32],
|
||||
[AS_HELP_STRING([--enable-m32],
|
||||
[Use -m32 for all compilation and link,
|
||||
including Verialtor and generated models.])],
|
||||
including Verilator and generated models.])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_ENABLE_M32=yes ;;
|
||||
no) CFG_ENABLE_M32=no ;;
|
||||
|
||||
+21
-14
@@ -10,9 +10,12 @@ contributions flow more efficiently.
|
||||
Did you find a bug?
|
||||
-------------------
|
||||
|
||||
- Please **Ensure the bug was not already reported** by searching
|
||||
- Please **ensure the bug was not already reported** by searching
|
||||
`Verilator Issues <https://verilator.org/issues>`__.
|
||||
|
||||
- Please **download the latest development GitHub version**, build, and see
|
||||
if the issue has been fixed.
|
||||
|
||||
- If you're unable to find an open issue addressing the problem, `open a
|
||||
new Verilator issue <https://verilator.org/issues/new>`__.
|
||||
|
||||
@@ -20,21 +23,28 @@ Did you find a bug?
|
||||
demonstrating the bug and expected behavior that is not occurring.
|
||||
|
||||
- The ideal example works against other simulators, and is in the
|
||||
test_regress/t test format, as described in `docs/internals
|
||||
<internals.rst>`__.
|
||||
test_regress/t test format, as described in
|
||||
`Verilator Internals Documentation
|
||||
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
|
||||
|
||||
|
||||
Did you write a patch that fixes a bug?
|
||||
---------------------------------------
|
||||
|
||||
- Please `Open a new issue <https://verilator.org/issues/new>`__.
|
||||
- Please `Open a new Verilator issue <https://verilator.org/issues/new>`__
|
||||
if there is not one already describing the bug.
|
||||
|
||||
- You may attach a patch to the issue, or (preferred) may request a
|
||||
GitHub pull request.
|
||||
- Please `Open a Verilator pull request
|
||||
<https://github.com/verilator/verilator/pulls>`__.
|
||||
|
||||
- Verilator uses GitHub Actions to provide continuous integration. You
|
||||
may want to enable Actions on your GitHub branch to ensure your changes
|
||||
keep the tests passing. See `docs/internals <internals.rst>`__.
|
||||
- See the coding conventions, and other developer information in
|
||||
``docs/internals.rst`` in the distribution, or as rendered at
|
||||
`Verilator Internals Documentation
|
||||
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
|
||||
|
||||
- Verilator uses GitHub Actions to provide continuous integration. You
|
||||
may want to enable Actions on your GitHub branch to ensure your changes
|
||||
keep the tests passing.
|
||||
|
||||
- Your source-code contributions must be certified as open source,
|
||||
under the `Developer Certificate of
|
||||
@@ -56,13 +66,10 @@ Did you write a patch that fixes a bug?
|
||||
contribution.
|
||||
|
||||
- Your test contributions are generally considered released into the
|
||||
Creative Commons Public Domain (CC0), unless you request otherwise or
|
||||
Creative Commons Public Domain (CC0), unless you request otherwise, or
|
||||
put a GNU/Artistic license on your file.
|
||||
|
||||
- Most important is we get your patch. If you'd like to clean up
|
||||
indentation and related issues ahead of our feedback, that is
|
||||
appreciated; please see the coding conventions in `docs/internals
|
||||
<internals.rst>`__.
|
||||
- Most important is we get your patch.
|
||||
|
||||
|
||||
Do you have questions?
|
||||
|
||||
@@ -3,6 +3,7 @@ under the Developer Certificate of Origin (https://developercertificate.org/).
|
||||
|
||||
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||
|
||||
Adam Bagley
|
||||
Adrien Le Masle
|
||||
Ahmed El-Mahmoudy
|
||||
Aleksander Kiryk
|
||||
@@ -13,6 +14,7 @@ Ameya Vikram Singh
|
||||
Andreas Kuster
|
||||
Andrew Nolte
|
||||
Arkadiusz Kozdra
|
||||
Cameron Kirk
|
||||
Chris Randall
|
||||
Chuxuan Wang
|
||||
Conor McCullough
|
||||
@@ -27,7 +29,9 @@ Drew Taussig
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Rippey
|
||||
Eyck Jentzsch
|
||||
Fan Shupei
|
||||
Felix Neumärker
|
||||
Felix Yan
|
||||
Garrett Smith
|
||||
Geza Lore
|
||||
@@ -58,6 +62,7 @@ Jamie Iles
|
||||
Jan Van Winkel
|
||||
Jean Berniolles
|
||||
Jeremy Bennett
|
||||
Jesse Taube
|
||||
Jevin Sweval
|
||||
Jiacheng Qian
|
||||
Jiuyang Liu
|
||||
@@ -65,6 +70,8 @@ Joey Liu
|
||||
John Coiner
|
||||
John Demme
|
||||
Jonathan Drolet
|
||||
Joseph Nwabueze
|
||||
Josep Sans
|
||||
Josh Redford
|
||||
Julie Schwartz
|
||||
Julien Margetts
|
||||
@@ -75,6 +82,7 @@ Keith Colbert
|
||||
Kevin Kiningham
|
||||
Kritik Bhimani
|
||||
Krzysztof Bieganski
|
||||
Krzysztof Boroński
|
||||
Kuba Ober
|
||||
Larry Doolittle
|
||||
Ludwig Rogiers
|
||||
@@ -103,6 +111,7 @@ Nathan Myers
|
||||
Patrick Stewart
|
||||
Paul Wright
|
||||
Pawel Sagan
|
||||
Peter Debacker
|
||||
Peter Horvath
|
||||
Peter Monsson
|
||||
Philipp Wagner
|
||||
@@ -113,12 +122,15 @@ Qingyao Sun
|
||||
Rafal Kapuscik
|
||||
Raynard Qiao
|
||||
Richard Myers
|
||||
Risto Pejašinović
|
||||
Robert Balas
|
||||
Rupert Swarbrick
|
||||
Ryszard Rozak
|
||||
Samuel Riedel
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
Srinivasan Venkataramanan
|
||||
Stefan Wallentowitz
|
||||
Stephen Henry
|
||||
Steven Hugg
|
||||
@@ -130,6 +142,7 @@ Tobias Wölfel
|
||||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Topa Topino
|
||||
Toru Niina
|
||||
Tymoteusz Blazejczyk
|
||||
Udi Finkelstein
|
||||
Unai Martinez-Corral
|
||||
@@ -148,3 +161,4 @@ Yutetsu TAKATSUKASA
|
||||
Yu-Sheng Lin
|
||||
Yves Mathieu
|
||||
Zhanglei Wang
|
||||
Zixi Li
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. comment: generated by t_lint_width_docs_bad
|
||||
.. comment: generated by t_lint_widthexpand_docs_bad
|
||||
.. code-block:: sv
|
||||
:linenos:
|
||||
:emphasize-lines: 3
|
||||
@@ -1,4 +1,4 @@
|
||||
.. comment: generated by t_lint_width_docs_bad
|
||||
.. comment: generated by t_lint_widthexpand_docs_bad
|
||||
.. code-block:: sv
|
||||
:emphasize-lines: 1
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.. comment: generated by t_lint_widthexpand_docs_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-WIDTHEXPAND: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
|
||||
@@ -1,4 +0,0 @@
|
||||
.. comment: generated by t_lint_width_docs_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-WIDTH: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
|
||||
+13
-9
@@ -10,7 +10,6 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# -- Path setup
|
||||
|
||||
from datetime import datetime
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@@ -24,10 +23,18 @@ def get_vlt_version():
|
||||
filename = "../../Makefile"
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
for line in fh:
|
||||
match = re.search(r"PACKAGE_VERSION_NUMBER *= *([a-z0-9.]+)", line)
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)",
|
||||
line)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return "unknown"
|
||||
return match.group(1), match.group(2)
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line)
|
||||
if match:
|
||||
try:
|
||||
data = os.popen('git log -n 1 --pretty=%cs').read()
|
||||
except Exception:
|
||||
data = "" # fallback, and Sphinx will fill in today's date
|
||||
return "Devel " + match.group(1), data
|
||||
return "unknown", "unknown"
|
||||
|
||||
|
||||
def setup(app):
|
||||
@@ -44,8 +51,8 @@ author = 'Wilson Snyder'
|
||||
# The master toctree document.
|
||||
master_doc = "index"
|
||||
|
||||
version = get_vlt_version()
|
||||
release = get_vlt_version()
|
||||
version, today_fmt = get_vlt_version()
|
||||
release = version
|
||||
|
||||
rst_prolog = """
|
||||
.. role:: vlopt(option)
|
||||
@@ -89,9 +96,6 @@ source_suffix = [".rst"]
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# Date format to ISO
|
||||
today_fmt = datetime.now().strftime("%F")
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
|
||||
@@ -120,6 +120,15 @@ code. This is a feature, as using the SystemC pin interconnect scheme
|
||||
everywhere would reduce performance by an order of magnitude.
|
||||
|
||||
|
||||
Verilated API
|
||||
=============
|
||||
|
||||
The API to a Verilated model is the C++ headers in the include/ directory
|
||||
in the distribution. These headers use Doxygen comments, `///` and `//<`,
|
||||
to indicate and document those functions that are part of the Verilated
|
||||
public API.
|
||||
|
||||
|
||||
Direct Programming Interface (DPI)
|
||||
==================================
|
||||
|
||||
@@ -374,9 +383,11 @@ changed on the specified clock edge.
|
||||
.. code-block:: bash
|
||||
|
||||
cat >our.v <<'EOF'
|
||||
module our (input clk);
|
||||
reg readme /*verilator public_flat_rd*/;
|
||||
reg writeme /*verilator public_flat_rw @(posedge clk) */;
|
||||
module our #(
|
||||
parameter WIDTH /*verilator public_flat_rd*/ = 32
|
||||
) (input clk);
|
||||
reg [WIDTH-1:0] readme /*verilator public_flat_rd*/;
|
||||
reg [WIDTH-1:0] writeme /*verilator public_flat_rw @(posedge clk) */;
|
||||
initial $finish;
|
||||
endmodule
|
||||
EOF
|
||||
@@ -398,12 +409,14 @@ accesses the above signal "readme" would be:
|
||||
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
|
||||
if (!vh1) vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found");
|
||||
const char* name = vpi_get_str(vpiName, vh1);
|
||||
printf("Module name: %s\n", name); // Prints "readme"
|
||||
const char* type = vpi_get_str(vpiType, vh1);
|
||||
const int size = vpi_get(vpiSize, vh1);
|
||||
printf("register name: %s, type: %s, size: %d\n", name, type, size); // Prints "register name: readme, type: vpiReg, size: 32"
|
||||
|
||||
s_vpi_value v;
|
||||
v.format = vpiIntVal;
|
||||
vpi_get_value(vh1, &v);
|
||||
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
|
||||
printf("Value of %s: %d\n", name, v.value.integer); // Prints "Value of readme: 0"
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -479,11 +492,12 @@ distribution.
|
||||
Verilated and VerilatedContext
|
||||
==============================
|
||||
|
||||
Multiple Verilated models may be part of the same simulation context, that
|
||||
is share a VPI interface, sense of time, and common settings. This common
|
||||
simulation context information is stored in a ``VerilatedContext``
|
||||
Multiple C++ Verilated models may be part of the same simulation context,
|
||||
that is share a VPI interface, sense of time, and common settings. This
|
||||
common simulation context information is stored in a ``VerilatedContext``
|
||||
structure. If a ``VerilatedContext`` is not created prior to creating a
|
||||
model, a default global one is created automatically.
|
||||
model, a default global one is created automatically. SystemC requires
|
||||
using only the single, default VerilatedContext.
|
||||
|
||||
The ``Verilated::`` methods, including the ``Verilated::commandArgs`` call
|
||||
shown above, call VerilatedContext methods using the default global
|
||||
|
||||
@@ -22,10 +22,6 @@ Verilated_heavy.h
|
||||
"verilated.h". Verilated_heavy.h is planned for removal no sooner than
|
||||
July 2022.
|
||||
|
||||
Option `--cdc`
|
||||
The experimental `--cdc` option is believed to be generally unused and is
|
||||
planned for removal no sooner than January 2023.
|
||||
|
||||
Option `-O<letter>`
|
||||
The debug `-O<letter>` options have been replaced with
|
||||
`-fno-<optimization>` debug options to match GCC. The old options are
|
||||
|
||||
@@ -155,18 +155,6 @@ Summary:
|
||||
Specify C++ without SystemC output mode; see also the :vlopt:`--sc`
|
||||
option.
|
||||
|
||||
.. option:: --cdc
|
||||
|
||||
Permanently experimental. Perform some clock domain crossing checks and
|
||||
issue related warnings (CDCRSTLOGIC) and then exit; if warnings other
|
||||
than CDC warnings are needed, make a second run with
|
||||
:vlopt:`--lint-only`. Additional warning information is also written to
|
||||
the file :file:`<prefix>__cdc.txt`.
|
||||
|
||||
Currently only checks some items that other CDC tools missed; if you are
|
||||
interested in adding more traditional CDC checks, please contact the
|
||||
authors.
|
||||
|
||||
.. option:: -CFLAGS <flags>
|
||||
|
||||
Add specified C compiler argument to the generated makefiles. For
|
||||
@@ -434,7 +422,7 @@ Summary:
|
||||
Preprocess the source code, but do not compile, similar to C++
|
||||
preprocessing using :command:`gcc -E`. Output is written to standard
|
||||
out. Beware of enabling debugging messages, as they will also go to
|
||||
standard out.
|
||||
standard out. See :vlopt:`--no-std`, which is implied by this.
|
||||
|
||||
See also :vlopt:`--dump-defines`, :vlopt:`-P`, and
|
||||
:vlopt:`--pp-comments` options.
|
||||
@@ -707,9 +695,10 @@ Summary:
|
||||
.. option:: -j [<value>]
|
||||
|
||||
Specify the level of parallelism for :vlopt:`--build` if
|
||||
:vlopt:`--build-jobs` isn't provided. If zero, uses the number of threads
|
||||
in the current hardware. Otherwise, the <value> must be a positive
|
||||
integer specifying the maximum number of parallel build jobs.
|
||||
:vlopt:`--build-jobs` isn't provided, and the internal compilation steps
|
||||
of Verilator if :vlopt:`--verilate-jobs` isn't provided. If zero, uses
|
||||
the number of threads in the current hardware. Otherwise, must be a
|
||||
positive integer specifying the maximum number of parallel build jobs.
|
||||
|
||||
.. option:: --l2-name <value>
|
||||
|
||||
@@ -1112,6 +1101,18 @@ Summary:
|
||||
marking only those signals that need public_flat_rw is typically
|
||||
significantly better performing.
|
||||
|
||||
.. option:: --public-depth <level>
|
||||
|
||||
Enables public as with :vlopt:`--public-flat-rw`, but only to the specified depth of modules.
|
||||
It operates at the module maximum level, so if a module's cells are A.B.X and A.X, the
|
||||
a --public-depth 3 must be used to make module X public, and both A.B.X and A.X will be public.
|
||||
|
||||
.. option:: --public-params
|
||||
|
||||
Declares all parameters public as if they had
|
||||
:code:`/*verilator public_flat_rd*/`
|
||||
metacomments.
|
||||
|
||||
.. option:: -pvalue+<name>=<value>
|
||||
|
||||
Overwrites the given parameter(s) of the top-level module. See
|
||||
@@ -1201,6 +1202,10 @@ Summary:
|
||||
by size (plain :vlopt:`--stats` just gives a count). See
|
||||
:vlopt:`--stats`, which is implied by this.
|
||||
|
||||
.. option:: --no-std
|
||||
|
||||
Prevents parsing standard library.
|
||||
|
||||
.. option:: --structs-packed
|
||||
|
||||
Converts all unpacked structures to packed structures, and issues an
|
||||
@@ -1429,6 +1434,15 @@ Summary:
|
||||
execute only the build. This can be useful for rebuilding the Verilated code
|
||||
produced by a previous invocation of Verilator.
|
||||
|
||||
.. option:: --verilate-jobs [<value>]
|
||||
|
||||
Specify the level of parallelism for the internal compilation steps of
|
||||
Verilator. If zero, uses the number of threads in the current hardware.
|
||||
Otherwise, must be a positive integer specifying the maximum number of
|
||||
parallel build jobs.
|
||||
|
||||
See also :vlopt:`-j`.
|
||||
|
||||
.. option:: +verilog1995ext+<ext>
|
||||
|
||||
Synonym for :vlopt:`+1364-1995ext+\<ext\>`.
|
||||
@@ -1500,10 +1514,10 @@ Summary:
|
||||
.. option:: -Wno-lint
|
||||
|
||||
Disable all lint-related warning messages, and all style warnings. This is
|
||||
equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE
|
||||
equivalent to ``-Wno-ALWCOMBORDER -Wno-ASCRANGE -Wno-BSSPACE -Wno-CASEINCOMPLETE
|
||||
-Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS
|
||||
-Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-LITENDIAN -Wno-PINCONNECTEMPTY
|
||||
-Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
|
||||
-Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-PINCONNECTEMPTY
|
||||
-Wno-PINMISSING -Wno-STATICVAR -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
|
||||
-Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL
|
||||
-Wno-WIDTH`` plus the list shown for Wno-style.
|
||||
|
||||
@@ -1528,6 +1542,8 @@ Summary:
|
||||
:command:`gcc -Wpedantic`. Rarely used, and intended only for strict
|
||||
compliance tests.
|
||||
|
||||
This option changes :option:`ASSIGNIN` from an error to a warning.
|
||||
|
||||
.. option:: -Wwarn-<message>
|
||||
|
||||
Enables the specified warning message.
|
||||
@@ -1538,7 +1554,7 @@ Summary:
|
||||
enabled), but do not affect style messages. This is equivalent to
|
||||
``-Wwarn-ALWCOMBORDER -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE
|
||||
-Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CASEWITHX -Wwarn-CMPCONST
|
||||
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-LITENDIAN
|
||||
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-ASCRANGE
|
||||
-Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``.
|
||||
|
||||
.. option:: -Wwarn-style
|
||||
|
||||
@@ -6,10 +6,10 @@ verilator_coverage
|
||||
|
||||
Verilator_coverage processes Verilated model-generated coverage reports.
|
||||
|
||||
With --annotate, it reads the specified coverage data file and generates
|
||||
annotated source code with coverage metrics annotated. If multiple
|
||||
coverage points exist on the same source code line, additional lines will
|
||||
be inserted to report the additional points.
|
||||
With `--annotate`, it reads the specified coverage data file and generates
|
||||
annotated source code with coverage metrics annotated. With
|
||||
`--annotate-points` the coverage points corresponding to each line are also
|
||||
shown.
|
||||
|
||||
Additional Verilog-XL-style standard arguments specify the search paths
|
||||
necessary to find the source code on which the coverage analysis was
|
||||
@@ -58,6 +58,18 @@ to read multiple inputs. If no data file is specified, by default,
|
||||
Specifies the directory name to which source files with annotated coverage
|
||||
data should be written.
|
||||
|
||||
Converting from the Verilator coverage data format to the info format is
|
||||
lossy; the info will have all forms of coverage merged line coverage, and
|
||||
if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
|
||||
The first character of the line shows a summary of the coverage; this
|
||||
allows use of grep to filter the report. `%` indicates at least one point
|
||||
on the line was below the coverage limit. `+` indicates an
|
||||
:option:`--annotate-points` point was at or above the limit, and `-` that
|
||||
the point was below the limit.
|
||||
|
||||
.. option:: --annotate-all
|
||||
|
||||
Specifies all files should be shown. By default, only those source files
|
||||
@@ -70,6 +82,13 @@ coverage hits, then the coverage point will be considered above the
|
||||
threshold, and the coverage report will put a "%" to indicate the coverage
|
||||
is insufficient. Defaults to 10.
|
||||
|
||||
.. option:: --annotate-points
|
||||
|
||||
Specifies all coverage points should be shown after each line of text. By
|
||||
default, only source lines are shown.
|
||||
|
||||
with low coverage are written to the output directory.
|
||||
|
||||
.. option:: --help
|
||||
|
||||
Displays a help summary, the program version, and exits.
|
||||
|
||||
@@ -446,6 +446,33 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
Same as :option:`public_flat_rw` configuration file option.
|
||||
|
||||
.. option:: /*verilator&32;public_[|flat|flat_rd|flat_rw]_on [@(<edge_list>)]*/ (as scope)
|
||||
|
||||
Used to wrap multiple signals and parameters with the respective public attribute.
|
||||
See attribute above for their respective behavior. Cannot be nested. e.g:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
/*verilator public_flat_rw_on*/
|
||||
logic clk;
|
||||
logic rst;
|
||||
parameter width = 8;
|
||||
/* verilator public_off*/
|
||||
logic data;
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
logic clk /*verilator public_flat_rw*/;
|
||||
logic rst /*verilator public_flat_rw*/;
|
||||
parameter width /*verilator public_flat_rw*/ = 8;
|
||||
logic data;
|
||||
|
||||
.. option:: /*verilator&32;public_off*/
|
||||
|
||||
Terminates the previous `/*verilator public*_on*/` directive; see above.
|
||||
|
||||
.. option:: /*verilator&32;public_module*/
|
||||
|
||||
Used after a module statement to indicate the module should not be
|
||||
|
||||
@@ -461,6 +461,10 @@ chandle
|
||||
Treated as a "longint"; does not yet warn about operations specified as
|
||||
illegal on chandles.
|
||||
|
||||
checker
|
||||
Treated as a "module"; does not yet warn about many constructs illegal
|
||||
inside a checker.
|
||||
|
||||
disable
|
||||
Disable statements may be used only if the block being disabled is a
|
||||
block the disable statement itself is inside. This was commonly used to
|
||||
|
||||
@@ -498,3 +498,20 @@ Clang. The process in GCC 10 was as follows:
|
||||
Clang and GCC also support -fauto-profile, which uses sample-based
|
||||
feedback-directed optimization. See the appropriate compiler
|
||||
documentation.
|
||||
|
||||
|
||||
.. _Runtime Debugging
|
||||
|
||||
Runtime Debugging
|
||||
=================
|
||||
|
||||
To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a
|
||||
similar tool. Typically you will want to have debugger symbols inserted by
|
||||
the compiler, assertions enabled in the C library, and assertions enabled
|
||||
in the Verilated library. (These options slow down the executable, so do
|
||||
this only when debugging.) To enable this, Verilate with:
|
||||
|
||||
-CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG
|
||||
|
||||
The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options pass arguments
|
||||
directly to the compiler or linker.
|
||||
|
||||
+66
-21
@@ -74,7 +74,8 @@ List Of Warnings
|
||||
.. option:: Unsupported: ....
|
||||
|
||||
This error indicates that the code uses a Verilog language construct
|
||||
that is not yet supported in Verilator. See the Limitations chapter.
|
||||
that is not yet supported in Verilator. See also :ref:`Language
|
||||
Limitations`.
|
||||
|
||||
|
||||
.. option:: ALWCOMBORDER
|
||||
@@ -96,6 +97,24 @@ List Of Warnings
|
||||
simulate correctly.
|
||||
|
||||
|
||||
.. option:: ASCRANGE
|
||||
|
||||
.. TODO better example
|
||||
|
||||
Warns that a packed vector is declared with ascending bit range
|
||||
(i.e. [0:7]). Descending bit range is now the overwhelming standard,
|
||||
and ascending ranges are now thus often due to simple oversight
|
||||
instead of intent (a notable exception is the OpenPOWER code base).
|
||||
|
||||
It also warns that an instance is declared with ascending range
|
||||
(i.e. [0:7] or [7]) and is connected to an N-wide signal.
|
||||
The bits will likely be in the reversed order from what people may expect
|
||||
(i.e., instance [0] will connect to signal bit [N-1] not bit [0]).
|
||||
|
||||
Ignoring this warning will only suppress the lint check; it will
|
||||
simulate correctly.
|
||||
|
||||
|
||||
.. option:: ASSIGNDLY
|
||||
|
||||
.. TODO better example
|
||||
@@ -317,9 +336,11 @@ List Of Warnings
|
||||
|
||||
.. option:: CDCRSTLOGIC
|
||||
|
||||
With :vlopt:`--cdc` only, it warns that asynchronous flop reset terms come
|
||||
from other than primary inputs or flopped outputs, creating the
|
||||
potential for reset glitches.
|
||||
Historical, never issued since version 5.008.
|
||||
|
||||
Warned with a no longer supported clock domain crossing option that
|
||||
asynchronous flop reset terms came from other than primary inputs or
|
||||
flopped outputs, creating the potential for reset glitches.
|
||||
|
||||
|
||||
.. option:: CLKDATA
|
||||
@@ -375,6 +396,16 @@ List Of Warnings
|
||||
simulators.
|
||||
|
||||
|
||||
.. option:: CONSTRAINTIGN
|
||||
|
||||
Warns that Verilator does not support :code:`constraint`,
|
||||
:code:`constraint_mode`, or :code:`rand_mode`, and the construct was are
|
||||
ignored.
|
||||
|
||||
Ignoring this warning may make Verilator randomize() simulations differ
|
||||
from other simulators.
|
||||
|
||||
|
||||
.. option:: CONTASSREG
|
||||
|
||||
.. TODO better example
|
||||
@@ -735,7 +766,7 @@ List Of Warnings
|
||||
|
||||
This is a warning because the static default differs from C++, differs
|
||||
from class member function/tasks. Static is a more dangerous default
|
||||
then automatic as static prevents the function from being reinterant,
|
||||
then automatic as static prevents the function from being reentrant,
|
||||
which may be a source of bugs, and/or performance issues.
|
||||
|
||||
If the function does not require static behavior, change it to "function
|
||||
@@ -847,18 +878,10 @@ List Of Warnings
|
||||
|
||||
.. TODO better example
|
||||
|
||||
Warns that a packed vector is declared with little endian bit numbering
|
||||
(i.e. [0:7]). Big endian bit numbering is now the overwhelming
|
||||
standard, and little numbering is now thus often due to simple oversight
|
||||
instead of intent.
|
||||
|
||||
It also warns that an instance is declared with little endian range
|
||||
(i.e. [0:7] or [7]) and is connected to an N-wide signal. Based on IEEE
|
||||
the bits will likely be backward from what people may expect
|
||||
(i.e., instance [0] will connect to signal bit [N-1] not bit [0]).
|
||||
|
||||
Ignoring this warning will only suppress the lint check; it will
|
||||
simulate correctly.
|
||||
The naming of this warning is in contradiction with the common
|
||||
interpretation of little endian. It was therefore renamed to
|
||||
:option:`ASCRANGE`. While :option:`LITENDIAN` remains for
|
||||
backwards compatibility, new projects should use :option:`ASCRANGE`.
|
||||
|
||||
|
||||
.. option:: MINTYPMAX
|
||||
@@ -1299,6 +1322,17 @@ List Of Warnings
|
||||
* The variable is tristate or bidirectional. (e.g., :code:`inout`).
|
||||
|
||||
|
||||
.. option:: STATICVAR
|
||||
|
||||
Warns that a static variable declared in a loop with declaration assignment
|
||||
was converted to automatic. Often such variables were intended to
|
||||
instead be declared "automatic".
|
||||
|
||||
Ignoring this warning may make Verilator differ from other simulators,
|
||||
which will treat the variable as static. Verilator may in future versions also
|
||||
treat the variable as static.
|
||||
|
||||
|
||||
.. option:: STMTDLY
|
||||
|
||||
Warns that the code has a statement with a delayed time in front of it.
|
||||
@@ -1790,16 +1824,27 @@ List Of Warnings
|
||||
|
||||
For example, this is a missized index:
|
||||
|
||||
.. include:: ../../docs/gen/ex_WIDTH_1_faulty.rst
|
||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_faulty.rst
|
||||
|
||||
Results in:
|
||||
Results in a WIDTHEXPAND warning:
|
||||
|
||||
.. include:: ../../docs/gen/ex_WIDTH_1_msg.rst
|
||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_msg.rst
|
||||
|
||||
One possible fix:
|
||||
|
||||
.. include:: ../../docs/gen/ex_WIDTH_1_fixed.rst
|
||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst
|
||||
|
||||
.. option:: WIDTHTRUNC
|
||||
|
||||
A more granular WIDTH warning, for when a value is truncated
|
||||
|
||||
.. option:: WIDTHEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is zero expanded
|
||||
|
||||
.. option:: WIDTHXZEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is X/Z expanded
|
||||
|
||||
.. option:: WIDTHCONCAT
|
||||
|
||||
|
||||
+6
-14
@@ -628,16 +628,12 @@ coroutines ``co_await`` its ``join`` function, and forked ones call ``done``
|
||||
when they're finished. Once the required number of coroutines (set using
|
||||
``setCounter``) finish execution, the forking coroutine is resumed.
|
||||
|
||||
Awaitable Utilities
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
``VlForever``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
There are also two small utility awaitable types:
|
||||
|
||||
* ``VlNow`` is an awaitable that suspends and immediately resumes coroutines.
|
||||
It is used for forcing a coroutine to be moved onto the heap. See the `Forks`
|
||||
section for more detail.
|
||||
* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass`
|
||||
section for more detail.
|
||||
A small utility awaitable type. It allows for blocking a coroutine forever. It
|
||||
is currently only used for ``wait`` statements that await a constant false
|
||||
condition. See the `Timing Pass` section for more details.
|
||||
|
||||
Timing Pass
|
||||
~~~~~~~~~~~
|
||||
@@ -749,9 +745,7 @@ doesn't suspend the forking process.
|
||||
|
||||
In forked processes, references to local variables are only allowed in
|
||||
``fork..join``, as this is the only case that ensures the lifetime of these
|
||||
locals are at least as long as the execution of the forked processes. This is
|
||||
where ``VlNow`` is used, to ensure the locals are moved to the heap before they
|
||||
are passed by reference to the forked processes.
|
||||
locals are at least as long as the execution of the forked processes.
|
||||
|
||||
|
||||
Multithreaded Mode
|
||||
@@ -1807,8 +1801,6 @@ IEEE 1800-2017 6.12 "shortreal"
|
||||
Little/no tool support, and easily promoted to real.
|
||||
IEEE 1800-2017 11.11 Min, typ, max
|
||||
No SDF support, so will always use typical.
|
||||
IEEE 1800-2017 11.12 "let"
|
||||
Little/no tool support, makes it difficult to implement parsers.
|
||||
IEEE 1800-2017 20.16 Stochastic analysis
|
||||
Little industry use.
|
||||
IEEE 1800-2017 20.17 PLA modeling
|
||||
|
||||
+28
-1
@@ -6,6 +6,7 @@ Alexandre
|
||||
Ami
|
||||
Amir
|
||||
Anastasiadis
|
||||
Anglin
|
||||
Anikin
|
||||
Antmicro
|
||||
Antonin
|
||||
@@ -42,6 +43,8 @@ Chandan
|
||||
Chitlesh
|
||||
Christophe
|
||||
Cochrane
|
||||
Conda
|
||||
Corteggiani
|
||||
Cuan
|
||||
Cygwin
|
||||
DErrico
|
||||
@@ -96,6 +99,7 @@ Fredieu
|
||||
GTKWave
|
||||
Galbi
|
||||
Gantt
|
||||
Garnal
|
||||
Gartner
|
||||
Gelinek
|
||||
Geoff
|
||||
@@ -188,6 +192,7 @@ Laurens
|
||||
Lavino
|
||||
Leber
|
||||
Leendert
|
||||
Lem
|
||||
Lesik
|
||||
Liland
|
||||
Liu
|
||||
@@ -207,6 +212,7 @@ Matveyenko
|
||||
Maupin
|
||||
Mdir
|
||||
Mednick
|
||||
Menküc
|
||||
Michiels
|
||||
Microsystems
|
||||
Milanovic
|
||||
@@ -223,8 +229,10 @@ Muhlestein
|
||||
Multithreaded
|
||||
Multithreading
|
||||
NOUNOPTFLAT
|
||||
NaN
|
||||
Nalbantis
|
||||
Narayan
|
||||
Nassim
|
||||
Nauticus
|
||||
Newgard
|
||||
Nigam
|
||||
@@ -295,6 +303,7 @@ Solomatnikov
|
||||
Solt
|
||||
Southwell
|
||||
Srini
|
||||
Srinivasan
|
||||
Stamness
|
||||
Stephane
|
||||
Stoddard
|
||||
@@ -319,6 +328,7 @@ Thiede
|
||||
Thierry
|
||||
Thyer
|
||||
Tichelaar
|
||||
Timi
|
||||
Tomov
|
||||
Tood
|
||||
Topa
|
||||
@@ -343,6 +353,7 @@ Vdeeptemp
|
||||
Vdly
|
||||
Vemumtab
|
||||
Vemuri
|
||||
Venkataramanan
|
||||
Veriable
|
||||
Verialted
|
||||
Verilate
|
||||
@@ -353,6 +364,7 @@ Verilator
|
||||
Verilog
|
||||
Vighnesh
|
||||
Viktor
|
||||
Vilp
|
||||
Vm
|
||||
Vukobratovic
|
||||
Wai
|
||||
@@ -376,6 +388,7 @@ Xuan
|
||||
Xuanqi
|
||||
Yazdanbakhsh
|
||||
Yi
|
||||
Yike
|
||||
Yinan
|
||||
Yosys
|
||||
Yu
|
||||
@@ -452,6 +465,7 @@ commandArgsPlusMatch
|
||||
compilable
|
||||
concat
|
||||
concats
|
||||
conf
|
||||
config
|
||||
const
|
||||
constexpr
|
||||
@@ -512,6 +526,7 @@ dumpportson
|
||||
dumpvars
|
||||
dut
|
||||
dx
|
||||
dynarray
|
||||
elab
|
||||
elike
|
||||
elsif
|
||||
@@ -520,6 +535,7 @@ endcelldefine
|
||||
endfunction
|
||||
endgenerate
|
||||
endian
|
||||
endianness
|
||||
endif
|
||||
endmodule
|
||||
endprotect
|
||||
@@ -541,6 +557,7 @@ exe
|
||||
executables
|
||||
expr
|
||||
extern
|
||||
ezchi
|
||||
fanin
|
||||
fasttrace
|
||||
fauto
|
||||
@@ -635,6 +652,7 @@ lcov
|
||||
ld
|
||||
leavinel
|
||||
len
|
||||
libc
|
||||
libext
|
||||
libgoogle
|
||||
libsystemc
|
||||
@@ -653,7 +671,9 @@ logicals
|
||||
longint
|
||||
lossy
|
||||
lsb
|
||||
lubc
|
||||
lvalue
|
||||
lvalues
|
||||
lxt
|
||||
macromodule
|
||||
makefile
|
||||
@@ -678,12 +698,15 @@ mtasks
|
||||
mulithreaded
|
||||
mult
|
||||
multidim
|
||||
multidriven
|
||||
multiinterfaces
|
||||
multiline
|
||||
multipling
|
||||
multipoint
|
||||
multithread
|
||||
multithreaded
|
||||
multithreading
|
||||
musl
|
||||
mutexes
|
||||
mux
|
||||
myftptoyman
|
||||
@@ -714,6 +737,7 @@ ortegon
|
||||
oversubscription
|
||||
parallelized
|
||||
param
|
||||
parameterization
|
||||
parameterized
|
||||
params
|
||||
parens
|
||||
@@ -762,6 +786,7 @@ pulldowns
|
||||
pullup
|
||||
pvalue
|
||||
pwd
|
||||
py
|
||||
qrq
|
||||
radix
|
||||
randc
|
||||
@@ -807,6 +832,7 @@ specparam
|
||||
splitme
|
||||
spp
|
||||
sqrt
|
||||
srandom
|
||||
src
|
||||
srcdir
|
||||
srcfile
|
||||
@@ -838,6 +864,7 @@ svdpi
|
||||
swrite
|
||||
sys
|
||||
systemc
|
||||
tenghtt
|
||||
testbench
|
||||
threadsafe
|
||||
threashold
|
||||
@@ -909,6 +936,7 @@ vlt
|
||||
vltstd
|
||||
vluint
|
||||
vpi
|
||||
vpiDefName
|
||||
vpiLeftRange
|
||||
vpiModule
|
||||
vpiSize
|
||||
@@ -938,4 +966,3 @@ ypq
|
||||
yurivict
|
||||
zdave
|
||||
Øyvind
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
# cmake ..
|
||||
# cmake --build .
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_hello_c)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
# cmake ..
|
||||
# cmake --build .
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_hello_sc CXX)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
# cmake ..
|
||||
# cmake --build .
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_protect_lib)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
# cmake ..
|
||||
# cmake --build .
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_tracing_c)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
# cmake ..
|
||||
# cmake --build .
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
|
||||
project(cmake_tracing_sc_example CXX)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//======================================================================
|
||||
|
||||
// SystemC global header
|
||||
#include <systemc.h>
|
||||
#include <systemc>
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
@@ -15,6 +15,8 @@
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
using namespace sc_core;
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// See a similar example walkthrough in the verilator manpage.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ CPPFLAGS += -DVL_DEBUG=1
|
||||
# Turn on some more compiler lint flags (when configured appropriately)
|
||||
# For testing inside Verilator, "configure --enable-ccwarn" will do this
|
||||
# automatically; otherwise you may want this unconditionally enabled
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
USER_CPPFLAGS_WALL += -W -Werror -Wall
|
||||
endif
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ CPPFLAGS += -Wno-deprecated
|
||||
# Turn on some more flags (when configured appropriately)
|
||||
# For testing inside Verilator, "configure --enable-ccwarn" will do this
|
||||
# automatically; otherwise you may want this unconditionally enabled
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
USER_CPPFLAGS_WALL += -W -Werror -Wall
|
||||
endif
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <memory>
|
||||
|
||||
// SystemC global header
|
||||
#include <systemc.h>
|
||||
#include <systemc>
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
@@ -23,6 +23,8 @@
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
using namespace sc_core;
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||
|
||||
|
||||
+42
-50
@@ -58,6 +58,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
@@ -131,7 +132,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
||||
#define FST_GZIO_LEN (32768)
|
||||
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) || defined(__aarch64__)
|
||||
#define FST_DO_MISALIGNED_OPS
|
||||
#endif
|
||||
|
||||
@@ -334,26 +335,22 @@ return(NULL);
|
||||
/*
|
||||
* mmap compatibility
|
||||
*/
|
||||
#if defined __CYGWIN__ || defined __MINGW32__
|
||||
#if defined __MINGW32__
|
||||
#include <limits.h>
|
||||
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
||||
#define fstMunmap(__addr,__len) free(__addr)
|
||||
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
|
||||
|
||||
static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
|
||||
{
|
||||
(void)__off;
|
||||
HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL,
|
||||
PAGE_READWRITE, (DWORD)(__len >> 32),
|
||||
(DWORD)__len, NULL);
|
||||
if (!handle) { return NULL; }
|
||||
|
||||
unsigned char *pnt = (unsigned char *)malloc(__len);
|
||||
fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
|
||||
size_t i;
|
||||
|
||||
lseek(__fd, 0, SEEK_SET);
|
||||
for(i=0;i<__len;i+=SSIZE_MAX)
|
||||
{
|
||||
read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
|
||||
}
|
||||
lseek(__fd, cur_offs, SEEK_SET);
|
||||
return(pnt);
|
||||
void *ptr = MapViewOfFileEx(handle, FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
0, (DWORD)__off, (SIZE_T)__len, (LPVOID)NULL);
|
||||
CloseHandle(handle);
|
||||
return ptr;
|
||||
}
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
@@ -984,14 +981,26 @@ fflush(xc->handle);
|
||||
*/
|
||||
static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage)
|
||||
{
|
||||
#if !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||
if(pnt == MAP_FAILED)
|
||||
if(pnt == NULL
|
||||
#ifdef MAP_FAILED
|
||||
|| pnt == MAP_FAILED
|
||||
#endif
|
||||
)
|
||||
{
|
||||
fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
|
||||
#if !defined(__MINGW32__)
|
||||
perror("Why");
|
||||
#else
|
||||
LPSTR mbuf = NULL;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&mbuf, 0, NULL);
|
||||
fprintf(stderr, "%s", mbuf);
|
||||
LocalFree(mbuf);
|
||||
#endif
|
||||
pnt = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1037,34 +1046,11 @@ if(!xc->curval_mem)
|
||||
|
||||
static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
|
||||
{
|
||||
#if !defined __CYGWIN__ && !defined __MINGW32__
|
||||
(void)is_closing;
|
||||
#endif
|
||||
|
||||
fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
|
||||
xc->valpos_mem = NULL;
|
||||
|
||||
#if defined __CYGWIN__ || defined __MINGW32__
|
||||
if(xc->curval_mem)
|
||||
{
|
||||
if(!is_closing) /* need to flush out for next emulated mmap() read */
|
||||
{
|
||||
unsigned char *pnt = xc->curval_mem;
|
||||
int __fd = fileno(xc->curval_handle);
|
||||
fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
|
||||
size_t i;
|
||||
size_t __len = xc->maxvalpos;
|
||||
|
||||
lseek(__fd, 0, SEEK_SET);
|
||||
for(i=0;i<__len;i+=SSIZE_MAX)
|
||||
{
|
||||
write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
|
||||
}
|
||||
lseek(__fd, cur_offs, SEEK_SET);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fstMunmap(xc->curval_mem, xc->maxvalpos);
|
||||
xc->curval_mem = NULL;
|
||||
}
|
||||
@@ -3412,6 +3398,7 @@ int flat_hier_alloc_len;
|
||||
unsigned do_rewind : 1;
|
||||
char str_scope_nam[FST_ID_NAM_SIZ+1];
|
||||
char str_scope_comp[FST_ID_NAM_SIZ+1];
|
||||
char *str_scope_attr;
|
||||
|
||||
unsigned fseek_failed : 1;
|
||||
|
||||
@@ -4140,7 +4127,7 @@ if(!(isfeof=feof(xc->fh)))
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
@@ -4152,7 +4139,7 @@ if(!(isfeof=feof(xc->fh)))
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
@@ -4169,15 +4156,19 @@ if(!(isfeof=feof(xc->fh)))
|
||||
xc->hier.htyp = FST_HT_ATTRBEGIN;
|
||||
xc->hier.u.attr.typ = fgetc(xc->fh);
|
||||
xc->hier.u.attr.subtype = fgetc(xc->fh);
|
||||
xc->hier.u.attr.name = pnt = xc->str_scope_nam;
|
||||
if(!xc->str_scope_attr)
|
||||
{
|
||||
xc->str_scope_attr = (char *)calloc(1, FST_ID_NAM_ATTR_SIZ+1);
|
||||
}
|
||||
xc->hier.u.attr.name = pnt = xc->str_scope_attr;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* scopename */
|
||||
}; /* attrname */
|
||||
pnt[cl] = 0;
|
||||
xc->hier.u.attr.name_length = cl;
|
||||
|
||||
@@ -4237,7 +4228,7 @@ if(!(isfeof=feof(xc->fh)))
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
if(cl < FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
@@ -4376,7 +4367,7 @@ while(!feof(xc->fh))
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
@@ -4398,7 +4389,7 @@ while(!feof(xc->fh))
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
@@ -4487,7 +4478,7 @@ while(!feof(xc->fh))
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
if(cl < FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
@@ -4974,6 +4965,7 @@ if(xc)
|
||||
free(xc->signal_typs); xc->signal_typs = NULL;
|
||||
free(xc->signal_lens); xc->signal_lens = NULL;
|
||||
free(xc->filename); xc->filename = NULL;
|
||||
free(xc->str_scope_attr); xc->str_scope_attr = NULL;
|
||||
|
||||
if(xc->fh)
|
||||
{
|
||||
|
||||
+118
-37
@@ -232,9 +232,9 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
|
||||
char* const bufp = new char[len + 1];
|
||||
VL_VSNPRINTF(bufp, len + 1, formatp, ap);
|
||||
|
||||
std::string out{bufp, len}; // Not const to allow move optimization
|
||||
std::string result{bufp, len}; // Not const to allow move optimization
|
||||
delete[] bufp;
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t _vl_dbg_sequence_number() VL_MT_SAFE {
|
||||
@@ -255,30 +255,76 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
|
||||
// includes that otherwise would be required in every Verilated module
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
const std::string out = _vl_string_vprintf(formatp, ap);
|
||||
const std::string result = _vl_string_vprintf(formatp, ap);
|
||||
va_end(ap);
|
||||
// printf("-imm-V{t%d,%" PRId64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(),
|
||||
// out.c_str());
|
||||
// result.c_str());
|
||||
|
||||
// Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF
|
||||
// from within the guts of the thread execution machinery (and it goes
|
||||
// to the screen and not into the queues we're debugging)
|
||||
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
|
||||
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), result.c_str());
|
||||
}
|
||||
|
||||
void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
|
||||
va_list ap;
|
||||
va_start(ap, formatp);
|
||||
const std::string out = _vl_string_vprintf(formatp, ap);
|
||||
const std::string result = _vl_string_vprintf(formatp, ap);
|
||||
va_end(ap);
|
||||
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
||||
VL_PRINTF("%s", out.c_str());
|
||||
VL_PRINTF("%s", result.c_str());
|
||||
}});
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Random -- Mostly called at init time, so not inline.
|
||||
|
||||
VlRNG::VlRNG() VL_MT_SAFE {
|
||||
// Starting point for this new class comes from the global RNG
|
||||
VlRNG& fromr = vl_thread_rng();
|
||||
m_state = fromr.m_state;
|
||||
// Advance the *source* so it can later generate a new number
|
||||
// Xoroshiro128+ algorithm
|
||||
fromr.m_state[1] ^= fromr.m_state[0];
|
||||
fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1]
|
||||
^ (fromr.m_state[1] << 14));
|
||||
fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28);
|
||||
}
|
||||
uint64_t VlRNG::rand64() VL_MT_UNSAFE {
|
||||
// Xoroshiro128+ algorithm
|
||||
const uint64_t result = m_state[0] + m_state[1];
|
||||
m_state[1] ^= m_state[0];
|
||||
m_state[0] = (((m_state[0] << 55) | (m_state[0] >> 9)) ^ m_state[1] ^ (m_state[1] << 14));
|
||||
m_state[1] = (m_state[1] << 36) | (m_state[1] >> 28);
|
||||
return result;
|
||||
}
|
||||
uint64_t VlRNG::vl_thread_rng_rand64() VL_MT_SAFE {
|
||||
VlRNG& fromr = vl_thread_rng();
|
||||
const uint64_t result = fromr.m_state[0] + fromr.m_state[1];
|
||||
fromr.m_state[1] ^= fromr.m_state[0];
|
||||
fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1]
|
||||
^ (fromr.m_state[1] << 14));
|
||||
fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28);
|
||||
return result;
|
||||
}
|
||||
void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE {
|
||||
m_state[0] = n;
|
||||
m_state[1] = m_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(m_state[0]) < 10) m_state[0] = ~m_state[0];
|
||||
if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1];
|
||||
}
|
||||
// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
|
||||
// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) {
|
||||
// Unused: memcpy(m_state, state.data(), sizeof(m_state));
|
||||
// Unused: }
|
||||
// Unused: }
|
||||
// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
|
||||
// Unused: std::string result{reinterpret_cast<const char *>(&m_state), sizeof(m_state)};
|
||||
// Unused: return result;
|
||||
// Unused: }
|
||||
|
||||
static uint32_t vl_sys_rand32() VL_MT_SAFE {
|
||||
// Return random 32-bits using system library.
|
||||
// Used only to construct seed for Verilator's PRNG.
|
||||
@@ -292,27 +338,23 @@ static uint32_t vl_sys_rand32() VL_MT_SAFE {
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t vl_rand64() VL_MT_SAFE {
|
||||
static thread_local uint64_t t_state[2];
|
||||
VlRNG& VlRNG::vl_thread_rng() VL_MT_SAFE {
|
||||
static thread_local VlRNG t_rng{0};
|
||||
static thread_local uint32_t t_seedEpoch = 0;
|
||||
// For speed, we use a thread-local epoch number to know when to reseed
|
||||
// A thread always belongs to a single context, so this works out ok
|
||||
if (VL_UNLIKELY(t_seedEpoch != VerilatedContextImp::randSeedEpoch())) {
|
||||
// Set epoch before state, to avoid race case with new seeding
|
||||
t_seedEpoch = VerilatedContextImp::randSeedEpoch();
|
||||
t_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64();
|
||||
t_state[1] = t_state[0];
|
||||
// Same as srandom() but here as needs to be VL_MT_SAFE
|
||||
t_rng.m_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64();
|
||||
t_rng.m_state[1] = t_rng.m_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];
|
||||
if (VL_COUNTONES_I(t_rng.m_state[0]) < 10) t_rng.m_state[0] = ~t_rng.m_state[0];
|
||||
if (VL_COUNTONES_I(t_rng.m_state[1]) < 10) t_rng.m_state[1] = ~t_rng.m_state[1];
|
||||
}
|
||||
// Xoroshiro128+ algorithm
|
||||
const uint64_t result = t_state[0] + t_state[1];
|
||||
t_state[1] ^= t_state[0];
|
||||
t_state[0] = (((t_state[0] << 55) | (t_state[0] >> 9)) ^ t_state[1] ^ (t_state[1] << 14));
|
||||
t_state[1] = (t_state[1] << 36) | (t_state[1] >> 28);
|
||||
return result;
|
||||
return t_rng;
|
||||
}
|
||||
|
||||
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
@@ -321,6 +363,12 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
return outwp;
|
||||
}
|
||||
|
||||
WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = rngr.rand64();
|
||||
// Last word is unclean
|
||||
return outwp;
|
||||
}
|
||||
|
||||
IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE {
|
||||
// $random - seed is a new seed to apply, then we return new seed
|
||||
Verilated::threadContextp()->randSeed(static_cast<int>(seedr));
|
||||
@@ -518,12 +566,12 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE
|
||||
// Skip check for rhs == 0, as short-circuit doesn't save time
|
||||
if (VL_UNLIKELY(lhs == 0)) return 0;
|
||||
QData power = lhs;
|
||||
QData out = 1ULL;
|
||||
QData result = 1ULL;
|
||||
for (int bit = 0; bit < rbits; ++bit) {
|
||||
if (bit > 0) power = power * power;
|
||||
if (VL_BITISSET_W(rwp, bit)) out *= power;
|
||||
if (VL_BITISSET_W(rwp, bit)) result *= power;
|
||||
}
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
|
||||
@@ -645,7 +693,7 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) {
|
||||
std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) VL_MT_SAFE {
|
||||
const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp();
|
||||
const std::string suffix = ctxImpp->timeFormatSuffix();
|
||||
const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15
|
||||
@@ -1411,6 +1459,12 @@ IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
|
||||
outputr = std::string{::std::strerror(ret)};
|
||||
return ret;
|
||||
}
|
||||
IData VL_FERROR_IW(IData fpi, int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
std::string output;
|
||||
const IData ret = VL_FERROR_IN(fpi, output /*ref*/);
|
||||
_vl_string_to_vint(obits, outwp, output.length(), output.c_str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) {
|
||||
return Verilated::threadContextp()->impp()->fdNew(filename.c_str(), mode.c_str());
|
||||
@@ -1645,15 +1699,15 @@ std::string VL_STACKTRACE_N() VL_MT_SAFE {
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (!strings) return "Unable to backtrace\n";
|
||||
|
||||
std::string out = "Backtrace:\n";
|
||||
for (int j = 0; j < nptrs; j++) out += std::string{strings[j]} + std::string{"\n"};
|
||||
std::string result = "Backtrace:\n";
|
||||
for (int j = 0; j < nptrs; j++) result += std::string{strings[j]} + std::string{"\n"};
|
||||
free(strings);
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
void VL_STACKTRACE() VL_MT_SAFE {
|
||||
const std::string out = VL_STACKTRACE_N();
|
||||
VL_PRINTF("%s", out.c_str());
|
||||
const std::string result = VL_STACKTRACE_N();
|
||||
VL_PRINTF("%s", result.c_str());
|
||||
}
|
||||
|
||||
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
||||
@@ -1793,19 +1847,20 @@ std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_NX("'h%0x", 8, lhs); }
|
||||
std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_NX("'h%0x", 16, lhs); }
|
||||
std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_NX("'h%0x", 32, lhs); }
|
||||
std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_NX("'h%0x", 64, lhs); }
|
||||
std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_NX("%d", 64, lhs); }
|
||||
std::string VL_TO_STRING_W(int words, const WDataInP obj) {
|
||||
return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj);
|
||||
}
|
||||
|
||||
std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE {
|
||||
std::string out = ld;
|
||||
for (auto& cr : out) cr = std::tolower(cr);
|
||||
return out;
|
||||
std::string result = ld;
|
||||
for (auto& cr : result) cr = std::tolower(cr);
|
||||
return result;
|
||||
}
|
||||
std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE {
|
||||
std::string out = ld;
|
||||
for (auto& cr : out) cr = std::toupper(cr);
|
||||
return out;
|
||||
std::string result = ld;
|
||||
for (auto& cr : result) cr = std::toupper(cr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
|
||||
@@ -1861,6 +1916,32 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
|
||||
if (errno != 0) v = 0;
|
||||
return static_cast<IData>(v);
|
||||
}
|
||||
IData VL_NTOI_I(int obits, const std::string& str) VL_PURE { return VL_NTOI_Q(obits, str); }
|
||||
QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE {
|
||||
QData out = 0;
|
||||
const char* const datap = str.data();
|
||||
int pos = static_cast<int>(str.length()) - 1;
|
||||
int bit = 0;
|
||||
while (bit < obits && pos >= 0) {
|
||||
out |= static_cast<QData>(datap[pos]) << VL_BITBIT_Q(bit);
|
||||
bit += 8;
|
||||
--pos;
|
||||
}
|
||||
return out & VL_MASK_Q(obits);
|
||||
}
|
||||
void VL_NTOI_W(int obits, WDataOutP owp, const std::string& str) VL_PURE {
|
||||
const int words = VL_WORDS_I(obits);
|
||||
for (int i = 0; i < words; ++i) owp[i] = 0;
|
||||
const char* const datap = str.data();
|
||||
int pos = static_cast<int>(str.length()) - 1;
|
||||
int bit = 0;
|
||||
while (bit < obits && pos >= 0) {
|
||||
owp[VL_BITWORD_I(bit)] |= static_cast<EData>(datap[pos]) << VL_BITBIT_I(bit);
|
||||
bit += 8;
|
||||
--pos;
|
||||
}
|
||||
owp[words - 1] &= VL_MASK_E(obits);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Readmem/writemem
|
||||
@@ -2948,7 +3029,7 @@ VerilatedModule::~VerilatedModule() {
|
||||
// VerilatedVar:: Methods
|
||||
|
||||
// cppcheck-suppress unusedFunction // Used by applications
|
||||
uint32_t VerilatedVarProps::entSize() const {
|
||||
uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
||||
uint32_t size = 1;
|
||||
switch (vltype()) {
|
||||
case VLVT_PTR: size = sizeof(void*); break;
|
||||
@@ -2968,7 +3049,7 @@ size_t VerilatedVarProps::totalSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
|
||||
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
|
||||
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
|
||||
const int indxAdj = indx - low(dim);
|
||||
@@ -3087,7 +3168,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFindError(int funcnum) const {
|
||||
void* VerilatedScope::exportFindError(int funcnum) const VL_MT_SAFE {
|
||||
// Slowpath - Called only when find has failed
|
||||
const std::string msg
|
||||
= (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum)
|
||||
|
||||
+50
-10
@@ -30,6 +30,13 @@
|
||||
#ifndef VERILATOR_VERILATED_H_
|
||||
#define VERILATOR_VERILATED_H_
|
||||
#define VERILATOR_VERILATED_H_INTERNAL_
|
||||
#ifdef VERILATOR_INTERNAL_
|
||||
// This file contains definition of VerilationMutex that should
|
||||
// only be used by verilated code. Verilator itself should use
|
||||
// mutex from V3Mutex.h. Make sure this file isn't included in
|
||||
// verilator code.
|
||||
#error "verilated.h should only be included in verilated code"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
#include "verilatedos.h"
|
||||
@@ -47,6 +54,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -141,6 +149,15 @@ enum VerilatedVarFlags {
|
||||
VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Utility functions
|
||||
|
||||
template <size_t N>
|
||||
inline constexpr size_t roundUpToMultipleOf(size_t value) {
|
||||
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
|
||||
return (value + N - 1) & ~(N - 1);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Mutex and threading support
|
||||
|
||||
@@ -175,6 +192,19 @@ public:
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
|
||||
/// Acquire/lock mutex and check for stop request
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
while (true) {
|
||||
checkStopRequestFunction();
|
||||
if (m_mutex.try_lock()) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
@@ -192,10 +222,19 @@ public:
|
||||
}
|
||||
/// Destruct and unlock the mutex
|
||||
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
|
||||
/// Unlock the mutex
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||
/// Lock the mutex
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||
/// Unlock the mutex
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
|
||||
/// Acquire/lock mutex and check for stop request.
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
m_mutexr.lockCheckStopRequest(checkStopRequestFunction);
|
||||
}
|
||||
};
|
||||
|
||||
// Internals: Remember the calling thread at construction time, and make
|
||||
@@ -584,6 +623,7 @@ public: // But for internal use only
|
||||
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
|
||||
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
|
||||
~VerilatedSyms();
|
||||
VL_UNCOPYABLE(VerilatedSyms);
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
@@ -624,7 +664,7 @@ public: // But internals only - called from VerilatedModule's
|
||||
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
|
||||
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
|
||||
void scopeDump() const;
|
||||
void* exportFindError(int funcnum) const;
|
||||
void* exportFindError(int funcnum) const VL_MT_SAFE;
|
||||
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
||||
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
|
||||
@@ -922,18 +962,18 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_s.m_timeprecision = value;
|
||||
#if VM_SC
|
||||
const sc_time sc_res = sc_get_time_resolution();
|
||||
if (sc_res == sc_time(1, SC_SEC)) {
|
||||
const sc_core::sc_time sc_res = sc_core::sc_get_time_resolution();
|
||||
if (sc_res == sc_core::sc_time(1, sc_core::SC_SEC)) {
|
||||
sc_prec = 0;
|
||||
} else if (sc_res == sc_time(1, SC_MS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_MS)) {
|
||||
sc_prec = 3;
|
||||
} else if (sc_res == sc_time(1, SC_US)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_US)) {
|
||||
sc_prec = 6;
|
||||
} else if (sc_res == sc_time(1, SC_NS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_NS)) {
|
||||
sc_prec = 9;
|
||||
} else if (sc_res == sc_time(1, SC_PS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_PS)) {
|
||||
sc_prec = 12;
|
||||
} else if (sc_res == sc_time(1, SC_FS)) {
|
||||
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) {
|
||||
sc_prec = 15;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -67,7 +67,7 @@ VK_CPPFLAGS_ALWAYS += \
|
||||
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
VK_CPPFLAGS_WALL += -Wall $(CFG_CXXFLAGS_WEXTRA) -Werror
|
||||
endif
|
||||
|
||||
@@ -235,14 +235,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
|
||||
ifneq ($(VM_DEFAULT_RULES),0)
|
||||
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
|
||||
# and user files passed on the Verilator command line use this rule.
|
||||
# We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
|
||||
# allow USER_CPPFLAGS to override them
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
$(VK_SLOW_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
$(VK_GLOBAL_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
|
||||
$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
#Default rule embedded in make:
|
||||
|
||||
@@ -208,11 +208,11 @@ private:
|
||||
// Forward to . so we have a whole word
|
||||
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
|
||||
|
||||
std::string out = prefix + "*" + suffix;
|
||||
std::string result = prefix + "*" + suffix;
|
||||
|
||||
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
|
||||
// <<"\ncho="<<out<<endl;
|
||||
return out;
|
||||
// <<"\ncho="<<result<<endl;
|
||||
return result;
|
||||
}
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
|
||||
VL_REQUIRES(m_mutex) {
|
||||
|
||||
+11
-11
@@ -19,8 +19,8 @@
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef VERILATOR_VERILATED_VCD_SC_H_
|
||||
#define VERILATOR_VERILATED_VCD_SC_H_
|
||||
#ifndef VERILATOR_VERILATED_FST_SC_H_
|
||||
#define VERILATOR_VERILATED_FST_SC_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
@@ -36,23 +36,23 @@
|
||||
/// with the SystemC simulation kernel, just like a SystemC-documented
|
||||
/// trace format.
|
||||
|
||||
class VerilatedFstSc final : sc_trace_file, public VerilatedFstC {
|
||||
class VerilatedFstSc final : sc_core::sc_trace_file, public VerilatedFstC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFstSc);
|
||||
|
||||
public:
|
||||
/// Construct a SC trace object, and register with the SystemC kernel
|
||||
VerilatedFstSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an
|
||||
// annoying "to turn off" message.
|
||||
const sc_time t1sec{1, SC_SEC};
|
||||
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
|
||||
if (t1sec.to_default_time_units() != 0) {
|
||||
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
|
||||
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
|
||||
}
|
||||
/// Destruct, flush, and close the dump
|
||||
~VerilatedFstSc() override { close(); }
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
// METHODS - for SC kernel
|
||||
// Called by SystemC simulate()
|
||||
void cycle(bool delta_cycle) override {
|
||||
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
|
||||
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
|
||||
}
|
||||
|
||||
// Override VerilatedFstC. Must be called after starting simulation.
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
void set_time_unit(int exponent10_seconds) override {} // deprecated
|
||||
#endif
|
||||
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
@@ -96,8 +96,8 @@ private:
|
||||
// Formatting matches that of sc_trace.h
|
||||
// LCOV_EXCL_START
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_time )
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
|
||||
@@ -260,7 +260,7 @@ extern void _vl_debug_print_w(int lbits, WDataInP const iwp) VL_MT_SAFE;
|
||||
#if defined(SYSTEMC_VERSION)
|
||||
/// Return current simulation time
|
||||
// Already defined: extern sc_time sc_time_stamp();
|
||||
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_time_stamp().value(); }
|
||||
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_core::sc_time_stamp().value(); }
|
||||
#else // Non-SystemC
|
||||
# if !defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)
|
||||
# ifdef VL_TIME_STAMP64
|
||||
@@ -2164,6 +2164,9 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno
|
||||
}
|
||||
|
||||
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
|
||||
extern IData VL_NTOI_I(int obits, const std::string& str) VL_PURE;
|
||||
extern QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE;
|
||||
extern void VL_NTOI_W(int obits, WDataOutP owp, const std::string& str) VL_PURE;
|
||||
|
||||
extern IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE;
|
||||
|
||||
@@ -2198,10 +2201,10 @@ inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs
|
||||
return lhs + rhs;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNQ(const std::string& lhs, IData rep) VL_PURE {
|
||||
std::string out;
|
||||
out.reserve(lhs.length() * rep);
|
||||
for (unsigned times = 0; times < rep; ++times) out += lhs;
|
||||
return out;
|
||||
std::string result;
|
||||
result.reserve(lhs.length() * rep);
|
||||
for (unsigned times = 0; times < rep; ++times) result += lhs;
|
||||
return result;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(lhs, rep);
|
||||
@@ -2212,6 +2215,7 @@ extern std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE;
|
||||
extern std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE;
|
||||
|
||||
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
|
||||
extern IData VL_FERROR_IW(IData fpi, int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
|
||||
extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||
// METHODS
|
||||
static VerilatedThreadMsgQueue& threadton() {
|
||||
static VerilatedThreadMsgQueue& threadton() VL_MT_SAFE {
|
||||
static thread_local VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "systemc.h"
|
||||
#include <systemc>
|
||||
|
||||
//=============================================================================
|
||||
// For \internal use, get a pointer to m_data in the sc_bv_base class,
|
||||
@@ -37,9 +37,9 @@
|
||||
// use cast magic to get at it. Saves patching get_datap in SystemC.
|
||||
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
|
||||
// This class is thread safe (though most of SystemC is not).
|
||||
class VlScBvExposer final : public sc_bv_base {
|
||||
class VlScBvExposer final : public sc_dt::sc_bv_base {
|
||||
public:
|
||||
static const uint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE {
|
||||
static const uint32_t* sp_datap(const sc_dt::sc_bv_base& base) VL_MT_SAFE {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp();
|
||||
}
|
||||
const uint32_t* sp_datatp() const { return reinterpret_cast<uint32_t*>(m_data); }
|
||||
|
||||
+113
-71
@@ -26,92 +26,134 @@
|
||||
// verilator lint_off TIMESCALEMOD
|
||||
// verilator lint_off UNUSEDSIGNAL
|
||||
package std;
|
||||
class mailbox #(type T);
|
||||
protected int m_bound;
|
||||
protected T m_queue[$];
|
||||
// The process class is not implemented, but it's predeclared here,
|
||||
// so the linter accepts references to it.
|
||||
typedef class process;
|
||||
|
||||
function new(int bound = 0);
|
||||
m_bound = bound;
|
||||
endfunction
|
||||
class mailbox #(type T);
|
||||
protected int m_bound;
|
||||
protected T m_queue[$];
|
||||
|
||||
function int num();
|
||||
return m_queue.size();
|
||||
endfunction
|
||||
function new(int bound = 0);
|
||||
m_bound = bound;
|
||||
endfunction
|
||||
|
||||
task put(T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
if (m_bound != 0)
|
||||
wait (m_queue.size() < m_bound);
|
||||
function int num();
|
||||
return m_queue.size();
|
||||
endfunction
|
||||
|
||||
task put(T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
if (m_bound != 0)
|
||||
wait (m_queue.size() < m_bound);
|
||||
m_queue.push_back(message);
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_put(T message);
|
||||
if (num() < m_bound) begin
|
||||
m_queue.push_back(message);
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
|
||||
function int try_put(T message);
|
||||
if (num() < m_bound) begin
|
||||
m_queue.push_back(message);
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
task get(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
message = m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
|
||||
task get(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
function int try_get(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
|
||||
function int try_get(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue.pop_front();
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
task peek(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
message = m_queue[0];
|
||||
`endif
|
||||
endtask
|
||||
|
||||
task peek(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
function int try_peek(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue[0];
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
function int try_peek(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue[0];
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
class semaphore;
|
||||
protected int m_keyCount;
|
||||
|
||||
class semaphore;
|
||||
protected int m_keyCount;
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_keyCount >= keyCount);
|
||||
m_keyCount -= keyCount;
|
||||
`endif
|
||||
endtask
|
||||
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_keyCount >= keyCount);
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount >= keyCount) begin
|
||||
m_keyCount -= keyCount;
|
||||
`endif
|
||||
endtask
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class process;
|
||||
typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state;
|
||||
static process _s_global_process;
|
||||
static function process self();
|
||||
// Unsupported, emulating with single process' state
|
||||
if (!_s_global_process) _s_global_process = new;
|
||||
return _s_global_process;
|
||||
endfunction
|
||||
function state status();
|
||||
// Unsupported, emulating with single process' state
|
||||
return RUNNING;
|
||||
endfunction
|
||||
function void kill();
|
||||
$error("std::process::kill() not supported");
|
||||
endfunction
|
||||
task await();
|
||||
$error("std::process::await() not supported");
|
||||
endtask
|
||||
function void suspend();
|
||||
$error("std::process::suspend() not supported");
|
||||
endfunction
|
||||
function void resume();
|
||||
$error("std::process::resume() not supported");
|
||||
endfunction
|
||||
// When really implemented, srandom must operates on the process, but for
|
||||
// now rely on the srandom() that is automatically generated for all
|
||||
// classes.
|
||||
// function void srandom(int seed);
|
||||
// endfunction
|
||||
function string get_randstate();
|
||||
// Could operate on all proceses for now
|
||||
// No error, as harmless until set_randstate is called
|
||||
return "NOT_SUPPORTED";
|
||||
endfunction
|
||||
function void set_randstate(string randstate);
|
||||
$error("std::process::set_randstate() not supported");
|
||||
// Could operate on all proceses for now
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount >= keyCount) begin
|
||||
m_keyCount -= keyCount;
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
// verilator lint_off IMPORTSTAR
|
||||
import std::*;
|
||||
|
||||
@@ -137,35 +137,35 @@ public:
|
||||
~VerilatedVarProps() = default;
|
||||
// METHODS
|
||||
bool magicOk() const { return m_magic == MAGIC; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
VerilatedVarType vltype() const VL_MT_SAFE { return m_vltype; }
|
||||
VerilatedVarFlags vldir() const {
|
||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
||||
}
|
||||
uint32_t entSize() const;
|
||||
uint32_t entSize() const VL_MT_SAFE;
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
// DPI compatible C standard layout
|
||||
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
||||
int udims() const { return m_udims; }
|
||||
int udims() const VL_MT_SAFE { return m_udims; }
|
||||
int dims() const { return m_pdims + m_udims; }
|
||||
const VerilatedRange& packed() const { return m_packed; }
|
||||
const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; }
|
||||
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
||||
// DPI accessors
|
||||
int left(int dim) const {
|
||||
int left(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.left()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
|
||||
: 0;
|
||||
}
|
||||
int right(int dim) const {
|
||||
int right(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.right()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
|
||||
: 0;
|
||||
}
|
||||
int low(int dim) const {
|
||||
int low(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.low()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
|
||||
: 0;
|
||||
}
|
||||
int high(int dim) const {
|
||||
int high(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.high()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
||||
: 0;
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
|
||||
: 0;
|
||||
}
|
||||
int elements(int dim) const {
|
||||
int elements(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.elements()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
|
||||
: 0;
|
||||
@@ -183,7 +183,7 @@ public:
|
||||
// Total size in bytes (note DPI limited to 4GB)
|
||||
size_t totalSize() const;
|
||||
// Adjust a data pointer to access a given array element, NULL if something goes bad
|
||||
void* datapAdjustIndex(void* datap, int dim, int indx) const;
|
||||
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
@@ -203,22 +203,22 @@ public:
|
||||
, m_datap{const_cast<void*>(datap)} {}
|
||||
~VerilatedDpiOpenVar() = default;
|
||||
// METHODS
|
||||
void* datap() const { return m_datap; }
|
||||
void* datap() const VL_MT_SAFE { return m_datap; }
|
||||
// METHODS - from VerilatedVarProps
|
||||
bool magicOk() const { return m_propsp->magicOk(); }
|
||||
VerilatedVarType vltype() const { return m_propsp->vltype(); }
|
||||
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
|
||||
const VerilatedRange& packed() const { return m_propsp->packed(); }
|
||||
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
|
||||
int udims() const { return m_propsp->udims(); }
|
||||
int left(int dim) const { return m_propsp->left(dim); }
|
||||
int right(int dim) const { return m_propsp->right(dim); }
|
||||
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
|
||||
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
|
||||
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
|
||||
int low(int dim) const { return m_propsp->low(dim); }
|
||||
int high(int dim) const { return m_propsp->high(dim); }
|
||||
int increment(int dim) const { return m_propsp->increment(dim); }
|
||||
int elements(int dim) const { return m_propsp->elements(dim); }
|
||||
size_t totalSize() const { return m_propsp->totalSize(); }
|
||||
void* datapAdjustIndex(void* datap, int dim, int indx) const {
|
||||
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
|
||||
return m_propsp->datapAdjustIndex(datap, dim, indx);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -312,16 +312,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine.
|
||||
// Allows forcing the move of coroutine locals to the heap.
|
||||
|
||||
struct VlNow {
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
bool await_suspend(std::coroutine_handle<>) const { return false; } // Resume immediately
|
||||
void await_resume() const {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant
|
||||
// wait statements.
|
||||
|
||||
+72
-16
@@ -45,6 +45,7 @@ extern std::string VL_TO_STRING(CData lhs);
|
||||
extern std::string VL_TO_STRING(SData lhs);
|
||||
extern std::string VL_TO_STRING(IData lhs);
|
||||
extern std::string VL_TO_STRING(QData lhs);
|
||||
extern std::string VL_TO_STRING(double lhs);
|
||||
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
|
||||
extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
||||
|
||||
@@ -78,9 +79,9 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
||||
template <std::size_t T_size> //
|
||||
class VlTriggerVec final {
|
||||
// TODO: static assert T_size > 0, and don't generate when empty
|
||||
private:
|
||||
|
||||
// MEMBERS
|
||||
std::array<bool, T_size> m_flags; // State of the assoc array
|
||||
alignas(16) std::array<uint64_t, roundUpToMultipleOf<64>(T_size) / 64> m_flags; // The flags
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
@@ -90,10 +91,18 @@ public:
|
||||
// METHODS
|
||||
|
||||
// Set all elements to false
|
||||
void clear() { m_flags.fill(false); }
|
||||
void clear() { m_flags.fill(0); }
|
||||
|
||||
// Reference to element at 'index'
|
||||
bool& at(size_t index) { return m_flags.at(index); }
|
||||
// Word at given 'wordIndex'
|
||||
uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; }
|
||||
|
||||
// Set specified flag to given value
|
||||
void set(size_t index, bool value) {
|
||||
uint64_t& w = m_flags[index / 64];
|
||||
const size_t bitIndex = index % 64;
|
||||
w &= ~(1ULL << bitIndex);
|
||||
w |= (static_cast<uint64_t>(value) << bitIndex);
|
||||
}
|
||||
|
||||
// Return true iff at least one element is set
|
||||
bool any() const {
|
||||
@@ -103,13 +112,13 @@ public:
|
||||
}
|
||||
|
||||
// Set all elements true in 'this' that are set in 'other'
|
||||
void set(const VlTriggerVec<T_size>& other) {
|
||||
void thisOr(const VlTriggerVec<T_size>& other) {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i];
|
||||
}
|
||||
|
||||
// Set elements of 'this' to 'a & !b' element-wise
|
||||
void andNot(const VlTriggerVec<T_size>& a, const VlTriggerVec<T_size>& b) {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] && !b.m_flags[i];
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] & ~b.m_flags[i];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -135,14 +144,34 @@ public:
|
||||
};
|
||||
|
||||
inline std::string VL_TO_STRING(const VlEvent& e) {
|
||||
return std::string("triggered=") + (e.isTriggered() ? "true" : "false");
|
||||
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Shuffle RNG
|
||||
// Random
|
||||
|
||||
extern uint64_t vl_rand64() VL_MT_SAFE;
|
||||
// Random Number Generator with internal state
|
||||
class VlRNG final {
|
||||
std::array<uint64_t, 2> m_state;
|
||||
|
||||
public:
|
||||
// The default constructor simply sets state, to avoid vl_rand64()
|
||||
// having to check for construction at each call
|
||||
// Alternative: seed with zero and check on rand64() call
|
||||
VlRNG() VL_MT_SAFE;
|
||||
explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {}
|
||||
void srandom(uint64_t n) VL_MT_UNSAFE;
|
||||
// Unused: std::string get_randstate() const VL_MT_UNSAFE;
|
||||
// Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE;
|
||||
uint64_t rand64() VL_MT_UNSAFE;
|
||||
// Threadsafe, but requires use on vl_thread_rng
|
||||
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
|
||||
static VlRNG& vl_thread_rng() VL_MT_SAFE;
|
||||
};
|
||||
|
||||
inline uint64_t vl_rand64() VL_MT_SAFE { return VlRNG::vl_thread_rng_rand64(); }
|
||||
|
||||
// RNG for shuffle()
|
||||
class VlURNG final {
|
||||
public:
|
||||
using result_type = size_t;
|
||||
@@ -151,6 +180,11 @@ public:
|
||||
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
|
||||
};
|
||||
|
||||
// These require the class object to have the thread safety lock
|
||||
inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
extern WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE;
|
||||
|
||||
//===================================================================
|
||||
// Readmem/Writemem operation classes
|
||||
|
||||
@@ -369,18 +403,17 @@ public:
|
||||
// Can't just overload operator[] or provide a "at" reference to set,
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(int32_t index) {
|
||||
static thread_local T_Value s_throwAway;
|
||||
static thread_local T_Value t_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;
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(int32_t index) const {
|
||||
static thread_local 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();
|
||||
@@ -388,6 +421,10 @@ public:
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// Access with an index counted from end (e.g. q[$])
|
||||
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
|
||||
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
|
||||
|
||||
// function void q.insert(index, value);
|
||||
void insert(int32_t index, const T_Value& value) {
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
|
||||
@@ -403,6 +440,12 @@ public:
|
||||
for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
|
||||
return out;
|
||||
}
|
||||
VlQueue sliceFrontBack(int32_t lsb, int32_t msb) const {
|
||||
return slice(lsb, m_deque.size() - 1 - msb);
|
||||
}
|
||||
VlQueue sliceBackBack(int32_t lsb, int32_t msb) const {
|
||||
return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb);
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
@@ -1165,10 +1208,13 @@ public:
|
||||
// CONSTRUCTORS
|
||||
VlClassRef() = default;
|
||||
// Init with nullptr
|
||||
explicit VlClassRef(VlNull){};
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlClassRef(VlNull){};
|
||||
template <typename... T_Args>
|
||||
VlClassRef(VlDeleter& deleter, T_Args&&... args)
|
||||
: m_objp{new T_Class{std::forward<T_Args>(args)...}} {
|
||||
// () required here to avoid narrowing conversion warnings,
|
||||
// when a new() has an e.g. CData type and passed a 1U.
|
||||
: m_objp{new T_Class(std::forward<T_Args>(args)...)} {
|
||||
m_objp->m_deleterp = &deleter;
|
||||
refCountInc();
|
||||
}
|
||||
@@ -1185,6 +1231,16 @@ public:
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlClassRef(VlClassRef&& moved)
|
||||
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef(const VlClassRef<T_OtherClass>& copied)
|
||||
: m_objp{copied.m_objp} {
|
||||
refCountInc();
|
||||
}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef(VlClassRef<T_OtherClass>&& moved)
|
||||
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
|
||||
~VlClassRef() { refCountDec(); }
|
||||
|
||||
// METHODS
|
||||
|
||||
@@ -61,16 +61,6 @@ constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; // Maximum length of a VCD s
|
||||
// cache-lines.
|
||||
constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; // Size of a suffix entry
|
||||
|
||||
//=============================================================================
|
||||
// Utility functions: TODO: put these in a common place and share them.
|
||||
|
||||
template <size_t N>
|
||||
static size_t roundUpToMultipleOf(size_t value) {
|
||||
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
|
||||
size_t mask = N - 1;
|
||||
return (value + mask) & ~mask;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Specialization of the generics for this trace format
|
||||
|
||||
|
||||
@@ -36,23 +36,23 @@
|
||||
/// with the SystemC simulation kernel, just like a SystemC-documented
|
||||
/// trace format.
|
||||
|
||||
class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC {
|
||||
class VerilatedVcdSc final : sc_core::sc_trace_file, public VerilatedVcdC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdSc);
|
||||
|
||||
public:
|
||||
/// Construct a SC trace object, and register with the SystemC kernel
|
||||
VerilatedVcdSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an
|
||||
// annoying "to turn off" message.
|
||||
const sc_time t1sec{1, SC_SEC};
|
||||
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
|
||||
if (t1sec.to_default_time_units() != 0) {
|
||||
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
|
||||
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
|
||||
}
|
||||
/// Destruct, flush, and close the dump
|
||||
~VerilatedVcdSc() override { close(); }
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
// METHODS - for SC kernel
|
||||
// Called by SystemC simulate()
|
||||
void cycle(bool delta_cycle) override {
|
||||
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
|
||||
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
|
||||
}
|
||||
|
||||
// Override VerilatedVcdC. Must be called after starting simulation.
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
void set_time_unit(int exponent10_seconds) override {} // deprecated
|
||||
#endif
|
||||
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
@@ -95,8 +95,8 @@ private:
|
||||
// Formatting matches that of sc_trace.h
|
||||
// LCOV_EXCL_START
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_core::sc_time )
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
|
||||
@@ -791,7 +791,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE {
|
||||
}
|
||||
for (auto& ifuture : s().m_nextCbs) {
|
||||
const QData time = ifuture.first.first;
|
||||
const uint64_t id = ifuture.first.second;
|
||||
VerilatedVpiCbHolder& ho = ifuture.second;
|
||||
if (VL_UNLIKELY(!ho.invalid())) {
|
||||
VL_DBG_MSGF("- vpi: time=%" PRId64 "(NEXT) reason=%d=%s id=%" PRId64 "\n", time,
|
||||
@@ -802,7 +801,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE {
|
||||
}
|
||||
for (auto& ifuture : s().m_futureCbs) {
|
||||
const QData time = ifuture.first.first;
|
||||
const uint64_t id = ifuture.first.second;
|
||||
VerilatedVpiCbHolder& ho = ifuture.second;
|
||||
if (VL_UNLIKELY(!ho.invalid())) {
|
||||
VL_DBG_MSGF("- vpi: time=%" PRId64 " reason=%d=%s id=%" PRId64 "\n", time,
|
||||
|
||||
+14
-1
@@ -160,6 +160,13 @@
|
||||
#else
|
||||
# define VL_MT_SAFE
|
||||
#endif
|
||||
// Comment tag that function is threadsafe, only if
|
||||
// other threads doesn't change tree topology
|
||||
#if defined(__clang__)
|
||||
# define VL_MT_STABLE __attribute__((annotate("MT_STABLE")))
|
||||
#else
|
||||
# define VL_MT_STABLE
|
||||
#endif
|
||||
// Comment tag that function is threadsafe, only
|
||||
// during normal operation (post-init)
|
||||
#if defined(__clang__)
|
||||
@@ -519,6 +526,8 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
||||
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory");
|
||||
#elif defined(__aarch64__) || defined(__arm__)
|
||||
# define VL_CPU_RELAX() asm volatile("yield" ::: "memory")
|
||||
#elif defined(__hppa__) // HPPA does not currently have yield/pause
|
||||
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory")
|
||||
#elif defined(__loongarch__) // LoongArch does not currently have yield/pause
|
||||
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory")
|
||||
#elif defined(__mips64el__) || defined(__mips__) || defined(__mips64__) || defined(__mips64)
|
||||
@@ -594,8 +603,12 @@ reverse_wrapper<T> reverse_view(const T& v) {
|
||||
}
|
||||
|
||||
// C++17's std::as_const
|
||||
// `VL_MT_SAFE` annotation only applies to this function.
|
||||
// Object that is returned by this function is not considered
|
||||
// as MT_SAFE and any function call on this object still
|
||||
// needs to be `VL_MT_SAFE`.
|
||||
template <class T>
|
||||
T const& as_const(T& v) {
|
||||
T const& as_const(T& v) VL_MT_SAFE {
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
@@ -137,7 +137,7 @@ else
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
|
||||
+150
-70
@@ -37,6 +37,7 @@ def fully_qualified_name(node):
|
||||
class VlAnnotations:
|
||||
mt_start: bool = False
|
||||
mt_safe: bool = False
|
||||
stable_tree: bool = False
|
||||
mt_safe_postinit: bool = False
|
||||
mt_unsafe: bool = False
|
||||
mt_unsafe_one: bool = False
|
||||
@@ -48,12 +49,17 @@ class VlAnnotations:
|
||||
release: bool = False
|
||||
|
||||
def is_mt_safe_context(self):
|
||||
return (not (self.mt_unsafe or self.mt_unsafe_one)
|
||||
and (self.mt_safe or self.mt_start))
|
||||
return self.mt_safe and not (self.mt_unsafe or self.mt_unsafe_one)
|
||||
|
||||
def is_pure_context(self):
|
||||
return self.pure
|
||||
|
||||
def is_stabe_tree_context(self):
|
||||
# stable tree context requires calls to be marked
|
||||
# as MT_SAFE or MT_STABLE
|
||||
# Functions in MT_START needs to be MT_SAFE or MT_STABLE
|
||||
return self.stable_tree or self.mt_start
|
||||
|
||||
def is_mt_unsafe_call(self):
|
||||
return self.mt_unsafe or self.mt_unsafe_one
|
||||
|
||||
@@ -66,6 +72,9 @@ class VlAnnotations:
|
||||
def is_pure_call(self):
|
||||
return self.pure
|
||||
|
||||
def is_stabe_tree_call(self):
|
||||
return self.stable_tree
|
||||
|
||||
def __or__(self, other: "VlAnnotations"):
|
||||
result = VlAnnotations()
|
||||
for key, value in dataclasses.asdict(self).items():
|
||||
@@ -94,6 +103,8 @@ class VlAnnotations:
|
||||
result.mt_start = True
|
||||
elif node.displayname == "MT_SAFE":
|
||||
result.mt_safe = True
|
||||
elif node.displayname == "MT_STABLE":
|
||||
result.stable_tree = True
|
||||
elif node.displayname == "MT_SAFE_POSTINIT":
|
||||
result.mt_safe_postinit = True
|
||||
elif node.displayname == "MT_UNSAFE":
|
||||
@@ -196,6 +207,7 @@ class DiagnosticKind(Enum):
|
||||
ANNOTATIONS_DEF_DECL_MISMATCH = enum.auto()
|
||||
NON_PURE_CALL_IN_PURE_CTX = enum.auto()
|
||||
NON_MT_SAFE_CALL_IN_MT_SAFE_CTX = enum.auto()
|
||||
NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX = enum.auto()
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.value < other.value
|
||||
@@ -239,6 +251,7 @@ class CallAnnotationsValidator:
|
||||
self._call_location: Optional[FunctionInfo] = None
|
||||
self._caller: Optional[FunctionInfo] = None
|
||||
self._level: int = 0
|
||||
self._constructor_context: int = 0
|
||||
|
||||
def compile_and_analyze_file(self, source_file: str,
|
||||
compiler_args: list[str],
|
||||
@@ -300,6 +313,67 @@ class CallAnnotationsValidator:
|
||||
annotations = VlAnnotations.from_nodes_list(children)
|
||||
return (True, refd, annotations, children)
|
||||
|
||||
def check_mt_safe_call(self, node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
is_mt_safe = False
|
||||
|
||||
if annotations.is_mt_safe_call():
|
||||
is_mt_safe = True
|
||||
elif not annotations.is_mt_unsafe_call():
|
||||
# Check whether the object the method is called on is mt-safe
|
||||
def find_object_ref(node):
|
||||
try:
|
||||
node = next(node.get_children())
|
||||
if node.kind == CursorKind.DECL_REF_EXPR:
|
||||
# Operator on an argument or local object
|
||||
return node
|
||||
if node.kind != CursorKind.MEMBER_REF_EXPR:
|
||||
return None
|
||||
if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL:
|
||||
# Operator on a member object
|
||||
return node
|
||||
node = next(node.get_children())
|
||||
if node.kind == CursorKind.UNEXPOSED_EXPR:
|
||||
node = next(node.get_children())
|
||||
return node
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
refn = find_object_ref(node)
|
||||
if self._constructor_context and not refn:
|
||||
# we are in constructor and no object reference means
|
||||
# we are calling local method. It is MT safe
|
||||
# only if this method is also only calling local methods or
|
||||
# MT-safe methods
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
is_mt_safe = True
|
||||
# class/struct member
|
||||
elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
||||
refn = refn.referenced
|
||||
refna = VlAnnotations.from_nodes_list(refn.get_children())
|
||||
if refna.guarded or self._constructor_context:
|
||||
is_mt_safe = True
|
||||
# variable
|
||||
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
||||
# This is probably a local or an argument.
|
||||
# Calling methods on local pointers or references is MT-safe,
|
||||
# but on argument pointers or references is not.
|
||||
if "*" not in refn.type.spelling and "&" not in refn.type.spelling:
|
||||
is_mt_safe = True
|
||||
# local variable
|
||||
if refn.referenced.kind == CursorKind.VAR_DECL:
|
||||
is_mt_safe = True
|
||||
elif refn and refn.kind == CursorKind.CALL_EXPR:
|
||||
if self._constructor_context:
|
||||
# call to local function from constructor context
|
||||
# safe if this function also calling local methods or
|
||||
# MT-safe methods
|
||||
self.dispatch_call_node(refn)
|
||||
is_mt_safe = True
|
||||
return is_mt_safe
|
||||
|
||||
# Call handling
|
||||
|
||||
def process_method_call(self, node: clang.cindex.Cursor,
|
||||
@@ -310,47 +384,22 @@ class CallAnnotationsValidator:
|
||||
|
||||
# MT-safe context
|
||||
if ctx.is_mt_safe_context():
|
||||
is_mt_safe = False
|
||||
|
||||
if annotations.is_mt_safe_call():
|
||||
is_mt_safe = True
|
||||
elif not annotations.is_mt_unsafe_call():
|
||||
# Check whether the object the method is called on is mt-safe
|
||||
def find_object_ref(node):
|
||||
try:
|
||||
node = next(node.get_children())
|
||||
if node.kind == CursorKind.DECL_REF_EXPR:
|
||||
# Operator on an argument or local object
|
||||
return node
|
||||
if node.kind != CursorKind.MEMBER_REF_EXPR:
|
||||
return None
|
||||
if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL:
|
||||
# Operator on a member object
|
||||
return node
|
||||
node = next(node.get_children())
|
||||
if node.kind == CursorKind.UNEXPOSED_EXPR:
|
||||
node = next(node.get_children())
|
||||
return node
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
refn = find_object_ref(node)
|
||||
# class/struct member
|
||||
if refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
||||
refn = refn.referenced
|
||||
refna = VlAnnotations.from_nodes_list(refn.get_children())
|
||||
if refna.guarded:
|
||||
is_mt_safe = True
|
||||
# variable
|
||||
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
||||
# This is probably a local or an argument. Assume it's safe.
|
||||
is_mt_safe = True
|
||||
|
||||
if not is_mt_safe:
|
||||
if not self.check_mt_safe_call(node, refd, annotations):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_stabe_tree_call()
|
||||
or annotations.is_pure_call()
|
||||
or self.check_mt_safe_call(node, refd, annotations)):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
self.emit_diagnostic(
|
||||
@@ -368,6 +417,17 @@ class CallAnnotationsValidator:
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_pure_call()
|
||||
or annotations.is_mt_safe_call()
|
||||
or annotations.is_stabe_tree_call()):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
@@ -380,7 +440,20 @@ class CallAnnotationsValidator:
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
|
||||
# Constructors are always OK in MT-safe context.
|
||||
# Constructors are OK in MT-safe context
|
||||
# only if they call local methods or MT-safe functions.
|
||||
if ctx.is_mt_safe_context() or self._constructor_context:
|
||||
self._constructor_context += 1
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self._constructor_context -= 1
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
self._constructor_context += 1
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self._constructor_context -= 1
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
@@ -396,11 +469,19 @@ class CallAnnotationsValidator:
|
||||
if not supported:
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return
|
||||
return True
|
||||
|
||||
assert refd is not None
|
||||
if self._is_ignored_call(refd):
|
||||
return
|
||||
return True
|
||||
|
||||
if "std::function" in refd.displayname:
|
||||
# Workaroud for missing support for lambda annotations
|
||||
# in c++11.
|
||||
# If function takes std::function as argument,
|
||||
# assume, that this std::function will be called inside it.
|
||||
self.process_function_definition(node)
|
||||
return False
|
||||
|
||||
assert self._call_location is not None
|
||||
node_file = os.path.abspath(node.location.file.name)
|
||||
@@ -412,37 +493,40 @@ class CallAnnotationsValidator:
|
||||
or refd.kind == CursorKind.CXX_METHOD
|
||||
and refd.is_static_method()):
|
||||
self.process_function_call(refd, annotations)
|
||||
return
|
||||
# Function pointer
|
||||
if refd.kind in [
|
||||
elif refd.kind in [
|
||||
CursorKind.VAR_DECL, CursorKind.FIELD_DECL,
|
||||
CursorKind.PARM_DECL
|
||||
]:
|
||||
self.process_function_call(refd, annotations)
|
||||
return
|
||||
# Non-static class methods
|
||||
if refd.kind == CursorKind.CXX_METHOD:
|
||||
elif refd.kind == CursorKind.CXX_METHOD:
|
||||
self.process_method_call(node, refd, annotations)
|
||||
return
|
||||
# Conversion method (e.g. `operator int()`)
|
||||
if refd.kind == CursorKind.CONVERSION_FUNCTION:
|
||||
elif refd.kind == CursorKind.CONVERSION_FUNCTION:
|
||||
self.process_method_call(node, refd, annotations)
|
||||
return
|
||||
# Constructors
|
||||
if refd.kind == CursorKind.CONSTRUCTOR:
|
||||
elif refd.kind == CursorKind.CONSTRUCTOR:
|
||||
self.process_constructor_call(refd, annotations)
|
||||
return
|
||||
|
||||
# Ignore other callables
|
||||
print(f"{refd.location.file.name}:{refd.location.line}: "
|
||||
f"{refd.displayname} {refd.kind}\n"
|
||||
f" from: {node.location.file.name}:{node.location.line}")
|
||||
else:
|
||||
# Ignore other callables, but report them
|
||||
print("Unknown callable: "
|
||||
f"{refd.location.file.name}:{refd.location.line}: "
|
||||
f"{refd.displayname} {refd.kind}\n"
|
||||
f" from: {node.location.file.name}:{node.location.line}")
|
||||
return True
|
||||
|
||||
# Definition handling
|
||||
|
||||
def dispatch_node_inside_definition(self, node: clang.cindex.Cursor):
|
||||
if node.kind == CursorKind.CALL_EXPR:
|
||||
self.dispatch_call_node(node)
|
||||
if self.dispatch_call_node(node) is False:
|
||||
return None
|
||||
elif node.is_definition() and node.kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
||||
]:
|
||||
self.process_function_definition(node)
|
||||
return None
|
||||
|
||||
return self.iterate_children(node.get_children(),
|
||||
@@ -461,9 +545,6 @@ class CallAnnotationsValidator:
|
||||
|
||||
assert refd is not None
|
||||
|
||||
prev_caller = self._caller
|
||||
prev_call_location = self._call_location
|
||||
|
||||
def_annotations = VlAnnotations.from_nodes_list(node_children)
|
||||
|
||||
if not (def_annotations.is_empty() or def_annotations == annotations):
|
||||
@@ -480,13 +561,14 @@ class CallAnnotationsValidator:
|
||||
# for callees validation.
|
||||
self._caller = FunctionInfo.from_node(node, refd,
|
||||
def_annotations | annotations)
|
||||
prev_call_location = self._call_location
|
||||
self._call_location = self._caller
|
||||
|
||||
self.iterate_children(node_children,
|
||||
self.dispatch_node_inside_definition)
|
||||
|
||||
self._call_location = prev_call_location
|
||||
self._caller = prev_caller
|
||||
self._caller = prev_call_location
|
||||
|
||||
return None
|
||||
|
||||
@@ -704,8 +786,7 @@ class TopDownSummaryPrinter():
|
||||
info: FunctionInfo
|
||||
calees: set[FunctionInfo]
|
||||
mismatch: Optional[FunctionInfo] = None
|
||||
non_mt_safe_call_in_mt_safe: Optional[FunctionInfo] = None
|
||||
non_pure_call_in_pure: Optional[FunctionInfo] = None
|
||||
reason: Optional[DiagnosticKind] = None
|
||||
|
||||
def __init__(self):
|
||||
self._is_first_group = True
|
||||
@@ -727,15 +808,12 @@ class TopDownSummaryPrinter():
|
||||
if func is None:
|
||||
func = TopDownSummaryPrinter.FunctionCallees(diag.source, set())
|
||||
self._funcs[usr] = func
|
||||
func.reason = diag.kind
|
||||
if diag.kind == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
|
||||
func.mismatch = diag.target
|
||||
else:
|
||||
func.calees.add(diag.target)
|
||||
self._unsafe_in_safe.add(diag.target.usr)
|
||||
if diag.kind == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX:
|
||||
func.non_mt_safe_call_in_mt_safe = diag.target
|
||||
elif diag.kind == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
|
||||
func.non_pure_call_in_pure = diag.target
|
||||
|
||||
def print_summary(self, root_dir: str):
|
||||
row_groups: dict[str, list[list[str]]] = {}
|
||||
@@ -748,12 +826,14 @@ class TopDownSummaryPrinter():
|
||||
|
||||
row_group = []
|
||||
name = f"\"{func_info.name}\" "
|
||||
if func.mismatch:
|
||||
if func.reason == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
|
||||
name += "declaration does not match definition"
|
||||
elif func.non_mt_safe_call_in_mt_safe:
|
||||
elif func.reason == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX:
|
||||
name += "is mtsafe but calls non-mtsafe function(s)"
|
||||
elif func.non_pure_call_in_pure:
|
||||
elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
|
||||
name += "is pure but calls non-pure function(s)"
|
||||
elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX:
|
||||
name += "is stable_tree but calls non-stable_tree or non-mtsafe"
|
||||
else:
|
||||
name += "for unknown reason (please add description)"
|
||||
|
||||
|
||||
+2
-2
@@ -47,7 +47,6 @@ set(HEADERS
|
||||
V3Case.h
|
||||
V3Cast.h
|
||||
V3CCtors.h
|
||||
V3Cdc.h
|
||||
V3Class.h
|
||||
V3Clean.h
|
||||
V3Clock.h
|
||||
@@ -150,6 +149,7 @@ set(HEADERS
|
||||
V3SymTable.h
|
||||
V3Table.h
|
||||
V3Task.h
|
||||
V3ThreadPool.h
|
||||
V3Timing.h
|
||||
V3Trace.h
|
||||
V3TraceDecl.h
|
||||
@@ -186,7 +186,6 @@ set(COMMON_SOURCES
|
||||
V3CUse.cpp
|
||||
V3Case.cpp
|
||||
V3Cast.cpp
|
||||
V3Cdc.cpp
|
||||
V3Class.cpp
|
||||
V3Clean.cpp
|
||||
V3Clock.cpp
|
||||
@@ -283,6 +282,7 @@ set(COMMON_SOURCES
|
||||
V3Subst.cpp
|
||||
V3Table.cpp
|
||||
V3Task.cpp
|
||||
V3ThreadPool.cpp
|
||||
V3Trace.cpp
|
||||
V3TraceDecl.cpp
|
||||
V3Tristate.cpp
|
||||
|
||||
+3
-3
@@ -50,7 +50,7 @@ obj_dbg:
|
||||
.PHONY: ../bin/verilator_bin$(EXEEXT) ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT)
|
||||
|
||||
opt: ../bin/verilator_bin$(EXEEXT)
|
||||
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
|
||||
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
|
||||
../bin/verilator_bin$(EXEEXT): ../bin/verilator_bin_dbg$(EXEEXT)
|
||||
-cp -p $< $@.tmp
|
||||
-mv -f $@.tmp $@
|
||||
@@ -70,7 +70,7 @@ dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT
|
||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
||||
|
||||
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
|
||||
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
|
||||
endif
|
||||
endif
|
||||
@@ -78,7 +78,7 @@ endif
|
||||
prefiles::
|
||||
prefiles:: config_rev.h
|
||||
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
|
||||
config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP)
|
||||
config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP)
|
||||
$(PYTHON3) ${srcdir}/config_rev ${srcdir} >$@
|
||||
|
||||
# Human convenience
|
||||
|
||||
+16
-15
@@ -92,11 +92,12 @@ endif
|
||||
# -lfl not needed as Flex invoked with %nowrap option
|
||||
LIBS = $(CFG_LIBS) -lm
|
||||
|
||||
CPPFLAGS += -DVERILATOR_INTERNAL_
|
||||
CPPFLAGS += -MMD
|
||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGS += -MP # Only works on recent GCC versions
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
|
||||
#CPPFLAGS += -pedantic-errors
|
||||
else
|
||||
@@ -114,7 +115,7 @@ ifeq ($(CFG_WITH_DEFENV),yes)
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC_ARCH=\"$(SYSTEMC_ARCH)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC_INCLUDE=\"$(SYSTEMC_INCLUDE)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC_LIBDIR=\"$(SYSTEMC_LIBDIR)\"
|
||||
ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit
|
||||
ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit
|
||||
CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(pkgdatadir)\"
|
||||
else
|
||||
CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(VERILATOR_ROOT)\"
|
||||
@@ -155,7 +156,7 @@ RAW_OBJS = \
|
||||
V3ActiveTop.o \
|
||||
V3Assert.o \
|
||||
V3AssertPre.o \
|
||||
V3Ast.o \
|
||||
V3Ast.o \
|
||||
V3AstNodes.o \
|
||||
V3Begin.o \
|
||||
V3Branch.o \
|
||||
@@ -164,7 +165,6 @@ RAW_OBJS = \
|
||||
V3CUse.o \
|
||||
V3Case.o \
|
||||
V3Cast.o \
|
||||
V3Cdc.o \
|
||||
V3Class.o \
|
||||
V3Clean.o \
|
||||
V3Clock.o \
|
||||
@@ -265,6 +265,7 @@ RAW_OBJS = \
|
||||
V3TSP.o \
|
||||
V3Table.o \
|
||||
V3Task.o \
|
||||
V3ThreadPool.o \
|
||||
V3Timing.o \
|
||||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
@@ -322,26 +323,26 @@ V3Number_test: V3Number_test.o
|
||||
|
||||
#### Modules
|
||||
|
||||
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
|
||||
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
|
||||
$(PYTHON3) $(ASTGEN) $(ASTGENFLAGS) $*.cpp
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
%.o: %.cpp
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
%.o: %.c
|
||||
%.o: %.c
|
||||
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
|
||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
#### Generated files
|
||||
@@ -365,14 +366,14 @@ V3ParseBison.c: verilog.y $(BISONPRE)
|
||||
@echo "If you get errors from verilog.y below, try upgrading bison to version 1.875 or newer."
|
||||
$(PYTHON3) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $<
|
||||
|
||||
V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
||||
V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
||||
${LEX} --version
|
||||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
|
||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
|
||||
$(PYTHON3) $(FLEXFIX) V3Lexer <$< >$@
|
||||
|
||||
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
||||
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
||||
${LEX} --version
|
||||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
|
||||
+7
-7
@@ -54,7 +54,7 @@ private:
|
||||
const string m_name; // Only used for .dot file generation
|
||||
const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
|
||||
|
||||
string typestr() const { // "
|
||||
string typestr() const VL_MT_SAFE { // "
|
||||
switch (m_type) {
|
||||
case VT_BLOCK: return "(||)"; // basic block node
|
||||
case VT_BRANCH: return "(&&)"; // if/else branch mode
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
: V3GraphVertex{graphp}
|
||||
, m_name{name}
|
||||
, m_type{type} {}
|
||||
string name() const override { return m_name + " " + typestr(); }
|
||||
string name() const override VL_MT_STABLE { return m_name + " " + typestr(); }
|
||||
string dotColor() const override { return user() ? "green" : "black"; }
|
||||
virtual int type() const { return m_type; }
|
||||
};
|
||||
@@ -309,7 +309,7 @@ AstActive*& ActiveNamer::getSpecialActive<AstSenItem::Combo>() {
|
||||
//######################################################################
|
||||
// Latch checking visitor
|
||||
|
||||
class ActiveLatchCheckVisitor final : public VNVisitor {
|
||||
class ActiveLatchCheckVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Input:
|
||||
@@ -329,20 +329,20 @@ private:
|
||||
LatchDetectGraphVertex* const parentp = m_graph.currentp();
|
||||
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
|
||||
m_graph.addPathVertex(branchp, "IF");
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
m_graph.addPathVertex(branchp, "ELSE");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
m_graph.currentp(parentp);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ActiveLatchCheckVisitor(AstNode* nodep, bool expectLatch) {
|
||||
m_graph.begin();
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
m_graph.latchCheck(nodep, expectLatch);
|
||||
}
|
||||
~ActiveLatchCheckVisitor() override = default;
|
||||
|
||||
+29
-10
@@ -43,6 +43,7 @@ private:
|
||||
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
|
||||
unsigned m_modPastNum = 0; // Module past numbering
|
||||
unsigned m_modStrobeNum = 0; // Module $strobe numbering
|
||||
const AstNodeProcedure* m_procedurep = nullptr; // Current procedure
|
||||
VDouble0 m_statCover; // Statistic tracking
|
||||
VDouble0 m_statAsNotImm; // Statistic tracking
|
||||
VDouble0 m_statAsImm; // Statistic tracking
|
||||
@@ -50,14 +51,22 @@ private:
|
||||
bool m_inSampled = false; // True inside a sampled expression
|
||||
|
||||
// METHODS
|
||||
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
|
||||
return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message,
|
||||
VDisplayType severity) {
|
||||
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
|
||||
return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
} else {
|
||||
return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
}
|
||||
}
|
||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||
nodep->fmtp()->text(
|
||||
assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType()));
|
||||
nodep->displayType(VDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
// cppcheck-suppress nullPointer
|
||||
AstNodeExpr* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
|
||||
if (AstNodeExpr* const timesp = nodep->fmtp()->exprsp()) {
|
||||
@@ -145,6 +154,11 @@ private:
|
||||
} else {
|
||||
UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensitivity");
|
||||
sentreep->unlinkFrBack();
|
||||
if (m_procedurep) {
|
||||
// To support this need queue of asserts to activate
|
||||
nodep->v3error("Unsupported: Procedural concurent assertion with"
|
||||
" clocking event inside always (IEEE 1800-2917 16.14.6)");
|
||||
}
|
||||
}
|
||||
//
|
||||
AstNode* bodysp = nullptr;
|
||||
@@ -176,7 +190,7 @@ private:
|
||||
const bool force = VN_IS(nodep, AssertIntrinsic);
|
||||
if (passsp) passsp = newIfAssertOn(passsp, force);
|
||||
if (failsp) failsp = newIfAssertOn(failsp, force);
|
||||
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||
if (!passsp && !failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||
ifp = new AstIf{nodep->fileline(), propp, passsp, failsp};
|
||||
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||
// It's more LIKELY that we'll take the nullptr if clause
|
||||
@@ -350,8 +364,7 @@ private:
|
||||
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* inp = newSampledExpr(exprp);
|
||||
AstVar* invarp = nullptr;
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
sentreep->unlinkFrBack();
|
||||
AstSenTree* const sentreep = nodep->sentreep()->unlinkFrBack();
|
||||
AstAlways* const alwaysp
|
||||
= new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr};
|
||||
m_modp->addStmtsp(alwaysp);
|
||||
@@ -414,9 +427,10 @@ private:
|
||||
replaceDisplay(nodep, "-Info");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_WARNING) {
|
||||
replaceDisplay(nodep, "%%Warning");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_ERROR
|
||||
|| nodep->displayType() == VDisplayType::DT_FATAL) {
|
||||
} else if (nodep->displayType() == VDisplayType::DT_ERROR) {
|
||||
replaceDisplay(nodep, "%%Error");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_FATAL) {
|
||||
replaceDisplay(nodep, "%%Fatal");
|
||||
} else if (nodep->displayType() == VDisplayType::DT_MONITOR) {
|
||||
nodep->displayType(VDisplayType::DT_DISPLAY);
|
||||
const auto fl = nodep->fileline();
|
||||
@@ -496,6 +510,11 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeProcedure* nodep) override {
|
||||
VL_RESTORER(m_procedurep);
|
||||
m_procedurep = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstBegin* nodep) override {
|
||||
// This code is needed rather than a visitor in V3Begin,
|
||||
// because V3Assert is called before V3Begin
|
||||
|
||||
+16
-9
@@ -63,9 +63,10 @@ private:
|
||||
|
||||
// METHODS
|
||||
|
||||
AstSenTree* newSenTree(AstNode* nodep) {
|
||||
AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr) {
|
||||
// Create sentree based on clocked or default clock
|
||||
// Return nullptr for always
|
||||
if (useTreep) return useTreep;
|
||||
AstSenTree* newp = nullptr;
|
||||
AstSenItem* senip = m_senip;
|
||||
if (!senip && m_defaultClockingp) senip = m_defaultClockingp->sensesp();
|
||||
@@ -228,7 +229,7 @@ private:
|
||||
// always queue.push(<sampled var>);
|
||||
AstCMethodHard* const pushp = new AstCMethodHard{
|
||||
flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push",
|
||||
new AstTime(nodep->fileline(), m_modp->timeunit())};
|
||||
new AstTime{nodep->fileline(), m_modp->timeunit()}};
|
||||
pushp->addPinsp(exprp->cloneTree(false));
|
||||
pushp->dtypeSetVoid();
|
||||
m_clockingp->addNextHere(
|
||||
@@ -237,7 +238,7 @@ private:
|
||||
// always @<clocking event> queue.pop(<skew>, /*out*/<skewed var>});
|
||||
AstCMethodHard* const popp = new AstCMethodHard{
|
||||
flp, new AstVarRef{flp, queueVarp, VAccess::READWRITE}, "pop",
|
||||
new AstTime(nodep->fileline(), m_modp->timeunit())};
|
||||
new AstTime{nodep->fileline(), m_modp->timeunit()}};
|
||||
popp->addPinsp(skewp->unlinkFrBack());
|
||||
popp->addPinsp(refp);
|
||||
popp->dtypeSetVoid();
|
||||
@@ -362,17 +363,19 @@ private:
|
||||
clearAssertInfo();
|
||||
}
|
||||
void visit(AstFell* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstPast* nodep) override {
|
||||
@@ -381,30 +384,34 @@ private:
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
void visit(AstRose* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstStable* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq{fl, past, exprp->cloneTree(false)};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
|
||||
+147
-42
@@ -87,8 +87,8 @@ string AstNode::encodeName(const string& namein) {
|
||||
// Encode signal name raw from parser, then not called again on same signal
|
||||
string out;
|
||||
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
|
||||
if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
|
||||
: isalnum(pos[0])) {
|
||||
if ((pos == namein.begin()) ? std::isalpha(pos[0]) // digits can't lead identifiers
|
||||
: std::isalnum(pos[0])) {
|
||||
out += pos[0];
|
||||
} else if (pos[0] == '_') {
|
||||
if (pos[1] == '_') {
|
||||
@@ -125,7 +125,9 @@ string AstNode::encodeNumber(int64_t num) {
|
||||
}
|
||||
}
|
||||
|
||||
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
|
||||
string AstNode::nameProtect() const VL_MT_STABLE {
|
||||
return VIdProtect::protectIf(name(), protect());
|
||||
}
|
||||
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
|
||||
|
||||
string AstNode::shortName() const {
|
||||
@@ -155,10 +157,9 @@ string AstNode::vcdName(const string& namein) {
|
||||
return prettyName(pretty);
|
||||
}
|
||||
|
||||
string AstNode::prettyName(const string& namein) {
|
||||
string AstNode::prettyName(const string& namein) VL_PURE {
|
||||
// This function is somewhat hot, so we short-circuit some compares
|
||||
string pretty;
|
||||
pretty = "";
|
||||
pretty.reserve(namein.length());
|
||||
for (const char* pos = namein.c_str(); *pos;) {
|
||||
if (pos[0] == '-' && pos[1] == '>') { // ->
|
||||
@@ -187,11 +188,14 @@ string AstNode::prettyName(const string& namein) {
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3])
|
||||
&& isxdigit(pos[4])) {
|
||||
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3])
|
||||
&& std::isxdigit(pos[4])) {
|
||||
char value = 0;
|
||||
value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10));
|
||||
value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10));
|
||||
value += 16
|
||||
* (std::isdigit(pos[3]) ? (pos[3] - '0')
|
||||
: (std::tolower(pos[3]) - 'a' + 10));
|
||||
value
|
||||
+= (std::isdigit(pos[4]) ? (pos[4] - '0') : (std::tolower(pos[4]) - 'a' + 10));
|
||||
pretty += value;
|
||||
pos += 5;
|
||||
continue;
|
||||
@@ -206,7 +210,82 @@ string AstNode::prettyName(const string& namein) {
|
||||
return pretty;
|
||||
}
|
||||
|
||||
string AstNode::prettyTypeName() const {
|
||||
string AstNode::vpiName(const string& namein) {
|
||||
// This is slightly different from prettyName, in that when we encounter escaped characters,
|
||||
// we change that identifier to an escaped identifier, wrapping it with '\' and ' '
|
||||
// as specified in LRM 23.6
|
||||
string pretty;
|
||||
pretty.reserve(namein.length());
|
||||
bool inEscapedIdent = false;
|
||||
int lastIdent = 0;
|
||||
|
||||
for (const char* pos = namein.c_str(); *pos;) {
|
||||
char specialChar = 0;
|
||||
if (pos[0] == '-' && pos[1] == '>') { // ->
|
||||
specialChar = '.';
|
||||
pos += 2;
|
||||
} else if (pos[0] == '_' && pos[1] == '_') { // __
|
||||
if (0 == std::strncmp(pos, "__BRA__", 7)) {
|
||||
specialChar = '[';
|
||||
pos += 7;
|
||||
} else if (0 == std::strncmp(pos, "__KET__", 7)) {
|
||||
specialChar = ']';
|
||||
pos += 7;
|
||||
} else if (0 == std::strncmp(pos, "__DOT__", 7)) {
|
||||
specialChar = '.';
|
||||
pos += 7;
|
||||
} else if (0 == std::strncmp(pos, "__PVT__", 7)) {
|
||||
pos += 7;
|
||||
continue;
|
||||
} else if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3])
|
||||
&& std::isxdigit(pos[4])) {
|
||||
char value = 0;
|
||||
value += 16
|
||||
* (std::isdigit(pos[3]) ? (pos[3] - '0')
|
||||
: (std::tolower(pos[3]) - 'a' + 10));
|
||||
value
|
||||
+= (std::isdigit(pos[4]) ? (pos[4] - '0') : (std::tolower(pos[4]) - 'a' + 10));
|
||||
|
||||
// __ doesn't always imply escaped ident
|
||||
if (value != '_') inEscapedIdent = true;
|
||||
|
||||
pretty += value;
|
||||
pos += 5;
|
||||
continue;
|
||||
}
|
||||
} else if (pos[0] == '.') {
|
||||
specialChar = '.';
|
||||
++pos;
|
||||
}
|
||||
|
||||
if (specialChar) {
|
||||
if (inEscapedIdent && (specialChar == '[' || specialChar == '.')) {
|
||||
pretty += " ";
|
||||
pretty.insert(lastIdent, "\\");
|
||||
inEscapedIdent = false;
|
||||
}
|
||||
|
||||
pretty += specialChar;
|
||||
|
||||
if (specialChar == ']' || specialChar == '.') {
|
||||
lastIdent = pretty.length();
|
||||
inEscapedIdent = false;
|
||||
}
|
||||
} else {
|
||||
pretty += pos[0];
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (inEscapedIdent) {
|
||||
pretty += " ";
|
||||
pretty.insert(lastIdent, "\\");
|
||||
}
|
||||
if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
||||
if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
|
||||
return pretty;
|
||||
}
|
||||
|
||||
string AstNode::prettyTypeName() const VL_MT_STABLE {
|
||||
if (name() == "") return typeName();
|
||||
return std::string{typeName()} + " '" + prettyName() + "'";
|
||||
}
|
||||
@@ -219,17 +298,19 @@ void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int line
|
||||
// Called on all major tree changers.
|
||||
// Only for use for those really nasty bugs relating to internals
|
||||
// Note this may be null.
|
||||
// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
||||
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
// if (debug() && nodep) cout << "-treeChange: V3Ast.cpp:" << lineno
|
||||
// << " Tree Change for " << prefix << ": "
|
||||
// << cvtToHex(nodep) << " <e" << AstNode::s_editCntGbl << ">"
|
||||
// << "m_iterpp=" << (void*)nodep->m_iterpp << endl;
|
||||
// if (debug()) {
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// // Commenting out the section below may crash, as the tree state
|
||||
// // between edits is not always consistent for printing
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// v3Global.rootp()->dumpTree("- treeChange: ");
|
||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||
// else this->dumpTree(prefix);
|
||||
// this->checkTree();
|
||||
// if (next||1) nodep->dumpTreeAndNext(cout, prefix);
|
||||
// else nodep->dumpTree(prefix);
|
||||
// nodep->checkTree();
|
||||
// v3Global.rootp()->checkTree();
|
||||
//}
|
||||
#endif
|
||||
@@ -268,7 +349,8 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp) {
|
||||
newtailp->m_headtailp = headp;
|
||||
headp->m_headtailp = newtailp;
|
||||
newp->editCountInc();
|
||||
if (oldtailp->m_iterpp) *(oldtailp->m_iterpp) = newp; // Iterate on new item
|
||||
// No change of m_iterpp, as only changing m_nextp of current node;
|
||||
// the current node is still the one at the iteration point
|
||||
}
|
||||
debugTreeChange(nodep, "-addNextOut:", __LINE__, true);
|
||||
return nodep;
|
||||
@@ -318,7 +400,8 @@ void AstNode::addNextHere(AstNode* newp) {
|
||||
} // else is head, and we're inserting into the middle, so no other change
|
||||
}
|
||||
|
||||
if (this->m_iterpp) *(this->m_iterpp) = newp; // Iterate on new item
|
||||
// No change of m_iterpp, as adding after current node;
|
||||
// the current node is still the one at the iteration point
|
||||
debugTreeChange(this, "-addHereOut: ", __LINE__, true);
|
||||
}
|
||||
|
||||
@@ -486,8 +569,10 @@ AstNode* AstNode::unlinkFrBackWithNext(VNRelinker* linkerp) {
|
||||
// Relink
|
||||
oldp->m_backp = nullptr;
|
||||
// Iterator fixup
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
if (oldp->m_iterpp) {
|
||||
*(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
}
|
||||
debugTreeChange(oldp, "-unlinkWNextOut: ", __LINE__, true);
|
||||
return oldp;
|
||||
}
|
||||
@@ -501,7 +586,11 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
|
||||
if (linkerp) {
|
||||
linkerp->m_oldp = oldp;
|
||||
linkerp->m_backp = backp;
|
||||
linkerp->m_iterpp = oldp->m_iterpp;
|
||||
if (oldp->m_iterpp) { // Assumes we will always relink() if want to keep iterating
|
||||
linkerp->m_iterpp = oldp->m_iterpp;
|
||||
*(oldp->m_iterpp) = nullptr;
|
||||
oldp->m_iterpp = nullptr;
|
||||
}
|
||||
if (backp->m_nextp == oldp) {
|
||||
linkerp->m_chg = VNRelinker::RELINK_NEXT;
|
||||
} else if (backp->m_op1p == oldp) {
|
||||
@@ -546,12 +635,15 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
|
||||
}
|
||||
}
|
||||
// Iterator fixup
|
||||
if (oldp->m_iterpp) *(oldp->m_iterpp) = oldp->m_nextp;
|
||||
if (oldp->m_iterpp) { // Only if no linker, point to next in list
|
||||
if (oldp->m_nextp) oldp->m_nextp->m_iterpp = oldp->m_iterpp;
|
||||
*(oldp->m_iterpp) = oldp->m_nextp;
|
||||
oldp->m_iterpp = nullptr;
|
||||
}
|
||||
// Relink
|
||||
oldp->m_nextp = nullptr;
|
||||
oldp->m_backp = nullptr;
|
||||
oldp->m_headtailp = this;
|
||||
oldp->m_iterpp = nullptr;
|
||||
oldp->m_headtailp = oldp;
|
||||
debugTreeChange(oldp, "-unlinkFrBkOut: ", __LINE__, true);
|
||||
return oldp;
|
||||
}
|
||||
@@ -589,12 +681,12 @@ void AstNode::relink(VNRelinker* linkerp) {
|
||||
// Iterator fixup
|
||||
if (linkerp->m_iterpp) {
|
||||
// If we're iterating over a next() link, we need to follow links off the
|
||||
// NEW node. Thus we pass iteration information via a pointer in the node.
|
||||
// NEW node, which is always assumed to be what we are relinking to.
|
||||
// This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing
|
||||
// across every function.
|
||||
// If anyone has a cleaner way, I'd be grateful.
|
||||
*(linkerp->m_iterpp) = newp;
|
||||
newp->m_iterpp = linkerp->m_iterpp;
|
||||
*(newp->m_iterpp) = newp;
|
||||
}
|
||||
// Empty the linker so not used twice accidentally
|
||||
linkerp->m_backp = nullptr;
|
||||
@@ -756,6 +848,7 @@ void AstNode::deleteNode() {
|
||||
this->m_op2p = reinterpret_cast<AstNode*>(0x1);
|
||||
this->m_op3p = reinterpret_cast<AstNode*>(0x1);
|
||||
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
|
||||
this->m_iterpp = reinterpret_cast<AstNode**>(0x1);
|
||||
if (
|
||||
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
|
||||
true
|
||||
@@ -830,7 +923,7 @@ void AstNode::iterateChildren(VNVisitor& v) {
|
||||
if (m_op4p) m_op4p->iterateAndNext(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateChildrenConst(VNVisitor& v) {
|
||||
void AstNode::iterateChildrenConst(VNVisitorConst& v) {
|
||||
// This is a very hot function
|
||||
ASTNODE_PREFETCH(m_op1p);
|
||||
ASTNODE_PREFETCH(m_op2p);
|
||||
@@ -871,13 +964,13 @@ void AstNode::iterateAndNext(VNVisitor& v) {
|
||||
niterp->m_iterpp = nullptr;
|
||||
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
|
||||
nodep = niterp;
|
||||
} else { // Unchanged node, just continue loop
|
||||
} else { // Unchanged node (though maybe updated m_next), just continue loop
|
||||
nodep = niterp->m_nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::iterateListBackwards(VNVisitor& v) {
|
||||
void AstNode::iterateListBackwardsConst(VNVisitorConst& v) {
|
||||
AstNode* nodep = this;
|
||||
while (nodep->m_nextp) nodep = nodep->m_nextp;
|
||||
while (nodep) {
|
||||
@@ -891,14 +984,14 @@ void AstNode::iterateListBackwards(VNVisitor& v) {
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::iterateChildrenBackwards(VNVisitor& v) {
|
||||
if (m_op1p) m_op1p->iterateListBackwards(v);
|
||||
if (m_op2p) m_op2p->iterateListBackwards(v);
|
||||
if (m_op3p) m_op3p->iterateListBackwards(v);
|
||||
if (m_op4p) m_op4p->iterateListBackwards(v);
|
||||
void AstNode::iterateChildrenBackwardsConst(VNVisitorConst& v) {
|
||||
if (m_op1p) m_op1p->iterateListBackwardsConst(v);
|
||||
if (m_op2p) m_op2p->iterateListBackwardsConst(v);
|
||||
if (m_op3p) m_op3p->iterateListBackwardsConst(v);
|
||||
if (m_op4p) m_op4p->iterateListBackwardsConst(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateAndNextConst(VNVisitor& v) {
|
||||
void AstNode::iterateAndNextConst(VNVisitorConst& v) {
|
||||
// Keep following the current list even if edits change it
|
||||
AstNode* nodep = this;
|
||||
do {
|
||||
@@ -1002,7 +1095,7 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
|
||||
//======================================================================
|
||||
// Debugging
|
||||
|
||||
void AstNode::checkTreeIter(const AstNode* prevBackp) const {
|
||||
void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
|
||||
// private: Check a tree and children
|
||||
UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent");
|
||||
switch (this->type()) {
|
||||
@@ -1052,7 +1145,7 @@ void AstNode::checkIter() const {
|
||||
if (m_iterpp) {
|
||||
dumpPtrs(cout);
|
||||
// Perhaps something forgot to clear m_iterpp?
|
||||
this->v3fatalSrc("Iteration link should be nullptr");
|
||||
this->v3fatalSrc("Iteration link m_iterpp should be nullptr");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1186,7 +1279,17 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump)
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_MT_SAFE {
|
||||
bool AstNode::isTreePureRecurse() const {
|
||||
// Should memoize this if call commonly
|
||||
if (!this->isPure()) return false;
|
||||
if (this->op1p() && !this->op1p()->isTreePureRecurse()) return false;
|
||||
if (this->op2p() && !this->op2p()->isTreePureRecurse()) return false;
|
||||
if (this->op3p() && !this->op3p()->isTreePureRecurse()) return false;
|
||||
if (this->op4p() && !this->op4p()->isTreePureRecurse()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
v3errorEnd(str);
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
@@ -1216,9 +1319,9 @@ string AstNode::instanceStr() const {
|
||||
|
||||
return "";
|
||||
}
|
||||
void AstNode::v3errorEnd(std::ostringstream& str) const {
|
||||
void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
if (!m_fileline) {
|
||||
V3Error::v3errorEnd(str, instanceStr());
|
||||
V3Error::s().v3errorEnd(str, instanceStr());
|
||||
} else {
|
||||
std::ostringstream nsstr;
|
||||
nsstr << str.str();
|
||||
@@ -1231,8 +1334,8 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
||||
// Don't look for instance name when warning is disabled.
|
||||
// In case of large number of warnings, this can
|
||||
// take significant amount of time
|
||||
m_fileline->v3errorEnd(nsstr,
|
||||
m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr());
|
||||
m_fileline->v3errorEnd(
|
||||
nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,7 +1358,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) {
|
||||
dtypeSetLogicUnsized(width, widthMin, numeric);
|
||||
} else {
|
||||
if (width == dtypep()->width() && widthMin == dtypep()->widthMin()
|
||||
&& numeric == dtypep()->numeric())
|
||||
&& numeric == dtypep()->numeric()
|
||||
// Enums need to become direct sizes to avoid later ENUMVALUE errors
|
||||
&& !VN_IS(dtypep()->skipRefToEnump(), EnumDType))
|
||||
return; // Correct already
|
||||
// FUTURE: We may be pointing at a two state data type, and this may
|
||||
// convert it to logic. Since the AstVar remains correct, we
|
||||
|
||||
+124
-88
@@ -102,11 +102,11 @@ public:
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const VL_MT_SAFE { return m_e; }
|
||||
};
|
||||
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_MT_SAFE {
|
||||
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_PURE {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; }
|
||||
constexpr bool operator==(const VNType& lhs, VNType::en rhs) VL_PURE { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VNType::en lhs, const VNType& rhs) VL_PURE { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VNType& rhs) { return os << rhs.ascii(); }
|
||||
|
||||
// ######################################################################
|
||||
@@ -371,7 +371,6 @@ public:
|
||||
//
|
||||
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
|
||||
//
|
||||
ENUM_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
ENUM_FIRST, // V3Width processes
|
||||
ENUM_LAST, // V3Width processes
|
||||
ENUM_NUM, // V3Width processes
|
||||
@@ -380,8 +379,7 @@ public:
|
||||
ENUM_NAME, // V3Width processes
|
||||
ENUM_VALID, // V3Width processes
|
||||
//
|
||||
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
//
|
||||
TYPEID, // V3Width processes
|
||||
TYPENAME, // V3Width processes
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
@@ -407,10 +405,9 @@ public:
|
||||
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
|
||||
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
|
||||
"DT_PUBLIC",
|
||||
"ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
|
||||
"ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
|
||||
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID",
|
||||
"MEMBER_BASE",
|
||||
"TYPENAME",
|
||||
"TYPEID", "TYPENAME",
|
||||
"VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
||||
@@ -473,7 +470,7 @@ public:
|
||||
_ENUM_MAX
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
const char* ascii() const VL_MT_SAFE {
|
||||
static const char* const names[] = {"%E-unk",
|
||||
"bit",
|
||||
"byte",
|
||||
@@ -570,7 +567,8 @@ public:
|
||||
}
|
||||
bool isIntNumeric() const { // Enum increment supported
|
||||
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|
||||
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
|
||||
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64
|
||||
|| m_e == TIME);
|
||||
}
|
||||
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
|
||||
return (m_e == LOGIC || m_e == BIT);
|
||||
@@ -805,6 +803,10 @@ public:
|
||||
bool isTemp() const {
|
||||
return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP);
|
||||
}
|
||||
bool isVPIAccessible() const {
|
||||
return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == PORT || m_e == WIRE
|
||||
|| m_e == TRI0 || m_e == TRI1);
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) VL_MT_SAFE {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
@@ -1095,21 +1097,21 @@ public:
|
||||
}
|
||||
//
|
||||
VNumRange() = default;
|
||||
VNumRange(int hi, int lo, bool littleEndian) { init(hi, lo, littleEndian); }
|
||||
VNumRange(int hi, int lo, bool ascending) { init(hi, lo, ascending); }
|
||||
VNumRange(int left, int right)
|
||||
: m_left{left}
|
||||
, m_right{right}
|
||||
, m_ranged{true} {}
|
||||
~VNumRange() = default;
|
||||
// MEMBERS
|
||||
void init(int hi, int lo, bool littleEndian) {
|
||||
void init(int hi, int lo, bool ascending) {
|
||||
if (lo > hi) {
|
||||
const int t = hi;
|
||||
hi = lo;
|
||||
lo = t;
|
||||
}
|
||||
m_left = littleEndian ? lo : hi;
|
||||
m_right = littleEndian ? hi : lo;
|
||||
m_left = ascending ? lo : hi;
|
||||
m_right = ascending ? hi : lo;
|
||||
m_ranged = true;
|
||||
}
|
||||
int left() const { return m_left; }
|
||||
@@ -1120,10 +1122,10 @@ public:
|
||||
int lo() const VL_MT_SAFE {
|
||||
return m_left > m_right ? m_right : m_left;
|
||||
} // How to show a declaration
|
||||
int leftToRightInc() const { return littleEndian() ? 1 : -1; }
|
||||
int leftToRightInc() const { return ascending() ? 1 : -1; }
|
||||
int elements() const VL_MT_SAFE { return hi() - lo() + 1; }
|
||||
bool ranged() const { return m_ranged; }
|
||||
bool littleEndian() const { return m_left < m_right; }
|
||||
bool ascending() const { return m_left < m_right; }
|
||||
int hiMaxSelect() const {
|
||||
return (lo() < 0 ? hi() - lo() : hi());
|
||||
} // Maximum value a [] select may index
|
||||
@@ -1371,13 +1373,38 @@ public:
|
||||
virtual ~VNDeleter() { doDeletes(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// VNVisitorConst -- Allows new functions to be called on each node
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
// This only has the constant fuctions for non-modifying visitors.
|
||||
// For more typical usage see VNVisitor
|
||||
|
||||
class VNVisitorConst VL_NOT_FINAL : public VNDeleter {
|
||||
friend class AstNode;
|
||||
|
||||
public:
|
||||
/// Call visit()s on nodep
|
||||
inline void iterateConst(AstNode* nodep);
|
||||
/// Call visit()s on nodep
|
||||
inline void iterateConstNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep's children
|
||||
inline void iterateChildrenConst(AstNode* nodep);
|
||||
/// Call visit()s on nodep's children in backp() order
|
||||
inline void iterateChildrenBackwardsConst(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
|
||||
inline void iterateAndNextConstNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
|
||||
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
|
||||
|
||||
virtual void visit(AstNode* nodep) = 0;
|
||||
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// VNVisitor -- Allows new functions to be called on each node
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
|
||||
class VNVisitor VL_NOT_FINAL : public VNDeleter {
|
||||
friend class AstNode;
|
||||
|
||||
class VNVisitor VL_NOT_FINAL : public VNVisitorConst {
|
||||
public:
|
||||
/// Call visit()s on nodep
|
||||
inline void iterate(AstNode* nodep);
|
||||
@@ -1385,21 +1412,10 @@ public:
|
||||
inline void iterateNull(AstNode* nodep);
|
||||
/// Call visit()s on nodep's children
|
||||
inline void iterateChildren(AstNode* nodep);
|
||||
/// Call visit()s on nodep's children in backp() order
|
||||
inline void iterateChildrenBackwards(AstNode* nodep);
|
||||
/// Call visit()s on const nodep's children
|
||||
inline void iterateChildrenConst(AstNode* nodep);
|
||||
/// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list
|
||||
inline void iterateAndNextNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
|
||||
inline void iterateAndNextConstNull(AstNode* nodep);
|
||||
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
|
||||
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
|
||||
/// Return edited nodep; see comments in V3Ast.cpp
|
||||
inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
|
||||
|
||||
virtual void visit(AstNode* nodep) = 0;
|
||||
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -1424,6 +1440,13 @@ protected:
|
||||
|
||||
public:
|
||||
VNRelinker() = default;
|
||||
~VNRelinker() {
|
||||
// Relink is needed so m_iterpp's get restored, e.g. can't have:
|
||||
// ->unlinkFrBack(relinker);
|
||||
// if (only_sometimes) relinker.relink(newp);
|
||||
UDEBUGONLY(
|
||||
UASSERT_STATIC(!m_backp, "Active linker must be relink()ed before destruction"););
|
||||
}
|
||||
inline void relink(AstNode* newp);
|
||||
AstNode* oldp() const { return m_oldp; }
|
||||
void dump(std::ostream& str = std::cout) const;
|
||||
@@ -1543,7 +1566,7 @@ class AstNode VL_NOT_FINAL {
|
||||
private:
|
||||
AstNode* cloneTreeIter();
|
||||
AstNode* cloneTreeIterList();
|
||||
void checkTreeIter(const AstNode* prevBackp) const VL_MT_SAFE;
|
||||
void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE;
|
||||
bool gateTreeIter() const;
|
||||
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
|
||||
bool gateOnly);
|
||||
@@ -1599,14 +1622,14 @@ public:
|
||||
// ACCESSORS
|
||||
VNType type() const VL_MT_SAFE { return m_type; }
|
||||
const char* typeName() const VL_MT_SAFE { return type().ascii(); } // See also prettyTypeName
|
||||
AstNode* nextp() const VL_MT_SAFE { return m_nextp; }
|
||||
AstNode* backp() const VL_MT_SAFE { return m_backp; }
|
||||
AstNode* nextp() const VL_MT_STABLE { return m_nextp; }
|
||||
AstNode* backp() const VL_MT_STABLE { return m_backp; }
|
||||
AstNode* abovep() const; // Parent node above, only when no nextp() as otherwise slow
|
||||
AstNode* op1p() const VL_MT_SAFE { return m_op1p; }
|
||||
AstNode* op2p() const VL_MT_SAFE { return m_op2p; }
|
||||
AstNode* op3p() const VL_MT_SAFE { return m_op3p; }
|
||||
AstNode* op4p() const VL_MT_SAFE { return m_op4p; }
|
||||
AstNodeDType* dtypep() const VL_MT_SAFE { return m_dtypep; }
|
||||
AstNode* op1p() const VL_MT_STABLE { return m_op1p; }
|
||||
AstNode* op2p() const VL_MT_STABLE { return m_op2p; }
|
||||
AstNode* op3p() const VL_MT_STABLE { return m_op3p; }
|
||||
AstNode* op4p() const VL_MT_STABLE { return m_op4p; }
|
||||
AstNodeDType* dtypep() const VL_MT_STABLE { return m_dtypep; }
|
||||
AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : nullptr); }
|
||||
AstNode* firstAbovep() const { // Returns nullptr when second or later in list
|
||||
return ((backp() && backp()->nextp() != this) ? backp() : nullptr);
|
||||
@@ -1653,7 +1676,7 @@ public:
|
||||
static constexpr int INSTR_COUNT_PLI = 20; // PLI routines
|
||||
|
||||
// ACCESSORS
|
||||
virtual string name() const VL_MT_SAFE { return ""; }
|
||||
virtual string name() const VL_MT_STABLE { return ""; }
|
||||
virtual string origName() const { return ""; }
|
||||
virtual void name(const string& name) {
|
||||
this->v3fatalSrc("name() called on object without name() method");
|
||||
@@ -1661,21 +1684,23 @@ public:
|
||||
virtual void tag(const string& text) {}
|
||||
virtual string tag() const { return ""; }
|
||||
virtual string verilogKwd() const { return ""; }
|
||||
string nameProtect() const VL_MT_SAFE; // Name with --protect-id applied
|
||||
string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied
|
||||
string origNameProtect() const; // origName with --protect-id applied
|
||||
string shortName() const; // Name with __PVT__ removed for concatenating scopes
|
||||
static string dedotName(const string& namein); // Name with dots removed
|
||||
static string prettyName(const string& namein); // Name for printing out to the user
|
||||
static string prettyName(const string& namein) VL_PURE; // Name for printing out to the user
|
||||
static string vpiName(const string& namein); // Name for vpi access
|
||||
static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors)
|
||||
return std::string{"'"} + prettyName(namein) + "'";
|
||||
}
|
||||
static string
|
||||
encodeName(const string& namein); // Encode user name into internal C representation
|
||||
// Encode user name into internal C representation
|
||||
static string encodeName(const string& namein);
|
||||
static string encodeNumber(int64_t num); // Encode number into internal C representation
|
||||
static string vcdName(const string& namein); // Name for printing out to vcd files
|
||||
string prettyName() const VL_MT_SAFE { return prettyName(name()); }
|
||||
string prettyName() const VL_MT_STABLE { return prettyName(name()); }
|
||||
string prettyNameQ() const { return prettyNameQ(name()); }
|
||||
string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name)
|
||||
// "VARREF" for error messages (NOT dtype's pretty name)
|
||||
string prettyTypeName() const VL_MT_STABLE;
|
||||
virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
|
||||
FileLine* fileline() const VL_MT_SAFE { return m_fileline; }
|
||||
void fileline(FileLine* fl) { m_fileline = fl; }
|
||||
@@ -1694,25 +1719,25 @@ public:
|
||||
void protect(bool flag) { m_flags.protect = flag; }
|
||||
|
||||
// TODO stomp these width functions out, and call via dtypep() instead
|
||||
inline int width() const VL_MT_SAFE;
|
||||
inline int width() const VL_MT_STABLE;
|
||||
inline int widthMin() const;
|
||||
int widthMinV() const {
|
||||
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
|
||||
}
|
||||
int widthWords() const { return VL_WORDS_I(width()); }
|
||||
bool isQuad() const VL_MT_SAFE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
|
||||
bool isWide() const VL_MT_SAFE { return (width() > VL_QUADSIZE); }
|
||||
inline bool isDouble() const;
|
||||
inline bool isSigned() const;
|
||||
inline bool isString() const;
|
||||
bool isQuad() const VL_MT_STABLE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
|
||||
bool isWide() const VL_MT_STABLE { return (width() > VL_QUADSIZE); }
|
||||
inline bool isDouble() const VL_MT_STABLE;
|
||||
inline bool isSigned() const VL_MT_STABLE;
|
||||
inline bool isString() const VL_MT_STABLE;
|
||||
|
||||
// clang-format off
|
||||
VNUser user1u() const VL_MT_SAFE {
|
||||
VNUser user1u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0});
|
||||
}
|
||||
AstNode* user1p() const VL_MT_SAFE { return user1u().toNodep(); }
|
||||
AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); }
|
||||
void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; }
|
||||
void user1p(void* userp) { user1u(VNUser{userp}); }
|
||||
int user1() const { return user1u().toInt(); }
|
||||
@@ -1721,12 +1746,12 @@ public:
|
||||
int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc()
|
||||
static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user2u() const VL_MT_SAFE {
|
||||
VNUser user2u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0});
|
||||
}
|
||||
AstNode* user2p() const VL_MT_SAFE { return user2u().toNodep(); }
|
||||
AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); }
|
||||
void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; }
|
||||
void user2p(void* userp) { user2u(VNUser{userp}); }
|
||||
int user2() const { return user2u().toInt(); }
|
||||
@@ -1735,12 +1760,12 @@ public:
|
||||
int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc()
|
||||
static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user3u() const VL_MT_SAFE {
|
||||
VNUser user3u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0});
|
||||
}
|
||||
AstNode* user3p() const VL_MT_SAFE { return user3u().toNodep(); }
|
||||
AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); }
|
||||
void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; }
|
||||
void user3p(void* userp) { user3u(VNUser{userp}); }
|
||||
int user3() const { return user3u().toInt(); }
|
||||
@@ -1749,12 +1774,12 @@ public:
|
||||
int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc()
|
||||
static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user4u() const VL_MT_SAFE {
|
||||
VNUser user4u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0});
|
||||
}
|
||||
AstNode* user4p() const VL_MT_SAFE { return user4u().toNodep(); }
|
||||
AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); }
|
||||
void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; }
|
||||
void user4p(void* userp) { user4u(VNUser{userp}); }
|
||||
int user4() const { return user4u().toInt(); }
|
||||
@@ -1763,12 +1788,12 @@ public:
|
||||
int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc()
|
||||
static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user5u() const VL_MT_SAFE {
|
||||
VNUser user5u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy");
|
||||
return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0});
|
||||
}
|
||||
AstNode* user5p() const VL_MT_SAFE { return user5u().toNodep(); }
|
||||
AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); }
|
||||
void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; }
|
||||
void user5p(void* userp) { user5u(VNUser{userp}); }
|
||||
int user5() const { return user5u().toInt(); }
|
||||
@@ -1852,12 +1877,15 @@ public:
|
||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
|
||||
// METHODS - dump and error
|
||||
void v3errorEnd(std::ostringstream& str) const VL_MT_SAFE;
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
|
||||
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||
VL_REQUIRES(V3Error::s().m_mutex);
|
||||
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
return fileline()->warnContextPrimary();
|
||||
}
|
||||
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
||||
string warnMore() const { return fileline()->warnMore(); }
|
||||
string warnOther() const { return fileline()->warnOther(); }
|
||||
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
|
||||
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
|
||||
|
||||
virtual void dump(std::ostream& str = std::cout) const;
|
||||
static void dumpGdb(const AstNode* nodep); // For GDB only
|
||||
@@ -1901,7 +1929,7 @@ public:
|
||||
// Does tree of this == node2p?, not allowing non-isGateOptimizable
|
||||
inline bool sameGateTree(const AstNode* node2p) const;
|
||||
void deleteTree(); // Always deletes the next link
|
||||
void checkTree() const VL_MT_SAFE {
|
||||
void checkTree() const VL_MT_STABLE {
|
||||
if (v3Global.opt.debugCheck()) checkTreeIter(backp());
|
||||
}
|
||||
void checkIter() const;
|
||||
@@ -1920,6 +1948,8 @@ public:
|
||||
void dumpTreeDot(std::ostream& os = std::cout) const;
|
||||
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
|
||||
|
||||
bool isTreePureRecurse() const;
|
||||
|
||||
// METHODS - queries
|
||||
// Changes control flow, disable some optimizations
|
||||
virtual bool isBrancher() const { return false; }
|
||||
@@ -1956,26 +1986,27 @@ public:
|
||||
virtual const char* broken() const { return nullptr; }
|
||||
|
||||
// INVOKERS
|
||||
virtual void accept(VNVisitor& v) = 0;
|
||||
virtual void accept(VNVisitorConst& v) = 0;
|
||||
|
||||
protected:
|
||||
// All VNVisitor related functions are called as methods off the visitor
|
||||
friend class VNVisitor;
|
||||
friend class VNVisitorConst;
|
||||
// Use instead VNVisitor::iterateChildren
|
||||
void iterateChildren(VNVisitor& v);
|
||||
// Use instead VNVisitor::iterateChildrenBackwards
|
||||
void iterateChildrenBackwards(VNVisitor& v);
|
||||
// Use instead VNVisitor::iterateChildrenBackwardsConst
|
||||
void iterateChildrenBackwardsConst(VNVisitorConst& v);
|
||||
// Use instead VNVisitor::iterateChildrenConst
|
||||
void iterateChildrenConst(VNVisitor& v);
|
||||
void iterateChildrenConst(VNVisitorConst& v);
|
||||
// Use instead VNVisitor::iterateAndNextNull
|
||||
void iterateAndNext(VNVisitor& v);
|
||||
// Use instead VNVisitor::iterateAndNextConstNull
|
||||
void iterateAndNextConst(VNVisitor& v);
|
||||
void iterateAndNextConst(VNVisitorConst& v);
|
||||
// Use instead VNVisitor::iterateSubtreeReturnEdits
|
||||
AstNode* iterateSubtreeReturnEdits(VNVisitor& v);
|
||||
|
||||
private:
|
||||
void iterateListBackwards(VNVisitor& v);
|
||||
void iterateListBackwardsConst(VNVisitorConst& v);
|
||||
|
||||
// For internal use only.
|
||||
// Note: specializations for particular node types are provided by 'astgen'
|
||||
@@ -1984,7 +2015,7 @@ private:
|
||||
|
||||
// For internal use only.
|
||||
template <typename TargetType, typename DeclType>
|
||||
constexpr static bool uselessCast() {
|
||||
constexpr static bool uselessCast() VL_PURE {
|
||||
using NonRef = typename std::remove_reference<DeclType>::type;
|
||||
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
||||
using NonCV = typename std::remove_cv<NonPtr>::type;
|
||||
@@ -1993,7 +2024,7 @@ private:
|
||||
|
||||
// For internal use only.
|
||||
template <typename TargetType, typename DeclType>
|
||||
constexpr static bool impossibleCast() {
|
||||
constexpr static bool impossibleCast() VL_PURE {
|
||||
using NonRef = typename std::remove_reference<DeclType>::type;
|
||||
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
||||
using NonCV = typename std::remove_cv<NonPtr>::type;
|
||||
@@ -2027,7 +2058,7 @@ public:
|
||||
|
||||
// For use via the VN_AS macro only
|
||||
template <typename T, typename E>
|
||||
static T* privateAs(AstNode* nodep) VL_MT_SAFE {
|
||||
static T* privateAs(AstNode* nodep) VL_PURE {
|
||||
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
|
||||
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
|
||||
@@ -2036,7 +2067,7 @@ public:
|
||||
return reinterpret_cast<T*>(nodep);
|
||||
}
|
||||
template <typename T, typename E>
|
||||
static const T* privateAs(const AstNode* nodep) VL_MT_SAFE {
|
||||
static const T* privateAs(const AstNode* nodep) VL_PURE {
|
||||
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
|
||||
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
|
||||
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
|
||||
@@ -2475,24 +2506,29 @@ struct std::equal_to<VNRef<T_Node>> final {
|
||||
//######################################################################
|
||||
// Inline VNVisitor METHODS
|
||||
|
||||
void VNVisitorConst::iterateConst(AstNode* nodep) { nodep->accept(*this); }
|
||||
void VNVisitorConst::iterateConstNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->accept(*this);
|
||||
}
|
||||
void VNVisitorConst::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
|
||||
void VNVisitorConst::iterateChildrenBackwardsConst(AstNode* nodep) {
|
||||
nodep->iterateChildrenBackwardsConst(*this);
|
||||
}
|
||||
void VNVisitorConst::iterateAndNextConstNullBackwards(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateListBackwardsConst(*this);
|
||||
}
|
||||
void VNVisitorConst::iterateAndNextConstNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
|
||||
}
|
||||
|
||||
void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); }
|
||||
void VNVisitor::iterateNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->accept(*this);
|
||||
}
|
||||
void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); }
|
||||
void VNVisitor::iterateChildrenBackwards(AstNode* nodep) {
|
||||
nodep->iterateChildrenBackwards(*this);
|
||||
}
|
||||
void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
|
||||
void VNVisitor::iterateAndNextNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this);
|
||||
}
|
||||
void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateListBackwards(*this);
|
||||
}
|
||||
void VNVisitor::iterateAndNextConstNull(AstNode* nodep) {
|
||||
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
|
||||
}
|
||||
AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
|
||||
return nodep->iterateSubtreeReturnEdits(*this);
|
||||
}
|
||||
|
||||
+15
-15
@@ -25,7 +25,7 @@
|
||||
//######################################################################
|
||||
// Inline METHODS
|
||||
|
||||
int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; }
|
||||
int AstNode::width() const VL_MT_STABLE { return dtypep() ? dtypep()->width() : 0; }
|
||||
int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; }
|
||||
bool AstNode::width1() const { // V3Const uses to know it can optimize
|
||||
return dtypep() && dtypep()->width() == 1;
|
||||
@@ -33,13 +33,13 @@ bool AstNode::width1() const { // V3Const uses to know it can optimize
|
||||
int AstNode::widthInstrs() const {
|
||||
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
|
||||
}
|
||||
bool AstNode::isDouble() const VL_MT_SAFE {
|
||||
bool AstNode::isDouble() const VL_MT_STABLE {
|
||||
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
|
||||
}
|
||||
bool AstNode::isString() const VL_MT_SAFE {
|
||||
bool AstNode::isString() const VL_MT_STABLE {
|
||||
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
|
||||
}
|
||||
bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
|
||||
bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); }
|
||||
|
||||
bool AstNode::isZero() const {
|
||||
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
|
||||
@@ -61,12 +61,12 @@ bool AstNode::sameGateTree(const AstNode* node2p) const {
|
||||
return sameTreeIter(this, node2p, true, true);
|
||||
}
|
||||
|
||||
int AstNodeArrayDType::left() const VL_MT_SAFE { return rangep()->leftConst(); }
|
||||
int AstNodeArrayDType::right() const VL_MT_SAFE { return rangep()->rightConst(); }
|
||||
int AstNodeArrayDType::hi() const VL_MT_SAFE { return rangep()->hiConst(); }
|
||||
int AstNodeArrayDType::lo() const VL_MT_SAFE { return rangep()->loConst(); }
|
||||
int AstNodeArrayDType::elementsConst() const VL_MT_SAFE { return rangep()->elementsConst(); }
|
||||
VNumRange AstNodeArrayDType::declRange() const VL_MT_SAFE { return VNumRange{left(), right()}; }
|
||||
int AstNodeArrayDType::left() const VL_MT_STABLE { return rangep()->leftConst(); }
|
||||
int AstNodeArrayDType::right() const VL_MT_STABLE { return rangep()->rightConst(); }
|
||||
int AstNodeArrayDType::hi() const VL_MT_STABLE { return rangep()->hiConst(); }
|
||||
int AstNodeArrayDType::lo() const VL_MT_STABLE { return rangep()->loConst(); }
|
||||
int AstNodeArrayDType::elementsConst() const VL_MT_STABLE { return rangep()->elementsConst(); }
|
||||
VNumRange AstNodeArrayDType::declRange() const VL_MT_STABLE { return VNumRange{left(), right()}; }
|
||||
|
||||
AstRange::AstRange(FileLine* fl, int left, int right)
|
||||
: ASTGEN_SUPER_Range(fl) {
|
||||
@@ -78,16 +78,16 @@ AstRange::AstRange(FileLine* fl, const VNumRange& range)
|
||||
leftp(new AstConst{fl, static_cast<uint32_t>(range.left())});
|
||||
rightp(new AstConst{fl, static_cast<uint32_t>(range.right())});
|
||||
}
|
||||
int AstRange::leftConst() const {
|
||||
int AstRange::leftConst() const VL_MT_STABLE {
|
||||
AstConst* const constp = VN_CAST(leftp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
int AstRange::rightConst() const {
|
||||
int AstRange::rightConst() const VL_MT_STABLE {
|
||||
AstConst* const constp = VN_CAST(rightp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
|
||||
int AstQueueDType::boundConst() const VL_MT_SAFE {
|
||||
int AstQueueDType::boundConst() const VL_MT_STABLE {
|
||||
AstConst* const constp = VN_CAST(boundp(), Const);
|
||||
return (constp ? constp->toSInt() : 0);
|
||||
}
|
||||
@@ -123,8 +123,8 @@ int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nra
|
||||
int AstBasicDType::elements() const {
|
||||
return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements());
|
||||
}
|
||||
bool AstBasicDType::littleEndian() const {
|
||||
return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian());
|
||||
bool AstBasicDType::ascending() const {
|
||||
return (rangep() ? rangep()->ascending() : m.m_nrange.ascending());
|
||||
}
|
||||
|
||||
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
|
||||
|
||||
+116
-96
@@ -60,10 +60,12 @@ public:
|
||||
/// are compound when methods calls operate on object, or when
|
||||
/// under another compound-requiring object e.g. class
|
||||
virtual bool isCompound() const = 0;
|
||||
// Integral or packed, allowed inside an unpacked union/struct
|
||||
virtual bool isIntegralOrPacked() const { return !isCompound(); }
|
||||
// (Slow) recurse down to find basic data type
|
||||
virtual AstBasicDType* basicp() const = 0;
|
||||
virtual AstBasicDType* basicp() const VL_MT_STABLE = 0;
|
||||
// recurses over typedefs/const/enum to next non-typeref type
|
||||
virtual AstNodeDType* skipRefp() const = 0;
|
||||
virtual AstNodeDType* skipRefp() const VL_MT_STABLE = 0;
|
||||
// recurses over typedefs to next non-typeref-or-const type
|
||||
virtual AstNodeDType* skipRefToConstp() const = 0;
|
||||
// recurses over typedefs/const to next non-typeref-or-enum/struct type
|
||||
@@ -84,7 +86,7 @@ public:
|
||||
// Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
virtual bool similarDType(const AstNodeDType* samep) const = 0;
|
||||
// Iff has a non-null subDTypep(), as generic node function
|
||||
virtual AstNodeDType* subDTypep() const { return nullptr; }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_SAFE { return nullptr; }
|
||||
virtual bool isFourstate() const;
|
||||
// Ideally an IEEE $typename
|
||||
virtual string prettyDTypeName() const { return prettyTypeName(); }
|
||||
@@ -124,12 +126,13 @@ public:
|
||||
const char* charIQWN() const {
|
||||
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
|
||||
}
|
||||
string cType(const string& name, bool forFunc, bool isRef) const VL_MT_SAFE;
|
||||
bool isLiteralType() const VL_MT_SAFE; // Represents a C++ LiteralType? (can be constexpr)
|
||||
string cType(const string& name, bool forFunc, bool isRef) const VL_MT_STABLE;
|
||||
// Represents a C++ LiteralType? (can be constexpr)
|
||||
bool isLiteralType() const VL_MT_STABLE;
|
||||
|
||||
private:
|
||||
class CTypeRecursed;
|
||||
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_SAFE;
|
||||
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_STABLE;
|
||||
};
|
||||
class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
|
||||
// Array data type, ie "some_dtype var_name [2:0]"
|
||||
@@ -168,29 +171,29 @@ public:
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE {
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE {
|
||||
return subDTypep()->basicp();
|
||||
} // (Slow) recurse down to find basic data type
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override {
|
||||
return elementsConst() * subDTypep()->widthTotalBytes();
|
||||
}
|
||||
inline int left() const;
|
||||
inline int right() const;
|
||||
inline int hi() const;
|
||||
inline int lo() const;
|
||||
inline int elementsConst() const;
|
||||
inline VNumRange declRange() const;
|
||||
inline int left() const VL_MT_STABLE;
|
||||
inline int right() const VL_MT_STABLE;
|
||||
inline int hi() const VL_MT_STABLE;
|
||||
inline int lo() const VL_MT_STABLE;
|
||||
inline int elementsConst() const VL_MT_STABLE;
|
||||
inline VNumRange declRange() const VL_MT_STABLE;
|
||||
};
|
||||
class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
|
||||
// A struct or union; common handling
|
||||
@@ -200,6 +203,7 @@ private:
|
||||
using MemberNameMap = std::map<const std::string, AstMemberDType*>;
|
||||
// MEMBERS
|
||||
string m_name; // Name from upper typedef, if any
|
||||
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
||||
MemberNameMap m_members;
|
||||
const int m_uniqueNum;
|
||||
bool m_packed;
|
||||
@@ -228,7 +232,7 @@ public:
|
||||
: VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
BasicDType));
|
||||
}
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
@@ -238,14 +242,14 @@ public:
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
return this == samep; // We don't compare members, require exact equivalence
|
||||
}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool packed() const VL_MT_SAFE { return m_packed; }
|
||||
void packed(bool flag) { m_packed = flag; }
|
||||
// packed() but as don't support unpacked, presently all structs
|
||||
static bool packedUnsup() { return true; }
|
||||
void isFourstate(bool flag) { m_isFourstate = flag; }
|
||||
bool isFourstate() const override { return m_isFourstate; }
|
||||
bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; }
|
||||
void clearCache() { m_members.clear(); }
|
||||
void repairMemberCache();
|
||||
AstMemberDType* findMember(const string& name) const {
|
||||
@@ -255,6 +259,8 @@ public:
|
||||
static int lo() { return 0; }
|
||||
int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays
|
||||
VNumRange declRange() const { return VNumRange{hi(), lo()}; }
|
||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
@@ -275,7 +281,7 @@ public:
|
||||
this->valuep(valuep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstEnumItem;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
@@ -331,7 +337,7 @@ public:
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
@@ -340,13 +346,13 @@ public:
|
||||
AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; }
|
||||
void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); }
|
||||
//
|
||||
AstNodeDType* keyDTypep() const VL_MT_SAFE {
|
||||
AstNodeDType* keyDTypep() const VL_MT_STABLE {
|
||||
return m_keyDTypep ? m_keyDTypep : keyChildDTypep();
|
||||
}
|
||||
void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
@@ -396,14 +402,11 @@ public:
|
||||
ASTGEN_MEMBERS_AstBasicDType;
|
||||
void dump(std::ostream& str) const override;
|
||||
// width/widthMin/numeric compared elsewhere
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
|
||||
return m == sp->m;
|
||||
}
|
||||
bool same(const AstNode* samep) const override;
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
return type() == samep->type() && same(samep);
|
||||
}
|
||||
string name() const override { return m.m_keyword.ascii(); }
|
||||
string name() const override VL_MT_STABLE { return m.m_keyword.ascii(); }
|
||||
string prettyDTypeName() const override;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(dtypep() != this);
|
||||
@@ -418,8 +421,8 @@ public:
|
||||
}
|
||||
}
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return (AstBasicDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return (AstBasicDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
@@ -462,14 +465,15 @@ public:
|
||||
inline int hi() const;
|
||||
inline int lo() const;
|
||||
inline int elements() const;
|
||||
int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration
|
||||
int right() const { return littleEndian() ? hi() : lo(); }
|
||||
inline bool littleEndian() const;
|
||||
int left() const { return ascending() ? lo() : hi(); } // How to show a declaration
|
||||
int right() const { return ascending() ? hi() : lo(); }
|
||||
inline bool ascending() const;
|
||||
bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; }
|
||||
bool untyped() const { return keyword() == VBasicDTypeKwd::UNTYPED; }
|
||||
VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; }
|
||||
void cvtRangeConst(); // Convert to smaller representation
|
||||
bool isCompound() const override { return isString(); }
|
||||
bool isIntegralOrPacked() const override { return keyword().isIntNumeric(); }
|
||||
};
|
||||
class AstBracketArrayDType final : public AstNodeDType {
|
||||
// Associative/Queue/Normal array data type, ie "[dtype_or_expr]"
|
||||
@@ -485,13 +489,13 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstBracketArrayDType;
|
||||
bool similarDType(const AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); }
|
||||
AstNodeDType* subDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return childDTypep(); }
|
||||
// METHODS
|
||||
// Will be removed in V3Width, which relies on this
|
||||
// being a child not a dtype pointed node
|
||||
bool maybePointedTo() const override { return false; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); }
|
||||
@@ -524,19 +528,19 @@ public:
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override;
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
string name() const override VL_MT_STABLE;
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return 0; }
|
||||
int widthTotalBytes() const override { return 0; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
AstNodeDType* subDTypep() const override { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
AstClass* classp() const { return m_classp; }
|
||||
AstClass* classp() const VL_MT_STABLE { return m_classp; }
|
||||
void classp(AstClass* nodep) { m_classp = nodep; }
|
||||
bool isCompound() const override { return true; }
|
||||
};
|
||||
@@ -572,13 +576,15 @@ public:
|
||||
return skipRefp()->similarDType(samep->skipRefp());
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
@@ -619,18 +625,20 @@ public:
|
||||
return type() == samep->type() && same(samep);
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
void* containerp() const { return m_containerp; }
|
||||
// METHODS
|
||||
// op1 = Range of variable
|
||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool isCompound() const override { return false; }
|
||||
};
|
||||
@@ -673,15 +681,15 @@ public:
|
||||
string prettyDTypeName() const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
@@ -700,13 +708,13 @@ public:
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
@@ -750,17 +758,19 @@ public:
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
@@ -812,8 +822,8 @@ public:
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
void cloneRelink() override;
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
@@ -839,6 +849,7 @@ class AstMemberDType final : public AstNodeDType {
|
||||
// A member of a struct/union
|
||||
// PARENT: AstNodeUOrStructDType
|
||||
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
||||
// @astgen op3 := valuep : Optional[AstNode]
|
||||
private:
|
||||
AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing)
|
||||
string m_name; // Name of variable
|
||||
@@ -846,10 +857,12 @@ private:
|
||||
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
||||
// UNSUP: int m_randType; // Randomization type (IEEE)
|
||||
public:
|
||||
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
||||
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
||||
AstNode* valuep)
|
||||
: ASTGEN_SUPER_MemberDType(fl)
|
||||
, m_name{name} {
|
||||
childDTypep(dtp); // Only for parser
|
||||
this->valuep(valuep);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
refDTypep(nullptr);
|
||||
}
|
||||
@@ -862,7 +875,8 @@ public:
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_AstMemberDType;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
const char* broken() const override {
|
||||
@@ -873,7 +887,9 @@ public:
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
@@ -881,10 +897,10 @@ public:
|
||||
//
|
||||
// (Slow) recurse down to find basic data type (Note don't need virtual -
|
||||
// AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
// op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
@@ -921,9 +937,11 @@ public:
|
||||
ASTGEN_MEMBERS_AstParamTypeDType;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
@@ -934,7 +952,7 @@ public:
|
||||
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
// METHODS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
@@ -957,8 +975,8 @@ public:
|
||||
AstNodeDType* dtypep() const { return nullptr; }
|
||||
// METHODS
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
@@ -1012,17 +1030,17 @@ public:
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string prettyDTypeName() const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
inline int boundConst() const;
|
||||
inline int boundConst() const VL_MT_STABLE;
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
@@ -1072,15 +1090,15 @@ public:
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
string prettyDTypeName() const override {
|
||||
return subDTypep() ? prettyName(subDTypep()->name()) : prettyName();
|
||||
}
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE {
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE {
|
||||
return subDTypep() ? subDTypep()->basicp() : nullptr;
|
||||
}
|
||||
AstNodeDType* subDTypep() const override;
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE;
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE {
|
||||
// Skip past both the Ref and the Typedef
|
||||
if (subDTypep()) {
|
||||
return subDTypep()->skipRefp();
|
||||
@@ -1109,9 +1127,9 @@ public:
|
||||
int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||
AstTypedef* typedefp() const { return m_typedefp; }
|
||||
AstTypedef* typedefp() const VL_MT_SAFE { return m_typedefp; }
|
||||
void typedefp(AstTypedef* nodep) { m_typedefp = nodep; }
|
||||
AstNodeDType* refDTypep() const { return m_refDTypep; }
|
||||
AstNodeDType* refDTypep() const VL_MT_SAFE { return m_refDTypep; }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return refDTypep(); }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
@@ -1153,13 +1171,15 @@ public:
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
// op1 = Range of variable
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return sizeof(std::map<std::string, std::string>); }
|
||||
@@ -1191,13 +1211,15 @@ public:
|
||||
bool similarDType(const AstNodeDType* samep) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
@@ -1216,13 +1238,13 @@ public:
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
// cppcheck-suppress csyleCast
|
||||
@@ -1256,15 +1278,15 @@ public:
|
||||
bool similarDType(const AstNodeDType* samep) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE {
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return sizeof(std::map<std::string, std::string>); }
|
||||
@@ -1315,19 +1337,17 @@ public:
|
||||
std::vector<AstUnpackArrayDType*> unpackDimensions();
|
||||
void isCompound(bool flag) { m_isCompound = flag; }
|
||||
bool isCompound() const override VL_MT_SAFE { return m_isCompound; }
|
||||
bool isIntegralOrPacked() const override { return false; }
|
||||
};
|
||||
|
||||
// === AstNodeUOrStructDType ===
|
||||
class AstStructDType final : public AstNodeUOrStructDType {
|
||||
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
||||
public:
|
||||
// VSigning below is mispurposed to indicate if packed or not
|
||||
AstStructDType(FileLine* fl, VSigning numericUnpack)
|
||||
: ASTGEN_SUPER_StructDType(fl, numericUnpack) {}
|
||||
ASTGEN_MEMBERS_AstStructDType;
|
||||
string verilogKwd() const override { return "struct"; }
|
||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||
};
|
||||
class AstUnionDType final : public AstNodeUOrStructDType {
|
||||
public:
|
||||
|
||||
+211
-34
@@ -236,7 +236,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool isGateOptimizable() const override;
|
||||
string dotted() const { return m_dotted; } // * = Scope name or ""
|
||||
string inlinedDots() const { return m_inlinedDots; }
|
||||
@@ -249,6 +249,7 @@ public:
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
bool pli() const { return m_pli; }
|
||||
void pli(bool flag) { m_pli = flag; }
|
||||
bool isPure() const override;
|
||||
|
||||
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -321,7 +322,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstNodeTermop;
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(VNVisitor& v) {}
|
||||
void iterateChildren(VNVisitorConst& v) {}
|
||||
void dump(std::ostream& str) const override;
|
||||
};
|
||||
class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
|
||||
@@ -473,7 +474,7 @@ public:
|
||||
const char* broken() const override;
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
void cloneRelink() override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
VAccess access() const { return m_access; }
|
||||
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
|
||||
@@ -491,7 +492,7 @@ public:
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(VNVisitor& v) {}
|
||||
void iterateChildren(VNVisitorConst& v) {}
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
@@ -531,7 +532,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstArg;
|
||||
bool hasDType() const override { return false; }
|
||||
string name() const override { return m_name; } // * = Pin name, ""=go by number
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
|
||||
|
||||
@@ -609,7 +610,7 @@ public:
|
||||
this->addPinsp(pinsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCMethodHard;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCMethodHard* asamep = static_cast<const AstCMethodHard*>(samep);
|
||||
@@ -643,7 +644,7 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
||||
};
|
||||
class AstCastParse final : public AstNodeExpr {
|
||||
// Cast to appropriate type, where we haven't determined yet what the data type is
|
||||
@@ -688,7 +689,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCellArrayRef;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Array name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -709,7 +710,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCellRef;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Array name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -745,7 +746,7 @@ public:
|
||||
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
|
||||
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
|
||||
AstNodeModule* classOrPackagep() const;
|
||||
@@ -790,6 +791,51 @@ public:
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstConsPackMember final : public AstNodeExpr {
|
||||
// Construct a packed array single emement [member1: value1]
|
||||
// Don't need the member we are constructing, as the dtypep can get us to it
|
||||
// @astgen op2 := rhsp : AstNodeExpr
|
||||
public:
|
||||
explicit AstConsPackMember(FileLine* fl, AstMemberDType* dtypep, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_ConsPackMember(fl) {
|
||||
this->dtypep(dtypep);
|
||||
this->rhsp(rhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConsPackMember;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), MemberDType));
|
||||
return nullptr;
|
||||
}
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstConsPackUOrStruct final : public AstNodeExpr {
|
||||
// Construct a packed struct and return object, '{member1: value1, member2: value2}
|
||||
// Don't need the class we are constructing, as the dtypep can get us to it
|
||||
// @astgen op1 := membersp : List[AstConsPackMember]
|
||||
public:
|
||||
explicit AstConsPackUOrStruct(FileLine* fl, AstNodeUOrStructDType* dtypep,
|
||||
AstConsPackMember* membersp = nullptr)
|
||||
: ASTGEN_SUPER_ConsPackUOrStruct(fl) {
|
||||
this->dtypep(dtypep);
|
||||
this->addMembersp(membersp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConsPackUOrStruct;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), NodeUOrStructDType));
|
||||
return nullptr;
|
||||
}
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstConsQueue final : public AstNodeExpr {
|
||||
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
|
||||
// @astgen op1 := lhsp : Optional[AstNode]
|
||||
@@ -944,7 +990,7 @@ public:
|
||||
initWithNumber();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConst;
|
||||
string name() const override { return num().ascii(); } // * = Value
|
||||
string name() const override VL_MT_STABLE { return num().ascii(); } // * = Value
|
||||
const V3Number& num() const VL_MT_SAFE { return m_num; } // * = Value
|
||||
V3Number& num() { return m_num; } // * = Value
|
||||
uint32_t toUInt() const { return num().toUInt(); }
|
||||
@@ -1012,7 +1058,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstEnumItemRef;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return itemp()->name(); }
|
||||
string name() const override VL_MT_STABLE { return itemp()->name(); }
|
||||
int instrCount() const override { return 0; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override {
|
||||
@@ -1022,7 +1068,7 @@ public:
|
||||
const AstEnumItemRef* const sp = static_cast<const AstEnumItemRef*>(samep);
|
||||
return itemp() == sp->itemp();
|
||||
}
|
||||
AstEnumItem* itemp() const { return m_itemp; }
|
||||
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
@@ -1063,9 +1109,50 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpen final : public AstNodeExpr {
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
// @astgen op3 := modep : AstNodeExpr
|
||||
public:
|
||||
AstFOpen(FileLine* fl, AstNodeExpr* filenamep, AstNodeExpr* modep)
|
||||
: ASTGEN_SUPER_FOpen(fl) {
|
||||
this->filenamep(filenamep);
|
||||
this->modep(modep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpen;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpenMcd final : public AstNodeExpr {
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
public:
|
||||
AstFOpenMcd(FileLine* fl, AstNodeExpr* filenamep)
|
||||
: ASTGEN_SUPER_FOpenMcd(fl) {
|
||||
this->filenamep(filenamep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpenMcd;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFRead final : public AstNodeExpr {
|
||||
// @astgen op1 := memp : AstNode // VarRef for result
|
||||
// @astgen op2 := filep : AstNode // file (must be a VarRef)
|
||||
@@ -1122,7 +1209,7 @@ public:
|
||||
this->filep(filep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFScanF;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string verilogKwd() const override { return "$fscanf"; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -1183,9 +1270,10 @@ class AstFell final : public AstNodeExpr {
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
// @astgen op2 := sentreep : Optional[AstSenTree]
|
||||
public:
|
||||
AstFell(FileLine* fl, AstNodeExpr* exprp)
|
||||
AstFell(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
|
||||
: ASTGEN_SUPER_Fell(fl) {
|
||||
this->exprp(exprp);
|
||||
this->sentreep(sentreep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFell;
|
||||
string emitVerilog() override { return "$fell(%l)"; }
|
||||
@@ -1318,7 +1406,7 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool index() const { return m_index; }
|
||||
};
|
||||
@@ -1344,7 +1432,8 @@ public:
|
||||
void cloneRelink() override;
|
||||
const char* broken() const override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return false; }
|
||||
@@ -1408,7 +1497,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstParseRef;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstParseRef* const asamep = static_cast<const AstParseRef*>(samep);
|
||||
return (expect() == asamep->expect() && m_name == asamep->m_name);
|
||||
@@ -1485,7 +1574,7 @@ public:
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
||||
};
|
||||
class AstRand final : public AstNodeExpr {
|
||||
// $random/$random(seed) or $urandom/$urandom(seed)
|
||||
@@ -1531,14 +1620,35 @@ public:
|
||||
bool reset() const { return m_reset; }
|
||||
bool urandom() const { return m_urandom; }
|
||||
};
|
||||
class AstRandRNG final : public AstNodeExpr {
|
||||
// Random used in a class using VlRNG
|
||||
// Return a random number, based upon width()
|
||||
public:
|
||||
AstRandRNG(FileLine* fl, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_RandRNG(fl) {
|
||||
dtypep(dtp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstRandRNG;
|
||||
string emitVerilog() override { return "%f$rngrandom()"; }
|
||||
string emitC() override {
|
||||
return isWide() ? "VL_RANDOM_RNG_%nq(__Vm_rng, %nw, %P)" //
|
||||
: "VL_RANDOM_RNG_%nq(__Vm_rng)";
|
||||
}
|
||||
bool cleanOut() const override { return false; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstRose final : public AstNodeExpr {
|
||||
// Verilog $rose
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
// @astgen op2 := sentreep : Optional[AstSenTree]
|
||||
public:
|
||||
AstRose(FileLine* fl, AstNodeExpr* exprp)
|
||||
AstRose(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
|
||||
: ASTGEN_SUPER_Rose(fl) {
|
||||
this->exprp(exprp);
|
||||
this->sentreep(sentreep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstRose;
|
||||
string emitVerilog() override { return "$rose(%l)"; }
|
||||
@@ -1581,7 +1691,7 @@ public:
|
||||
addExprsp(exprsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSFormatF;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return text() == static_cast<const AstSFormatF*>(samep)->text();
|
||||
@@ -1616,7 +1726,7 @@ public:
|
||||
this->fromp(fromp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSScanF;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string verilogKwd() const override { return "$sscanf"; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -1754,9 +1864,10 @@ class AstStable final : public AstNodeExpr {
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
// @astgen op2 := sentreep : Optional[AstSenTree]
|
||||
public:
|
||||
AstStable(FileLine* fl, AstNodeExpr* exprp)
|
||||
AstStable(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
|
||||
: ASTGEN_SUPER_Stable(fl) {
|
||||
this->exprp(exprp);
|
||||
this->sentreep(sentreep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstStable;
|
||||
string emitVerilog() override { return "$stable(%l)"; }
|
||||
@@ -1800,7 +1911,8 @@ public:
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_AstStructSel;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return false; }
|
||||
@@ -1880,7 +1992,7 @@ public:
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool cleanOut() const override { return true; }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
||||
};
|
||||
class AstTimePrecision final : public AstNodeExpr {
|
||||
// Verilog $timeprecision
|
||||
@@ -2108,7 +2220,7 @@ public:
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opCompareNN(lhs, rhs, m_ignoreCase);
|
||||
}
|
||||
string name() const override { return m_ignoreCase ? "icompare" : "compare"; }
|
||||
string name() const override VL_MT_STABLE { return m_ignoreCase ? "icompare" : "compare"; }
|
||||
string emitVerilog() override {
|
||||
return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))";
|
||||
}
|
||||
@@ -2313,6 +2425,7 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
AstNode* charp() const { return rhsp(); }
|
||||
@@ -2331,7 +2444,7 @@ public:
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opGetcN(lhs, rhs);
|
||||
}
|
||||
string name() const override { return "getc"; }
|
||||
string name() const override VL_MT_STABLE { return "getc"; }
|
||||
string emitVerilog() override { return "%k(%l.getc(%r))"; }
|
||||
string emitC() override { return "VL_GETC_N(%li,%ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
@@ -3304,6 +3417,30 @@ public:
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
bool stringFlavor() const override { return true; }
|
||||
};
|
||||
class AstEqT final : public AstNodeBiCom {
|
||||
// Equal (==) for data types
|
||||
public:
|
||||
AstEqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_EqT(fl, lhsp, rhsp) {
|
||||
dtypeSetBit();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstEqT;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstEqT{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
V3ERROR_NA;
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f== %r)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { return "=="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
};
|
||||
class AstLogEq final : public AstNodeBiCom {
|
||||
public:
|
||||
AstLogEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
@@ -3419,6 +3556,30 @@ public:
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
bool stringFlavor() const override { return true; }
|
||||
};
|
||||
class AstNeqT final : public AstNodeBiCom {
|
||||
// Not-equal (!=) for data types
|
||||
public:
|
||||
AstNeqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_NeqT(fl, lhsp, rhsp) {
|
||||
dtypeSetBit();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstNeqT;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstNeqT{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
V3ERROR_NA;
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f!= %r)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { return "!="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
};
|
||||
|
||||
// === AstNodeBiComAsv ===
|
||||
class AstAdd final : public AstNodeBiComAsv {
|
||||
@@ -3913,7 +4074,6 @@ public:
|
||||
BROKEN_RTN(!fromp());
|
||||
return nullptr;
|
||||
}
|
||||
void dump(std::ostream& str) const override;
|
||||
};
|
||||
class AstNew final : public AstNodeFTaskRef {
|
||||
// New as constructor
|
||||
@@ -4164,7 +4324,7 @@ public:
|
||||
const V3Number& ths) override {
|
||||
out.opPutcN(lhs, rhs, ths);
|
||||
}
|
||||
string name() const override { return "putc"; }
|
||||
string name() const override VL_MT_STABLE { return "putc"; }
|
||||
string emitVerilog() override { return "%k(%l.putc(%r,%t))"; }
|
||||
string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
@@ -4271,7 +4431,7 @@ public:
|
||||
const V3Number& ths) override {
|
||||
out.opSubstrN(lhs, rhs, ths);
|
||||
}
|
||||
string name() const override { return "substr"; }
|
||||
string name() const override VL_MT_STABLE { return "substr"; }
|
||||
string emitVerilog() override { return "%k(%l.substr(%r,%t))"; }
|
||||
string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
@@ -4348,15 +4508,15 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstAtoN;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); }
|
||||
string name() const override {
|
||||
string name() const override VL_MT_STABLE {
|
||||
switch (m_fmt) {
|
||||
case ATOI: return "atoi";
|
||||
case ATOHEX: return "atohex";
|
||||
case ATOOCT: return "atooct";
|
||||
case ATOBIN: return "atobin";
|
||||
case ATOREAL: return "atoreal";
|
||||
default: V3ERROR_NA;
|
||||
}
|
||||
V3ERROR_NA_RETURN("");
|
||||
}
|
||||
string emitVerilog() override { return "%l." + name() + "()"; }
|
||||
string emitC() override {
|
||||
@@ -4366,8 +4526,8 @@ public:
|
||||
case ATOOCT: return "VL_ATOI_N(%li, 8)";
|
||||
case ATOBIN: return "VL_ATOI_N(%li, 2)";
|
||||
case ATOREAL: return "std::atof(%li.c_str())";
|
||||
default: V3ERROR_NA;
|
||||
}
|
||||
V3ERROR_NA_RETURN("");
|
||||
}
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
@@ -4495,7 +4655,7 @@ public:
|
||||
dtypeSetString();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCvtPackString;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
|
||||
string emitVerilog() override { return "%f$_CAST(%l)"; }
|
||||
string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
@@ -4559,6 +4719,7 @@ public:
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 16; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
@@ -4575,6 +4736,7 @@ public:
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
@@ -4674,6 +4836,21 @@ public:
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
};
|
||||
class AstNToI final : public AstNodeUniop {
|
||||
// String to any-size integral
|
||||
public:
|
||||
AstNToI(FileLine* fl, AstNodeExpr* lhsp, AstNodeDType* dtypep = nullptr)
|
||||
: ASTGEN_SUPER_NToI(fl, lhsp) {
|
||||
this->dtypep(dtypep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstNToI;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNToI(lhs); }
|
||||
string emitVerilog() override { return "'(%l)"; }
|
||||
string emitC() override { return "VL_NTOI_%nq(%nw, %P, %li)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
};
|
||||
class AstNegate final : public AstNodeUniop {
|
||||
public:
|
||||
AstNegate(FileLine* fl, AstNodeExpr* lhsp)
|
||||
|
||||
+95
-110
@@ -48,7 +48,7 @@ protected:
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstNodeBlock;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; } // * = Block name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool unnamed() const { return m_unnamed; }
|
||||
bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); }
|
||||
@@ -118,7 +118,7 @@ protected:
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstNodeFTask;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); }
|
||||
// {AstFunc only} op1 = Range output variable
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstNodeFile;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstNodeModule VL_NOT_FINAL : public AstNode {
|
||||
@@ -210,6 +210,7 @@ private:
|
||||
bool m_modTrace : 1; // Tracing this module
|
||||
bool m_inLibrary : 1; // From a library, no error if not used, never top level
|
||||
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
|
||||
bool m_hasGParam : 1; // Has global parameter (for link)
|
||||
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
|
||||
bool m_internal : 1; // Internally created
|
||||
bool m_recursive : 1; // Recursive module
|
||||
@@ -223,6 +224,7 @@ protected:
|
||||
, m_modTrace{false}
|
||||
, m_inLibrary{false}
|
||||
, m_dead{false}
|
||||
, m_hasGParam{false}
|
||||
, m_hierBlock{false}
|
||||
, m_internal{false}
|
||||
, m_recursive{false}
|
||||
@@ -232,7 +234,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstNodeModule;
|
||||
void dump(std::ostream& str) const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
virtual bool timescaleMatters() const = 0;
|
||||
// ACCESSORS
|
||||
void name(const string& name) override { m_name = name; }
|
||||
@@ -250,6 +252,8 @@ public:
|
||||
bool modTrace() const { return m_modTrace; }
|
||||
void dead(bool flag) { m_dead = flag; }
|
||||
bool dead() const { return m_dead; }
|
||||
void hasGParam(bool flag) { m_hasGParam = flag; }
|
||||
bool hasGParam() const { return m_hasGParam; }
|
||||
void hierBlock(bool flag) { m_hierBlock = flag; }
|
||||
bool hierBlock() const { return m_hierBlock; }
|
||||
void internal(bool flag) { m_internal = flag; }
|
||||
@@ -369,7 +373,7 @@ public:
|
||||
this->addPasssp(passsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstNodeCoverOrAssert;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool same(const AstNode* samep) const override { return samep->name() == name(); }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
@@ -508,7 +512,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstActive;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
// Statements are broken into pieces, as some must come before others.
|
||||
@@ -533,7 +537,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstBind;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Bind Target name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Bind Target name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
};
|
||||
class AstCFunc final : public AstNode {
|
||||
@@ -603,7 +607,7 @@ public:
|
||||
m_dpiTraceInit = false;
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
@@ -698,7 +702,7 @@ public:
|
||||
, m_useType{useType} {}
|
||||
ASTGEN_MEMBERS_AstCUse;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
VUseType useType() const { return m_useType; }
|
||||
};
|
||||
class AstCaseItem final : public AstNode {
|
||||
@@ -751,7 +755,7 @@ public:
|
||||
const char* broken() const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Cell name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string origName() const override { return m_origName; } // * = Original name
|
||||
void origName(const string& name) { m_origName = name; }
|
||||
@@ -790,7 +794,7 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
const char* broken() const override;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Cell name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
||||
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void scopep(AstScope* scp) { m_scopep = scp; }
|
||||
@@ -799,19 +803,24 @@ public:
|
||||
VTimescale timeunit() const { return m_timeunit; }
|
||||
};
|
||||
class AstClassExtends final : public AstNode {
|
||||
// class extends class name, or class implements class name
|
||||
// Children: List of AstParseRef for packages/classes
|
||||
// during early parse, then moves to dtype
|
||||
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
||||
// @astgen op2 := classOrPkgsp : Optional[AstNode]
|
||||
const bool m_isImplements = false; // class implements
|
||||
public:
|
||||
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp)
|
||||
: ASTGEN_SUPER_ClassExtends(fl) {
|
||||
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements)
|
||||
: ASTGEN_SUPER_ClassExtends(fl)
|
||||
, m_isImplements{isImplements} {
|
||||
this->classOrPkgsp(classOrPkgsp); // Only for parser
|
||||
}
|
||||
ASTGEN_MEMBERS_AstClassExtends;
|
||||
void dump(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
string verilogKwd() const override { return "extends"; }
|
||||
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
|
||||
AstClass* classp() const; // Class being extended (after link)
|
||||
bool isImplements() const { return m_isImplements; }
|
||||
};
|
||||
class AstClocking final : public AstNode {
|
||||
// Parents: MODULE
|
||||
@@ -822,19 +831,23 @@ class AstClocking final : public AstNode {
|
||||
// @astgen op4 := eventp : Optional[AstVar]
|
||||
std::string m_name; // Clocking block name
|
||||
const bool m_isDefault = false; // True if default clocking
|
||||
const bool m_isGlobal = false; // True if global clocking
|
||||
|
||||
public:
|
||||
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
|
||||
AstClockingItem* itemsp, bool isDefault)
|
||||
AstClockingItem* itemsp, bool isDefault, bool isGlobal)
|
||||
: ASTGEN_SUPER_Clocking(fl)
|
||||
, m_isDefault{isDefault} {
|
||||
, m_isDefault{isDefault}
|
||||
, m_isGlobal{isGlobal} {
|
||||
m_name = name;
|
||||
this->sensesp(sensesp);
|
||||
addItemsp(itemsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstClocking;
|
||||
std::string name() const override { return m_name; }
|
||||
void dump(std::ostream& str) const override;
|
||||
std::string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool isDefault() const { return m_isDefault; }
|
||||
bool isGlobal() const { return m_isGlobal; }
|
||||
};
|
||||
class AstClockingItem final : public AstNode {
|
||||
// Parents: CLOCKING
|
||||
@@ -850,8 +863,8 @@ public:
|
||||
: ASTGEN_SUPER_ClockingItem(fl) {
|
||||
m_direction = direction;
|
||||
this->skewp(skewp);
|
||||
if (AstAssign* const assignp = VN_CAST(clockingDeclp, Assign)) {
|
||||
this->assignp(assignp);
|
||||
if (AstAssign* const clkAssignp = VN_CAST(clockingDeclp, Assign)) {
|
||||
this->assignp(clkAssignp);
|
||||
} else {
|
||||
exprp(VN_AS(clockingDeclp, NodeExpr));
|
||||
}
|
||||
@@ -903,7 +916,7 @@ public:
|
||||
, m_path{path} {
|
||||
this->rhsp(rhsp);
|
||||
}
|
||||
string name() const override { return m_name; } // * = Scope name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
||||
ASTGEN_MEMBERS_AstDefParam;
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
string path() const { return m_path; }
|
||||
@@ -921,7 +934,7 @@ public:
|
||||
, m_name{vname}
|
||||
, m_cname{cname} {}
|
||||
ASTGEN_MEMBERS_AstDpiExport;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string cname() const { return m_cname; }
|
||||
void cname(const string& cname) { m_cname = cname; }
|
||||
@@ -939,7 +952,7 @@ public:
|
||||
BROKEN_RTN(!fmtp());
|
||||
return nullptr;
|
||||
}
|
||||
string verilogKwd() const override { return (string("$") + string(displayType().ascii())); }
|
||||
string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
@@ -982,7 +995,7 @@ public:
|
||||
BROKEN_RTN(!m_depGraphp);
|
||||
return nullptr;
|
||||
}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
V3Graph* depGraphp() { return m_depGraphp; }
|
||||
const V3Graph* depGraphp() const { return m_depGraphp; }
|
||||
};
|
||||
@@ -1020,7 +1033,7 @@ public:
|
||||
AstIntfRef(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_IntfRef(fl)
|
||||
, m_name{name} {}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
ASTGEN_MEMBERS_AstIntfRef;
|
||||
};
|
||||
class AstMTaskBody final : public AstNode {
|
||||
@@ -1057,7 +1070,7 @@ public:
|
||||
, m_name{name} {
|
||||
this->addVarsp(varsp);
|
||||
}
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
ASTGEN_MEMBERS_AstModport;
|
||||
};
|
||||
@@ -1079,7 +1092,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool isImport() const { return !m_export; }
|
||||
bool isExport() const { return m_export; }
|
||||
AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable
|
||||
@@ -1102,7 +1115,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void direction(const VDirection& flag) { m_direction = flag; }
|
||||
VDirection direction() const { return m_direction; }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
@@ -1136,9 +1149,9 @@ public:
|
||||
ASTGEN_MEMBERS_AstNetlist;
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override { V3ERROR_NA; }
|
||||
string name() const override { return "$root"; }
|
||||
string name() const override VL_MT_STABLE { return "$root"; }
|
||||
void dump(std::ostream& str) const override;
|
||||
AstNodeModule* topModulep() const { // Top module in hierarchy
|
||||
AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy
|
||||
return modulesp(); // First one in the list, for now
|
||||
}
|
||||
AstTypeTable* typeTablep() { return m_typeTablep; }
|
||||
@@ -1185,7 +1198,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
};
|
||||
@@ -1211,7 +1224,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
};
|
||||
@@ -1224,7 +1237,8 @@ private:
|
||||
AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule.
|
||||
AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule.
|
||||
bool m_param = false; // Pin connects to parameter
|
||||
bool m_svImplicit = false; // Pin is SystemVerilog .name'ed
|
||||
bool m_svDotName = false; // Pin is SystemVerilog .name'ed
|
||||
bool m_svImplicit = false; // Pin is SystemVerilog .name'ed, allow implicit
|
||||
public:
|
||||
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
|
||||
: ASTGEN_SUPER_Pin(fl)
|
||||
@@ -1236,7 +1250,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstPin;
|
||||
void dump(std::ostream& str) const override;
|
||||
const char* broken() const override;
|
||||
string name() const override { return m_name; } // * = Pin name, ""=go by number
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string prettyOperatorName() const override;
|
||||
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
|
||||
@@ -1248,6 +1262,8 @@ public:
|
||||
void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; }
|
||||
bool param() const { return m_param; }
|
||||
void param(bool flag) { m_param = flag; }
|
||||
bool svDotName() const { return m_svDotName; }
|
||||
void svDotName(bool flag) { m_svDotName = flag; }
|
||||
bool svImplicit() const { return m_svImplicit; }
|
||||
void svImplicit(bool flag) { m_svImplicit = flag; }
|
||||
};
|
||||
@@ -1262,7 +1278,7 @@ public:
|
||||
, m_pinNum{pinnum}
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstPort;
|
||||
string name() const override { return m_name; } // * = Port name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Port name
|
||||
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
|
||||
};
|
||||
class AstPragma final : public AstNode {
|
||||
@@ -1340,11 +1356,11 @@ public:
|
||||
void cloneRelink() override;
|
||||
const char* broken() const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override { return m_name; } // * = Scope name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void dump(std::ostream& str) const override;
|
||||
string nameDotless() const;
|
||||
string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); }
|
||||
string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); }
|
||||
AstNodeModule* modp() const { return m_modp; }
|
||||
//
|
||||
AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; }
|
||||
@@ -1528,9 +1544,11 @@ public:
|
||||
ASTGEN_MEMBERS_AstTypedef;
|
||||
void dump(std::ostream& str) const override;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
// METHODS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
@@ -1550,7 +1568,7 @@ public:
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstTypedefFwd;
|
||||
// METHODS
|
||||
string name() const override { return m_name; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
};
|
||||
class AstUdpTable final : public AstNode {
|
||||
@@ -1570,7 +1588,7 @@ public:
|
||||
: ASTGEN_SUPER_UdpTableLine(fl)
|
||||
, m_text{text} {}
|
||||
ASTGEN_MEMBERS_AstUdpTableLine;
|
||||
string name() const override { return m_text; }
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string text() const { return m_text; }
|
||||
};
|
||||
class AstVar final : public AstNode {
|
||||
@@ -1740,7 +1758,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstVar;
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override VL_MT_SAFE { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string origName() const override { return m_origName; } // * = Original name
|
||||
@@ -1771,17 +1789,17 @@ public:
|
||||
string dpiTmpVarType(const string& varName) const;
|
||||
// Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "",
|
||||
bool asRef = false) const VL_MT_SAFE;
|
||||
bool asRef = false) const VL_MT_STABLE;
|
||||
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
|
||||
string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration
|
||||
void combineType(VVarType type);
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* dtypeSkipRefp() const VL_MT_SAFE { return subDTypep()->skipRefp(); }
|
||||
AstNodeDType* dtypeSkipRefp() const VL_MT_STABLE { return subDTypep()->skipRefp(); }
|
||||
// (Slow) recurse down to find basic data type (Note don't need virtual -
|
||||
// AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const VL_MT_SAFE { return subDTypep()->basicp(); }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_SAFE {
|
||||
AstBasicDType* basicp() const VL_MT_STABLE { return subDTypep()->basicp(); }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
|
||||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
void ansi(bool flag) { m_ansi = flag; }
|
||||
@@ -1980,11 +1998,11 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override { return scopep()->name() + "->" + varp()->name(); }
|
||||
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
|
||||
void dump(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under
|
||||
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
|
||||
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
|
||||
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
void trace(bool flag) { m_trace = flag; }
|
||||
@@ -2090,14 +2108,17 @@ public:
|
||||
|
||||
// === AstNodeModule ===
|
||||
class AstClass final : public AstNodeModule {
|
||||
// @astgen op4 := extendsp : Optional[AstClassExtends]
|
||||
// @astgen op4 := extendsp : List[AstClassExtends]
|
||||
// TYPES
|
||||
using MemberNameMap = std::map<const std::string, AstNode*>;
|
||||
// MEMBERS
|
||||
MemberNameMap m_members; // Members or method children
|
||||
AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under
|
||||
bool m_virtual = false; // Virtual class
|
||||
bool m_extended = false; // Is extension or extended by other classes
|
||||
bool m_interfaceClass = false; // Interface class
|
||||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||
bool m_virtual = false; // Virtual class
|
||||
bool m_parameterized = false; // Parameterized class
|
||||
void insertCache(AstNode* nodep);
|
||||
|
||||
public:
|
||||
@@ -2125,11 +2146,19 @@ public:
|
||||
}
|
||||
bool isExtended() const { return m_extended; }
|
||||
void isExtended(bool flag) { m_extended = flag; }
|
||||
bool isInterfaceClass() const { return m_interfaceClass; }
|
||||
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
|
||||
bool isVirtual() const { return m_virtual; }
|
||||
void isVirtual(bool flag) { m_virtual = flag; }
|
||||
bool needRNG() const { return m_needRNG; }
|
||||
void needRNG(bool flag) { m_needRNG = flag; }
|
||||
bool isParameterized() const { return m_parameterized; }
|
||||
void isParameterized(bool flag) { m_parameterized = flag; }
|
||||
// Return true if this class is an extension of base class (SLOW)
|
||||
// Accepts nullptrs
|
||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||
// Return the lowest class extended from, or this class
|
||||
AstClass* baseMostClassp();
|
||||
};
|
||||
class AstClassPackage final : public AstNodeModule {
|
||||
// The static information portion of a class (treated similarly to a package)
|
||||
@@ -2315,20 +2344,20 @@ public:
|
||||
inline AstRange(FileLine* fl, int left, int right);
|
||||
inline AstRange(FileLine* fl, const VNumRange& range);
|
||||
ASTGEN_MEMBERS_AstRange;
|
||||
inline int leftConst() const VL_MT_SAFE;
|
||||
inline int rightConst() const VL_MT_SAFE;
|
||||
int hiConst() const VL_MT_SAFE {
|
||||
inline int leftConst() const VL_MT_STABLE;
|
||||
inline int rightConst() const VL_MT_STABLE;
|
||||
int hiConst() const VL_MT_STABLE {
|
||||
const int l = leftConst();
|
||||
const int r = rightConst();
|
||||
return l > r ? l : r;
|
||||
}
|
||||
int loConst() const VL_MT_SAFE {
|
||||
int loConst() const VL_MT_STABLE {
|
||||
const int l = leftConst();
|
||||
const int r = rightConst();
|
||||
return l > r ? r : l;
|
||||
}
|
||||
int elementsConst() const VL_MT_SAFE { return hiConst() - loConst() + 1; }
|
||||
bool littleEndian() const { return leftConst() < rightConst(); }
|
||||
int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; }
|
||||
bool ascending() const { return leftConst() < rightConst(); }
|
||||
void dump(std::ostream& str) const override;
|
||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
@@ -2431,7 +2460,7 @@ public:
|
||||
, m_name{name}
|
||||
, m_showAt{showAt} {}
|
||||
ASTGEN_MEMBERS_AstComment;
|
||||
string name() const override { return m_name; } // * = Text
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Text
|
||||
bool same(const AstNode* samep) const override { return true; } // Ignore name in comments
|
||||
virtual bool showAt() const { return m_showAt; }
|
||||
};
|
||||
@@ -2572,7 +2601,7 @@ public:
|
||||
: ASTGEN_SUPER_Disable(fl)
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstDisable;
|
||||
string name() const override { return m_name; } // * = Block name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool isBrancher() const override {
|
||||
return true; // SPECIAL: We don't process code after breaks
|
||||
@@ -2614,8 +2643,8 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
string verilogKwd() const override {
|
||||
return (filep() ? string("$f") + string(displayType().ascii())
|
||||
: string("$") + string(displayType().ascii()));
|
||||
return (filep() ? string{"$f"} + string{displayType().ascii()}
|
||||
: string{"$"} + string{displayType().ascii()});
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
@@ -2632,17 +2661,13 @@ public:
|
||||
bool addNewline() const { return displayType().addNewline(); }
|
||||
};
|
||||
class AstDoWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNodeExpr
|
||||
// @astgen op3 := stmtsp : List[AstNode]
|
||||
// @astgen op4 := incsp : List[AstNode]
|
||||
// @astgen op1 := condp : AstNodeExpr
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
public:
|
||||
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr,
|
||||
AstNode* incsp = nullptr)
|
||||
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr)
|
||||
: ASTGEN_SUPER_DoWhile(fl) {
|
||||
condp(conditionp);
|
||||
addStmtsp(stmtsp);
|
||||
addIncsp(incsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstDoWhile;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
@@ -2720,46 +2745,6 @@ public:
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpen final : public AstNodeStmt {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
// @astgen op1 := filep : AstNodeExpr
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
// @astgen op3 := modep : AstNodeExpr
|
||||
public:
|
||||
AstFOpen(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep, AstNodeExpr* modep)
|
||||
: ASTGEN_SUPER_FOpen(fl) {
|
||||
this->filep(filep);
|
||||
this->filenamep(filenamep);
|
||||
this->modep(modep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpen;
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpenMcd final : public AstNodeStmt {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
// @astgen op1 := filep : AstNodeExpr
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
public:
|
||||
AstFOpenMcd(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep)
|
||||
: ASTGEN_SUPER_FOpenMcd(fl) {
|
||||
this->filep(filep);
|
||||
this->filenamep(filenamep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFOpenMcd;
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFinish final : public AstNodeStmt {
|
||||
public:
|
||||
explicit AstFinish(FileLine* fl)
|
||||
@@ -2802,7 +2787,7 @@ public:
|
||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
};
|
||||
class AstJumpBlock final : public AstNodeStmt {
|
||||
// Block of code including a JumpGo and JumpLabel
|
||||
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
|
||||
// Parents: {statement list}
|
||||
// Children: {statement list, with JumpGo and JumpLabel below}
|
||||
// @astgen op1 := stmtsp : List[AstNode]
|
||||
@@ -2907,7 +2892,7 @@ public:
|
||||
: ASTGEN_SUPER_PrintTimeScale(fl) {}
|
||||
ASTGEN_MEMBERS_AstPrintTimeScale;
|
||||
void name(const string& name) override { m_name = name; }
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void dump(std::ostream& str) const override;
|
||||
string verilogKwd() const override { return "$printtimescale"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
@@ -3126,7 +3111,7 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
int instrCount() const override { return 100; } // Large...
|
||||
ASTGEN_MEMBERS_AstTraceDecl;
|
||||
string name() const override { return m_showname; }
|
||||
string name() const override VL_MT_STABLE { return m_showname; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool same(const AstNode* samep) const override { return false; }
|
||||
|
||||
+59
-30
@@ -60,6 +60,12 @@ void AstNodeFTaskRef::cloneRelink() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AstNodeFTaskRef::isPure() const {
|
||||
// TODO: For non-DPI functions we could traverse the AST of function's body to determine
|
||||
// pureness.
|
||||
return this->taskp() && this->taskp()->dpiImport() && this->taskp()->pure();
|
||||
}
|
||||
|
||||
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
|
||||
|
||||
const char* AstNodeVarRef::broken() const {
|
||||
@@ -109,6 +115,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
|
||||
}
|
||||
|
||||
const char* AstNodeUOrStructDType::broken() const {
|
||||
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||
std::unordered_set<AstMemberDType*> exists;
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
exists.insert(itemp);
|
||||
@@ -226,6 +233,15 @@ int AstBasicDType::widthTotalBytes() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool AstBasicDType::same(const AstNode* samep) const {
|
||||
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
|
||||
if (!rangep() && !sp->rangep() && m == sp->m) {
|
||||
return true;
|
||||
} else {
|
||||
return m == sp->m && rangep() && rangep()->sameTree(sp->rangep());
|
||||
}
|
||||
}
|
||||
|
||||
int AstNodeUOrStructDType::widthTotalBytes() const {
|
||||
if (width() <= 8) {
|
||||
return 1;
|
||||
@@ -381,7 +397,7 @@ string AstVar::verilogKwd() const {
|
||||
}
|
||||
|
||||
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
|
||||
bool asRef) const VL_MT_SAFE {
|
||||
bool asRef) const VL_MT_STABLE {
|
||||
UASSERT_OBJ(!forReturn, this,
|
||||
"Internal data is never passed as return, but as first argument");
|
||||
string ostatic;
|
||||
@@ -567,7 +583,7 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
} else {
|
||||
class converter final : public dpiTypesToStringConverter {
|
||||
string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
||||
return string(varp->isReadOnly() ? "const " : "")
|
||||
return string{varp->isReadOnly() ? "const " : ""}
|
||||
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
||||
}
|
||||
string primitive(const AstVar* varp) const override {
|
||||
@@ -630,13 +646,13 @@ string AstVar::dpiTmpVarType(const string& varName) const {
|
||||
|
||||
string AstVar::scType() const {
|
||||
if (isScBigUint()) {
|
||||
return (string("sc_biguint<") + cvtToStr(widthMin())
|
||||
return (string{"sc_biguint<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (isScUint()) {
|
||||
return (string("sc_uint<") + cvtToStr(widthMin())
|
||||
return (string{"sc_uint<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (isScBv()) {
|
||||
return (string("sc_bv<") + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
||||
return (string{"sc_bv<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
||||
} else if (widthMin() == 1) {
|
||||
return "bool";
|
||||
} else if (widthMin() <= VL_IDATASIZE) {
|
||||
@@ -675,7 +691,7 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
|
||||
bool AstNodeDType::isFourstate() const { return basicp() && basicp()->isFourstate(); }
|
||||
|
||||
class AstNodeDType::CTypeRecursed final {
|
||||
public:
|
||||
@@ -698,12 +714,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_SAFE {
|
||||
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_STABLE {
|
||||
const CTypeRecursed info = cTypeRecurse(false);
|
||||
return info.render(name, isRef);
|
||||
}
|
||||
|
||||
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_MT_STABLE {
|
||||
// Legacy compound argument currently just passed through and unused
|
||||
CTypeRecursed info;
|
||||
|
||||
@@ -728,18 +744,18 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlSampleQueue<" + sub.m_type + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
||||
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||
info.m_type = "VlClassRef<" + EmitCBase::prefixNameProtect(adtypep) + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) {
|
||||
info.m_type = EmitCBaseVisitor::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
||||
info.m_type = EmitCBase::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (adtypep->isCompound()) compound = true;
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
||||
info.m_type = "VlUnpacked<" + sub.m_type;
|
||||
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
|
||||
info.m_type += ">";
|
||||
} else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) {
|
||||
const auto* const sdtypep = VN_AS(dtypep, StructDType);
|
||||
info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep);
|
||||
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
|
||||
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
||||
info.m_type = EmitCBase::prefixNameProtect(sdtypep);
|
||||
} else if (const AstBasicDType* const 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
|
||||
@@ -840,7 +856,7 @@ int AstNodeDType::widthPow2() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool AstNodeDType::isLiteralType() const VL_MT_SAFE {
|
||||
bool AstNodeDType::isLiteralType() const VL_MT_STABLE {
|
||||
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
|
||||
return dtypep->keyword().isLiteralType();
|
||||
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
|
||||
@@ -869,7 +885,7 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
||||
continue;
|
||||
}
|
||||
// AstNodeSelPre stashes the associated variable under an ATTROF
|
||||
// of VAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
|
||||
// of VAttrType::VAR_BASE so it isn't constified
|
||||
else if (VN_IS(nodep, AttrOf)) {
|
||||
nodep = VN_AS(nodep, AttrOf)->fromp();
|
||||
continue;
|
||||
@@ -910,10 +926,10 @@ void AstScope::cloneRelink() {
|
||||
}
|
||||
}
|
||||
string AstScope::nameDotless() const {
|
||||
string out = shortName();
|
||||
string result = shortName();
|
||||
string::size_type pos;
|
||||
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
|
||||
return out;
|
||||
while ((pos = result.find('.')) != string::npos) result.replace(pos, 1, "__");
|
||||
return result;
|
||||
}
|
||||
|
||||
AstVarScope* AstScope::createTemp(const string& name, unsigned width) {
|
||||
@@ -1448,6 +1464,13 @@ void AstClass::repairCache() {
|
||||
}
|
||||
}
|
||||
}
|
||||
AstClass* AstClass::baseMostClassp() {
|
||||
AstClass* basep = this;
|
||||
while (basep->extendsp() && basep->extendsp()->classp()) {
|
||||
basep = basep->extendsp()->classp();
|
||||
}
|
||||
return basep;
|
||||
}
|
||||
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
|
||||
// TAIL RECURSIVE
|
||||
if (!refClassp || !baseClassp) return false;
|
||||
@@ -1458,6 +1481,7 @@ bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* ba
|
||||
void AstClass::dump(std::ostream& str) const {
|
||||
this->AstNodeModule::dump(str);
|
||||
if (isExtended()) str << " [EXT]";
|
||||
if (isInterfaceClass()) str << " [IFCCLS]";
|
||||
if (isVirtual()) str << " [VIRT]";
|
||||
}
|
||||
const char* AstClass::broken() const {
|
||||
@@ -1471,6 +1495,10 @@ void AstClass::cloneRelink() {
|
||||
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||
}
|
||||
}
|
||||
void AstClassExtends::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isImplements()) str << " [IMPLEMENTS]";
|
||||
}
|
||||
AstClass* AstClassExtends::classp() const {
|
||||
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
||||
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
||||
@@ -1509,6 +1537,11 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (immediate()) str << " [IMMEDIATE]";
|
||||
}
|
||||
void AstClocking::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isDefault()) str << " [DEFAULT]";
|
||||
if (isGlobal()) str << " [GLOBAL]";
|
||||
}
|
||||
void AstDisplay::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
// str << " " << displayType().ascii();
|
||||
@@ -1636,6 +1669,10 @@ void AstLogOr::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
if (sideEffect()) str << " [SIDE]";
|
||||
}
|
||||
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str << "member";
|
||||
}
|
||||
void AstMemberSel::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
str << " -> ";
|
||||
@@ -1652,15 +1689,6 @@ const char* AstMemberSel::broken() const {
|
||||
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
||||
return nullptr;
|
||||
}
|
||||
void AstMethodCall::dump(std::ostream& str) const {
|
||||
this->AstNodeFTaskRef::dump(str);
|
||||
str << " -> ";
|
||||
if (taskp()) {
|
||||
taskp()->dump(str);
|
||||
} else {
|
||||
str << " -> UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstModportFTaskRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isExport()) str << " EXPORT";
|
||||
@@ -1704,6 +1732,7 @@ void AstPin::dump(std::ostream& str) const {
|
||||
} else {
|
||||
str << " ->UNLINKED";
|
||||
}
|
||||
if (svDotName()) str << " [.n]";
|
||||
if (svImplicit()) str << " [.SV]";
|
||||
}
|
||||
const char* AstPin::broken() const {
|
||||
@@ -1746,7 +1775,7 @@ void AstTypedef::dump(std::ostream& str) const {
|
||||
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstRange::dump(std::ostream& str) const {
|
||||
this->AstNodeRange::dump(str);
|
||||
if (littleEndian()) str << " [LITTLE]";
|
||||
if (ascending()) str << " [ASCENDING]";
|
||||
}
|
||||
void AstParamTypeDType::dump(std::ostream& str) const {
|
||||
this->AstNodeDType::dump(str);
|
||||
@@ -1792,7 +1821,7 @@ void AstRefDType::cloneRelink() {
|
||||
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||
}
|
||||
}
|
||||
AstNodeDType* AstRefDType::subDTypep() const {
|
||||
AstNodeDType* AstRefDType::subDTypep() const VL_MT_STABLE {
|
||||
if (typedefp()) return typedefp()->subDTypep();
|
||||
return refDTypep(); // Maybe nullptr
|
||||
}
|
||||
@@ -2292,7 +2321,7 @@ int AstCMethodHard::instrCount() const {
|
||||
if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) {
|
||||
// TODO: add a more structured description of library methods, rather than using string
|
||||
// matching. See #3715.
|
||||
if (basicp->isTriggerVec() && m_name == "at") {
|
||||
if (basicp->isTriggerVec() && m_name == "word") {
|
||||
// This is an important special case for scheduling so we compute it precisely,
|
||||
// it is simply a load.
|
||||
return INSTR_COUNT_LD;
|
||||
|
||||
+46
-4
@@ -19,6 +19,7 @@
|
||||
// Look for BEGINs
|
||||
// BEGIN(VAR...) -> VAR ... {renamed}
|
||||
// FOR -> WHILEs
|
||||
// Move static function variables and their AstInitialStatic blocks before a function
|
||||
//
|
||||
// There are two scopes; named BEGINs change %m and variable scopes.
|
||||
// Unnamed BEGINs change only variable, not $display("%m") scope.
|
||||
@@ -64,13 +65,14 @@ private:
|
||||
// STATE
|
||||
BeginState* const m_statep; // Current global state
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
|
||||
string m_displayScope; // Name of %m in $display/AstScopeName
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_ifDepth = 0; // Current if depth
|
||||
bool m_keepBegins = false; // True if begins should not be inlined
|
||||
std::set<AstVar*> m_staticFuncVars; // Static variables from m_ftaskp
|
||||
|
||||
// METHODS
|
||||
|
||||
@@ -121,11 +123,41 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void renameAndStaticsRecurse(AstNode* const nodep) {
|
||||
// Rename references and move InitialStatic items
|
||||
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
|
||||
const auto it = m_staticFuncVars.find(varrefp->varp());
|
||||
if (it != m_staticFuncVars.end()) varrefp->name((*it)->name());
|
||||
}
|
||||
|
||||
if (nodep->op1p()) renameAndStaticsRecurse(nodep->op1p());
|
||||
if (nodep->op2p()) renameAndStaticsRecurse(nodep->op2p());
|
||||
if (nodep->op3p()) renameAndStaticsRecurse(nodep->op3p());
|
||||
if (nodep->op4p()) renameAndStaticsRecurse(nodep->op4p());
|
||||
if (nodep->nextp()) renameAndStaticsRecurse(nodep->nextp());
|
||||
|
||||
if (VN_IS(nodep, InitialStatic)) {
|
||||
nodep->unlinkFrBack();
|
||||
m_ftaskp->addHereThisAsNext(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstFork* nodep) override {
|
||||
// Keep this begin to group its statements together
|
||||
// Keep begins in forks to group their statements together
|
||||
VL_RESTORER(m_keepBegins);
|
||||
m_keepBegins = true;
|
||||
// If a statement is not a begin, wrap it in a begin. This fixes an issue when the
|
||||
// statement is a task call that gets inlined later (or any other statement that gets
|
||||
// replaced with multiple statements)
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (!VN_IS(stmtp, Begin)) {
|
||||
AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr};
|
||||
stmtp->replaceWith(beginp);
|
||||
beginp->addStmtsp(stmtp);
|
||||
stmtp = beginp;
|
||||
}
|
||||
}
|
||||
dotNames(nodep, "__FORK__");
|
||||
nodep->name("");
|
||||
}
|
||||
@@ -165,6 +197,7 @@ private:
|
||||
m_ftaskp = nodep;
|
||||
m_liftedp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
renameAndStaticsRecurse(nodep);
|
||||
if (m_liftedp) {
|
||||
// Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced
|
||||
if (AstNode* const stmtsp = nodep->stmtsp()) {
|
||||
@@ -174,6 +207,7 @@ private:
|
||||
nodep->addStmtsp(m_liftedp);
|
||||
m_liftedp = nullptr;
|
||||
}
|
||||
m_staticFuncVars.clear();
|
||||
m_ftaskp = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +244,15 @@ private:
|
||||
}
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
if (m_unnamedScope != "") {
|
||||
// If static variable, move it outside a function.
|
||||
if (nodep->lifetime().isStatic() && m_ftaskp) {
|
||||
const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name();
|
||||
nodep->name(newName);
|
||||
nodep->unlinkFrBack();
|
||||
m_ftaskp->addHereThisAsNext(nodep);
|
||||
m_staticFuncVars.insert(nodep);
|
||||
nodep->funcLocal(false);
|
||||
} else if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(dot(m_unnamedScope, nodep->name()));
|
||||
m_statep->userMarkChanged(nodep);
|
||||
@@ -257,7 +299,7 @@ private:
|
||||
// To keep correct visual order, must add before other Text's
|
||||
AstText* const afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->addScopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
|
||||
nodep->addScopeAttrp(new AstText{nodep->fileline(), string{"__DOT__"} + scname});
|
||||
if (afterp) nodep->addScopeAttrp(afterp);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
||||
+7
-7
@@ -38,7 +38,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
//######################################################################
|
||||
// Branch state, as a visitor of each AstNode
|
||||
|
||||
class BranchVisitor final : public VNVisitor {
|
||||
class BranchVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
@@ -71,12 +71,12 @@ private:
|
||||
{
|
||||
// Do if
|
||||
reset();
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
const int ifLikely = m_likely;
|
||||
const int ifUnlikely = m_unlikely;
|
||||
// Do else
|
||||
reset();
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
const int elseLikely = m_likely;
|
||||
const int elseUnlikely = m_unlikely;
|
||||
// Compute
|
||||
@@ -91,16 +91,16 @@ private:
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
nodep->funcp()->user1Inc();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCFunc* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
m_cfuncsp.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNode* nodep) override {
|
||||
checkUnlikely(nodep);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
// CONSTRUCTORS
|
||||
explicit BranchVisitor(AstNetlist* nodep) {
|
||||
reset();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
calc_tasks();
|
||||
}
|
||||
~BranchVisitor() override = default;
|
||||
|
||||
+7
-2
@@ -62,6 +62,8 @@ public:
|
||||
}
|
||||
} s_brokenCntGlobal;
|
||||
|
||||
static bool s_brokenAllowMidvisitorCheck = false;
|
||||
|
||||
//######################################################################
|
||||
// Table of allocated AstNode pointers
|
||||
|
||||
@@ -144,7 +146,7 @@ bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinka
|
||||
//######################################################################
|
||||
// Check every node in tree
|
||||
|
||||
class BrokenCheckVisitor final : public VNVisitor {
|
||||
class BrokenCheckVisitor final : public VNVisitorConst {
|
||||
bool m_inScope = false; // Under AstScope
|
||||
|
||||
// Constants for marking we are under/not under a node
|
||||
@@ -172,6 +174,7 @@ private:
|
||||
const char* const whyp = nodep->broken();
|
||||
UASSERT_OBJ(!whyp, nodep,
|
||||
"Broken link in node (or something without maybePointedTo): " << whyp);
|
||||
if (!s_brokenAllowMidvisitorCheck) nodep->checkIter();
|
||||
if (nodep->dtypep()) {
|
||||
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
|
||||
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
|
||||
@@ -312,7 +315,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterateConstNull(nodep); }
|
||||
~BrokenCheckVisitor() override = default;
|
||||
};
|
||||
|
||||
@@ -351,6 +354,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
|
||||
}
|
||||
}
|
||||
|
||||
void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck = flag; }
|
||||
|
||||
//######################################################################
|
||||
// Self test
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ public:
|
||||
static bool isLinkable(const AstNode* nodep);
|
||||
static void addNewed(const AstNode* nodep);
|
||||
static void deleted(const AstNode* nodep);
|
||||
// Called on error to say may be inside visitor,
|
||||
// Disables checks that may misfire if not called at stable point between visitors
|
||||
static void allowMidvisitorCheck(bool flag);
|
||||
static void selfTest();
|
||||
};
|
||||
|
||||
|
||||
+6
-2
@@ -70,7 +70,7 @@ private:
|
||||
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
|
||||
string preventUnusedStmt;
|
||||
if (m_type.isClass()) {
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->argTypes(EmitCBase::symClassVar());
|
||||
preventUnusedStmt = "if (false && vlSymsp) {} // Prevent unused\n";
|
||||
} else if (m_type.isCoverage()) {
|
||||
funcp->argTypes("bool first");
|
||||
@@ -148,6 +148,7 @@ private:
|
||||
m_modp = nodep;
|
||||
V3CCtorsBuilder var_reset{nodep, "_ctor_var_reset",
|
||||
VN_IS(nodep, Class) ? VCtorType::CLASS : VCtorType::MODULE};
|
||||
// cppcheck-suppress danglingLifetime
|
||||
m_varResetp = &var_reset;
|
||||
iterateChildren(nodep);
|
||||
|
||||
@@ -155,6 +156,9 @@ private:
|
||||
V3CCtorsBuilder configure_coverage{nodep, "_configure_coverage", VCtorType::COVERAGE};
|
||||
for (AstNode* np = nodep->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) {
|
||||
// ... else we don't have a static VlSym to be able to coverage insert
|
||||
UASSERT_OBJ(!VN_IS(nodep, Class), coverp,
|
||||
"CoverDecl should be in class's package, not class itself");
|
||||
np = coverp->backp();
|
||||
configure_coverage.add(coverp->unlinkFrBack());
|
||||
}
|
||||
@@ -198,7 +202,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
explicit CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
~CCtorsVisitor() override = default;
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ class CUseVisitor final : public VNVisitor {
|
||||
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
|
||||
|
||||
// Add a CUse for every struct that requires a declaration
|
||||
AstStructDType* const stypep = VN_CAST(nodep->skipRefp(), StructDType);
|
||||
AstNodeUOrStructDType* const stypep = VN_CAST(nodep->skipRefp(), NodeUOrStructDType);
|
||||
if (stypep && stypep->classOrPackagep()) {
|
||||
addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name());
|
||||
iterateChildren(stypep);
|
||||
|
||||
+5
-5
@@ -53,7 +53,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CaseLintVisitor final : public VNVisitor {
|
||||
class CaseLintVisitor final : public VNVisitorConst {
|
||||
private:
|
||||
const AstNodeCase* m_caseExprp
|
||||
= nullptr; // Under a CASE value node, if so the relevant case statement
|
||||
@@ -79,10 +79,10 @@ private:
|
||||
// Check for X/Z in non-casex statements
|
||||
{
|
||||
m_caseExprp = nodep;
|
||||
iterate(nodep->exprp());
|
||||
iterateConst(nodep->exprp());
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
iterateAndNextNull(itemp->condsp());
|
||||
iterateAndNextConstNull(itemp->condsp());
|
||||
}
|
||||
m_caseExprp = nullptr;
|
||||
}
|
||||
@@ -108,11 +108,11 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); }
|
||||
~CaseLintVisitor() override = default;
|
||||
};
|
||||
|
||||
|
||||
-765
@@ -1,765 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Clock Domain Crossing Lint
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Cdc's Transformations:
|
||||
//
|
||||
// Create V3Graph-ish graph
|
||||
// Find all negedge reset flops
|
||||
// Trace back to previous flop
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Cdc.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcBaseVisitor VL_NOT_FINAL : public VNVisitor {
|
||||
public:
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Graph support classes
|
||||
|
||||
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
AstScope* const m_scopep;
|
||||
AstNode* const m_nodep;
|
||||
AstSenTree* m_srcDomainp = nullptr;
|
||||
AstSenTree* m_dstDomainp = nullptr;
|
||||
bool m_srcDomainSet : 1;
|
||||
bool m_dstDomainSet : 1;
|
||||
bool m_asyncPath : 1;
|
||||
|
||||
public:
|
||||
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
|
||||
: V3GraphVertex{graphp}
|
||||
, m_scopep{scopep}
|
||||
, m_nodep{nodep}
|
||||
, m_srcDomainSet{false}
|
||||
, m_dstDomainSet{false}
|
||||
, m_asyncPath{false} {}
|
||||
~CdcEitherVertex() override = default;
|
||||
// ACCESSORS
|
||||
FileLine* fileline() const override { return nodep()->fileline(); }
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
AstSenTree* srcDomainp() const { return m_srcDomainp; }
|
||||
void srcDomainp(AstSenTree* nodep) { m_srcDomainp = nodep; }
|
||||
bool srcDomainSet() const { return m_srcDomainSet; }
|
||||
void srcDomainSet(bool flag) { m_srcDomainSet = flag; }
|
||||
AstSenTree* dstDomainp() const { return m_dstDomainp; }
|
||||
void dstDomainp(AstSenTree* nodep) { m_dstDomainp = nodep; }
|
||||
bool dstDomainSet() const { return m_dstDomainSet; }
|
||||
void dstDomainSet(bool flag) { m_dstDomainSet = flag; }
|
||||
bool asyncPath() const { return m_asyncPath; }
|
||||
void asyncPath(bool flag) { m_asyncPath = flag; }
|
||||
};
|
||||
|
||||
class CdcVarVertex final : public CdcEitherVertex {
|
||||
AstVarScope* const m_varScp;
|
||||
int m_cntAsyncRst = 0;
|
||||
bool m_fromFlop = false;
|
||||
|
||||
public:
|
||||
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: CdcEitherVertex{graphp, scopep, varScp}
|
||||
, m_varScp{varScp} {}
|
||||
~CdcVarVertex() override = default;
|
||||
// ACCESSORS
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
string dotColor() const override {
|
||||
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
|
||||
}
|
||||
int cntAsyncRst() const { return m_cntAsyncRst; }
|
||||
void cntAsyncRst(int flag) { m_cntAsyncRst = flag; }
|
||||
bool fromFlop() const { return m_fromFlop; }
|
||||
void fromFlop(bool flag) { m_fromFlop = flag; }
|
||||
};
|
||||
|
||||
class CdcLogicVertex final : public CdcEitherVertex {
|
||||
bool m_hazard : 1;
|
||||
bool m_isFlop : 1;
|
||||
|
||||
public:
|
||||
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
|
||||
: CdcEitherVertex{graphp, scopep, nodep}
|
||||
, m_hazard{false}
|
||||
, m_isFlop{false} {
|
||||
srcDomainp(sensenodep);
|
||||
dstDomainp(sensenodep);
|
||||
}
|
||||
~CdcLogicVertex() override = default;
|
||||
// ACCESSORS
|
||||
string name() const override { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
|
||||
string dotColor() const override { return hazard() ? "black" : "yellow"; }
|
||||
bool hazard() const { return m_hazard; }
|
||||
void setHazard(AstNode* nodep) {
|
||||
m_hazard = true;
|
||||
nodep->user3(true);
|
||||
}
|
||||
void clearHazard() { m_hazard = false; }
|
||||
bool isFlop() const { return m_isFlop; }
|
||||
void isFlop(bool flag) { m_isFlop = flag; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcDumpVisitor final : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// {statement}Node::user3 -> bool, indicating not hazard
|
||||
std::ofstream* const m_ofp = nullptr; // Output file
|
||||
string m_prefix;
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
*m_ofp << m_prefix;
|
||||
if (nodep->user3()) {
|
||||
*m_ofp << " %%";
|
||||
} else {
|
||||
*m_ofp << " ";
|
||||
}
|
||||
*m_ofp << nodep->prettyTypeName() << "\n";
|
||||
const string lastPrefix = m_prefix;
|
||||
m_prefix = lastPrefix + "1:";
|
||||
iterateAndNextNull(nodep->op1p());
|
||||
m_prefix = lastPrefix + "2:";
|
||||
iterateAndNextNull(nodep->op2p());
|
||||
m_prefix = lastPrefix + "3:";
|
||||
iterateAndNextNull(nodep->op3p());
|
||||
m_prefix = lastPrefix + "4:";
|
||||
iterateAndNextNull(nodep->op4p());
|
||||
m_prefix = lastPrefix;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix)
|
||||
: m_ofp{ofp}
|
||||
, m_prefix{prefix} {
|
||||
iterate(nodep);
|
||||
}
|
||||
~CdcDumpVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcWidthVisitor final : public CdcBaseVisitor {
|
||||
private:
|
||||
size_t m_maxFilenameLen = 0;
|
||||
int m_maxLineno = 0;
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Keeping line+filename lengths separate is much faster than calling ascii().length()
|
||||
if (nodep->fileline()->lineno() >= m_maxLineno) {
|
||||
m_maxLineno = nodep->fileline()->lineno() + 1;
|
||||
}
|
||||
if (nodep->fileline()->filename().length() >= m_maxFilenameLen) {
|
||||
m_maxFilenameLen = nodep->fileline()->filename().length() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
~CdcWidthVisitor() override = default;
|
||||
// ACCESSORS
|
||||
int maxWidth() const {
|
||||
size_t width = 1;
|
||||
width += m_maxFilenameLen;
|
||||
width += 1; // The :
|
||||
width += cvtToStr(m_maxLineno).length();
|
||||
width += 1; // Final :
|
||||
return static_cast<int>(width);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
class CdcVisitor final : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet
|
||||
// AstVarScope::user2 -> bool Used in sensitivity list
|
||||
// {statement}Node::user1p -> CdcLogicVertex* for this statement
|
||||
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
|
||||
const VNUser1InUse m_inuser1;
|
||||
const VNUser2InUse m_inuser2;
|
||||
const VNUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
|
||||
AstScope* m_scopep = nullptr; // Current scope being processed
|
||||
const AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstSenTree* m_domainp = nullptr; // Current sentree
|
||||
bool m_inDly = false; // In delayed assign
|
||||
int m_inSenItem = 0; // Number of senitems
|
||||
string m_ofFilename; // Output filename
|
||||
std::ofstream* m_ofp; // Output file
|
||||
uint32_t m_userGeneration = 0; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth = 0; // Characters in longest fileline
|
||||
|
||||
// METHODS
|
||||
void iterateNewStmt(AstNode* nodep) {
|
||||
if (m_scopep) {
|
||||
VL_RESTORER(m_logicVertexp);
|
||||
UINFO(4, " STMT " << nodep << endl);
|
||||
m_logicVertexp = new CdcLogicVertex{&m_graph, m_scopep, nodep, m_domainp};
|
||||
if (m_domainp && m_domainp->hasClocked()) { // To/from a flop
|
||||
m_logicVertexp->isFlop(true);
|
||||
m_logicVertexp->srcDomainp(m_domainp);
|
||||
m_logicVertexp->srcDomainSet(true);
|
||||
m_logicVertexp->dstDomainp(m_domainp);
|
||||
m_logicVertexp->dstDomainSet(true);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
||||
if (false && debug() >= 9) {
|
||||
UINFO(9, "Trace Logic:\n");
|
||||
nodep->dumpTree("- log1: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdcVarVertex* makeVarVertex(AstVarScope* varscp) {
|
||||
CdcVarVertex* vertexp = reinterpret_cast<CdcVarVertex*>(varscp->user1p());
|
||||
if (!vertexp) {
|
||||
UINFO(6, "New vertex " << varscp << endl);
|
||||
vertexp = new CdcVarVertex{&m_graph, m_scopep, varscp};
|
||||
varscp->user1p(vertexp);
|
||||
if (varscp->varp()->isUsedClock()) {}
|
||||
if (varscp->varp()->isPrimaryIO()) {
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are
|
||||
// now This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* const ioVertexp
|
||||
= new CdcLogicVertex{&m_graph, varscp->scopep(), varscp->varp(), nullptr};
|
||||
if (varscp->varp()->isWritable()) {
|
||||
new V3GraphEdge{&m_graph, vertexp, ioVertexp, 1};
|
||||
} else {
|
||||
new V3GraphEdge{&m_graph, ioVertexp, vertexp, 1};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_inSenItem) {
|
||||
varscp->user2(true); // It's like a clock...
|
||||
// TODO: In the future mark it here and do normal clock tree glitch checks also
|
||||
} else if (varscp->user2()) { // It was detected in a sensitivity list earlier
|
||||
// And now it's used as logic. So must be a reset.
|
||||
vertexp->cntAsyncRst(vertexp->cntAsyncRst() + 1);
|
||||
}
|
||||
return vertexp;
|
||||
}
|
||||
|
||||
void warnAndFile(AstNode* nodep, V3ErrorCode code, const string& msg) {
|
||||
static bool told_file = false;
|
||||
nodep->v3warnCode(code, msg);
|
||||
if (!told_file) {
|
||||
told_file = true;
|
||||
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
|
||||
}
|
||||
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << '\n';
|
||||
}
|
||||
|
||||
void setNodeHazard(AstNode* nodep) {
|
||||
// Need to not clear if warnings are off (rather than when report it)
|
||||
// as bypassing this warning may turn up another path that isn't warning off'ed.
|
||||
// We can't modifyWarnOff here, as one instantiation might not be
|
||||
// an issue until we find a hitting flop.
|
||||
// Furthermore, a module like a "Or" module would only get flagged
|
||||
// once, even though the signals feeding it are radically different.
|
||||
if (!m_domainp || m_domainp->hasCombo()) {
|
||||
// Source flop logic in a posedge block is OK for reset (not async though)
|
||||
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
|
||||
UINFO(8, "Set hazard " << nodep << endl);
|
||||
m_logicVertexp->setHazard(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string spaces(int level) {
|
||||
string out;
|
||||
while (level--) out += " ";
|
||||
return out;
|
||||
} // LCOV_EXCL_LINE
|
||||
static string pad(unsigned column, const string& in) {
|
||||
string out = in;
|
||||
while (out.length() < column) out += ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
void analyze() {
|
||||
UINFO(3, __FUNCTION__ << ": " << endl);
|
||||
if (dumpGraph() > 6) m_graph.dumpDotFilePrefixed("cdc_pre");
|
||||
// This will MAX across edge weights
|
||||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
|
||||
//
|
||||
if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("cdc_simp");
|
||||
//
|
||||
analyzeReset();
|
||||
}
|
||||
|
||||
int filelineWidth() {
|
||||
if (!m_filelineWidth) {
|
||||
const CdcWidthVisitor visitor{v3Global.rootp()};
|
||||
m_filelineWidth = visitor.maxWidth();
|
||||
}
|
||||
return m_filelineWidth;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// RESET REPORT
|
||||
|
||||
void analyzeReset() {
|
||||
// Find all async reset wires, and trace backwards
|
||||
// userClearVertices is very slow, so we use a generation count instead
|
||||
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (vvertexp->cntAsyncRst()) {
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
UINFO(8, " Trace One async: " << vvertexp << endl);
|
||||
// Twice, as we need to detect, then propagate
|
||||
CdcEitherVertex* const markp = traceAsyncRecurse(vvertexp, false);
|
||||
if (markp) { // Mark is non-nullptr if something bad on this path
|
||||
UINFO(9, " Trace One bad! " << vvertexp << endl);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
traceAsyncRecurse(vvertexp, true);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
dumpAsync(vvertexp, markp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
|
||||
// First pass: Return vertex of any hazardous stuff attached, or nullptr if OK
|
||||
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
|
||||
if (vertexp->user() >= m_userGeneration) return nullptr; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
CdcEitherVertex* mark_outp = nullptr;
|
||||
UINFO(9, " Trace: " << vertexp << endl);
|
||||
|
||||
// Clear out in prep for marking next path
|
||||
if (!mark) vertexp->asyncPath(false);
|
||||
|
||||
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Any logic considered bad, at the moment, anyhow
|
||||
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
|
||||
// And keep tracing back so the user can understand what's up
|
||||
} else if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
if (mark) vvertexp->asyncPath(true);
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
|
||||
// Show the source "input" statement if it exists
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* const eFromVertexp
|
||||
= static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
// Also ok if from flop, but partially trace the flop so more obvious to users
|
||||
if (vvertexp->fromFlop()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* const eFromVertexp
|
||||
= static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
CdcEitherVertex* const submarkp = traceAsyncRecurse(eFromVertexp, mark);
|
||||
if (submarkp && !mark_outp) mark_outp = submarkp;
|
||||
}
|
||||
|
||||
if (mark) vertexp->asyncPath(true);
|
||||
return mark_outp;
|
||||
}
|
||||
|
||||
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
|
||||
const AstNode* const nodep = vertexp->varScp();
|
||||
*m_ofp << "\n";
|
||||
*m_ofp << "\n";
|
||||
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
if (!eToVertexp) targetp = eToVertexp;
|
||||
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (vvertexp->isFlop() // IE the target flop that is upsetting us
|
||||
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
|
||||
targetp = eToVertexp;
|
||||
// UINFO(9," targetasync "<<targetp->name()<<" "<<" from
|
||||
// "<<vertexp->name()<<endl);
|
||||
break;
|
||||
}
|
||||
} // else it might be random logic that's not relevant
|
||||
}
|
||||
// UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
|
||||
warnAndFile(markp->nodep(), V3ErrorCode::CDCRSTLOGIC,
|
||||
"Logic in path that feeds async reset, via signal: " + nodep->prettyNameQ());
|
||||
dumpAsyncRecurse(targetp, "", " ", 0);
|
||||
}
|
||||
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep,
|
||||
int level) {
|
||||
// level=0 is special, indicates to dump destination flop
|
||||
// Return true if printed anything
|
||||
// If mark, also mark the output even if nothing hazardous below
|
||||
if (vertexp->user() >= m_userGeneration) return false; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
if (!vertexp->asyncPath() && level != 0) return false; // Not part of path
|
||||
|
||||
// Other logic in the path
|
||||
const string cont = prefix + sep;
|
||||
string nextsep = " ";
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
|
||||
}
|
||||
|
||||
// Dump single variable/logic block
|
||||
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
|
||||
AstNode* const nodep = vertexp->nodep();
|
||||
const string front
|
||||
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
|
||||
if (VN_IS(nodep, VarScope)) {
|
||||
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
|
||||
} else {
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(),
|
||||
vertexp->srcDomainp(), true);
|
||||
if (debug()) { CdcDumpVisitor{nodep, m_ofp, front + "DBG: "}; }
|
||||
}
|
||||
|
||||
nextsep = " | ";
|
||||
if (level)
|
||||
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
|
||||
|
||||
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Now that we've printed a path with this hazard, don't bother to print any more
|
||||
// Otherwise, we'd get a path for almost every destination flop
|
||||
vvertexp->clearHazard();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// EDGE REPORTS
|
||||
|
||||
void edgeReport() {
|
||||
// Make report of all signal names and what clock edges they have
|
||||
//
|
||||
// Due to flattening, many interesting direct-connect signals are
|
||||
// lost, so we can't make a report showing I/Os for a low level
|
||||
// module. Disabling flattening though makes us consider each
|
||||
// signal in it's own unique clock domain.
|
||||
|
||||
UINFO(3, __FUNCTION__ << ": " << endl);
|
||||
|
||||
// Trace all sources and sinks
|
||||
for (const bool& traceDests : {false, true}) {
|
||||
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
|
||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
UINFO(9, " Trace One edge: " << vvertexp << endl);
|
||||
edgeDomainRecurse(vvertexp, traceDests, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const 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() << '\n';
|
||||
|
||||
std::deque<string> report; // Sort output by name
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
const AstVar* const varp = vvertexp->varScp()->varp();
|
||||
{
|
||||
string what = "wire";
|
||||
if (varp->isPrimaryIO()) what = varp->direction().prettyName();
|
||||
|
||||
std::ostringstream os;
|
||||
os.setf(std::ios::left);
|
||||
// Module name - doesn't work due to flattening having lost the original
|
||||
// so we assume the modulename matches the filebasename
|
||||
const string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
|
||||
os << " " << std::setw(20) << fname;
|
||||
os << " " << std::setw(8) << what;
|
||||
os << " " << std::setw(40) << vvertexp->varScp()->prettyName();
|
||||
os << " SRC=";
|
||||
if (vvertexp->srcDomainp()) {
|
||||
V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
|
||||
}
|
||||
os << " DST=";
|
||||
if (vvertexp->dstDomainp()) {
|
||||
V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
|
||||
}
|
||||
os << std::setw(0);
|
||||
os << '\n';
|
||||
report.push_back(os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
stable_sort(report.begin(), report.end());
|
||||
for (const auto& line : report) *ofp << line;
|
||||
}
|
||||
|
||||
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
||||
// Scan back to inputs/outputs, flops, and compute clock domain information
|
||||
UINFO(8, spaces(level) << " Tracein " << vertexp << endl);
|
||||
if (vertexp->user() >= m_userGeneration) return; // Mid-Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
// Variables from flops already are domained
|
||||
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) {
|
||||
return;
|
||||
} // Fully computed
|
||||
|
||||
std::set<AstSenTree*> senouts; // List of all sensitivities for new signal
|
||||
if (dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
} else if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
// If primary I/O, give it domain of the input
|
||||
const AstVar* const varp = vvertexp->varScp()->varp();
|
||||
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
|
||||
senouts.insert(new AstSenTree{
|
||||
varp->fileline(), new AstSenItem{varp->fileline(), AstSenItem::Combo{}}});
|
||||
}
|
||||
}
|
||||
|
||||
// Now combine domains of sources/dests
|
||||
if (traceDests) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
|
||||
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
|
||||
}
|
||||
} else {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* const eFromVertexp
|
||||
= static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
|
||||
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert list of senses into one sense node
|
||||
AstSenTree* senoutp = nullptr;
|
||||
bool senedited = false;
|
||||
for (const auto& itr : senouts) {
|
||||
if (!senoutp) {
|
||||
senoutp = itr;
|
||||
} else {
|
||||
if (!senedited) {
|
||||
senedited = true;
|
||||
senoutp = senoutp->cloneTree(true);
|
||||
}
|
||||
senoutp->addSensesp(itr->sensesp()->cloneTree(true));
|
||||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
if (senedited) senoutp = VN_AS(V3Const::constifyExpensiveEdit(senoutp), SenTree);
|
||||
if (traceDests) {
|
||||
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->dstDomainp(senoutp);
|
||||
if (debug() >= 9) {
|
||||
UINFO(9, spaces(level) + " Tracedst " << vertexp);
|
||||
if (senoutp) {
|
||||
V3EmitV::verilogForTree(senoutp, cout);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->srcDomainp(senoutp);
|
||||
if (debug() >= 9) {
|
||||
UINFO(9, spaces(level) + " Tracesrc " << vertexp);
|
||||
if (senoutp) {
|
||||
V3EmitV::verilogForTree(senoutp, cout);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstScope* nodep) override {
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
void visit(AstActive* nodep) override {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4, " BLOCK " << nodep << endl);
|
||||
AstNode::user2ClearTree();
|
||||
m_domainp = nodep->sensesp();
|
||||
// Ignore static initializers, initial and final blocks
|
||||
if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
m_domainp = nullptr;
|
||||
AstNode::user2ClearTree();
|
||||
}
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_scopep) {
|
||||
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
|
||||
AstVarScope* const varscp = nodep->varScopep();
|
||||
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
CdcVarVertex* const varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5, " VARREF to " << varscp << endl);
|
||||
// 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->access().isWriteOrRW()) {
|
||||
new V3GraphEdge{&m_graph, m_logicVertexp, varvertexp, 1};
|
||||
if (m_inDly) {
|
||||
varvertexp->fromFlop(true);
|
||||
varvertexp->srcDomainp(m_domainp);
|
||||
varvertexp->srcDomainSet(true);
|
||||
}
|
||||
} else {
|
||||
if (varvertexp->cntAsyncRst()) {
|
||||
// UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge{&m_graph, varvertexp, m_logicVertexp, CDC_WEIGHT_ASYNC};
|
||||
} else {
|
||||
// UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge{&m_graph, varvertexp, m_logicVertexp, 1};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void visit(AstAssignDly* nodep) override {
|
||||
VL_RESTORER(m_inDly);
|
||||
m_inDly = true;
|
||||
iterateChildren(nodep);
|
||||
m_inDly = false;
|
||||
}
|
||||
void visit(AstSenItem* nodep) override {
|
||||
m_inSenItem = true;
|
||||
iterateChildren(nodep);
|
||||
m_inSenItem = false;
|
||||
}
|
||||
void visit(AstAlways* nodep) override { iterateNewStmt(nodep); }
|
||||
void visit(AstAlwaysPublic* nodep) override {
|
||||
// CDC doesn't care about public variables
|
||||
}
|
||||
void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); }
|
||||
void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
|
||||
void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); }
|
||||
|
||||
// Expressions that shouldn't cause us to clear hazard
|
||||
void visit(AstConst*) override {}
|
||||
void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstConcat* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNot* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstSel* nodep) override {
|
||||
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNodeSel* nodep) override {
|
||||
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Ignores
|
||||
void visit(AstInitial*) override {}
|
||||
void visit(AstInitialAutomatic*) override {}
|
||||
void visit(AstInitialStatic*) override {}
|
||||
void visit(AstTraceDecl*) override {}
|
||||
void visit(AstCoverToggle*) override {}
|
||||
void visit(AstNodeDType*) override {}
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
void visit(AstNodeExpr* nodep) override {
|
||||
setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CdcVisitor(AstNode* nodep) {
|
||||
// Make report of all signal names and what clock edges they have
|
||||
const string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt";
|
||||
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() << '\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";
|
||||
*m_ofp << "repeating recursively forwards to the destination flop(s).\n";
|
||||
*m_ofp << "%% Indicates the operator considered potentially hazardous.\n";
|
||||
|
||||
iterate(nodep);
|
||||
analyze();
|
||||
if (debug() >= 1) edgeReport(); // Not useful to users at the moment
|
||||
if (false) {
|
||||
*m_ofp << "\nDBG-test-dumper\n";
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true);
|
||||
*m_ofp << '\n';
|
||||
}
|
||||
}
|
||||
~CdcVisitor() override {
|
||||
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
void V3Cdc::cdcAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CdcVisitor{nodep}; }
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity block domains
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3CDC_H_
|
||||
#define VERILATOR_V3CDC_H_
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Cdc final {
|
||||
public:
|
||||
static void cdcAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+13
-6
@@ -156,6 +156,11 @@ private:
|
||||
// m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep));
|
||||
//}
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
// Need to declare coverage in package, where we have access to symbol table
|
||||
iterateChildren(nodep);
|
||||
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
|
||||
}
|
||||
void visit(AstInitial* nodep) override {
|
||||
// But not AstInitialAutomatic, which remains under the class
|
||||
iterateChildren(nodep);
|
||||
@@ -171,24 +176,26 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void setStructModulep(AstStructDType* const dtypep) {
|
||||
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
|
||||
// Give it a pointer to its package and a final name
|
||||
dtypep->classOrPackagep(m_modp);
|
||||
dtypep->name(dtypep->name() + "__struct" + cvtToStr(dtypep->uniqueNum()));
|
||||
dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp);
|
||||
dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct")
|
||||
+ cvtToStr(dtypep->uniqueNum()));
|
||||
|
||||
for (const AstMemberDType* itemp = dtypep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
AstStructDType* const subp = VN_CAST(itemp->skipRefp(), StructDType);
|
||||
AstNodeUOrStructDType* const subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
|
||||
// Recurse only into anonymous unpacked structs inside this definition,
|
||||
// other unpacked structs will be reached from another typedefs
|
||||
if (subp && !subp->packed() && subp->name().empty()) { setStructModulep(subp); }
|
||||
if (subp && !subp->packed() && subp->name().empty()) setStructModulep(subp);
|
||||
}
|
||||
}
|
||||
void visit(AstTypedef* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
|
||||
|
||||
AstStructDType* const dtypep = VN_CAST(nodep->dtypep(), StructDType);
|
||||
AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType);
|
||||
if (dtypep && !dtypep->packed()) {
|
||||
dtypep->name(nodep->name());
|
||||
setStructModulep(dtypep);
|
||||
|
||||
+5
-4
@@ -87,7 +87,8 @@ private:
|
||||
}
|
||||
void computeCppWidth(AstNode* nodep) {
|
||||
if (!nodep->user2() && nodep->hasDType()) {
|
||||
if (VN_IS(nodep, Var)
|
||||
if (VN_IS(nodep, Var) //
|
||||
|| VN_IS(nodep, ConsPackMember) //
|
||||
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType)
|
||||
@@ -97,9 +98,9 @@ private:
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) {
|
||||
} else {
|
||||
const AstStructDType* const dtypep
|
||||
= VN_CAST(nodep->dtypep()->skipRefp(), StructDType);
|
||||
if (!dtypep || dtypep->packed()) { setCppWidth(nodep); }
|
||||
const AstNodeUOrStructDType* const dtypep
|
||||
= VN_CAST(nodep->dtypep()->skipRefp(), NodeUOrStructDType);
|
||||
if (!dtypep || dtypep->packed()) setCppWidth(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -95,7 +95,7 @@ private:
|
||||
if (vscp->user1p()) return VN_AS(vscp->user1p(), VarScope);
|
||||
const AstVar* const varp = vscp->varp();
|
||||
const string newvarname
|
||||
= string("__Vsampled__") + vscp->scopep()->nameDotless() + "__" + varp->name();
|
||||
= string{"__Vsampled__"} + vscp->scopep()->nameDotless() + "__" + varp->name();
|
||||
FileLine* const flp = vscp->fileline();
|
||||
AstVar* const newvarp = new AstVar{flp, VVarType::MODULETEMP, newvarname, varp->dtypep()};
|
||||
newvarp->noReset(true); // Reset by below assign
|
||||
@@ -146,17 +146,19 @@ private:
|
||||
UASSERT_OBJ(nodep->hasClocked(), nodep, "Should have been converted by V3Sched");
|
||||
UASSERT_OBJ(nodep->stmtsp(), nodep, "Should not have been created if empty");
|
||||
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
|
||||
// Create 'if' statement, if needed
|
||||
if (!m_lastSenp || !nodep->sensesp()->sameTree(m_lastSenp)) {
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
clearLastSen();
|
||||
m_lastSenp = nodep->sensesp();
|
||||
// Make a new if statement
|
||||
m_lastIfp = makeActiveIf(m_lastSenp);
|
||||
relinker.relink(m_lastIfp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
|
||||
// Move statements to if
|
||||
|
||||
+7
-7
@@ -37,7 +37,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
static void makeVlToString(AstClass* nodep) {
|
||||
AstCFunc* const funcp
|
||||
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
|
||||
funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) + ">& obj");
|
||||
funcp->argTypes("const VlClassRef<" + EmitCBase::prefixNameProtect(nodep) + ">& obj");
|
||||
funcp->isMethod(false);
|
||||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
@@ -51,7 +51,7 @@ static void makeVlToString(AstClass* nodep) {
|
||||
static void makeVlToString(AstIface* nodep) {
|
||||
AstCFunc* const funcp
|
||||
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
|
||||
funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "* obj");
|
||||
funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "* obj");
|
||||
funcp->isMethod(false);
|
||||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
@@ -61,11 +61,11 @@ static void makeVlToString(AstIface* nodep) {
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
nodep->addStmtsp(funcp);
|
||||
}
|
||||
static void makeVlToString(AstStructDType* nodep) {
|
||||
static void makeVlToString(AstNodeUOrStructDType* nodep) {
|
||||
AstNodeModule* const modp = nodep->classOrPackagep();
|
||||
AstCFunc* const funcp
|
||||
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
|
||||
funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "& obj");
|
||||
funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "& obj");
|
||||
funcp->isMethod(false);
|
||||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
@@ -79,7 +79,7 @@ static void makeVlToString(AstStructDType* nodep) {
|
||||
} else {
|
||||
stmt += ", ";
|
||||
}
|
||||
stmt += itemp->nameProtect() + ":\" + ";
|
||||
stmt += VIdProtect::protect(itemp->prettyName()) + ":\" + ";
|
||||
if (VN_IS(itemp->dtypep()->skipRefp(), BasicDType) && itemp->isWide()) {
|
||||
stmt += "VL_TO_STRING_W";
|
||||
} else {
|
||||
@@ -137,7 +137,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
||||
string stmt = "out += ";
|
||||
if (!comma.empty()) stmt += "\", \"+ ";
|
||||
// comma = ", "; // Nothing further so not needed
|
||||
stmt += EmitCBaseVisitor::prefixNameProtect(nodep->extendsp()->dtypep());
|
||||
stmt += EmitCBase::prefixNameProtect(nodep->extendsp()->dtypep());
|
||||
stmt += "::to_string_middle();\n";
|
||||
nodep->user1(true); // So what we extend dumps this
|
||||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
|
||||
@@ -168,7 +168,7 @@ void V3Common::commonAll() {
|
||||
}
|
||||
for (AstNode* nodep = v3Global.rootp()->typeTablep()->typesp(); nodep;
|
||||
nodep = nodep->nextp()) {
|
||||
if (AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) {
|
||||
if (AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) {
|
||||
if (!dtypep->packed()) makeVlToString(dtypep);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-8
@@ -40,25 +40,31 @@ template <typename T>
|
||||
class V3ConfigWildcardResolver final {
|
||||
using Map = std::map<const std::string, T>;
|
||||
|
||||
Map m_mapWildcard; // Wildcard strings to entities
|
||||
Map m_mapResolved; // Resolved strings to converged entities
|
||||
mutable V3Mutex m_mutex; // protects members
|
||||
Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities
|
||||
Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities
|
||||
public:
|
||||
V3ConfigWildcardResolver() = default;
|
||||
~V3ConfigWildcardResolver() = default;
|
||||
|
||||
/// Update into maps from other
|
||||
void update(const V3ConfigWildcardResolver& other) {
|
||||
void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex)
|
||||
VL_EXCLUDES(other.m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
V3LockGuard otherLock{other.m_mutex};
|
||||
for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second);
|
||||
for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second);
|
||||
}
|
||||
|
||||
// Access and create a (wildcard) entity
|
||||
T& at(const string& name) {
|
||||
T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
// Don't store into wildcards if the name is not a wildcard string
|
||||
return m_mapWildcard[name];
|
||||
}
|
||||
// Access an entity and resolve wildcards that match it
|
||||
T* resolve(const string& name) {
|
||||
T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
// Lookup if it was resolved before, typically not
|
||||
auto it = m_mapResolved.find(name);
|
||||
if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second;
|
||||
@@ -78,7 +84,10 @@ public:
|
||||
return newp;
|
||||
}
|
||||
// Flush on update
|
||||
void flush() { m_mapResolved.clear(); }
|
||||
void flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
V3LockGuard lock{m_mutex};
|
||||
m_mapResolved.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// Only public_flat_rw has the sensitity tree
|
||||
@@ -332,8 +341,7 @@ public:
|
||||
}
|
||||
bool waive(V3ErrorCode code, const string& match) {
|
||||
for (const auto& itr : m_waivers) {
|
||||
if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT)
|
||||
|| (code.unusedError() && itr.first == V3ErrorCode::I_UNUSED))
|
||||
if ((code.isUnder(itr.first) || (itr.first == V3ErrorCode::I_LINT))
|
||||
&& VString::wildmatch(match, itr.second)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "V3Ast.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3Mutex.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
||||
+136
-99
@@ -70,7 +70,7 @@ static int countTrailingZeroes(uint64_t val) {
|
||||
// This visitor can be used in the post-expanded Ast from V3Expand, where the Ast satisfies:
|
||||
// - Constants are 64 bit at most (because words are accessed via AstWordSel)
|
||||
// - Variables are scoped.
|
||||
class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
class ConstBitOpTreeVisitor final : public VNVisitorConst {
|
||||
// NODE STATE
|
||||
// AstVarRef::user4u -> Base index of m_varInfos that points VarInfo
|
||||
// AstVarScope::user4u -> Same as AstVarRef::user4
|
||||
@@ -416,7 +416,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
{
|
||||
VL_RESTORER(m_leafp);
|
||||
m_leafp = &info;
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
|
||||
bool ok = !m_failed;
|
||||
@@ -431,7 +431,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
// VISITORS
|
||||
void visit(AstNode* nodep) override { CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); }
|
||||
void visit(AstCCast* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_leafp) m_leafp->updateBitRange(nodep);
|
||||
}
|
||||
void visit(AstShiftR* nodep) override {
|
||||
@@ -440,7 +440,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
|
||||
m_lsb += constp->toUInt();
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->lhsp());
|
||||
iterateConst(nodep->lhsp());
|
||||
m_leafp->updateBitRange(nodep);
|
||||
m_lsb -= constp->toUInt();
|
||||
}
|
||||
@@ -449,12 +449,10 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
AstNode* lhsp = nodep->lhsp();
|
||||
AstCCast* const castp = VN_CAST(lhsp, CCast);
|
||||
if (castp) lhsp = castp->lhsp();
|
||||
CONST_BITOP_RETURN_IF(!VN_IS(lhsp, VarRef) && !VN_IS(lhsp, Xor) && !VN_IS(lhsp, RedXor)
|
||||
&& !VN_IS(lhsp, ShiftR),
|
||||
lhsp);
|
||||
CONST_BITOP_RETURN_IF(!isXorTree() && !VN_IS(lhsp, VarRef) && !VN_IS(lhsp, ShiftR), lhsp);
|
||||
incrOps(nodep, __LINE__);
|
||||
m_polarity = !m_polarity;
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
// Don't restore m_polarity for Xor as it counts parity of the entire tree
|
||||
if (!isXorTree()) m_polarity = !m_polarity;
|
||||
if (m_leafp && castp) m_leafp->updateBitRange(castp);
|
||||
@@ -465,7 +463,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
|
||||
UASSERT_OBJ(m_leafp->wordIdx() == -1, nodep, "Unexpected nested WordSel");
|
||||
m_leafp->wordIdx(constp->toSInt());
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
}
|
||||
void visit(AstVarRef* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
@@ -529,7 +527,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
// Always reach past a plain making AND
|
||||
Restorer restorer{*this};
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->rhsp());
|
||||
iterateConst(nodep->rhsp());
|
||||
CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp());
|
||||
restorer.disableRestore(); // Now all checks passed
|
||||
} else if (nodep->type() == m_rootp->type()) { // And, Or, Xor
|
||||
@@ -542,13 +540,14 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
m_leafp = &leafInfo;
|
||||
AstNodeExpr* opp = right ? nodep->rhsp() : nodep->lhsp();
|
||||
const bool origFailed = m_failed;
|
||||
iterate(opp);
|
||||
iterateConst(opp);
|
||||
if (leafInfo.constp() || m_failed) {
|
||||
// Revert changes in leaf
|
||||
restorer.restoreNow();
|
||||
// Reach past a cast then add to frozen nodes to be added to final reduction
|
||||
if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp();
|
||||
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{m_polarity, m_lsb});
|
||||
const bool pol = isXorTree() || m_polarity; // Only AND/OR tree needs polarity
|
||||
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{pol, m_lsb});
|
||||
m_failed = origFailed;
|
||||
continue;
|
||||
}
|
||||
@@ -647,11 +646,11 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||
m_varInfos.push_back(nullptr);
|
||||
CONST_BITOP_RETURN_IF(!isAndTree() && !isOrTree() && !isXorTree(), nodep);
|
||||
if (AstNodeBiop* const biopp = VN_CAST(nodep, NodeBiop)) {
|
||||
iterate(biopp);
|
||||
iterateConst(biopp);
|
||||
} else {
|
||||
UASSERT_OBJ(VN_IS(nodep, RedXor), nodep, "Must be RedXor");
|
||||
incrOps(nodep, __LINE__);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
for (auto&& entry : m_bitPolarities) {
|
||||
getVarInfo(entry.m_info).setPolarity(entry.m_polarity, entry.m_bit);
|
||||
@@ -900,6 +899,7 @@ private:
|
||||
bool m_doV = false; // Verilog, not C++ conversion
|
||||
bool m_doGenerate = false; // Postpone width checking inside generate
|
||||
bool m_hasJumpDelay = false; // JumpGo or Delay under this while
|
||||
bool m_underRecFunc = false; // Under a recursive function
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstArraySel* m_selp = nullptr; // Current select
|
||||
const AstNode* m_scopep = nullptr; // Current scope
|
||||
@@ -1384,15 +1384,6 @@ private:
|
||||
// but for now can disable en masse until V3Purify takes effect.
|
||||
return m_doShort || VN_IS(nodep, VarRef) || VN_IS(nodep, Const);
|
||||
}
|
||||
bool isTreePureRecurse(AstNode* nodep) {
|
||||
// Should memoize this if call commonly
|
||||
if (!nodep->isPure()) return false;
|
||||
if (nodep->op1p() && !isTreePureRecurse(nodep->op1p())) return false;
|
||||
if (nodep->op2p() && !isTreePureRecurse(nodep->op2p())) return false;
|
||||
if (nodep->op3p() && !isTreePureRecurse(nodep->op3p())) return false;
|
||||
if (nodep->op4p() && !isTreePureRecurse(nodep->op4p())) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Extraction checks
|
||||
bool warnSelect(AstSel* nodep) {
|
||||
@@ -1466,6 +1457,7 @@ private:
|
||||
if (!thensp->lhsp()->sameGateTree(elsesp->lhsp())) return false;
|
||||
if (!thensp->rhsp()->gateTree()) return false;
|
||||
if (!elsesp->rhsp()->gateTree()) return false;
|
||||
if (m_underRecFunc) return false; // This optimization may lead to infinite recursion
|
||||
return true;
|
||||
}
|
||||
bool operandIfIf(const AstNodeIf* nodep) {
|
||||
@@ -2272,7 +2264,7 @@ private:
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Iterate modules backwards, in bottom-up order. That's faster
|
||||
iterateChildrenBackwards(nodep);
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
@@ -2754,52 +2746,74 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
struct SenItemCmp {
|
||||
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
|
||||
if (!lhsp->sensp() && rhsp->sensp()) return true;
|
||||
if (lhsp->sensp() && !rhsp->sensp()) return false;
|
||||
if (lhsp->varrefp() && !rhsp->varrefp()) return true;
|
||||
if (!lhsp->varrefp() && rhsp->varrefp()) return false;
|
||||
if (lhsp->varrefp() && rhsp->varrefp()) {
|
||||
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
|
||||
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
|
||||
class SenItemCmp final {
|
||||
static int cmp(const AstNodeExpr* ap, const AstNodeExpr* bp) {
|
||||
const VNType aType = ap->type();
|
||||
const VNType bType = bp->type();
|
||||
if (aType != bType) return static_cast<int>(bType) - static_cast<int>(aType);
|
||||
|
||||
if (const AstVarRef* const aRefp = VN_CAST(ap, VarRef)) {
|
||||
const AstVarRef* const bRefp = VN_AS(bp, VarRef);
|
||||
// Looks visually better if we keep sorted by name
|
||||
if (aRefp->name() < bRefp->name()) return -1;
|
||||
if (aRefp->name() > bRefp->name()) return 1;
|
||||
// But might be same name with different scopes
|
||||
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) return true;
|
||||
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) return false;
|
||||
if (aRefp->varScopep() < bRefp->varScopep()) return -1;
|
||||
if (aRefp->varScopep() > bRefp->varScopep()) return 1;
|
||||
// Or rarely, different data types
|
||||
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
|
||||
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
|
||||
} else if (AstCMethodHard* const lp = VN_CAST(lhsp->sensp(), CMethodHard)) {
|
||||
if (AstCMethodHard* const rp = VN_CAST(rhsp->sensp(), CMethodHard)) {
|
||||
if (AstVarRef* const lRefp = VN_CAST(lp->fromp(), VarRef)) {
|
||||
if (AstVarRef* const rRefp = VN_CAST(rp->fromp(), VarRef)) {
|
||||
if (lRefp->name() < rRefp->name()) return true;
|
||||
if (lRefp->name() > rRefp->name()) return false;
|
||||
// But might be same name with different scopes
|
||||
if (lRefp->varScopep() < rRefp->varScopep()) return true;
|
||||
if (lRefp->varScopep() > rRefp->varScopep()) return false;
|
||||
// Or rarely, different data types
|
||||
if (lRefp->dtypep() < rRefp->dtypep()) return true;
|
||||
if (lRefp->dtypep() > rRefp->dtypep()) return false;
|
||||
}
|
||||
}
|
||||
if (AstConst* lConstp = VN_CAST(lp->pinsp(), Const)) {
|
||||
if (AstConst* rConstp = VN_CAST(rp->pinsp(), Const)) {
|
||||
if (lConstp->toUInt() < rConstp->toUInt()) return true;
|
||||
if (lConstp->toUInt() > rConstp->toUInt()) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aRefp->dtypep() < bRefp->dtypep()) return -1;
|
||||
if (aRefp->dtypep() > bRefp->dtypep()) return 1;
|
||||
return 0;
|
||||
}
|
||||
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
|
||||
// note the SenTree optimizer requires this order (more
|
||||
// general first, less general last)
|
||||
if (lhsp->edgeType() < rhsp->edgeType()) return true;
|
||||
if (lhsp->edgeType() > rhsp->edgeType()) return false;
|
||||
return false;
|
||||
|
||||
if (const AstConst* const aConstp = VN_CAST(ap, Const)) {
|
||||
const AstConst* const bConstp = VN_AS(bp, Const);
|
||||
if (aConstp->toUQuad() < bConstp->toUQuad()) return -1;
|
||||
if (aConstp->toUQuad() > bConstp->toUQuad()) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (const AstNodeBiop* const aBiOpp = VN_CAST(ap, NodeBiop)) {
|
||||
const AstNodeBiop* const bBiOpp = VN_AS(bp, NodeBiop);
|
||||
// Compare RHSs first as LHS might be const, but the variable term should become
|
||||
// adjacent for optimization if identical.
|
||||
if (const int c = cmp(aBiOpp->rhsp(), bBiOpp->rhsp())) return c;
|
||||
return cmp(aBiOpp->lhsp(), bBiOpp->lhsp());
|
||||
}
|
||||
|
||||
if (const AstCMethodHard* const aCallp = VN_CAST(ap, CMethodHard)) {
|
||||
const AstCMethodHard* const bCallp = VN_AS(bp, CMethodHard);
|
||||
if (aCallp->name() < bCallp->name()) return -1;
|
||||
if (aCallp->name() > bCallp->name()) return 1;
|
||||
if (const int c = cmp(aCallp->fromp(), bCallp->fromp())) return c;
|
||||
AstNodeExpr* aPinsp = aCallp->pinsp();
|
||||
AstNodeExpr* bPinsp = bCallp->pinsp();
|
||||
while (aPinsp && bPinsp) {
|
||||
if (const int c = cmp(aPinsp, bPinsp)) return c;
|
||||
aPinsp = VN_AS(aPinsp->nextp(), NodeExpr);
|
||||
bPinsp = VN_AS(bPinsp->nextp(), NodeExpr);
|
||||
}
|
||||
return aPinsp ? -1 : bPinsp ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
|
||||
AstNodeExpr* const lSensp = lhsp->sensp();
|
||||
AstNodeExpr* const rSensp = rhsp->sensp();
|
||||
if (lSensp && rSensp) {
|
||||
// If both terms have sensitivity expressions, recursively compare them
|
||||
if (const int c = cmp(lSensp, rSensp)) return c < 0;
|
||||
} else if (lSensp || rSensp) {
|
||||
// Terms with sensitivity expressions come after those without
|
||||
return rSensp;
|
||||
}
|
||||
// Finally sort by edge, AFTER variable, as we want multiple edges for same var
|
||||
// adjacent. note the SenTree optimizer requires this order (more general first,
|
||||
// less general last)
|
||||
return lhsp->edgeType() < rhsp->edgeType();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2824,9 +2838,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
|
||||
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
|
||||
// Make things a little faster; check first if we need a sort
|
||||
// Pass 1: Sort the sensitivity items so "posedge a or b" and "posedge b or a" and
|
||||
// similar, optimizable expressions end up next to each other.
|
||||
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
|
||||
nextp = VN_AS(senp->nextp(), SenItem);
|
||||
// cppcheck-suppress unassignedVariable // cppcheck bug
|
||||
@@ -2846,35 +2859,53 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Pass2, remove dup edges
|
||||
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
|
||||
// Pass 2, remove duplicates and simplify adjacent terms if possible
|
||||
for (AstSenItem *senp = nodep->sensesp(), *nextp; senp; senp = nextp) {
|
||||
nextp = VN_AS(senp->nextp(), SenItem);
|
||||
AstSenItem* const litemp = senp;
|
||||
AstSenItem* const ritemp = nextp;
|
||||
if (ritemp) {
|
||||
if ((litemp->sensp() && ritemp->sensp()
|
||||
&& litemp->sensp()->sameGateTree(ritemp->sensp()))
|
||||
|| (!litemp->sensp() && !ritemp->sensp())) {
|
||||
// We've sorted in the order ANY, BOTH, POS, NEG,
|
||||
// so we don't need to try opposite orders
|
||||
if ((litemp->edgeType() == VEdgeType::ET_POSEDGE // POS or NEG -> BOTH
|
||||
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|
||||
|| (litemp->edgeType() == ritemp->edgeType()) // Identical edges
|
||||
) {
|
||||
// Fix edge of old node
|
||||
if (litemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|
||||
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
// Remove redundant node
|
||||
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
|
||||
VL_DANGLING(ritemp);
|
||||
// Try to collapse again
|
||||
nextp = litemp;
|
||||
if (!nextp) break;
|
||||
AstSenItem* const lItemp = senp;
|
||||
AstSenItem* const rItemp = nextp;
|
||||
AstNodeExpr* const lSenp = lItemp->sensp();
|
||||
AstNodeExpr* const rSenp = rItemp->sensp();
|
||||
if (!lSenp || !rSenp) continue;
|
||||
|
||||
if (lSenp->sameGateTree(rSenp)) {
|
||||
// POSEDGE or NEGEDGE -> BOTHEDGE. (We've sorted POSEDGE, before NEGEDGE, so we
|
||||
// do not need to test for the opposite orders.)
|
||||
if (lItemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
&& rItemp->edgeType() == VEdgeType::ET_NEGEDGE) {
|
||||
// Make both terms BOTHEDGE, the second will be removed below
|
||||
lItemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
rItemp->edgeType(VEdgeType::ET_BOTHEDGE);
|
||||
}
|
||||
|
||||
// Remove identical expressions
|
||||
if (lItemp->edgeType() == rItemp->edgeType()) {
|
||||
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
|
||||
nextp = lItemp;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not identical terms, check if they can be combined
|
||||
if (lSenp->width() != rSenp->width()) continue;
|
||||
if (AstAnd* const lAndp = VN_CAST(lSenp, And)) {
|
||||
if (AstAnd* const rAndp = VN_CAST(rSenp, And)) {
|
||||
if (AstConst* const lConstp = VN_CAST(lAndp->lhsp(), Const)) {
|
||||
if (AstConst* const rConstp = VN_CAST(rAndp->lhsp(), Const)) {
|
||||
if (lAndp->rhsp()->sameTree(rAndp->rhsp())) {
|
||||
const V3Number lNum{lConstp->num()};
|
||||
lConstp->num().opOr(lNum, rConstp->num());
|
||||
// Remove redundant term
|
||||
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
|
||||
nextp = lItemp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// nodep->dumpTree("- ssou: ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2954,7 +2985,7 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) {
|
||||
if (!isTreePureRecurse(nodep->condp())) {
|
||||
if (!nodep->condp()->isTreePureRecurse()) {
|
||||
// Condition has side effect - leave - perhaps in
|
||||
// future simplify to remove all but side effect terms
|
||||
} else {
|
||||
@@ -2982,6 +3013,7 @@ private:
|
||||
AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext();
|
||||
AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext();
|
||||
AstIf* const ifp = new AstIf{nodep->fileline(), condp, elsesp, thensp};
|
||||
ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info
|
||||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
@@ -3094,12 +3126,12 @@ private:
|
||||
if (!inPct && ch == '%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
} else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) {
|
||||
} else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
fmt += ch;
|
||||
switch (tolower(ch)) {
|
||||
switch (std::tolower(ch)) {
|
||||
case '%': break; // %% - just output a %
|
||||
case 'm': break; // %m - auto insert "name"
|
||||
case 'l': break; // %l - auto insert "library"
|
||||
@@ -3137,6 +3169,11 @@ private:
|
||||
VL_DO_DANGLING(replaceConstString(nodep, nodep->name()), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_underRecFunc);
|
||||
if (nodep->recursive()) m_underRecFunc = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstFuncRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
@@ -3190,7 +3227,7 @@ private:
|
||||
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->exprp()) {
|
||||
if (!nodep->exprp() || VN_IS(nodep->exprp(), Const)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
@@ -3209,7 +3246,7 @@ private:
|
||||
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Jump to label where label immediately follows label is not useful
|
||||
// Jump to label where label immediately follows this go is not useful
|
||||
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
// Keep the label, might be other jumps pointing to it, gets cleaned later
|
||||
|
||||
+4
-1
@@ -124,7 +124,10 @@ private:
|
||||
UINFO(9, "new " << declp << endl);
|
||||
|
||||
AstCoverInc* const incp = new AstCoverInc{fl, declp};
|
||||
if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) {
|
||||
if (!trace_var_name.empty()
|
||||
&& v3Global.opt.traceCoverage()
|
||||
// No module handle to trace inside classes
|
||||
&& !VN_IS(m_modp, Class)) {
|
||||
FileLine* const fl_nowarn = new FileLine{incp->fileline()};
|
||||
fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
|
||||
AstVar* const varp = new AstVar{fl_nowarn, VVarType::MODULETEMP, trace_var_name,
|
||||
|
||||
+1
-1
@@ -324,7 +324,7 @@ private:
|
||||
}
|
||||
}
|
||||
bool shouldDeleteTypedef(AstTypedef* typedefp) {
|
||||
if (auto* structp = VN_CAST(typedefp->subDTypep(), StructDType)) {
|
||||
if (auto* const structp = VN_CAST(typedefp->subDTypep(), NodeUOrStructDType)) {
|
||||
if (structp->user1() && !structp->packed()) return false;
|
||||
}
|
||||
return m_elimCells && !typedefp->attrPublic();
|
||||
|
||||
+11
-9
@@ -262,8 +262,8 @@ private:
|
||||
if (VN_IS(dimp, Const)) { // bit = const, can just use it
|
||||
dimreadps.push_front(dimp);
|
||||
} else {
|
||||
const string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
|
||||
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
const string bitvarname = string{"__Vdlyvdim"} + cvtToStr(dimension) + "__"
|
||||
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
AstVarScope* const bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
|
||||
AstAssign* const bitassignp = new AstAssign{
|
||||
@@ -282,8 +282,8 @@ private:
|
||||
// vlsb = constant, can just push constant into where we use it
|
||||
bitreadp = lsbvaluep;
|
||||
} else {
|
||||
const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
|
||||
+ cvtToStr(modVecNum));
|
||||
const string bitvarname
|
||||
= string{"__Vdlyvlsb__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
AstVarScope* const bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
|
||||
AstAssign* const bitassignp = new AstAssign{
|
||||
@@ -301,7 +301,7 @@ private:
|
||||
valreadp = nodep->rhsp()->unlinkFrBack();
|
||||
} else {
|
||||
const string valvarname
|
||||
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
= string{"__Vdlyvval__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
AstVarScope* const valvscp
|
||||
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
newlhsp = new AstVarRef{nodep->fileline(), valvscp, VAccess::WRITE};
|
||||
@@ -321,7 +321,7 @@ private:
|
||||
++m_statSharedSet;
|
||||
} else { // Create new one
|
||||
const string setvarname
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
= string{"__Vdlyvset__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
|
||||
if (!m_inSuspendableOrFork) {
|
||||
// Suspendables reset __Vdlyvset__ in the AstAlwaysPost
|
||||
@@ -474,14 +474,16 @@ private:
|
||||
m_inSuspendableOrFork = true;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCAwait* nodep) override { m_timingDomains.insert(nodep->sensesp()); }
|
||||
void visit(AstCAwait* nodep) override {
|
||||
if (nodep->sensesp()) m_timingDomains.insert(nodep->sensesp());
|
||||
}
|
||||
void visit(AstFireEvent* nodep) override {
|
||||
UASSERT_OBJ(v3Global.hasEvents(), nodep, "Inconsistent");
|
||||
FileLine* const flp = nodep->fileline();
|
||||
if (nodep->isDelayed()) {
|
||||
AstVarRef* const vrefp = VN_AS(nodep->operandp(), VarRef);
|
||||
vrefp->unlinkFrBack();
|
||||
const string newvarname = (string("__Vdly__") + vrefp->varp()->shortName());
|
||||
const string newvarname = string{"__Vdly__"} + vrefp->varp()->shortName();
|
||||
AstVarScope* const dlyvscp = createVarSc(vrefp->varScopep(), newvarname, 1, nullptr);
|
||||
|
||||
const auto dlyRef = [=](VAccess access) {
|
||||
@@ -570,7 +572,7 @@ private:
|
||||
checkActivePost(nodep, oldactivep);
|
||||
}
|
||||
if (!dlyvscp) { // First use of this delayed variable
|
||||
const string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
|
||||
const string newvarname = string{"__Vdly__"} + nodep->varp()->shortName();
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
|
||||
AstNodeAssign* const prep = new AstAssignPre{
|
||||
nodep->fileline(),
|
||||
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
AstCCall* const callp = new AstCCall{nodep->fileline(), funcp};
|
||||
callp->dtypeSetVoid();
|
||||
if (VN_IS(m_modp, Class)) {
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->argTypes(EmitCBase::symClassVar());
|
||||
callp->argTypes("vlSymsp");
|
||||
}
|
||||
UINFO(6, " New " << callp << endl);
|
||||
@@ -93,6 +93,7 @@ private:
|
||||
}
|
||||
}
|
||||
void visit(AstStmtExpr* nodep) override {} // Stop recursion after introducing new function
|
||||
void visit(AstJumpBlock*) override {} // Stop recursion as can't break up across a jump
|
||||
void visit(AstNodeStmt* nodep) override {
|
||||
m_depth++;
|
||||
if (m_depth > v3Global.opt.compLimitBlocks()) { // Already done
|
||||
|
||||
+2
-2
@@ -166,7 +166,7 @@ private:
|
||||
new AstEq{
|
||||
funcp->fileline(), new AstCExpr{funcp->fileline(), "this", 64},
|
||||
new AstCExpr{funcp->fileline(),
|
||||
string("&(") + funcp->scopep()->nameVlSym() + ")",
|
||||
string{"&("} + funcp->scopep()->nameVlSym() + ")",
|
||||
64}},
|
||||
returnp};
|
||||
newfuncp->addStmtsp(ifp);
|
||||
@@ -178,7 +178,7 @@ private:
|
||||
// to come up with some return value
|
||||
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
|
||||
// VDisplayType::DT_WARNING,
|
||||
// string("%%Error: ")+name+"() called with bad
|
||||
// string{"%%Error: "}+name+"() called with bad
|
||||
// scope", nullptr));
|
||||
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
||||
if (debug() >= 9) newfuncp->dumpTree("- newfunc: ");
|
||||
|
||||
+10
-5
@@ -503,14 +503,19 @@ public:
|
||||
inline bool inlined() const;
|
||||
|
||||
// Methods that allow DfgVertex to participate in error reporting/messaging
|
||||
void v3errorEnd(std::ostringstream& str) const { m_filelinep->v3errorEnd(str); }
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN {
|
||||
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
m_filelinep->v3errorEnd(str);
|
||||
}
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
m_filelinep->v3errorEndFatal(str);
|
||||
}
|
||||
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
|
||||
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
return fileline()->warnContextPrimary();
|
||||
}
|
||||
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
||||
string warnMore() const { return fileline()->warnMore(); }
|
||||
string warnOther() const { return fileline()->warnOther(); }
|
||||
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
|
||||
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
|
||||
|
||||
private:
|
||||
// For internal use only.
|
||||
|
||||
@@ -59,8 +59,7 @@ AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( //
|
||||
const DfgCountOnes* vtxp, AstNodeExpr* op1) {
|
||||
AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1};
|
||||
// Set dtype same as V3Width
|
||||
const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
|
||||
nodep->dtypeSetLogicSized(selwidth, VSigning::UNSIGNED);
|
||||
nodep->dtypeSetLogicSized(32, VSigning::UNSIGNED);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
|
||||
+20
-14
@@ -39,7 +39,7 @@ EmitCParentModule::EmitCParentModule() {
|
||||
//######################################################################
|
||||
// EmitCBaseVisitor implementation
|
||||
|
||||
string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
||||
string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
||||
modp = modp ? modp : EmitCParentModule::get(nodep);
|
||||
string name;
|
||||
if (nodep->isConstructor()) {
|
||||
@@ -57,15 +57,21 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
|
||||
return name;
|
||||
}
|
||||
|
||||
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) {
|
||||
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
|
||||
cfilep->slow(slow);
|
||||
cfilep->source(source);
|
||||
if (add) v3Global.rootp()->addFilesp(cfilep);
|
||||
AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source) {
|
||||
AstCFile* const cfilep = createCFile(filename, slow, source);
|
||||
v3Global.rootp()->addFilesp(cfilep);
|
||||
return cfilep;
|
||||
}
|
||||
|
||||
string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
|
||||
AstCFile* EmitCBaseVisitorConst::createCFile(const string& filename, bool slow,
|
||||
bool source) VL_MT_SAFE {
|
||||
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
|
||||
cfilep->slow(slow);
|
||||
cfilep->source(source);
|
||||
return cfilep;
|
||||
}
|
||||
|
||||
string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) {
|
||||
// Return argument list for given C function
|
||||
string args;
|
||||
if (nodep->isLoose() && !nodep->isStatic()) {
|
||||
@@ -95,8 +101,8 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
|
||||
return args;
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool withScope) {
|
||||
void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool withScope) {
|
||||
if (funcp->slow()) puts("VL_ATTR_COLD ");
|
||||
if (!funcp->isConstructor() && !funcp->isDestructor()) {
|
||||
puts(funcp->rtnTypeVoid());
|
||||
@@ -114,8 +120,8 @@ void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModul
|
||||
if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const");
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool cLinkage) {
|
||||
void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
|
||||
bool cLinkage) {
|
||||
ensureNewLine();
|
||||
if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n");
|
||||
if (cLinkage) puts("extern \"C\" ");
|
||||
@@ -129,7 +135,7 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule*
|
||||
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
||||
void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
|
||||
const AstBasicDType* const basicp = nodep->basicp();
|
||||
bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
||||
|
||||
@@ -217,7 +223,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
||||
void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
||||
string nl;
|
||||
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
||||
@@ -235,7 +241,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType)
|
||||
puts(nl);
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, VNType type) {
|
||||
void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) {
|
||||
// Short circuit if nothing to do. This can save a lot of time on large designs as this
|
||||
// function needs to traverse the entire module linearly.
|
||||
if (!v3Global.hasSCTextSections()) return;
|
||||
|
||||
+45
-38
@@ -40,7 +40,7 @@ public:
|
||||
EmitCParentModule();
|
||||
VL_UNCOPYABLE(EmitCParentModule);
|
||||
|
||||
static const AstNodeModule* get(const AstNode* nodep) {
|
||||
static const AstNodeModule* get(const AstNode* nodep) VL_MT_STABLE {
|
||||
return VN_AS(nodep->user4p(), NodeModule);
|
||||
}
|
||||
};
|
||||
@@ -48,51 +48,23 @@ public:
|
||||
//######################################################################
|
||||
// Base Visitor class -- holds output file pointer
|
||||
|
||||
class EmitCBaseVisitor VL_NOT_FINAL : public VNVisitor {
|
||||
class EmitCBase VL_NOT_FINAL {
|
||||
public:
|
||||
// STATE
|
||||
V3OutCFile* m_ofp = nullptr;
|
||||
bool m_trackText = false; // Always track AstText nodes
|
||||
// METHODS
|
||||
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
|
||||
void puts(const string& str) { ofp()->puts(str); }
|
||||
void putbs(const string& str) { ofp()->putbs(str); }
|
||||
void putsDecoration(const string& str) {
|
||||
if (v3Global.opt.decoration()) puts(str);
|
||||
}
|
||||
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
|
||||
void ensureNewLine() { ofp()->ensureNewLine(); }
|
||||
bool optSystemC() { return v3Global.opt.systemC(); }
|
||||
static string protect(const string& name) { return VIdProtect::protectIf(name, true); }
|
||||
static string protectIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectIf(name, doIt);
|
||||
}
|
||||
static string protectWordsIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectWordsIf(name, doIt);
|
||||
}
|
||||
static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; }
|
||||
static string voidSelfAssign(const AstNodeModule* modp) {
|
||||
const string className = prefixNameProtect(modp);
|
||||
return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className
|
||||
+ "*>(voidSelf);\n";
|
||||
}
|
||||
static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); }
|
||||
static string symClassName() VL_MT_STABLE {
|
||||
return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms");
|
||||
}
|
||||
static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; }
|
||||
static string symClassAssign() {
|
||||
return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n";
|
||||
}
|
||||
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
|
||||
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
|
||||
return v3Global.opt.modPrefix() + "_" + protect(nodep->name());
|
||||
static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix
|
||||
return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name());
|
||||
}
|
||||
static string topClassName() { // Return name of top wrapper module
|
||||
return v3Global.opt.prefix();
|
||||
}
|
||||
|
||||
static bool isConstPoolMod(const AstNode* modp) {
|
||||
return modp == v3Global.rootp()->constPoolp()->modp();
|
||||
}
|
||||
|
||||
static bool isAnonOk(const AstVar* varp) {
|
||||
return v3Global.opt.compLimitMembers() != 0 // Enabled
|
||||
&& !varp->isStatic() // Not a static variable
|
||||
@@ -100,8 +72,43 @@ public:
|
||||
&& !VN_IS(varp->dtypep()->skipRefp(), SampleQueueDType) // Aggregates can't be anon
|
||||
&& (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon
|
||||
}
|
||||
static bool isConstPoolMod(const AstNode* modp) {
|
||||
return modp == v3Global.rootp()->constPoolp()->modp();
|
||||
}
|
||||
};
|
||||
|
||||
static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true);
|
||||
class EmitCBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst, public EmitCBase {
|
||||
public:
|
||||
// STATE
|
||||
V3OutCFile* m_ofp = nullptr;
|
||||
bool m_trackText = false; // Always track AstText nodes
|
||||
// METHODS
|
||||
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
|
||||
void puts(const string& str) { ofp()->puts(str); }
|
||||
void putsHeader() { ofp()->putsHeader(); }
|
||||
void putbs(const string& str) { ofp()->putbs(str); }
|
||||
void putsDecoration(const string& str) {
|
||||
if (v3Global.opt.decoration()) puts(str);
|
||||
}
|
||||
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
|
||||
void ensureNewLine() { ofp()->ensureNewLine(); }
|
||||
bool optSystemC() { return v3Global.opt.systemC(); }
|
||||
static string protect(const string& name) VL_MT_SAFE { return VIdProtect::protect(name); }
|
||||
static string protectIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectIf(name, doIt);
|
||||
}
|
||||
static string protectWordsIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectWordsIf(name, doIt);
|
||||
}
|
||||
static string ifNoProtect(const string& in) VL_MT_SAFE {
|
||||
return v3Global.opt.protectIds() ? "" : in;
|
||||
}
|
||||
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
|
||||
static string topClassName() VL_MT_SAFE { // Return name of top wrapper module
|
||||
return v3Global.opt.prefix();
|
||||
}
|
||||
static AstCFile* newCFile(const string& filename, bool slow, bool source);
|
||||
static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE;
|
||||
string cFuncArgs(const AstCFunc* nodep);
|
||||
void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope);
|
||||
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
|
||||
@@ -110,8 +117,8 @@ public:
|
||||
void emitTextSection(const AstNodeModule* modp, VNType type);
|
||||
|
||||
// CONSTRUCTORS
|
||||
EmitCBaseVisitor() = default;
|
||||
~EmitCBaseVisitor() override = default;
|
||||
EmitCBaseVisitorConst() = default;
|
||||
~EmitCBaseVisitorConst() override = default;
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
//######################################################################
|
||||
// Emitter that can emit constant initializer expressions
|
||||
|
||||
class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor {
|
||||
class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||
// MEMBERS
|
||||
uint32_t m_unpackedWord = 0;
|
||||
bool m_inUnpacked = false;
|
||||
@@ -64,7 +64,7 @@ protected:
|
||||
ofp()->printf("%" PRIx64 "ULL", itr.first);
|
||||
ofp()->putsNoTracking(":");
|
||||
ofp()->putsNoTracking("{");
|
||||
iterate(nodep->getIndexValuep(itr.first));
|
||||
iterateConst(nodep->getIndexValuep(itr.first));
|
||||
ofp()->putsNoTracking("}");
|
||||
}
|
||||
puts("\n");
|
||||
@@ -83,7 +83,7 @@ protected:
|
||||
for (uint64_t n = 0; n < size; ++n) {
|
||||
m_unpackedWord = n;
|
||||
if (n) puts((n % tabMod) ? ", " : ",\n");
|
||||
iterate(nodep->getIndexDefaultedValuep(n));
|
||||
iterateConst(nodep->getIndexDefaultedValuep(n));
|
||||
}
|
||||
puts("\n");
|
||||
puts("}");
|
||||
|
||||
@@ -87,7 +87,7 @@ class EmitCConstPool final : public EmitCConstInit {
|
||||
puts("extern const ");
|
||||
puts(varp->dtypep()->cType(nameProtect, false, false));
|
||||
puts(" = ");
|
||||
iterate(varp->valuep());
|
||||
iterateConst(varp->valuep());
|
||||
puts(";\n");
|
||||
// Keep track of stats
|
||||
if (VN_IS(varp->dtypep(), UnpackArrayDType)) {
|
||||
|
||||
+23
-17
@@ -138,7 +138,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
||||
case 'i':
|
||||
COMMA;
|
||||
UASSERT_OBJ(detailp, nodep, "emitOperator() references undef node");
|
||||
iterateAndNextNull(detailp);
|
||||
iterateAndNextConstNull(detailp);
|
||||
needComma = true;
|
||||
break;
|
||||
default:
|
||||
@@ -155,7 +155,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
||||
puts("(");
|
||||
} else {
|
||||
// Normal text
|
||||
if (isalnum(pos[0])) needComma = true;
|
||||
if (std::isalnum(pos[0])) needComma = true;
|
||||
COMMA;
|
||||
string s;
|
||||
s += pos[0];
|
||||
@@ -174,7 +174,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
||||
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
|
||||
isStmt = false;
|
||||
puts("VL_FSCANF_IX(");
|
||||
iterate(dispp->filep());
|
||||
iterateConst(dispp->filep());
|
||||
puts(",");
|
||||
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
|
||||
isStmt = false;
|
||||
@@ -184,13 +184,13 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
||||
puts("X(");
|
||||
puts(cvtToStr(dispp->fromp()->widthMin()));
|
||||
puts(",");
|
||||
iterate(dispp->fromp());
|
||||
iterateConst(dispp->fromp());
|
||||
puts(",");
|
||||
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
|
||||
isStmt = true;
|
||||
if (dispp->filep()) {
|
||||
puts("VL_FWRITEF(");
|
||||
iterate(dispp->filep());
|
||||
iterateConst(dispp->filep());
|
||||
puts(",");
|
||||
} else {
|
||||
puts("VL_WRITEF(");
|
||||
@@ -200,7 +200,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
||||
puts("VL_SFORMAT_X(");
|
||||
puts(cvtToStr(dispp->lhsp()->widthMin()));
|
||||
putbs(",");
|
||||
iterate(dispp->lhsp());
|
||||
iterateConst(dispp->lhsp());
|
||||
putbs(",");
|
||||
} else if (VN_IS(nodep, SFormatF)) {
|
||||
isStmt = false;
|
||||
@@ -223,7 +223,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
||||
} else if (argp) {
|
||||
const bool addrof = isScan || (fmt == '@');
|
||||
if (addrof) puts("&(");
|
||||
iterate(argp);
|
||||
iterateConst(argp);
|
||||
if (!addrof) emitDatap(argp);
|
||||
if (addrof) puts(")");
|
||||
}
|
||||
@@ -262,7 +262,7 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
|
||||
}
|
||||
if (argp->widthMin() > 8 && fmtLetter == 'c') {
|
||||
// Technically legal, but surely not what the user intended.
|
||||
argp->v3warn(WIDTH, dispp->verilogKwd() << "of %c format of > 8 bit value");
|
||||
argp->v3warn(WIDTHTRUNC, dispp->verilogKwd() << "of %c format of > 8 bit value");
|
||||
}
|
||||
}
|
||||
// string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter;
|
||||
@@ -275,9 +275,9 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
|
||||
double dchars = mantissabits / 3.321928094887362 + 1.0;
|
||||
if (fmtLetter == 'd') dchars++; // space for sign
|
||||
const int nchars = int(dchars);
|
||||
pfmt = string("%") + cvtToStr(nchars) + fmtLetter;
|
||||
pfmt = string{"%"} + cvtToStr(nchars) + fmtLetter;
|
||||
} else {
|
||||
pfmt = string("%") + vfmt + fmtLetter;
|
||||
pfmt = string{"%"} + vfmt + fmtLetter;
|
||||
}
|
||||
m_emitDispState.pushFormat(pfmt);
|
||||
if (!ignore) {
|
||||
@@ -329,7 +329,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri
|
||||
m_emitDispState.pushFormat(*pos);
|
||||
} else { // Format character
|
||||
inPct = false;
|
||||
switch (tolower(pos[0])) {
|
||||
switch (std::tolower(pos[0])) {
|
||||
case '0': // FALLTHRU
|
||||
case '1': // FALLTHRU
|
||||
case '2': // FALLTHRU
|
||||
@@ -452,16 +452,16 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
|
||||
puts(cvtToStr(nodep->widthWords()));
|
||||
puts(", ");
|
||||
}
|
||||
iterateAndNextNull(nodep);
|
||||
iterateAndNextConstNull(nodep);
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
|
||||
putbs("VL_CVT_W_A(");
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
puts(", ");
|
||||
iterate(fromp);
|
||||
iterateConst(fromp);
|
||||
putbs(".atDefault()"); // Not accessed; only to get the proper type of values
|
||||
puts(")");
|
||||
}
|
||||
@@ -541,6 +541,12 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
|
||||
if (int(nodep->num().toDouble()) == nodep->num().toDouble()
|
||||
&& nodep->num().toDouble() < 1000 && nodep->num().toDouble() > -1000) {
|
||||
ofp()->printf("%3.1f", nodep->num().toDouble()); // Force decimal point
|
||||
} else if (std::isinf(nodep->num().toDouble())) {
|
||||
if (std::signbit(nodep->num().toDouble())) puts("-");
|
||||
ofp()->puts("std::numeric_limits<double>::infinity()");
|
||||
} else if (std::isnan(nodep->num().toDouble())) {
|
||||
if (std::signbit(nodep->num().toDouble())) puts("-");
|
||||
ofp()->puts("std::numeric_limits<double>::quiet_NaN()");
|
||||
} else {
|
||||
// Not %g as will not always put in decimal point, so not obvious to compiler
|
||||
// is a real number
|
||||
@@ -666,15 +672,15 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
|
||||
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp,
|
||||
"Should have swapped msb & lsb earlier.");
|
||||
const string ivar = string("__Vi") + cvtToStr(depth);
|
||||
const string ivar = string{"__Vi"} + cvtToStr(depth);
|
||||
const string pre = ("for (int " + ivar + " = " + cvtToStr(0) + "; " + ivar + " < "
|
||||
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
|
||||
const string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(),
|
||||
depth + 1, suffix + "[" + ivar + "]");
|
||||
const string post = "}\n";
|
||||
return below.empty() ? "" : pre + below + post;
|
||||
} else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) {
|
||||
const auto* const sdtypep = VN_AS(dtypep, StructDType);
|
||||
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
|
||||
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
||||
string literal;
|
||||
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
|
||||
+142
-122
@@ -34,13 +34,13 @@ constexpr int EMITC_NUM_CONSTW = 8;
|
||||
//######################################################################
|
||||
// Emit lazy forward declarations
|
||||
|
||||
class EmitCLazyDecls final : public VNVisitor {
|
||||
class EmitCLazyDecls final : public VNVisitorConst {
|
||||
// NODE STATE/TYPES
|
||||
// None allowed to support threaded emitting
|
||||
|
||||
// MEMBERS
|
||||
std::unordered_set<string> m_emittedManually; // Set of names already declared manually.
|
||||
EmitCBaseVisitor& m_emitter; // For access to file output
|
||||
EmitCBaseVisitorConst& m_emitter; // For access to file output
|
||||
bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic)
|
||||
std::set<AstNode*> m_emitted; // -> in set. Already emitted decl for symbols.
|
||||
|
||||
@@ -72,18 +72,18 @@ class EmitCLazyDecls final : public VNVisitor {
|
||||
// VISITORS
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
lazyDeclare(nodep->funcp());
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
void visit(AstAddrOfCFunc* nodep) override {
|
||||
lazyDeclare(nodep->funcp());
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
void visit(AstVarRef* nodep) override {
|
||||
AstVar* const varp = nodep->varp();
|
||||
// Only constant pool symbols are lazy declared for now ...
|
||||
if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) {
|
||||
if (EmitCBase::isConstPoolMod(EmitCParentModule::get(varp))) {
|
||||
lazyDeclareConstPoolVar(varp);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ class EmitCLazyDecls final : public VNVisitor {
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
explicit EmitCLazyDecls(EmitCBaseVisitor& emitter)
|
||||
explicit EmitCLazyDecls(EmitCBaseVisitorConst& emitter)
|
||||
: m_emitter(emitter) {}
|
||||
void emit(AstNode* nodep) {
|
||||
m_needsBlankLine = false;
|
||||
@@ -203,12 +203,12 @@ public:
|
||||
// variables. That way we could just invoke the appropriate emitter as needed.
|
||||
VL_RESTORER(m_emitConstInit);
|
||||
m_emitConstInit = true;
|
||||
iterate(initp);
|
||||
iterateConst(initp);
|
||||
}
|
||||
void putCommaIterateNext(AstNode* nodep, bool comma = false) {
|
||||
for (AstNode* subnodep = nodep; subnodep; subnodep = subnodep->nextp()) {
|
||||
if (comma) puts(", ");
|
||||
iterate(subnodep);
|
||||
iterateConst(subnodep);
|
||||
comma = true;
|
||||
}
|
||||
}
|
||||
@@ -273,17 +273,17 @@ public:
|
||||
|
||||
if (nodep->initsp()) {
|
||||
putsDecoration("// Init\n");
|
||||
iterateAndNextNull(nodep->initsp());
|
||||
iterateAndNextConstNull(nodep->initsp());
|
||||
}
|
||||
|
||||
if (nodep->stmtsp()) {
|
||||
putsDecoration("// Body\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
}
|
||||
|
||||
if (nodep->finalsp()) {
|
||||
putsDecoration("// Final\n");
|
||||
iterateAndNextNull(nodep->finalsp());
|
||||
iterateAndNextConstNull(nodep->finalsp());
|
||||
}
|
||||
|
||||
puts("}\n");
|
||||
@@ -309,9 +309,9 @@ public:
|
||||
} else {
|
||||
puts("I(");
|
||||
}
|
||||
iterateAndNextNull(selp->lsbp());
|
||||
iterateAndNextConstNull(selp->lsbp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->fromp());
|
||||
iterateAndNextConstNull(selp->fromp());
|
||||
if (rhs) puts(", ");
|
||||
} else {
|
||||
putbs("VL_ASSIGNSEL_");
|
||||
@@ -320,18 +320,18 @@ public:
|
||||
puts("(");
|
||||
puts(cvtToStr(selp->fromp()->widthMin()) + ",");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(selp->lsbp());
|
||||
iterateAndNextConstNull(selp->lsbp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->fromp());
|
||||
iterateAndNextConstNull(selp->fromp());
|
||||
puts(", ");
|
||||
}
|
||||
} else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
|
||||
iterateAndNextNull(selp->lhsp());
|
||||
iterateAndNextConstNull(selp->lhsp());
|
||||
puts(" = ");
|
||||
putbs("VL_PUTC_N(");
|
||||
iterateAndNextNull(selp->lhsp());
|
||||
iterateAndNextConstNull(selp->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(selp->rhsp());
|
||||
iterateAndNextConstNull(selp->rhsp());
|
||||
puts(", ");
|
||||
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) {
|
||||
putbs("VL_ASSIGN_"); // Set a systemC variable
|
||||
@@ -339,7 +339,7 @@ public:
|
||||
emitIQW(nodep);
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) {
|
||||
putbs("VL_ASSIGN_"); // Get a systemC variable
|
||||
@@ -347,7 +347,7 @@ public:
|
||||
emitScIQW(varp);
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) //
|
||||
&& !VN_IS(nodep->rhsp(), CExpr) //
|
||||
@@ -361,41 +361,41 @@ public:
|
||||
} else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
putbs("VL_ASSIGN_W(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else {
|
||||
paren = false;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(" ");
|
||||
ofp()->blockInc();
|
||||
decind = true;
|
||||
if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak();
|
||||
puts("= ");
|
||||
}
|
||||
if (rhs) iterateAndNextNull(nodep->rhsp());
|
||||
if (rhs) iterateAndNextConstNull(nodep->rhsp());
|
||||
if (paren) puts(")");
|
||||
if (decind) ofp()->blockDec();
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstAlwaysPublic*) override {}
|
||||
void visit(AstAssocSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs(".at(");
|
||||
AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType);
|
||||
UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type");
|
||||
if (adtypep->keyDTypep()->isWide()) {
|
||||
emitCvtWideArray(nodep->bitp(), nodep->fromp());
|
||||
} else {
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
iterateAndNextConstNull(nodep->bitp());
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstWildcardSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs(".at(");
|
||||
AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType);
|
||||
UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type");
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
iterateAndNextConstNull(nodep->bitp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCCall* nodep) override {
|
||||
@@ -427,14 +427,14 @@ public:
|
||||
void visit(AstCMethodCall* nodep) override {
|
||||
const AstCFunc* const funcp = nodep->funcp();
|
||||
UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall");
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
putbs("->");
|
||||
puts(funcp->nameProtect());
|
||||
emitCCallArgs(nodep, "");
|
||||
}
|
||||
void visit(AstCAwait* nodep) override {
|
||||
puts("co_await ");
|
||||
iterate(nodep->exprp());
|
||||
iterateConst(nodep->exprp());
|
||||
}
|
||||
void visit(AstCNew* nodep) override {
|
||||
if (VN_IS(nodep->dtypep(), VoidDType)) {
|
||||
@@ -447,7 +447,7 @@ public:
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
iterate(nodep->fromp());
|
||||
iterateConst(nodep->fromp());
|
||||
puts(".");
|
||||
puts(nodep->name());
|
||||
puts("(");
|
||||
@@ -458,7 +458,7 @@ public:
|
||||
if (VN_IS(nodep->fromp()->dtypep(), QueueDType) && subnodep->dtypep()->isWide()) {
|
||||
emitCvtWideArray(subnodep, nodep->fromp());
|
||||
} else {
|
||||
iterate(subnodep);
|
||||
iterateConst(subnodep);
|
||||
}
|
||||
comma = true;
|
||||
}
|
||||
@@ -477,7 +477,7 @@ public:
|
||||
}
|
||||
// Probably fragile, V3Task may need to convert to a AstCReturn
|
||||
puts(") { return ");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts("; }\n");
|
||||
}
|
||||
void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE
|
||||
@@ -492,9 +492,9 @@ public:
|
||||
if (!v3Global.opt.protectIds()) return;
|
||||
}
|
||||
if (!(nodep->protect() && v3Global.opt.protectIds())) {
|
||||
putsDecoration(string("// ") + nodep->name() + at + "\n");
|
||||
putsDecoration(string{"// "} + nodep->name() + at + "\n");
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
|
||||
@@ -537,7 +537,7 @@ public:
|
||||
}
|
||||
void visit(AstCReturn* nodep) override {
|
||||
puts("return (");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstDisplay* nodep) override {
|
||||
@@ -615,7 +615,7 @@ public:
|
||||
emitCvtPackStr(nodep->searchp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->outp());
|
||||
iterateAndNextConstNull(nodep->outp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstTestPlusArgs* nodep) override {
|
||||
@@ -624,10 +624,15 @@ public:
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFError* nodep) override {
|
||||
puts("VL_FERROR_IN(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
puts("VL_FERROR_I");
|
||||
puts(nodep->strp()->isString() ? "N(" : "W(");
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->strp());
|
||||
if (nodep->strp()->isWide()) {
|
||||
puts(cvtToStr(nodep->strp()->widthWords()));
|
||||
putbs(", ");
|
||||
}
|
||||
iterateAndNextConstNull(nodep->strp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFGetS* nodep) override {
|
||||
@@ -644,8 +649,7 @@ public:
|
||||
}
|
||||
}
|
||||
void visit(AstFOpen* nodep) override {
|
||||
iterateAndNextNull(nodep->filep());
|
||||
puts(" = VL_FOPEN_NN(");
|
||||
puts("VL_FOPEN_NN(");
|
||||
emitCvtPackStr(nodep->filenamep());
|
||||
putbs(", ");
|
||||
if (nodep->modep()->width() > 4 * 8)
|
||||
@@ -654,8 +658,7 @@ public:
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstFOpenMcd* nodep) override {
|
||||
iterateAndNextNull(nodep->filep());
|
||||
puts(" = VL_FOPEN_MCD_N(");
|
||||
puts("VL_FOPEN_MCD_N(");
|
||||
emitCvtPackStr(nodep->filenamep());
|
||||
puts(");\n");
|
||||
}
|
||||
@@ -691,18 +694,18 @@ public:
|
||||
{
|
||||
const bool need_ptr = !VN_IS(nodep->memp()->dtypep(), AssocArrayDType);
|
||||
if (need_ptr) puts(" &(");
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextConstNull(nodep->memp());
|
||||
if (need_ptr) puts(")");
|
||||
}
|
||||
putbs(", ");
|
||||
if (nodep->lsbp()) {
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
iterateAndNextConstNull(nodep->lsbp());
|
||||
} else {
|
||||
puts(cvtToStr(array_lo));
|
||||
}
|
||||
putbs(", ");
|
||||
if (nodep->msbp()) {
|
||||
iterateAndNextNull(nodep->msbp());
|
||||
iterateAndNextConstNull(nodep->msbp());
|
||||
} else {
|
||||
puts("~0ULL");
|
||||
}
|
||||
@@ -710,39 +713,37 @@ public:
|
||||
}
|
||||
void visit(AstFClose* nodep) override {
|
||||
puts("VL_FCLOSE_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts("); ");
|
||||
iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it.
|
||||
puts(" = 0;\n");
|
||||
}
|
||||
void visit(AstFFlush* nodep) override {
|
||||
if (!nodep->filep()) {
|
||||
puts("Verilated::runFlushCallbacks();\n");
|
||||
} else {
|
||||
puts("if (");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(") { VL_FFLUSH_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts("); }\n");
|
||||
}
|
||||
}
|
||||
void visit(AstFSeek* nodep) override {
|
||||
puts("(VL_FSEEK_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->offset());
|
||||
iterateAndNextConstNull(nodep->offset());
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->operation());
|
||||
iterateAndNextConstNull(nodep->operation());
|
||||
puts(") == -1 ? -1 : 0)");
|
||||
}
|
||||
void visit(AstFTell* nodep) override {
|
||||
puts("VL_FTELL_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFRewind* nodep) override {
|
||||
puts("(VL_FSEEK_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
puts(", 0, 0) == -1 ? -1 : 0)");
|
||||
}
|
||||
void visit(AstFRead* nodep) override {
|
||||
@@ -770,19 +771,19 @@ public:
|
||||
puts(cvtToStr(array_size));
|
||||
putbs(", ");
|
||||
puts("&(");
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextConstNull(nodep->memp());
|
||||
puts(")");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextConstNull(nodep->filep());
|
||||
putbs(", ");
|
||||
if (nodep->startp()) {
|
||||
iterateAndNextNull(nodep->startp());
|
||||
iterateAndNextConstNull(nodep->startp());
|
||||
} else {
|
||||
puts(cvtToStr(array_lo));
|
||||
}
|
||||
putbs(", ");
|
||||
if (nodep->countp()) {
|
||||
iterateAndNextNull(nodep->countp());
|
||||
iterateAndNextConstNull(nodep->countp());
|
||||
} else {
|
||||
puts(cvtToStr(array_size));
|
||||
}
|
||||
@@ -790,7 +791,7 @@ public:
|
||||
}
|
||||
void visit(AstSysFuncAsTask* nodep) override {
|
||||
if (!nodep->lhsp()->isWide()) puts("(void)");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
if (!nodep->lhsp()->isWide()) puts(";");
|
||||
}
|
||||
void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); }
|
||||
@@ -804,7 +805,7 @@ public:
|
||||
putbs(", ");
|
||||
}
|
||||
checkMaxWords(nodep->lhsp());
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstSystemF* nodep) override {
|
||||
@@ -816,18 +817,18 @@ public:
|
||||
putbs(", ");
|
||||
}
|
||||
checkMaxWords(nodep->lhsp());
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstStmtExpr* node) override {
|
||||
iterate(node->exprp());
|
||||
iterateConst(node->exprp());
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstJumpBlock* nodep) override {
|
||||
nodep->labelNum(++m_labelNum);
|
||||
puts("{\n"); // Make it visually obvious label jumps outside these
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(nodep->endStmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->endStmtsp());
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
@@ -837,13 +838,13 @@ public:
|
||||
puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
|
||||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
puts("while (");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
puts(") {\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->incsp());
|
||||
iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstNodeIf* nodep) override {
|
||||
@@ -852,20 +853,20 @@ public:
|
||||
puts(nodep->branchPred().ascii());
|
||||
puts("(");
|
||||
}
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
if (!nodep->branchPred().unknown()) puts(")");
|
||||
puts(") {\n");
|
||||
iterateAndNextNull(nodep->thensp());
|
||||
iterateAndNextConstNull(nodep->thensp());
|
||||
puts("}");
|
||||
if (!nodep->elsesp()) {
|
||||
puts("\n");
|
||||
} else {
|
||||
if (VN_IS(nodep->elsesp(), NodeIf) && !nodep->elsesp()->nextp()) {
|
||||
puts(" else ");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
} else {
|
||||
puts(" else {\n");
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
iterateAndNextConstNull(nodep->elsesp());
|
||||
puts("}\n");
|
||||
}
|
||||
}
|
||||
@@ -874,9 +875,9 @@ public:
|
||||
// GCC allows compound statements in expressions, but this is not standard.
|
||||
// So we use an immediate-evaluation lambda and comma operator
|
||||
putbs("([&]() {\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
puts("}(), ");
|
||||
iterateAndNextNull(nodep->resultp());
|
||||
iterateAndNextConstNull(nodep->resultp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstStop* nodep) override {
|
||||
@@ -904,6 +905,9 @@ public:
|
||||
void visit(AstRand* nodep) override {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr);
|
||||
}
|
||||
void visit(AstRandRNG* nodep) override {
|
||||
emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr);
|
||||
}
|
||||
void visit(AstTime* nodep) override {
|
||||
puts("VL_TIME_UNITED_Q(");
|
||||
if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units");
|
||||
@@ -920,13 +924,13 @@ public:
|
||||
}
|
||||
void visit(AstTimeFormat* nodep) override {
|
||||
puts("VL_TIMEFORMAT_IINI(");
|
||||
iterateAndNextNull(nodep->unitsp());
|
||||
iterateAndNextConstNull(nodep->unitsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->precisionp());
|
||||
iterateAndNextConstNull(nodep->precisionp());
|
||||
puts(", ");
|
||||
emitCvtPackStr(nodep->suffixp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->widthp());
|
||||
iterateAndNextConstNull(nodep->widthp());
|
||||
puts(", vlSymsp->_vm_contextp__);\n");
|
||||
}
|
||||
void visit(AstTimePrecision* nodep) override {
|
||||
@@ -945,23 +949,23 @@ public:
|
||||
void visit(AstTextBlock* nodep) override {
|
||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterate(childp);
|
||||
iterateConst(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
}
|
||||
void visit(AstCStmt* nodep) override {
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
}
|
||||
void visit(AstCExpr* nodep) override {
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
VL_RESTORER(m_inUC);
|
||||
m_inUC = true;
|
||||
putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n"));
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
puts("\n");
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
@@ -969,7 +973,7 @@ public:
|
||||
m_inUC = true;
|
||||
puts("\n");
|
||||
putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n"));
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
@@ -991,7 +995,7 @@ public:
|
||||
putbs("(");
|
||||
puts(nodep->emitSimpleOperator());
|
||||
puts(" ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
} else {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr);
|
||||
@@ -1007,11 +1011,11 @@ public:
|
||||
}
|
||||
if (emitSimpleOk(nodep)) {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(" ");
|
||||
putbs(nodep->emitSimpleOperator());
|
||||
puts(" ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
} else {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
|
||||
@@ -1033,7 +1037,7 @@ public:
|
||||
putbs("VL_REDXOR_");
|
||||
puts(cvtToStr(widthPow2));
|
||||
puts("(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
@@ -1044,7 +1048,7 @@ public:
|
||||
} else {
|
||||
puts("(QData)(");
|
||||
}
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstNodeCond* nodep) override {
|
||||
@@ -1053,27 +1057,27 @@ public:
|
||||
emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep());
|
||||
} else {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
putbs(" ? ");
|
||||
iterateAndNextNull(nodep->thenp());
|
||||
iterateAndNextConstNull(nodep->thenp());
|
||||
putbs(" : ");
|
||||
iterateAndNextNull(nodep->elsep());
|
||||
iterateAndNextConstNull(nodep->elsep());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs("->");
|
||||
puts(nodep->varp()->nameProtect());
|
||||
}
|
||||
void visit(AstStructSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
iterateAndNextConstNull(nodep->fromp());
|
||||
putbs(".");
|
||||
puts(nodep->nameProtect());
|
||||
}
|
||||
void visit(AstNullCheck* nodep) override {
|
||||
puts("VL_NULL_CHECK(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
putsQuoted(protect(nodep->fileline()->filename()));
|
||||
puts(", ");
|
||||
@@ -1083,7 +1087,7 @@ public:
|
||||
void visit(AstNewCopy* nodep) override {
|
||||
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", ");
|
||||
puts("*"); // i.e. make into a reference
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstSel* nodep) override {
|
||||
@@ -1101,9 +1105,9 @@ public:
|
||||
puts("OI(");
|
||||
if (nodep->lhsp()) puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
} else {
|
||||
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
|
||||
@@ -1121,7 +1125,7 @@ public:
|
||||
puts("I(");
|
||||
puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
const uint32_t rd_log2 = V3Number::log2b(VN_AS(nodep->rhsp(), Const)->toUInt());
|
||||
puts(cvtToStr(rd_log2) + ")");
|
||||
@@ -1133,9 +1137,9 @@ public:
|
||||
}
|
||||
void visit(AstCastDynamic* nodep) override {
|
||||
putbs("VL_CAST_DYNAMIC(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCountBits* nodep) override {
|
||||
@@ -1149,16 +1153,16 @@ public:
|
||||
// (which is always 32)
|
||||
puts(", ");
|
||||
}
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->thsp());
|
||||
iterateAndNextConstNull(nodep->thsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->fhsp());
|
||||
iterateAndNextConstNull(nodep->fhsp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstInitItem* nodep) override { iterateChildrenConst(nodep); }
|
||||
// Terminals
|
||||
void visit(AstVarRef* nodep) override {
|
||||
const AstVar* const varp = nodep->varp();
|
||||
@@ -1216,17 +1220,17 @@ public:
|
||||
puts("()");
|
||||
if (nodep->defaultp()) {
|
||||
putbs(".setDefault(");
|
||||
iterateAndNextNull(nodep->defaultp());
|
||||
iterateAndNextConstNull(nodep->defaultp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstSetAssoc* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
putbs(".set(");
|
||||
iterateAndNextNull(nodep->keyp());
|
||||
iterateAndNextConstNull(nodep->keyp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->valuep());
|
||||
iterateAndNextConstNull(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstConsWildcard* nodep) override {
|
||||
@@ -1234,17 +1238,17 @@ public:
|
||||
puts("()");
|
||||
if (nodep->defaultp()) {
|
||||
putbs(".setDefault(");
|
||||
iterateAndNextNull(nodep->defaultp());
|
||||
iterateAndNextConstNull(nodep->defaultp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstSetWildcard* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
putbs(".set(");
|
||||
iterateAndNextNull(nodep->keyp());
|
||||
iterateAndNextConstNull(nodep->keyp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->valuep());
|
||||
iterateAndNextConstNull(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstConsDynArray* nodep) override {
|
||||
@@ -1253,27 +1257,43 @@ public:
|
||||
puts("()");
|
||||
} else {
|
||||
puts("::cons(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
if (nodep->rhsp()) {
|
||||
puts(", ");
|
||||
putbs("");
|
||||
}
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstConsPackUOrStruct* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
puts("{");
|
||||
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
iterateConst(memberp);
|
||||
if (memberp->nextp()) { puts(", "); }
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
void visit(AstConsPackMember* nodep) override {
|
||||
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
|
||||
putbs(".");
|
||||
puts(vdtypep->name());
|
||||
puts(" = ");
|
||||
iterateConst(nodep->rhsp());
|
||||
}
|
||||
void visit(AstConsQueue* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
if (!nodep->lhsp()) {
|
||||
puts("()");
|
||||
} else {
|
||||
puts("::cons(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
if (nodep->rhsp()) {
|
||||
puts(", ");
|
||||
putbs("");
|
||||
}
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
@@ -1290,8 +1310,8 @@ public:
|
||||
|
||||
// Default
|
||||
void visit(AstNode* nodep) override {
|
||||
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
|
||||
iterateChildren(nodep);
|
||||
puts(string{"\n???? // "} + nodep->prettyTypeName() + "\n");
|
||||
iterateChildrenConst(nodep);
|
||||
// LCOV_EXCL_START
|
||||
if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress
|
||||
nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
@@ -1305,7 +1325,7 @@ public:
|
||||
: EmitCFunc{} {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
iterate(nodep);
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~EmitCFunc() override = default;
|
||||
};
|
||||
|
||||
+17
-11
@@ -117,7 +117,12 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
emitCurrentList();
|
||||
}
|
||||
void emitInternalVarDecls(const AstNodeModule* modp) {
|
||||
if (!VN_IS(modp, Class)) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (classp->needRNG()) {
|
||||
putsDecoration("\n// INTERNAL VARIABLES\n");
|
||||
puts("VlRNG __Vm_rng;\n");
|
||||
}
|
||||
} else { // not class
|
||||
putsDecoration("\n// INTERNAL VARIABLES\n");
|
||||
puts(symClassName() + "* const vlSymsp;\n");
|
||||
}
|
||||
@@ -136,7 +141,7 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
puts(varp->dtypep()->cType(varp->nameProtect(), false, false));
|
||||
if (canBeConstexpr) {
|
||||
puts(" = ");
|
||||
iterate(varp->valuep());
|
||||
iterateConst(varp->valuep());
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
@@ -161,7 +166,7 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
puts("void " + protect("__Vconfigure") + "(bool first);\n");
|
||||
}
|
||||
|
||||
if (v3Global.opt.coverage()) {
|
||||
if (v3Global.opt.coverage() && !VN_IS(modp, Class)) {
|
||||
decorateFirst(first, section);
|
||||
puts("void __vlCoverInsert(");
|
||||
puts(v3Global.opt.threads() ? "std::atomic<uint32_t>" : "uint32_t");
|
||||
@@ -200,7 +205,7 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
}
|
||||
puts(itemp->nameProtect());
|
||||
puts(" = ");
|
||||
iterate(itemp->valuep());
|
||||
iterateConst(itemp->valuep());
|
||||
if (VN_IS(itemp->nextp(), EnumItem)) puts(",");
|
||||
puts("\n");
|
||||
}
|
||||
@@ -208,13 +213,13 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
}
|
||||
}
|
||||
}
|
||||
void emitStructDecl(const AstNodeModule* modp, AstStructDType* sdtypep,
|
||||
std::set<AstStructDType*>& emitted) {
|
||||
void emitStructDecl(const AstNodeModule* modp, AstNodeUOrStructDType* sdtypep,
|
||||
std::set<AstNodeUOrStructDType*>& emitted) {
|
||||
if (emitted.count(sdtypep) > 0) return;
|
||||
emitted.insert(sdtypep);
|
||||
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
AstStructDType* subp = VN_CAST(itemp->skipRefp(), StructDType);
|
||||
AstNodeUOrStructDType* subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
|
||||
if (subp && !subp->packed()) {
|
||||
// Recurse if it belongs to the current module
|
||||
if (subp->classOrPackagep() == modp) {
|
||||
@@ -223,7 +228,8 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
}
|
||||
}
|
||||
}
|
||||
puts("struct " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n");
|
||||
puts(sdtypep->verilogKwd()); // "struct"/"union"
|
||||
puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n");
|
||||
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false));
|
||||
@@ -234,12 +240,12 @@ class EmitCHeader final : public EmitCConstInit {
|
||||
void emitStructs(const AstNodeModule* modp) {
|
||||
bool first = true;
|
||||
// Track structs that've been emitted already
|
||||
std::set<AstStructDType*> emitted;
|
||||
std::set<AstNodeUOrStructDType*> emitted;
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
const AstTypedef* const tdefp = VN_CAST(nodep, Typedef);
|
||||
if (!tdefp) continue;
|
||||
AstStructDType* const sdtypep
|
||||
= VN_CAST(tdefp->dtypep()->skipRefToEnump(), StructDType);
|
||||
AstNodeUOrStructDType* const sdtypep
|
||||
= VN_CAST(tdefp->dtypep()->skipRefToEnump(), NodeUOrStructDType);
|
||||
if (!sdtypep) continue;
|
||||
if (sdtypep->packed()) continue;
|
||||
decorateFirst(first, "\n// UNPACKED STRUCT TYPES\n");
|
||||
|
||||
+27
-28
@@ -33,27 +33,27 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
//######################################################################
|
||||
// Visitor that gathers the headers required by an AstCFunc
|
||||
|
||||
class EmitCGatherDependencies final : VNVisitor {
|
||||
class EmitCGatherDependencies final : VNVisitorConst {
|
||||
// Ordered set, as it is used as a key in another map.
|
||||
std::set<string> m_dependencies; // Header names to be included in output C++ file
|
||||
|
||||
// METHODS
|
||||
void addSymsDependency() { m_dependencies.insert(EmitCBaseVisitor::symClassName()); }
|
||||
void addSymsDependency() { m_dependencies.insert(EmitCBase::symClassName()); }
|
||||
void addModDependency(const AstNodeModule* modp) {
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(classp->classOrPackagep()));
|
||||
m_dependencies.insert(EmitCBase::prefixNameProtect(classp->classOrPackagep()));
|
||||
} else {
|
||||
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(modp));
|
||||
m_dependencies.insert(EmitCBase::prefixNameProtect(modp));
|
||||
}
|
||||
}
|
||||
void addDTypeDependency(const AstNodeDType* nodep) {
|
||||
if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) {
|
||||
m_dependencies.insert(
|
||||
EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep()));
|
||||
} else if (const AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) {
|
||||
EmitCBase::prefixNameProtect(dtypep->classp()->classOrPackagep()));
|
||||
} else if (const AstNodeUOrStructDType* const dtypep
|
||||
= VN_CAST(nodep, NodeUOrStructDType)) {
|
||||
if (!dtypep->packed()) {
|
||||
m_dependencies.insert(
|
||||
EmitCBaseVisitor::prefixNameProtect(dtypep->classOrPackagep()));
|
||||
m_dependencies.insert(EmitCBase::prefixNameProtect(dtypep->classOrPackagep()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ class EmitCGatherDependencies final : VNVisitor {
|
||||
// declaration of the receiver class, but their body very likely includes at least one
|
||||
// relative reference, so we are probably not loosing much.
|
||||
addModDependency(EmitCParentModule::get(cfuncp));
|
||||
iterate(cfuncp);
|
||||
iterateConst(cfuncp);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -174,8 +174,7 @@ class EmitCImp final : EmitCFunc {
|
||||
// Unfortunately we have some lint checks here, so we can't just skip processing.
|
||||
// We should move them to a different stage.
|
||||
const string filename = VL_DEV_NULL;
|
||||
m_cfilesr.push_back(
|
||||
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
|
||||
m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true));
|
||||
m_ofp = new V3OutCFile{filename};
|
||||
} else {
|
||||
string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp);
|
||||
@@ -185,12 +184,11 @@ class EmitCImp final : EmitCFunc {
|
||||
}
|
||||
if (m_slow) filename += "__Slow";
|
||||
filename += ".cpp";
|
||||
m_cfilesr.push_back(
|
||||
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
|
||||
m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true));
|
||||
m_ofp = v3Global.opt.systemC() ? new V3OutScFile{filename} : new V3OutCFile{filename};
|
||||
}
|
||||
|
||||
ofp()->putsHeader();
|
||||
putsHeader();
|
||||
puts("// DESCRIPTION: Verilator output: Design implementation internals\n");
|
||||
puts("// See " + topClassName() + ".h for the primary calling header\n");
|
||||
|
||||
@@ -198,6 +196,7 @@ class EmitCImp final : EmitCFunc {
|
||||
puts("\n#include \"verilated.h\"\n");
|
||||
if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n");
|
||||
puts("\n");
|
||||
puts("#include \"" + symClassName() + ".h\"\n");
|
||||
for (const string& name : headers) puts("#include \"" + name + ".h\"\n");
|
||||
|
||||
emitTextSection(m_modp, VNType::atScImpHdr);
|
||||
@@ -262,7 +261,7 @@ class EmitCImp final : EmitCFunc {
|
||||
puts(", ");
|
||||
puts(varp->nameProtect());
|
||||
puts("(");
|
||||
iterate(varp->valuep());
|
||||
iterateConst(varp->valuep());
|
||||
puts(")\n");
|
||||
} else if (varp->isIO() && varp->isSc()) {
|
||||
puts(", ");
|
||||
@@ -401,7 +400,7 @@ class EmitCImp final : EmitCFunc {
|
||||
const int vecnum = vects++;
|
||||
UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp,
|
||||
"Should have swapped msb & lsb earlier.");
|
||||
const string ivar = string("__Vi") + cvtToStr(vecnum);
|
||||
const string ivar = string{"__Vi"} + cvtToStr(vecnum);
|
||||
puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0));
|
||||
puts("; " + ivar + " < " + cvtToStr(arrayp->elementsConst()));
|
||||
puts("; ++" + ivar + ") {\n");
|
||||
@@ -415,7 +414,7 @@ class EmitCImp final : EmitCFunc {
|
||||
if (elementp->isWide()
|
||||
&& !(basicp && basicp->keyword() == VBasicDTypeKwd::STRING)) {
|
||||
const int vecnum = vects++;
|
||||
const string ivar = string("__Vi") + cvtToStr(vecnum);
|
||||
const string ivar = string{"__Vi"} + cvtToStr(vecnum);
|
||||
puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0));
|
||||
puts("; " + ivar + " < " + cvtToStr(elementp->widthWords()));
|
||||
puts("; ++" + ivar + ") {\n");
|
||||
@@ -454,9 +453,9 @@ class EmitCImp final : EmitCFunc {
|
||||
emitCtorImp(modp);
|
||||
emitConfigureImp(modp);
|
||||
emitDestructorImp(modp);
|
||||
emitCoverageImp();
|
||||
}
|
||||
emitSavableImp(modp);
|
||||
emitCoverageImp();
|
||||
} else {
|
||||
// From `systemc_implementation
|
||||
emitTextSection(modp, VNType::atScImp);
|
||||
@@ -514,7 +513,7 @@ class EmitCImp final : EmitCFunc {
|
||||
// Compute the hash of the dependencies, so we can add it to the filenames to
|
||||
// disambiguate them
|
||||
V3Hash hash;
|
||||
for (const string& name : *m_requiredHeadersp) { hash += name; }
|
||||
for (const string& name : *m_requiredHeadersp) hash += name;
|
||||
m_subFileName = "DepSet_" + hash.toString();
|
||||
// Open output file
|
||||
openNextOutputFile(*m_requiredHeadersp, m_subFileName);
|
||||
@@ -522,7 +521,7 @@ class EmitCImp final : EmitCFunc {
|
||||
for (AstCFunc* const funcp : pair.second) {
|
||||
VL_RESTORER(m_modp);
|
||||
m_modp = EmitCParentModule::get(funcp);
|
||||
iterate(funcp);
|
||||
iterateConst(funcp);
|
||||
}
|
||||
// Close output file
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
@@ -597,7 +596,7 @@ class EmitCTrace final : EmitCFunc {
|
||||
if (m_slow) filename += "__Slow";
|
||||
filename += ".cpp";
|
||||
|
||||
AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/);
|
||||
AstCFile* const cfilep = createCFile(filename, m_slow, true /*source*/);
|
||||
cfilep->support(true);
|
||||
m_cfilesr.push_back(cfilep);
|
||||
|
||||
@@ -606,9 +605,9 @@ class EmitCTrace final : EmitCFunc {
|
||||
} else {
|
||||
m_ofp = new V3OutCFile{filename};
|
||||
}
|
||||
m_ofp->putsHeader();
|
||||
m_ofp->puts("// DESCR"
|
||||
"IPTION: Verilator output: Tracing implementation internals\n");
|
||||
putsHeader();
|
||||
puts("// DESCR"
|
||||
"IPTION: Verilator output: Tracing implementation internals\n");
|
||||
|
||||
// Includes
|
||||
puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n");
|
||||
@@ -774,7 +773,7 @@ class EmitCTrace final : EmitCFunc {
|
||||
}
|
||||
|
||||
void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) {
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
const string func = nodep->full() ? "full" : "chg";
|
||||
bool emitWidth = true;
|
||||
if (nodep->dtypep()->basicp()->isDouble()) {
|
||||
@@ -817,7 +816,7 @@ class EmitCTrace final : EmitCFunc {
|
||||
} else if (emitTraceIsScBv(nodep)) {
|
||||
puts("VL_SC_BV_DATAP(");
|
||||
}
|
||||
iterate(varrefp); // Put var name out
|
||||
iterateConst(varrefp); // Put var name out
|
||||
// Tracing only supports 1D arrays
|
||||
if (nodep->declp()->arrayRange().ranged()) {
|
||||
if (arrayindex == -2) {
|
||||
@@ -839,7 +838,7 @@ class EmitCTrace final : EmitCFunc {
|
||||
puts(")");
|
||||
} else {
|
||||
puts("(");
|
||||
iterate(nodep->valuep());
|
||||
iterateConst(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
@@ -901,7 +900,7 @@ class EmitCTrace final : EmitCFunc {
|
||||
openNextOutputFile();
|
||||
// Emit functions
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterate(funcp); }
|
||||
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterateConst(funcp); }
|
||||
}
|
||||
// Close output file
|
||||
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
|
||||
|
||||
@@ -28,7 +28,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
class EmitCInlines final : EmitCBaseVisitor {
|
||||
class EmitCInlines final : EmitCBaseVisitorConst {
|
||||
// STATE
|
||||
|
||||
// METHODS
|
||||
@@ -37,26 +37,26 @@ class EmitCInlines final : EmitCBaseVisitor {
|
||||
void visit(AstCNew* nodep) override {
|
||||
if (v3Global.opt.savable())
|
||||
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstDumpCtl* nodep) override {
|
||||
if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeDistBiop* nodep) override {
|
||||
v3Global.setUsesProbDist();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeDistTriop* nodep) override {
|
||||
v3Global.setUsesProbDist();
|
||||
iterateChildren(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); }
|
||||
explicit EmitCInlines(AstNetlist* nodep) { iterateConst(nodep); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -64,5 +64,5 @@ public:
|
||||
|
||||
void V3EmitC::emitcInlines() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
EmitCInlines(v3Global.rootp());
|
||||
{ EmitCInlines{v3Global.rootp()}; }
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,12 +29,12 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
class EmitCMain final : EmitCBaseVisitor {
|
||||
class EmitCMain final : EmitCBaseVisitorConst {
|
||||
// METHODS
|
||||
|
||||
// VISITORS
|
||||
// This visitor doesn't really iterate, but exist to appease base class
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // LCOV_EXCL_LINE
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user