Compare commits

...
363 Commits
Author SHA1 Message Date
Wilson Snyder f79749e7b2 Version bump 2023-08-06 10:39:35 -04:00
Krzysztof Bieganski 1a77030c9b Internals: Speedup to only typecheck node child getters in debug builds (#4394) 2023-08-05 03:24:00 -04:00
Wilson Snyder 817ade27fb Commentary: Changes update 2023-08-05 03:18:00 -04:00
Aleksander Kiryk 4afa14b612 Internals: Remove m_pkgp and m_classp from WidthVisitor (#4402) 2023-08-05 03:07:23 -04:00
Krzysztof Bieganski 9caa79a7ea Internals: Remove the name field from AstVarRef (#4395) 2023-08-03 02:52:52 -04:00
Wilson Snyder 446f21d2a0 Tests: Fix more missing internal code coverage 2023-07-27 06:53:43 -04:00
Wilson Snyder 06521f6cf1 Tests: Fix some missing coverage, and cleanup some error messages 2023-07-27 06:53:43 -04:00
github action 75336670d7 Apply 'make format' 2023-07-27 09:44:05 +00:00
Andrew Miloradovsky 106a9fe67f Fix config_build.h issues (#4380) (#4381) 2023-07-27 05:42:35 -04:00
Wilson Snyder a5eccc199b Commentary: Changes update 2023-07-27 04:01:28 -04:00
Vito Gamberini 837d9f9d77 Require CMake config minimum version 3.13 (#4389) (#4390) 2023-07-26 17:54:18 -04:00
Anthony Donlon 959387b69f Support property declaration with empty parentheses (#4313) (#4317) 2023-07-26 05:18:21 -04:00
Ryszard Rozak fd0703b8c8 Fix selects on unpacked structs (#4359) 2023-07-25 12:50:24 +02:00
Ryszard Rozak 3ff608b9cb Fix non-public methods with wide output (#4364) 2023-07-25 04:55:58 -04:00
Aleksander Kiryk edc0a0e982 Optimize V3Number::opAdd (#4385) 2023-07-24 17:09:27 -04:00
Aleksander Kiryk 1549ff9185 Support more types in wait (#4374) 2023-07-24 08:14:01 -04:00
Wilson Snyder 3454641244 Commentary: Add website badge 2023-07-21 04:11:15 -04:00
Wilson Snyder 5dedf25e3b Commentary: Add website badge 2023-07-21 04:07:29 -04:00
Wilson Snyder 7214c180ae Commentary: Add website badge 2023-07-21 04:06:22 -04:00
Ryszard Rozak aa0ef554b3 Fix order of evaluation of function calls in statements (#4375) 2023-07-21 03:29:11 -04:00
Ryszard Rozak a6015863d8 Support for static method calls as default values of function arguments (#4378) 2023-07-21 03:27:00 -04:00
Aleksander Kiryk 5a694ccb8a Fix assign to input var in methods (#4367) 2023-07-17 09:52:37 -04:00
Aleksander Kiryk f7d09c671a Fix VlProcess not found (#4368) 2023-07-17 09:52:07 -04:00
Ryszard Rozak 4de1b22672 Fix handling of super.new calls (#4366) 2023-07-17 13:30:42 +02:00
Krzysztof Boroński 4bdda3f240 Improve propagation of process requirement and decouple it from suspendability (#4321) 2023-07-14 17:12:02 +02:00
Ryszard Rozak ced1dfeffd Fix select operation on assoc array with wide keys (#4360) 2023-07-12 18:48:24 +02:00
Krzysztof Boroński 0774f825cf Internals: Use pointer to const nodes in V3MemberMap (#4353) 2023-07-12 11:36:24 -04:00
Ryszard Rozak 23fe5c1b93 Fix string concatenations (#4354) 2023-07-10 12:58:54 -04:00
Wilson Snyder bd4afeea69 Tests: Fix removing line numbers (#4352) 2023-07-10 08:17:49 -04:00
Julian Daube 3ee9b33f8a Fix cmake astgen for Rocky Linux 8.7 (#4343) 2023-07-09 06:02:21 +05:00
Wilson Snyder 5be0813893 Explicity reference std:: in header files (#4338). No functional change intended. 2023-07-08 13:20:40 -04:00
Wilson Snyder f94c1b32e5 Internals: Make V3MemberMap to remove member cache (#4350) 2023-07-08 12:40:27 -04:00
Wilson Snyder ff4923cf67 Internals: Make V3MemberMap towards removing member cache (#4350) 2023-07-08 12:27:50 -04:00
Krzysztof Bieganski 5788bc8048 Propagate class timescale to class package (#4348)
Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-07-07 17:27:33 +02:00
Wilson SnyderandAhmed El-Mahmoudy 5749662194 Documentation: Drop analytics_id unless VERILATOR_ANALYTICS_ID set (#4333)
Co-authored-by: Ahmed El-Mahmoudy <[email protected]>
2023-07-07 10:44:33 -04:00
Krzysztof Bieganski d5d1cc47e0 Fix multiple edge timing controls in class methods (#4318) (#4320) (#4344)
Multiple edge timing controls in class methods would cause compilation errors on
the generated C++ code. This is because the `SenExprBuilder` used for these
would get recreated per timing control, resulting in duplicate variable names.
The fix is to have a single `SenExprBuilder` per scope.
2023-07-07 08:19:49 -04:00
Ryszard Rozak da043ca16d Fix comparison of class objects (#4346) 2023-07-07 16:20:23 +05:00
Aleksander Kiryk 9aa90569bf Support string replication with variable (#4341) 2023-07-07 13:05:06 +05:00
Wilson Snyder 294d78e0e2 Backout unstable dbb35ab8 (#4318) (#4320) 2023-07-05 14:26:28 -04:00
Wilson Snyder 8182c3fe2c Tests: Fix t_vpi_unimpl exiting early with missed error 2023-07-05 14:12:22 -04:00
Wilson Snyder 6f7bc38088 Tests: Improve specparam verilog.y coverage 2023-07-05 14:11:55 -04:00
Wilson Snyder dcbc0ccfdc Commentary: Revert lost name. 2023-07-05 13:55:47 -04:00
Aleksander Kiryk 399319dc1c Fix wildcard referring types (#4336) (#4342) 2023-07-05 13:08:00 -04:00
Krzysztof Bieganski 35d6da391b Fix multiple edge timing controls in class methods (#4318) (#4320)
Multiple edge timing controls in class methods would cause compilation errors on the generated C++ code. This is because the `SenExprBuilder` used for these would get recreated per timing control, resulting in duplicate variable names. The fix is to have a single `SenExprBuilder` per scope.
2023-07-05 10:36:10 +00:00
Aleksander Kiryk fcbd7c87af Fix unexpected RefDType on assoc arrays (#4337) 2023-07-04 18:13:22 +05:00
Ryszard Rozak 97feba6898 Support locator methods with "with" on assoc arrays (#4335) 2023-07-04 18:11:15 +05:00
Aleksander Kiryk 9249ffdb84 Fix queue slicing (#4329) 2023-07-03 13:55:24 -04:00
أحمد المحمودي 71df9e3381 Commentary: Fix typo of concurrent (#4332) 2023-07-02 16:12:09 -04:00
Wilson Snyder 3c964147be Add MISINDENT lint warning for misleading indentation. 2023-07-01 10:45:25 -04:00
Wilson Snyder 54b4b6b378 Internals: Fix missing calls to cleanFileline. 2023-07-01 08:59:26 -04:00
Wilson Snyder cff37f0775 Add GENUNNAMED lint warning.
Also fix generate-for blocks with empty statements getting lost.
2023-07-01 08:31:53 -04:00
Wilson Snyder 8b1cc3b303 Commentary: Changes update 2023-07-01 07:35:58 -04:00
Mariusz Glebocki 65b6121186 Revert .gdbinit modified by accident. (#4330)
`test_regress/.gdbinit` has been modified in
d42f9c095b most likely by accident.
Restore its previous content.
2023-06-30 16:57:31 -04:00
Ryszard Rozak 3d30527860 Fix unique..with method on queues of class objects (#4328) 2023-06-30 17:04:09 +02:00
Ryszard Rozak 24a9f7c650 Fix references to members of results of static methods (#4327) 2023-06-30 13:23:34 +02:00
Ryszard Rozak 242f661644 Fix selects of static members (#4326) 2023-06-30 09:12:22 +02:00
Aleksander Kiryk 32019d2bc4 Fix state update for always processes (#4311) 2023-06-29 09:21:49 -04:00
Krzysztof Boroński b252bb048f Fix unhandled overloads in V3InstrCount (#4324) 2023-06-28 08:49:56 -04:00
Ryszard Rozak ba47c01a01 Fix implicit calls of base class constructors with optional arguments (#4319) 2023-06-27 16:08:38 +02:00
Ryszard Rozak 51266898ec Fix comparison of string parameters (#4308) 2023-06-27 10:40:45 +02:00
Wilson Snyder f9164ab0d2 Internals: Assert dtype comparison. No functional change intended. 2023-06-25 07:40:00 -04:00
Wilson Snyder c43e707f43 Internals: refactor sameTreeIter. No functional change. 2023-06-25 07:26:45 -04:00
Mariusz Glebocki 85b7f828b3 Internals: Use std::packaged_task as a job wrapper; add and use V3ThreadPool::ScopedExclusiveAccess (#4310).
* Add VL_ASSERT_CAPABILITY; add assumeLocked and pretendUnlock to V3Mutex.

* Pass jobs as template-arguments and use std::packaged_task.

* Add and use V3ThreadPool::ScopedExclusiveAccess.
2023-06-23 18:25:12 -04:00
Wilson Snyder 7005a65d32 Tests: Attempt 20.04 fix for (#b1aec9b) (#4307) 2023-06-23 07:09:07 -04:00
Wilson Snyder 776d4e6ac2 CI: Build 20.04 on pull requests 2023-06-23 07:08:04 -04:00
Jiamin Zhu 1c88c3083c Fix splitting coroutines (#4297) (#4307) 2023-06-23 06:01:38 -04:00
Ryszard Rozak 4522834f7a Fix duplicate fork names (#4295) 2023-06-22 06:51:53 -04:00
Ryszard Rozak 9ee5fd0585 Fix handling of ref types in initial values of type parameters (#4304) 2023-06-20 14:10:07 -04:00
Wilson Snyder 63b2dbb827 Fix error when multiple duplicate DPI exports (#4301). 2023-06-20 06:26:46 -04:00
Wilson Snyder 5bee8ef15b Remove long deprecated verilated_heavy.h 2023-06-17 08:45:13 -04:00
Wilson Snyder e7de3d368f Commentary: Deprecation planned for 32-bit pointer -m32 mode (#4268). 2023-06-17 08:44:13 -04:00
Wilson Snyder d45deccc0a Internals: Favot std::array. No functional change intended. 2023-06-16 19:44:40 -04:00
Wilson Snyder d5b03ab721 Tests (#3806) (#3807) 2023-06-16 18:30:25 -04:00
Ryszard Rozak d1ff81a41c Fix class reference assignment checking (#4296) 2023-06-15 14:00:47 +02:00
Krzysztof Bieganski 43fa6858f6 Fix VlForkSync redeclaration (#4277)
Given nested forks, if the inner fork had a `join` or `join_any` at the end,
`V3Sched::transformForks()` would decide that the fork's `VlForkSync` variable
should be passed in from the outside. This resulted in the `VlForkSync` getting
redeclared as a function argument. Ultimately, it led to C++ compilation errors
due to variable redeclaration.

Fixed by rearranging the `if`s that decide whether a variable should be passed
in or left as-is.
2023-06-15 07:49:50 -04:00
Wilson Snyder db7eb45433 Contributors: Add Krzysztof Boronski and re-sort 2023-06-14 18:53:44 -04:00
Krzysztof Boronski 21c01ba97b V3Fork - transform processes that can outlive their parents into separate tasks (#4253)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-06-14 20:44:53 +02:00
Ryszard Rozak b517fb5ee3 Support some stream operations on queues (#4292) 2023-06-13 22:46:42 -04:00
Wilson Snyder 9dbc669199 devel release 2023-06-13 19:39:50 -04:00
Wilson Snyder 7d2d32420a Version bump 2023-06-13 19:31:57 -04:00
Wilson Snyder 48e98ea2bd Internals: Sort some error codes (#4253). No functional change intended. 2023-06-13 08:52:13 -04:00
Wilson Snyder 01d0f0327b Commentary (#4254) 2023-06-13 08:22:57 -04:00
Wilson Snyder 0dc887720d Tests: Fix tests, broke in commit 3a9eeabd 2023-06-12 22:38:45 -04:00
Wilson Snyder e08bbcdb07 Commentary 2023-06-12 21:59:52 -04:00
Wilson Snyder 70d26ec123 Commentary (#4211) (#4254) 2023-06-12 21:59:33 -04:00
Wilson Snyder a06f260f42 Fix C++11 compiler error with C++14 rbegin 2023-06-12 21:46:32 -04:00
Wilson Snyder d42f76c346 Tests: Fix tests, broke in commit 3a9eeabd 2023-06-12 21:36:23 -04:00
Wilson Snyder 66c3d6d2d1 Commentary 2023-06-12 20:52:29 -04:00
Wilson Snyder 81affad2dc Tests: Fix test, broke in previous commit 2023-06-12 20:41:33 -04:00
Wilson Snyder 2488af9066 Commentary: Changes update 2023-06-12 20:38:33 -04:00
Wilson Snyder 5cf9d78516 Commentary 2023-06-12 20:28:32 -04:00
Wilson Snyder 3a9eeabdb2 Tests: Auto detect and exit --timing with no coroutines 2023-06-12 20:09:12 -04:00
Julien Margetts ac4315e145 Fix LATCH warning on function local variables (#4221) (#4284) 2023-06-12 09:24:46 -04:00
John Wehle 5094e94df1 Fix tracing undefined alignment (#4201) (#4288) 2023-06-12 07:13:00 -04:00
Àlex Torregrosa 4b7b185d05 Fix VCD scope types (#4227) (#4282) 2023-06-08 11:43:04 -04:00
Aleksander Kiryk 6cb0335d28 Support array max (#4275) 2023-06-07 07:44:21 -04:00
Aleksander Kiryk c248318958 Fix struct redefinition (#4276) 2023-06-06 18:28:35 -04:00
Ryszard Rozak c3e5db5f04 Fix names of foreach blocks (#4264) 2023-06-06 16:24:42 +02:00
Krzysztof Bieganski 058233fc87 Set the global usesTiming flag if forks exist (#4274) 2023-06-06 09:35:12 -04:00
Mariusz Glebocki 186c851695 Internals: Avoid pessimistic mutex locking in waitIfStopRequested() (#4272). No functional change intended.
`stopRequested()` reads only atomic variables. It doesn't need a mutex
to do this.

This function is called in `waitIfStopRequested()`, which in turn
is called before execution of every job, and inside some jobs. With this
change the mutex inside `waitIfStopRequested` needs to be locked only in
very rare cases instead of every time.
2023-06-05 19:40:36 -04:00
Mariusz Glebocki 5aa36357f6 Internals: Use auto instead of SFINAE in return type (#4271). No functional change intended. 2023-06-05 18:53:19 -04:00
Wilson Snyder 191d30cf1c Update gtkwave from upstream (#4141) 2023-06-03 12:10:07 -04:00
Andrei Kostovski d8c2ecaaf8 Commentary: Update install.rst for help2man (#4260) (#4261) 2023-06-03 10:31:17 -04:00
github action a7b0551d23 Apply 'make format' 2023-06-03 14:11:23 +00:00
John Wehle dc34968fe7 Add class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250) 2023-06-03 10:07:39 -04:00
Jiamin Zhu 45f064f7cb Fix missing assignment for wide class members. (#4267) 2023-06-03 06:40:23 -07:00
Krzysztof Boroński 545caba720 Give iterated variables in foreach loops VAUTOM lifetimes (#4265)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-06-02 17:16:42 +02:00
Krzysztof Boroński 0e24f36fef Use STATIC lifetime for variables created from clocking items (#4262)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-06-01 17:49:27 +02:00
Aleksander Kiryk db7935faf3 Add std::process class (#4212) 2023-06-01 10:02:08 -04:00
Adrien Le Masle 9cc218db3e Fix incorrect multi-driven lint warning (#4231) (#4248) 2023-06-01 08:43:17 -04:00
Ryszard Rozak 15f8ebc562 Fix static methods with prototypes (#4220) 2023-05-31 21:18:32 -04:00
github action 205cae963b Apply 'make format' 2023-05-31 16:03:33 +00:00
Don Williamson df2746de71 Add --main-top-name option for C main TOP name (#4235) (#4249) 2023-05-31 09:02:26 -07:00
Risto Pejašinović 7f471d862e Fix operator == for unpacked struct, if elements are VlUnpacked arrays (#4247) 2023-05-31 08:34:34 -04:00
Risto Pejašinović 338acabe2b Fix AstStructSel clean when data type is structure (#4241) (#4244) 2023-05-30 23:44:48 -04:00
Ryszard Rozak 4f1f487ae4 Fix function calls in with statements (#4245) 2023-05-30 09:02:59 -04:00
Krzysztof Bieganski 77502aeb97 Add warning that timing controls in DPI exports are unsupported (#4238)
Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-05-30 09:00:10 -04:00
Ryszard Rozak ba82d43ca1 Support for condition operator on class objects (#4214) 2023-05-30 08:59:00 -04:00
Wilson Snyder e9135598b3 Fix method calls on function return values. 2023-05-29 18:51:27 -04:00
Risto Pejašinović 1c0739db10 Fix unpacked struct == and != operators (#4234) (#4240) 2023-05-29 12:08:39 -04:00
Ryszard Rozak dfd3907787 Mark AstMemberSel as clean (#4236) 2023-05-29 09:35:53 +02:00
Wilson Snyder 1069652701 Fix some AstExprStmt handling issues, towards side effect fixes. 2023-05-27 12:43:40 -04:00
Wilson Snyder 70b82f1aec Internals: V3Dead cleanups. No functional change. 2023-05-27 11:46:25 -04:00
Wilson Snyder 5573bdb219 Internals: Cleanup V3SplitAs VL_RESTORED. No functional change intended. 2023-05-27 10:43:04 -04:00
Wilson Snyder cf68578261 Internals: Cleanup V3SplitAs VL_RESTORED. No functional change intended. 2023-05-27 10:17:51 -04:00
Wilson Snyder f407d442d4 Commentary 2023-05-27 09:43:23 -04:00
Wilson Snyder 7f12ad9d91 Commentary: Changes update 2023-05-27 07:17:37 -04:00
Wilson Snyder 5efe9367d2 Fix SystemC signal copy macro use (#4135). 2023-05-27 07:00:26 -04:00
Wilson Snyder cfce92645f Tests: Check equality of complex types. 2023-05-26 18:01:11 -04:00
Krzysztof Bieganski 519792d02b Fix to commit coroutines immediately on wait statements (#4229)
Event-triggered coroutines live in two stages: 'uncommitted' and 'ready'. First
they land in 'uncommitted', meaning they can't be resumed yet. Only after
coroutines from the 'ready' queue are resumed, the 'uncommitted' ones are moved
to the 'ready' queue, and can be resumed. This is to avoid self-triggering in
situations like waiting for an event immediately after triggering it.

However, there is an issue with `wait` statements. If you have a `wait(b)`, it's
being translated into a loop that awaits a change in `b` as long as `b` is
false. If `b` is false at first, the coroutine is put into the `uncommitted`
queue. If `b` is set to true before it's committed, the coroutine won't get
resumed.

This patch fixes that by immediately committing event controls created from
`wait` statements. That means the coroutine from the example above will get
resumed from now on.
2023-05-25 20:20:44 -04:00
Jiamin Zhu bfa1f2d7ce Fix missing assignment for wide unpacked structs (#4233) 2023-05-25 20:13:02 -04:00
Aleksander Kiryk 42beaf467c Tests: Add incomplete type definition test (#4230) 2023-05-25 14:06:37 -04:00
Mariusz Glebocki 8303938d0e Internals: Make mutex classes uncopyable. (#4223) 2023-05-25 07:35:14 -04:00
Mariusz Glebocki 0ece155418 Internals: Move some includes to .cpp files. (#4224) 2023-05-24 18:53:14 -04:00
Ryszard Rozak 4f7e155e59 Fix class parameters of enum types (#4219) 2023-05-24 15:51:03 +02:00
Wilson Snyder ff324625e4 CI: Disable m32 on g++ 2023-05-23 23:04:24 -04:00
Wilson Snyder fd7515b046 Tests: Cleanup scenarios lines. No test run change. 2023-05-23 22:40:19 -04:00
Wilson Snyder 607f853bc7 CI: Disable m32 on g++ 2023-05-23 22:35:07 -04:00
Wilson Snyder 09fb1174f1 CI: Disable m32 on g++ 2023-05-23 22:34:27 -04:00
Wilson Snyder 542eaab3dd CI: Disable m32 on g++ 2023-05-23 22:28:40 -04:00
Wilson Snyder a301a498f5 CI: Disable m32 on g++ 2023-05-23 22:27:10 -04:00
Wilson Snyder d66e749ec8 CI: Fix mold build 2023-05-23 22:25:03 -04:00
Wilson Snyder c8ca54ea31 CI: Disable m32 on g++ 2023-05-23 22:24:47 -04:00
Wilson Snyder 5704552053 Fix ci for mold 2023-05-23 21:30:39 -04:00
Wilson Snyder 426069a4dd Configure for faster C++ linking using 'mold', if it is installed. 2023-05-23 21:26:29 -04:00
Wilson Snyder 19d0aabe7a Internals: Fix extra cast on ExprStmt. 2023-05-23 20:52:30 -04:00
Krzysztof Boroński fb0d735f68 Tests: Skip t_suspendable_deep if coroutines are not supported by CXX toolchain (#4217) 2023-05-23 14:02:40 -04:00
Krzysztof Boroński 167a30be1c Fix deep traversal of class inheritance timing (#4216) 2023-05-23 09:01:57 -04:00
Wilson Snyder 5982528274 Fix duplicate std:: declaration with -I (#4215). 2023-05-22 20:32:20 -04:00
Krzysztof Boroński de3095e3b4 Fix missing class forward declarations (#4151) 2023-05-22 08:29:01 -04:00
Wilson Snyder 8e0682f442 Fix V3Expand ignoring side effects 2023-05-21 21:02:39 -04:00
Wilson Snyder 140994d2c4 Internals: Cleanup more VL_RESTORER. No functional change intended. 2023-05-21 14:06:39 -04:00
Wilson Snyder 950e29d56e Internals: Cleanup some missing VL_RESTORER in V3Gate. No functional change intended. 2023-05-21 12:49:07 -04:00
Wilson Snyder 65667356b6 wip 2023-05-21 12:24:00 -04:00
Wilson Snyder 6b393e9d7c Internals: Allow statement-in-statement recursion in V3Premit 2023-05-21 12:03:13 -04:00
Wilson Snyder 4818130e4f Internals: Remove dead code, addBeforeStmt 2023-05-20 22:37:28 -04:00
Ryszard Rozak 9da3aacd08 Fix bit selections under parameterized classes (#4210) 2023-05-18 20:01:36 -04:00
Krzysztof Bieganski 729f8b9334 Move suspendable detection to a separate visitor (#4208)
This makes the implementation of the detection and propagation of the
suspendable property simpler and easier to read. More importantly, there are no
more jumps around the AST with the `visit` functions, which in some cases could
result in incorrect visitor context while in the `visit` function. See the added
test, which would cause Verilator to segfault before this patch.

In testing, verilation performance was not shown to be affected by this change.
Though there is a slight performance improvement from this patch, due to adding
one more check before refreshing class member cache.

Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-05-17 17:09:33 +00:00
Ryszard Rozak 279216048b Fix dotted references in parameterized classes (#4206) 2023-05-16 07:40:02 -04:00
Ryszard Rozak 2ce7a348df Fix references to members of parameterized base classes (#4196) 2023-05-15 19:50:04 -04:00
Wilson Snyder 46f719ceaa Tests: Fix some coverage holes 2023-05-13 20:15:03 -04:00
Mariusz Glebocki 949be301de Internals: Fix unbalanced V3LockGuard locking (#4193) 2023-05-13 10:32:33 -04:00
Mariusz Glebocki be429a5800 Internals: Lock the same mutex reference as specified in VL_ACQUIRE. (#4194) 2023-05-13 10:28:34 -04:00
Mariusz Glebocki e7714e0902 Internals: Add additional clang's thread safety analysis annotations (#4195)
* Simplify some Clang-specific attribute defines.

* Add `VL_RETURN_CAPABILITY` and `VL_PT_GUARDED_BY`.
2023-05-12 09:06:36 -04:00
Krzysztof Bieganski 4835ed6967 Fix forced assignments that override non-continuous assignments (#4183) (#4192)
Only assign forced value on release if it was forced in the first place.
2023-05-12 06:57:12 -04:00
Ryszard Rozak 0198a3fc52 Use unchanged copy of parameterized class for instantation (#4179) 2023-05-11 09:56:15 +02:00
Krzysztof Boroński e095bf1af0 Support inside expressions with strings and doubles (#4138) (#4139) 2023-05-10 20:36:41 -04:00
Aylon Chaim Porat d5de67c6dc Fix wide structure VL_TOSTRING_W generation (#4188) (#4189)
* V3Common.cpp::makeVlToString: fix `VL_TOSTRING_W` statement generation to include width argument

* fix contribution name

* add testcase for long struct `VL_TO_STRING_W` bug
2023-05-10 20:34:44 -04:00
Ryszard Rozak 2267db093f Fix hashes of instances of parameterized classes (#4182) 2023-05-10 18:34:29 -04:00
Ryszard Rozak 5aecfa98a1 Internals: Add param value string to hash in V3Param.cpp (#4186) 2023-05-10 17:52:17 -04:00
Wilson Snyder 485e230dd8 Commentary (#4187) 2023-05-10 17:51:22 -04:00
Wilson Snyder befb415f27 Fix mod/div/round argument side effects 2023-05-07 22:31:31 -04:00
Wilson Snyder c0490627bf Tests: Update historical 2023-05-07 22:00:52 -04:00
Wilson Snyder d269fbb446 Add creating __inputs.vpp file with --debug (#4177). 2023-05-07 17:58:14 -04:00
Wilson Snyder 444020f7c7 Fix super.new missing data type (#4147). 2023-05-07 16:47:34 -04:00
Wilson Snyder 6188083baa Tests: Improve randc tests 2023-05-07 15:08:44 -04:00
Wilson Snyder c2a524d80b Commentary (#4175) 2023-05-07 08:36:03 -04:00
Wilson Snyder e6f5a0495f Fix $fscanf of decimals overflowing variables (#4174). 2023-05-07 08:25:10 -04:00
Wilson Snyder 0606a29f13 Fix arrays of unpacked structs (#4173). 2023-05-06 21:41:17 -04:00
Wilson Snyder c6052830e1 Fix C++17 requirement on previous commit. 2023-05-06 20:23:35 -04:00
Wilson Snyder 4bb876aee5 Fix false IMPLICITSTATIC on package functions. 2023-05-06 19:48:22 -04:00
Wilson Snyder a3640c1767 Support get_randstate/set_randstate class method function. 2023-05-06 19:09:19 -04:00
Wilson Snyder 250c6950cf Fix randomize missing simple class rand members. 2023-05-06 18:33:08 -04:00
Wilson Snyder 76f5de6e54 Replace flake8 with ruff for Python linting 2023-05-06 06:08:32 -04:00
Wilson Snyder 1a1c5c5d44 Internals: Fix pylint warning 2023-05-06 06:05:11 -04:00
Wilson Snyder 4ae80f9a9f Commentary 2023-05-05 22:50:28 -04:00
github action 8a3cb8daa8 Apply 'make format' 2023-05-06 02:37:42 +00:00
Ethan Sifferman 64ab537b68 Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). 2023-05-05 22:36:51 -04:00
Wilson Snyder fdea386727 Fix false WIDTHEXPAND on array declarations (#3959). 2023-05-05 22:05:19 -04:00
Wilson Snyder 28944ed862 Fix crash on duplicate imported modules (#3231). 2023-05-05 20:31:48 -04:00
Wilson Snyder 3250ee5707 Commentary: Changes update 2023-05-05 20:24:45 -04:00
Wilson Snyder d308a561e4 Fix detection of wire/reg duplicates 2023-05-05 20:16:27 -04:00
Wilson Snyder 584f8cc9e7 Internal: With --xml-only support --debug-exit-uvm 2023-05-05 13:47:34 -04:00
Kamil Rakoczy 61e1483b74 Add multi-threaded Verilating at emit stage (#3608) 2023-05-05 08:36:20 -04:00
Wilson Snyder 3bb4e34044 Commentary 2023-05-04 19:04:38 -04:00
Kamil Rakoczy 832b17d4d2 clang_check_attributes: fix mt-safe checks for global objects in constructor context (#4171) 2023-05-04 14:00:30 -04:00
Krzysztof Bieganski 76c5875912 Fix marking overridden methods as coroutines (#4120) (#4169)
This patch fixes two cases where methods in base classes were not being marked
as coroutines, even though they were being overridden by coroutines.
- One case is the class member cache not getting refreshed for searched classes.
- The other is when the overriding methods are not declared as `virtual`. In
  that case, the `isVirtual()` getter on such a method returns false, which led
  to `V3Timing` skipping the step of searching for overridden methods.

Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-05-04 15:27:45 +02:00
Ryszard Rozak 266dc7679a Don't link AstRefDType if it has parameterized class ref (#4164) (#4170) 2023-05-04 15:09:01 +02:00
Jose Loyola d693dc85e4 Add Github action to build and push docker images (#4163) 2023-05-04 07:44:55 -04:00
Wilson Snyder add68130b8 Internals: Rename to dumpLevel(), to avoid confusion with make-a-dump() 2023-05-03 18:04:10 -04:00
Tudor Timi d9b5680a45 Fix crash caused by $display() optimization (#4165) (#4166) 2023-05-03 17:04:18 -04:00
Wilson Snyder dc25be536c Internals: Deprecate VL_ATTR_ALIGNED, use alignas instead. 2023-05-02 21:21:10 -04:00
Stefan Wallentowitz 7708c88e32 Fix duplicate static names in blocks in functions (#4144) (#4160)
Static variables of functions are created in the function. When blocks
in a function use identical names for static variables, we need to name
those variables properly.
2023-05-02 20:24:44 -04:00
february cozzocrea 707f230353 Commentary: Update install.rst help2man dependency (#4161) 2023-05-02 14:32:24 -04:00
Kamil Rakoczy 49d2eb9a08 Fix initialization order of initial static after function/task (#4159) 2023-05-02 11:50:57 -04:00
github action 128186ea68 Apply 'make format' 2023-05-02 11:29:45 +00:00
Hennadii ChernyshchykandOleh Maks 949be9d0a1 Optimize VPI callValueCbs (#4155)
Co-authored-by: Oleh Maks <[email protected]>
2023-05-02 07:28:56 -04:00
Wilson Snyder 3e986517c3 devel release 2023-04-30 07:10:14 -04:00
Wilson Snyder 5d3a9eec7f Version bump 2023-04-30 07:08:27 -04:00
Wilson Snyder 3d21a79148 Fix pylint warning 2023-04-29 22:22:38 -04:00
Wilson Snyder e15f5266a3 Commentary: Changes update 2023-04-29 22:16:53 -04:00
Toru Niina 9130eb8b99 Fix DPI function type alias (#4148) (#4149) 2023-04-28 07:21:09 -04:00
Ryszard Rozak 09e856d2f3 Fix deleting unused parameterized classes (#4150) 2023-04-28 07:20:25 -04:00
Ryszard Rozak ee5c0a2902 Support parameterized class references in extends statement (#4146) 2023-04-24 17:25:53 -04:00
Ryszard Rozak 621b7e63cf Print the type of provided RHS in class type check (#4145) 2023-04-24 17:24:04 -04:00
github action c6bf9fb89e Apply 'make format' 2023-04-24 11:29:33 +00:00
Risto PejašinovićandRisto Pejasinovic f794180865 Fix hier attribute of --xml-only cell section to respect begin blocks (#4129) (#4133)
Co-authored-by: Risto Pejasinovic <[email protected]>
2023-04-24 07:28:29 -04:00
Geza Lore 0e769d42a1 Optimize trigger evaluation
Pack the elements of VlTriggerVec as dense bits (instead of a 1 byte
bool per bit), and check whether they are set on a word granularity.
This effectively transforms conditions of the form `if (trig.at(0) |
trig.at(2) | trig.at(64))` into `if (trig.word(0) & 0x5 | trig.word(1) &
0x1)`. This improves OpenTitan ST by about 1%, worth more on some other
designs.
2023-04-24 09:09:36 +02:00
Wilson Snyder cbeb9d39ff Fix -CFLAGS to allow overriding optimization levels (#4140). 2023-04-23 10:18:48 -04:00
Wilson Snyder 5a98c1a3b1 Commentary 2023-04-23 10:10:05 -04:00
Geza Lore cac634d39b Fix DfgToAst conversion of CountBits (#4101) (#4143) 2023-04-23 08:49:44 -04:00
Peter Monsson 08330bad0b Fix variables in class methods to be automatic (#4111) (#4137) 2023-04-21 08:07:22 -04:00
Ryszard Rozak 84a46939b3 Fix class extend param references (#4136)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-04-20 07:11:35 -04:00
Kamil Rakoczy 65a484e00b Internal: Update clang_check_annotations conditions (#4134) 2023-04-20 07:02:31 -04:00
Krzysztof Boroński 843fdd3e57 Resolve class lvalues after parameterization (#4131) 2023-04-19 18:05:37 -04:00
Ryszard Rozak a10b51705f Fix class param extends A=B (#4128)
Visit global class params even if a class extends a param
2023-04-17 09:08:57 -03:00
Eyck Jentzsch df86e39845 Fix systemc namespace issues (#4126) (#4127)
* replaces use of "systemc.h" with <systemc> to avoid default namespace import
2023-04-17 06:57:29 -03:00
Wilson Snyder 7f49b6c102 Parse 'let' as unsupported 2023-04-16 17:23:16 -04:00
Krzysztof Boroński 754a0b8320 Fix to use parallel build for projects with a lot of files (#4116) 2023-04-14 18:52:05 -04:00
Krzysztof Boroński 7d3b3761b2 Fix including __Syms header in generated C++ files (#4123) 2023-04-14 11:53:27 -04:00
Ryszard Rozak d1b80ffa29 Support parameterized return types of methods (#4122) 2023-04-14 08:52:43 -04:00
Ryszard Rozak f95ce886f1 Fix duplicating parameter class types (#4115) 2023-04-14 06:51:33 -04:00
Wilson Snyder fa16eff003 Commentary (#4118) 2023-04-14 06:46:53 -04:00
Geza Lore 23f90b13f3 Do not create unnecessary DPI AstSenTrees
No functional change
2023-04-13 14:01:45 +01:00
Geza Lore 37e7b5dfc7 Fix unused/hard-coded argument
No functional change.
2023-04-13 14:01:37 +01:00
Kamil Rakoczy e1683afb31 Internals: V3ThreadPool: add function waiting for list of futures (#4112) 2023-04-12 08:49:48 -04:00
Kamil Rakoczy e38b359d75 Internals: Refactor for better clang thread-safety analysis (#4092) 2023-04-11 07:25:10 -04:00
Kamil Rakoczy b6dcec2710 Internals: Split Mutex class used in verilated code and verilator (#4048) 2023-04-11 07:23:24 -04:00
Wilson Snyder 0307d59c1f Fix unpacked structs under classes (#4102). 2023-04-10 19:40:34 -04:00
Wilson Snyder 3aa013c8db Tests: Remove old file 2023-04-10 19:40:34 -04:00
github action fc70876aa9 Apply 'make format' 2023-04-10 23:38:20 +00:00
Srinivasan Venkataramanan 722ab9306a Support class method calls without parenthesis (#3902) (#4082) 2023-04-10 19:37:24 -04:00
Wilson Snyder 2ab34b5eeb Fix false error on new const assignment (#4098). 2023-04-09 19:46:47 -04:00
Wilson Snyder e3bdae77a0 Tests: Add randsequence test 2023-04-09 17:08:04 -04:00
Wilson Snyder 663d6a1c8d Commentary 2023-04-09 10:23:35 -04:00
Wilson Snyder bf5cbb512e Add UNSUPPORTED on dotted disable instead of syntax error 2023-04-09 10:11:47 -04:00
Wilson Snyder d4bb58630e Support 'for' initialization with comma 2023-04-09 09:56:39 -04:00
Wilson Snyder fff0eb5d88 Internals: Use standard 'result' name for return variable. No functional change. 2023-04-08 22:11:28 -04:00
Wilson Snyder 7ae0c5d546 Internals: cppcheck fixes. No functional change intended 2023-04-08 21:36:32 -04:00
Wilson Snyder 114d93b212 Internals: Move -debug-exit-uvm to post V3LinkDot, just before V3Param (#1538) 2023-04-08 15:11:26 -04:00
Wilson Snyder 13a87e5514 Parse process class, and report runtime errors (#3612) 2023-04-08 15:04:42 -04:00
Wilson Snyder d67d75282c Support ++/-- on dotted member variables. 2023-04-07 20:57:17 -04:00
Kamil Rakoczy 827cbf22c9 Fix sense expression variable naming (#4081) 2023-04-07 07:23:37 -04:00
Wilson Snyder 2530cda507 Fix debug crash when no std:: used 2023-04-06 21:43:39 -04:00
Wilson Snyder 38000a3da0 Fix unnecessary verilated_std.sv waivers in --waiver-output. 2023-04-06 21:43:23 -04:00
Wilson Snyder 6c21b21ecc Internals: Indent verilated_std.sv with Verilog-mode. No functional change. 2023-04-06 21:27:16 -04:00
Wilson Snyder 8caf9be3e6 Internals: Favor {} constructor syntax. No functional change intended. 2023-04-06 21:04:26 -04:00
Krzysztof Bieganski cdb61842d6 Internals: Remove VlNow (#4089)
`VlNow{}` is completely unnecessary, as coroutines are always on the
heap (unless optimized out). Also fix access of var ref passed to forked processes.
2023-04-06 10:31:52 -04:00
Wilson Snyder 05660d1118 Add CONSTRAINTIGN warning when constraint ignored. Likewise ignore constraint_mode, rand_mode. 2023-04-05 21:27:37 -04:00
Ryszard Rozak a3f9221a67 Fix importing symbols from base class (#4084) 2023-04-04 20:56:18 -04:00
Wilson Snyder 7e1980af7a Tests: Avoid t_dist failures on deleted files. 2023-04-02 15:10:45 -04:00
Wilson Snyder 921fd919b5 Tests: Improve short circuit test 2023-04-01 23:10:05 -04:00
Robert BalasandRobert Balas fc5a5ea53d Commentary: Fix spelling mistakes (#4080)
Co-authored-by: Robert Balas <[email protected]>
2023-04-01 20:45:28 -04:00
Wilson Snyder 86156dd05b Revert false-positive static error (#4072) (#4077) 2023-04-01 18:54:37 -04:00
Wilson Snyder 3219ffddd4 Tests: Ignore commented out messages 2023-04-01 18:17:45 -04:00
Wilson Snyder 3a01c32bf9 Revert false-positive static error (#4072) (#4077) 2023-04-01 15:45:34 -04:00
Wilson Snyder 9ffd0a4e70 Support queue[$-1] selects. 2023-04-01 15:23:39 -04:00
Wilson Snyder 90e049c674 Internals: Remove unneeded variable. No functional change. 2023-04-01 11:46:43 -04:00
Wilson Snyder 69121633cf Support class srandom and class random stability. 2023-04-01 10:50:27 -04:00
Wilson Snyder 28eadded87 Update include/gtkwave from upstream 2023-04-01 10:38:47 -04:00
Wilson Snyder 93c598dd19 Commentary 2023-04-01 10:38:33 -04:00
Krzysztof Bieganski d012563ab1 Fix tracing with awaits at end of block (#4075) (#4076)
Given an await at the end of a block, e.g. at the end of a loop body, a trace
activity setter was not inserted, as there were no following statements. This
patch makes the activity update unconditional.
2023-03-31 13:51:31 -04:00
Krzysztof Bieganski 0b96789e65 Add error on static access to non-static class member (#4072)
Before this patch, it was possible to access non-static class members using
static access, which resulted in C++ compilation errors. This adds
verilation-time checks for such situations.
2023-03-27 10:46:51 -04:00
Wilson Snyder 947402bc57 Fix interface generate begin (#4065). 2023-03-26 08:49:38 -04:00
Yutetsu TAKATSUKASA d4107dce52 Improve xor tree optimization (#4071)
* AstNot does not have to be frozen in an xor tree during BitOp tree optimization.

* Tests: Update stats.
2023-03-26 20:36:32 +09:00
Yutetsu TAKATSUKASA 990b19e048 Fix incorrect optimization of bit op tree (#4059) (#4070) 2023-03-26 03:29:10 -04:00
Srinivasan Venkataramanan 2290e6ccf2 Fix info message prints under --assert (#4036) (#4053) 2023-03-24 19:22:48 -04:00
Wilson Snyder 14c8f072f1 Commentary 2023-03-24 19:06:07 -04:00
Krzysztof Bieganski c55df02b1a Fix C++ compile errors when passing class refs as task arg (#4063)
1. Fixes passing a null reference as a task argument. Before this patch it would
   cause a C++ compile error like `cannot convert ‘VlNull’ to ‘VlClassRef<...>’`.

2. Fixes passing a class reference as a task argument when the argument is a
   reference to a base class. Before the patch it would cause a C++ compile
   error like `cannot convert ‘VlClassRef<{DERIVED_CLASS}>’ to ‘VlClassRef<{BASE_CLASS}>`.
2023-03-24 13:18:59 -04:00
Ryszard Rozak 5b86248b54 Add error if class types don't match (#4064) 2023-03-24 13:18:20 -04:00
Josep Sans 449ac44131 Fix _Vilp used before declaration (#4057) (#4062) 2023-03-24 11:51:02 +01:00
Ryszard Rozak f439a7927f Fix parameters in a class body to be localparam (#4061) 2023-03-23 10:20:35 +01:00
Aleksander Kiryk 277bd67f72 Fix NBAs inside fork-joins (#4050) 2023-03-21 10:39:29 -04:00
Krzysztof Bieganski 5de8ccbf32 Fix task calls as fork statements (#4055)
Before this patch, calling tasks directly under forks would result in each
statement of these tasks being executed concurrently. This was due to Verilator
inlining tasks most of the time. Such inlined tasks' statements would simply
replace the original call, and there would be no indication that these used to
be grouped together. Ultimately resulting in `V3Timing` treating each statement
as a separate process.

The solution is simply to wrap each fork sub-statement in a begin in `V3Begin`
(except for the ones that are begins, as that would be pointless). `V3Begin` is
already aware of forks, and is supposed to avoid issues like this one, so it
seems like a natural fit. This also protects us from similar bugs, i.e. if some
statement gets replaced or expanded into multiple statements.

Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-03-21 13:50:53 +01:00
Wilson Snyder 577e0700ba Commentary: Changes update 2023-03-21 04:52:12 -04:00
github action 71a37484f5 Apply 'make format' 2023-03-21 08:43:31 +00:00
Jesse Taube daf157e6c0 Fix false LATCH warning on --assert 'unique else if' (#4033) (#4054). 2023-03-21 04:42:19 -04:00
Iztok Jeras 2aa6a229ca Change range order warning from LITENDIAN to ASCRANGE (#4010) 2023-03-20 20:44:11 -04:00
Wilson Snyder 9b869edd90 Internals: Fix cppcheck warnings. No functional change. 2023-03-18 19:28:48 -04:00
Wilson Snyder 2b21697b86 Support class extends of package::class. 2023-03-18 17:26:36 -04:00
Wilson Snyder 895ab8789b Internals: Fix recently added assertion false firing 2023-03-18 17:11:39 -04:00
Wilson Snyder 5f02f95ce6 Commentary (#3906) (#3931) 2023-03-18 15:49:11 -04:00
Wilson Snyder f2aac8c49a Internals: Use VNVisitorConst where possible, for better performance. No functional change indended. 2023-03-18 12:23:17 -04:00
Wilson Snyder 82e653a739 Internals: Avoid emit inheritance in V3EmitCBase. No functional change intended. 2023-03-18 12:23:17 -04:00
Tim Snyder 053f760e2a Fix characters from DEFENV literals for conda (#4035) (#4044)
The baked in DEFENV paths might end up with extra NULL characters
at the end if the binaries are installed by something that patches them
for relocatable installs (e.g. conda).  Avoid this issue by immediately
passing them through std::string::c_str() method to stop at the first NULL
2023-03-18 11:25:27 -04:00
Wilson Snyder ba9e141fae Commentary: Update CONTRIBUTING and internals xrefs (#4043) 2023-03-18 10:23:19 -04:00
Wilson Snyder d60a3e2b66 Fix random internal crashes (#666).
Internally, in V3Broken check m_interpp for null, and make several cleanups
in the addNext/addNextHere/unlinkFr* methods.
2023-03-18 09:48:26 -04:00
Yu-Sheng Lin 70c2d1eded Fix install, standardization in cmake CMakeLists.txt (#3974) 2023-03-18 07:38:09 -04:00
Wilson Snyder 80cbf81b3b Internals: Fix missing relink() and add assert 2023-03-17 22:29:48 -04:00
Kamil Rakoczy 798d7346cf Internals: Add VL_MT_SAFE attribute to functions that requires locking. (#3805) 2023-03-17 20:24:15 -04:00
Wilson Snyder d6c5d40f9b Internals: Add VNVisitorConst class. 2023-03-17 19:59:09 -04:00
Ryszard Rozak 371b8310d9 Support method calls without parenthesis (#4034)
* Support method class without parenthesis

Signed-off-by: Ryszard Rozak <[email protected]>

* Delete replaced nodes

Signed-off-by: Ryszard Rozak <[email protected]>

---------

Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-17 13:25:39 +01:00
Ryszard Rozak 1ac721af8f Add STATICVAR warning and convert to automatic (#4027) (#4030)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-17 07:48:41 -04:00
Wilson Snyder 85fd88ace2 Optimize duplicate JumpBlocks away (#4028) 2023-03-16 22:29:06 -04:00
Wilson Snyder ed1e377bb1 Fix large return blocks with --comp-limit-blocks (#4028). 2023-03-16 21:40:01 -04:00
Wilson Snyder 4240c29f4b Internals: Fix missing broken check 2023-03-16 21:14:49 -04:00
Wilson Snyder 51ba4a1531 Fix clocking block scope internal error (#4032). 2023-03-16 20:48:18 -04:00
Wilson Snyder d1b55cb7aa Fix compile error last commit (#4029) 2023-03-16 20:22:08 -04:00
Kamil Rakoczy bbf53bd5af Add VL_MT_SAFE attribute to several functions. (#3729) 2023-03-16 19:48:56 -04:00
Wilson Snyder b2ced6ff1d Add more debug info to --report-unoptflat graph (#4039) 2023-03-16 19:47:13 -04:00
Wilson Snyder a9b07fe7d7 Tests: Remove unintended t_0 test 2023-03-16 18:44:28 -04:00
Kamil Rakoczy 66e4656a8e Fix event controls reusing same variable (#4014) 2023-03-16 07:12:54 -04:00
Wilson Snyder 8f4d4f07a4 Commentary 2023-03-16 07:09:16 -04:00
Wilson Snyder 8e55580cde Update include/gtkwave from upstream 2023-03-15 22:11:06 -04:00
Wilson Snyder 8ae79066a2 Fix false ENUMVALUE on expressions and arrays. 2023-03-15 21:56:35 -04:00
Wilson Snyder 36da6a3563 Fix parsing #1_2 delays 2023-03-15 21:22:28 -04:00
Wilson Snyder 45690faea7 Parse defparam = as unsupported 2023-03-15 21:04:10 -04:00
Wilson Snyder 046fecbb35 Fix fclose(0). 2023-03-15 20:49:59 -04:00
Ryszard Rozak 0f6024ef3c Fix rand fields in base classes (#4025) 2023-03-15 11:48:18 -04:00
Wilson Snyder 2488b5a97f Fix pullup/pulldown to create implicit wires. 2023-03-14 21:14:27 -04:00
Wilson Snyder 56de6f1a9f Fix min/typ/max internal error 2023-03-14 20:40:58 -04:00
Wilson Snyder 0fc5d37901 Fix bounded queues with parameter bounds 2023-03-14 20:29:47 -04:00
Wilson Snyder ea4cc4e076 Parse nettype with package, still unsupported 2023-03-14 19:52:01 -04:00
Wilson Snyder 9e25c21fed Fix unpacked struct clocking 2023-03-14 19:35:40 -04:00
Ryszard Rozak fc3fdcc71c Tests: Fix randomize_method test (#4024) 2023-03-14 13:47:43 -04:00
Ryszard Rozak 80b7b8bbdb Don't call randomize on null field (#4023)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-14 14:48:06 +01:00
Wilson Snyder a8ce272e4a Commentary: spelling 2023-03-14 08:39:54 -04:00
Wilson Snyder 72963c4e20 Commentary (#4020) 2023-03-14 08:29:39 -04:00
Ryszard Rozak 4e5bd361e0 Internal: Fix dumping of AstMethodCall (#4021) 2023-03-14 06:54:45 -04:00
Ryszard Rozak ed1a9309d4 Throw warning if static variable is declared in a loop (#4018)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-14 10:03:08 +01:00
Ryszard Rozak 1d0a06438c Assign unique names for blocks in do..while loop (#4019) 2023-03-14 09:54:43 +01:00
Wilson Snyder 2c62714a30 Fix push to dynamic queue in struct (#4015). 2023-03-13 22:03:53 -04:00
Wilson Snyder f13e753b52 Change ZERODLY to a warning. 2023-03-12 21:28:14 -04:00
Wilson Snyder 39a5bce8a6 Parse covergroup, still unsupported. 2023-03-12 14:11:11 -04:00
Wilson Snyder ba953bfa94 Commentary: Changes update 2023-03-12 10:49:19 -04:00
Wilson Snyder 1debd0405b Support complicated IEEE 'for' assignments. 2023-03-12 10:46:40 -04:00
Wilson Snyder 1f1d9312d2 Parse event 'iff', still unsupported. 2023-03-11 22:39:59 -05:00
Wilson Snyder 259201b352 Support $fopen as an expression 2023-03-11 18:11:01 -05:00
Wilson Snyder bb45bd048e Commentary 2023-03-11 11:27:40 -05:00
Wilson Snyder 5489ec6eff Parse 'first_match', and still unsupported. 2023-03-11 11:08:37 -05:00
Wilson Snyder e55e81bcd0 Parse sequence 'local input', still unsupported. 2023-03-11 10:53:10 -05:00
Wilson Snyder 5c5c758718 Parse 'wait_order' and test, still unsupported. 2023-03-11 10:47:08 -05:00
Wilson Snyder b87669039e Commentary 2023-03-10 22:25:47 -05:00
Wilson Snyder 60a6ed2a20 Support assert property statement-else-statement 2023-03-10 22:13:17 -05:00
Wilson Snyder 81e8388c3f Parse 'expect', still unsupported. 2023-03-10 21:48:56 -05:00
Wilson Snyder 4532680e5f Internals: Cleanup assert/assume. No functional change. 2023-03-10 21:17:54 -05:00
Andrew Nolte fc17ab280a Add --public-depth to force public to a certain instance depth (#3952) 2023-03-09 21:48:05 -05:00
Wilson Snyder 621cd0f008 Internals: Framework for renaming warnings (#4010 partial) 2023-03-08 21:32:37 -05:00
Andrew Nolte 13c9877099 Add --public-params flag (#3990) 2023-03-08 19:38:26 -05:00
Wilson Snyder ff889fde18 Add debug comment when trace disabled (#4004). 2023-03-06 18:22:46 -05:00
Krzysztof Boroński f68c16a5e6 Fix symbol entries when inheriting classes (#3995) (#3996) 2023-03-06 07:43:58 -05:00
Ryszard Rozak cc45f64280 Add __PVT__ prefix to selects nodes (#4001) 2023-03-06 13:18:48 +01:00
Wilson Snyder 725ec088ea Parse 'sequence' declarations, property case/if, still unsupported. 2023-03-06 05:12:09 -05:00
Wilson Snyder 87c3de5aab Parse 'matches', still unsupported. 2023-03-05 23:58:54 -05:00
Wilson Snyder 6d7c04a3de Parse cycle delays and boolean abbrev, still unsupported. 2023-03-05 23:22:41 -05:00
Wilson Snyder d0f5ce0cc4 Parse intersect/throughout/within, still unsupported. 2023-03-05 19:57:09 -05:00
Wilson Snyder cb89ef9885 Parse more property expression syntax, as still unsupported 2023-03-05 19:42:21 -05:00
Wilson Snyder 90360d40fd Change property expression handling towards eventual more general expressions. 2023-03-05 18:52:55 -05:00
Wilson Snyder 15dcd326f8 Internals: Parse weak/strong but do not lex 2023-03-05 18:30:43 -05:00
Wilson Snyder ae1eb56695 Internals: Parser commentary 2023-03-05 17:59:17 -05:00
Wilson Snyder a47fd07585 Internals: Standard grammar for property_expression |-> |=>. 2023-03-05 16:59:24 -05:00
Wilson Snyder 19bc257002 Internals: UNSUPPORTED commentary 2023-03-05 16:45:07 -05:00
Wilson Snyder a1d4cd658e devel release 2023-03-04 11:31:58 -05:00
801 changed files with 21966 additions and 7290 deletions
+11 -7
View File
@@ -36,12 +36,14 @@ jobs:
m32: [0, 1]
exclude:
# Build pull requests only with ubuntu-22.04 and without m32
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
# - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04 clang++
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
- compiler: { cc: gcc, cxx: g++ }
m32: 1
include:
# Build GCC 10 on ubuntu-20.04
- os: ubuntu-20.04
@@ -105,12 +107,14 @@ jobs:
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1]
exclude:
# Build pull requests only with ubuntu-22.04 and without m32
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
# - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
- compiler: { cc: gcc, cxx: g++ }
m32: 1
include:
# Test with GCC 10 on ubuntu-20.04 without m32
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0}
+84
View File
@@ -0,0 +1,84 @@
# Build and push verilator docker image when tags are pushed to the repository.
# The following secrets must be configured in the github repository:
# DOCKER_HUB_NAMESPACE: docker hub namespace.
# DOCKER_HUB_USER: user name for logging into docker hub
# DOCKER_HUB_ACCESS_TOKEN: docker hub access token.
name: Build Verilator Container
on:
push:
tags: [ 'v*' ]
workflow_dispatch:
inputs:
manual_tag:
description: 'Git tag to use for image build'
required: true
type: string
add_latest_tag:
description: 'Tag workflow_dispatch docker image as "latest"'
required: true
type: boolean
default: false
jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
contexts:
- "ci/docker/run:verilator"
# - "ci/docker/buildenv:verilator-buildenv"
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Extract context variables
run: |
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
- name: Use manual tag
if: ${{ inputs.manual_tag }}
run: |
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v4
with:
images: |
${{ secrets.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
tags: |
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
buildkitd-flags: --debug
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and Push to Docker
uses: docker/build-push-action@v4
if: startsWith(github.ref, 'refs/tags/v')
with:
context: ${{ env.build_context }}
build-args: SOURCE_COMMIT=${{ env.git_tag }}
platforms: linux/arm64,linux/amd64
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
+5 -11
View File
@@ -15,7 +15,7 @@
cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
project(Verilator
VERSION 5.008
VERSION 5.014
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
+185 -7
View File
@@ -8,6 +8,185 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 5.014 2023-08-06
==========================
**Minor:**
* Deprecation planned for 32-bit pointer -m32 mode (#4268).
* Deprecate CMake config below version 3.13 (#4389) (#4390). [Vito Gamberini]
* Support some stream operations on queues (#4292). [Ryszard Rozak, Antmicro Ltd]
* Support property declaration with empty parentheses (#4313) (#4317). [Anthony Donlon]
* Support locator methods with "with" on assoc arrays (#4335). [Ryszard Rozak, Antmicro Ltd]
* Support string replication with variable (#4341). [Aleksander Kiryk, Antmicro Ltd]
* Support more types in wait (#4374). [Aleksander Kiryk, Antmicro Ltd]
* Support static method calls as default values of function arguments (#4378). [Ryszard Rozak, Antmicro Ltd]
* Add GENUNNAMED lint warning. [Srinivasan Venkataramanan, Deepa Palaniappan]
* Add MISINDENT lint warning for misleading indentation.
* Fix 'VlForkSync' redeclaration (#4277). [Krzysztof Bieganski, Antmicro Ltd]
* Fix processes that can outlive their parents (#4253). [Krzysztof Boronski, Antmicro Ltd]
* Fix duplicate fork names (#4295). [Ryszard Rozak, Antmicro Ltd]
* Fix splitting coroutines (#4297) (#4307). [Jiamin Zhu]
* Fix error when multiple duplicate DPI exports (#4301).
* Fix class reference assignment checking (#4296). [Ryszard Rozak, Antmicro Ltd]
* Fix handling of ref types in initial values of type parameters (#4304). [Ryszard Rozak, Antmicro Ltd]
* Fix comparison of string parameters (#4308). [Ryszard Rozak, Antmicro Ltd]
* Fix state update for always processes (#4311). [Aleksander Kiryk, Antmicro Ltd]
* Fix multiple edge timing controls in class methods (#4318) (#4320) (#4344). [Krzysztof Bieganski, Antmicro Ltd]
* Fix implicit calls of base class constructors with optional arguments (#4319). [Ryszard Rozak, Antmicro Ltd]
* Fix propagation of process requirement (#4321). [Krzysztof Boroński]
* Fix unhandled overloads in V3InstrCount (#4324). [Krzysztof Boroński]
* Fix selects of static members (#4326). [Ryszard Rozak, Antmicro Ltd]
* Fix references to members of results of static methods (#4327). [Ryszard Rozak, Antmicro Ltd]
* Fix unique..with method on queues of class objects (#4328). [Ryszard Rozak, Antmicro Ltd]
* Fix queue slicing (#4329). [Aleksander Kiryk, Antmicro Ltd]
* Fix wildcard referring types (#4336) (#4342). [Aleksander Kiryk, Antmicro Ltd]
* Fix comparison of class objects (#4346). [Ryszard Rozak, Antmicro Ltd]
* Fix unexpected RefDType on assoc arrays (#4337). [Aleksander Kiryk, Antmicro Ltd]
* Fix cmake astgen for Rocky Linux 8.7 (#4343). [Julian Daube]
* Fix class timescale in class packages (#4348). [Krzysztof Bieganski, Antmicro Ltd]
* Fix string concatenations (#4354). [Ryszard Rozak, Antmicro Ltd]
* Fix unlinked task error from broken context (#4355) (#4402). [Aleksander Kiryk, Antmicro Ltd]
* Fix selects on unpacked structs (#4359). [Ryszard Rozak, Antmicro Ltd]
* Fix select operation on assoc array with wide keys (#4360). [Ryszard Rozak, Antmicro Ltd]
* Fix non-public methods with wide output (#4364). [Ryszard Rozak, Antmicro Ltd]
* Fix handling of super.new calls (#4366). [Ryszard Rozak, Antmicro Ltd]
* Fix assign to input var in methods (#4367). [Aleksander Kiryk, Antmicro Ltd]
* Fix VlProcess not found (#4368). [Aleksander Kiryk, Antmicro Ltd]
* Fix order of evaluation of function calls in statements (#4375). [Ryszard Rozak, Antmicro Ltd]
* Fix config_build.h issues (#4380) (#4381). [Andrew Miloradovsky]
Verilator 5.012 2023-06-13
==========================
**Major:**
* With -j or --build-jobs, multithread Verilator's emit phase of Verilation. [Kamil Rakoczy, Antmicro Ltd]
Additional Verilator-internal stages will become multithreaded over time.
**Minor:**
* Add --main-top-name option for C main TOP name (#4235) (#4249). [Don Williamson]
* Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi]
* Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). [Ethan Sifferman]
* Add warning that timing controls in DPI exports are unsupported (#4238). [Krzysztof Bieganski, Antmicro Ltd]
* Support std::process class (#4212). [Aleksander Kiryk, Antmicro Ltd]
* Support inside expressions with strings and doubles (#4138) (#4139). [Krzysztof Boroński]
* Support get_randstate/set_randstate class method functions.
* Support for condition operator on class objects (#4214). [Ryszard Rozak, Antmicro Ltd]
* Support array max (#4275). [Aleksander Kiryk, Antmicro Ltd]
* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk]
* Configure for faster C++ linking using 'mold', if it is installed.
* Fix crash on duplicate imported modules (#3231). [Robert Balas]
* Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO]
* Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd]
* Fix SystemC signal copy macro use (#4135). [Josep Sans]
* Fix duplicate static names in blocks in functions (#4144) (#4160). [Stefan Wallentowitz]
* Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd]
* Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd]
* Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi]
* Fix arrays of unpacked structs (#4173). [Risto Pejašinović]
* Fix $fscanf of decimals overflowing variables (#4174). [Ahmed El-Mahmoudy]
* Fix super.new missing data type (#4147). [Tudor Timi]
* Fix missing class forward declarations (#4151). [Krzysztof Boroński]
* Fix hashes of instances of parameterized classes (#4182). [Ryszard Rozak, Antmicro Ltd]
* Fix forced assignments that override non-continuous assignments (#4183) (#4192). [Krzysztof Bieganski, Antmicro Ltd]
* Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat]
* Fix references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd]
* Fix tracing undefined alignment (#4201) (#4288) [John Wehle]
* Fix class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle]
* Fix dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd]
* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd]
* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl]
* Fix deep traversal of class inheritance timing (#4216). [Krzysztof Boroński]
* Fix class parameters of enum types (#4219). [Ryszard Rozak, Antmicro Ltd]
* Fix static methods with prototypes (#4220). [Ryszard Rozak, Antmicro Ltd]
* Fix LATCH warning on function local variables (#4221) (#4284) [Julien Margetts]
* Fix VCD scope types (#4227) (#4282). [Àlex Torregrosa]
* Fix incorrect multi-driven lint warning (#4231) (#4248). [Adrien Le Masle]
* Fix missing assignment for wide unpacked structs (#4233). [Jiamin Zhu]
* Fix unpacked struct == and != operators (#4234) (#4240). [Risto Pejašinović]
* Fix AstStructSel clean when data type is structure (#4241) (#4244). [Risto Pejašinović]
* Fix function calls in with statements (#4245). [Ryszard Rozak, Antmicro Ltd]
* Fix operator == for unpacked struct, if elements are VlUnpacked arrays (#4247). [Risto Pejašinović]
* Fix STATIC lifetime for variables created from clocking items (#4262). [Krzysztof Boroński]
* Fix names of foreach blocks (#4264). [Ryszard Rozak, Antmicro Ltd]
* Fix iterated variables in foreach loops to have VAUTOM lifetimes (#4265). [Krzysztof Boroński]
* Fix missing assignment for wide class members (#4267). [Jiamin Zhu]
* Fix the global uses timing flag when forks exist (#4274). [Krzysztof Bieganski, Antmicro Ltd]
* Fix struct redefinition (#4276). [Aleksander Kiryk, Antmicro Ltd]
* Fix detection of wire/reg duplicates.
* Fix false IMPLICITSTATIC on package functions.
* Fix method calls on function return values.
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
==========================
@@ -31,7 +210,6 @@ Verilator 5.008 2023-03-04
* 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 vpiDefName (#3906) (#3931). [Andrew Nolte]
* Support recursive methods (#3987). [Ryszard Rozak, Antmicro Ltd]
* Fix real parameters of infinity and NaN.
* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal]
@@ -41,8 +219,8 @@ Verilator 5.008 2023-03-04
* 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 paramaterized class function linkage (#3917). [Ryszard Rozak]
* Fix static members of type aliases of a parametrized class (#3922). [Ryszard Rozak, Antmicro Ltd]
* 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]
@@ -54,13 +232,13 @@ Verilator 5.008 2023-03-04
* 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 dicts declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd]
* 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 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.
@@ -80,7 +258,7 @@ Verilator 5.006 2023-01-22
* Support import/export lists in modport (#3886). [Gökçe Aydos]
* Support class queue equality (#3895). [Ilya Barkov]
* Support type case and type equality comparisons.
* Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
* 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]
@@ -94,7 +272,7 @@ Verilator 5.006 2023-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]
+6 -8
View File
@@ -424,17 +424,15 @@ YAPF_FLAGS = -i
yapf:
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
FLAKE8 = flake8
FLAKE8_FLAGS = \
--extend-exclude=fastcov.py \
--ignore=E123,E129,E251,E402,E501,W503,W504,E701
PYLINT = pylint
PYLINT_FLAGS = --score=n --disable=R0801
RUFF = ruff
RUFF_FLAGS = check --ignore=E402,E501,E701
lint-py:
-$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS)
-$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
-$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
format-pl-exec:
-chmod a+x test_regress/t/*.pl
@@ -451,8 +449,8 @@ install-msg:
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
# autoheader might not change config_build.h.in, so touch it
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
# autoheader might not change config_package.h.in, so touch it
${srcdir}/config_package.h: ${srcdir}/config_package.h.in configure
cd ${srcdir} && autoheader
touch $@
Makefile: Makefile.in config.status $(IN_WILD)
+11 -8
View File
@@ -1,12 +1,16 @@
.. Github doesn't render images unless absolute URL
.. Do not know of a conditional tag, "only: github" nor "github display" works
.. image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
:target: https://verilator.org
.. image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
:target: https://www.gnu.org/licenses/lgpl-3.0]
:target: https://www.gnu.org/licenses/lgpl-3.0
.. image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
:target: https://opensource.org/licenses/Artistic-2.0
.. image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
:target: https://repology.org/project/verilator/versions
.. image:: https://img.shields.io/docker/pulls/verilator/verilator
:target: https://hub.docker.com/r/verilator/verilator
.. image:: https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f
:target: https://www.codacy.com/gh/verilator/verilator
.. image:: https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg
@@ -57,17 +61,16 @@ files, the "Verilated" code.
These Verilated C++/SystemC files are then compiled by a C++ compiler
(gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper
file to instantiate the Verilated model. Executing the resulting executable
performs the design simulation. Verilator also supports linking Verilated
generated libraries, optionally encrypted, into other simulators.
file, to instantiate the Verilated model. Executing the resulting
executable performs the design simulation. Verilator also supports linking
Verilated generated libraries, optionally encrypted, into other simulators.
Verilator may not be the best choice if you are expecting a full-featured
replacement for a closed-source Verilog simulator, needs SDF annotation,
mixed-signal simulation, or are doing a quick class project (we recommend
`Icarus Verilog`_ for classwork.) However, if you are looking for a path
to migrate SystemVerilog to C++/SystemC, or want high-speed simulation of
synthesizable designs containing limited verification constructs, Verilator
is the tool for you.
designs, Verilator is the tool for you.
Performance
@@ -83,11 +86,11 @@ as `Icarus Verilog`_. Another 2-10x speedup might be gained from
multithreading (yielding 200-1000x total over interpreted simulators).
Verilator has typically similar or better performance versus the
closed-source Verilog simulators (Carbon Design Systems Carbonator,
closed-source Verilog simulators (e.g., Carbon Design Systems Carbonator,
Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
computes rather than licenses. Thus, Verilator gives you the best
cycles/dollar.
simulation cycles/dollar.
Installation & Documentation
+2
View File
@@ -372,6 +372,7 @@ detailed descriptions of these arguments.
--make <build-tool> Generate scripts for specified build tool
-MAKEFLAGS <flags> Arguments to pass to make during --build
--main Generate C++ main() file
--main-top-name Specify top name passed to Verilated model in generated C++ main
--max-num-width <value> Maximum number width (default: 64K)
--Mdir <directory> Name of output object directory
--MMD Create .d dependency files
@@ -404,6 +405,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
+7 -3
View File
@@ -61,7 +61,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
sudo apt-get update
sudo apt-get install ccache help2man libfl-dev ||
sudo apt-get install ccache help2man libfl-dev
if [ "$CI_RUNS_ON" != "ubuntu-22.04" ]; then
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ]; then
# Some conflict of libunwind verison on 22.04, can live without it for now
sudo apt-get install libgoogle-perftools-dev ||
sudo apt-get install libgoogle-perftools-dev
@@ -70,6 +70,10 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
sudo apt-get install libsystemc libsystemc-dev ||
sudo apt-get install libsystemc libsystemc-dev
fi
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
sudo apt-get install mold ||
sudo apt-get install mold
fi
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Parallel::Forker
fi
@@ -102,8 +106,8 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
sudo apt-get install gdb gtkwave lcov libfl-dev ccache
# Required for test_regress/t/t_dist_attributes.pl
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
sudo apt-get install libclang-dev ||
sudo apt-get install libclang-dev
sudo apt-get install libclang-dev mold ||
sudo apt-get install libclang-dev mold
pip3 install clang==14.0
fi
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
+7 -1
View File
@@ -19,10 +19,16 @@ RUN apt-get update \
ccache \
flex \
git \
help2man \
libfl2 \
libfl-dev \
libgoogle-perftools-dev \
numactl \
perl \
perl-doc \
python3 \
zlib1g \
zlib1g-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@@ -39,7 +45,7 @@ RUN git clone "${REPO}" verilator && \
git checkout "${SOURCE_COMMIT}" && \
autoconf && \
./configure && \
make -j "$(nproc)" && \
make && \
make install && \
cd .. && \
rm -r verilator
+9 -4
View File
@@ -5,16 +5,16 @@
# 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 CmakeLists.txt,
# 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.008 2023-03-04],
AC_INIT([Verilator],[5.014 2023-08-06],
[https://verilator.org],
[verilator],[https://verilator.org])
AC_CONFIG_HEADERS(src/config_build.h)
AC_CONFIG_HEADERS(src/config_package.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
# Version
@@ -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 ;;
@@ -470,6 +470,10 @@ m4_foreach([ldflag], [
AC_SUBST(CFG_LDLIBS_THREADS)
AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE)
# If 'mold' is installed, use it to link for faster buildtimes
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -fuse-ld=mold)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_VERILATED, -fuse-ld=mold)
# When linking partially statically
if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc)
@@ -480,6 +484,7 @@ else
LTCMALLOC=-ltcmalloc_minimal
fi
AC_SUBST(CFG_LDFLAGS_SRC)
AC_SUBST(CFG_LDFLAGS_VERILATED)
# The pthread library is required by tcmalloc, so add it if it exists. If it
# does not, the tcmalloc check below will fail anyway, and linking against
+21 -14
View File
@@ -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?
+28 -3
View File
@@ -12,8 +12,12 @@ Alex Chadwick
Aliaksei Chapyzhenka
Ameya Vikram Singh
Andreas Kuster
Andrei Kostovski
Andrew Miloradovsky
Andrew Nolte
Anthony Donlon
Arkadiusz Kozdra
Aylon Chaim Porat
Cameron Kirk
Chris Randall
Chuxuan Wang
@@ -24,14 +28,19 @@ David Horton
David Metz
David Stanford
David Turner
Don Williamson
Drew Ranck
Drew Taussig
Driss Hafdi
Edgar E. Iglesias
Eric Rippey
Ethan Sifferman
Eyck Jentzsch
Fan Shupei
february cozzocrea
Felix Neumärker
Felix Yan
G-A. Kamendje
Garrett Smith
Geza Lore
Gianfranco Costamagna
@@ -40,16 +49,16 @@ Gökçe Aydos
Graham Rushton
Guokai Chen
Gustav Svensk
G-A. Kamendje
Harald Heckmann
Hennadii Chernyshchyk
Howard Su
Huang Rui
Huanghuang Zhou
HungMingWu
HyungKi Jeong
Ilya Barkov
Iru Cai
Ivan Vnučec
Ilya Barkov
Iztok Jeras
Jake Merdich
James Hanlon
@@ -61,15 +70,21 @@ Jamie Iles
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
Jesse Taube
Jevin Sweval
Jiacheng Qian
Jiamin Zhu
Jiuyang Liu
Joey Liu
John Coiner
John Demme
John Wehle
Jonathan Drolet
Jose Loyola
Josep Sans
Joseph Nwabueze
Josh Redford
Julian Daube
Julie Schwartz
Julien Margetts
Kaleb Barrett
@@ -79,6 +94,7 @@ Keith Colbert
Kevin Kiningham
Kritik Bhimani
Krzysztof Bieganski
Krzysztof Boronski
Krzysztof Boroński
Kuba Ober
Larry Doolittle
@@ -105,6 +121,7 @@ Mostafa Gamal
Nandu Raj
Nathan Kohagen
Nathan Myers
Oleh Maksymenko
Patrick Stewart
Paul Wright
Pawel Sagan
@@ -119,23 +136,29 @@ 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
Sören Tempel
Teng Huang
Tim Hutt
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Topa Topino
Toru Niina
Tudor Timi
Tymoteusz Blazejczyk
Udi Finkelstein
Unai Martinez-Corral
@@ -143,15 +166,17 @@ Varun Koyyalagunta
Vassilis Papaefstathiou
Veripool API Bot
Victor Besyakov
Vito Gamberini
William D. Jones
Wilson Snyder
Xi Zhang
Yinan Xu
Yoda Lee
Yossi Nivin
Yu-Sheng Lin
Yuri Victorovich
Yutetsu TAKATSUKASA
Yu-Sheng Lin
Yves Mathieu
Zhanglei Wang
Zixi Li
أحمد المحمودي
+5 -1
View File
@@ -18,12 +18,16 @@
RST2HTML = rst2html
PYTHON3 = python3
DOXYGEN = doxygen
SPHINXOPTS ?= -c guide
SPHINXBUILD ?= sphinx-build
SOURCEDIR = guide
BUILDDIR = _build
SPHINXOPTS ?= -c guide
ifneq ($(VERILATOR_ANALYTICS_ID),)
SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID)
endif
######################################################################
.SUFFIXES:
+1 -2
View File
@@ -31,7 +31,7 @@ def get_vlt_version():
if match:
try:
data = os.popen('git log -n 1 --pretty=%cs').read()
except Exception:
except Exception: # pylint: disable=broad-except
data = "" # fallback, and Sphinx will fill in today's date
return "Devel " + match.group(1), data
return "unknown", "unknown"
@@ -115,7 +115,6 @@ html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_theme_options = {
'analytics_id': 'G-D27B0C9QEB',
'logo_only': True,
'style_nav_header_background': "#45acf8", # Default is #2980B9
# 'canonical_url':
+9
View File
@@ -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)
==================================
+4 -4
View File
@@ -17,10 +17,10 @@ C++11 compiler support
Verilator will require C++20 or newer compilers for both compiling
Verilator and compiling all Verilated models no sooner than January 2025.
Verilated_heavy.h
The legacy "verilated_heavy.h" include was replaced with just including
"verilated.h". Verilated_heavy.h is planned for removal no sooner than
July 2022.
32-bit compiler support
Verilator currently regresses both 64-bit and 32-bit pointer modes (GCC's
`-m64` and `-m32`). Support for 32-bit `-m32` mode will be deprecated no
sooner than January 2024.
Option `-O<letter>`
The debug `-O<letter>` options have been replaced with
+26 -6
View File
@@ -91,9 +91,29 @@ associated programs.
.. option:: VERILATOR_ROOT
Specifies the directory containing the distribution kit. This is used
to find the executable, Perl library, and include files. If not
specified, it will come from a default optionally specified at configure
time (before Verilator was compiled). It should not be specified if
using a pre-compiled Verilator package as the hard-coded value should be
correct. See :ref:`Installation`.
The ``VERILATOR_ROOT`` environment variable is used in several places:
* At ``./configure`` time: If set, it is embedded into the binary, and
at runtime if ``VERILATOR_ROOT`` is not set, the embedded value is
used for the runtime default.
* When ``verilator`` is run: If ``VERILATOR_ROOT`` is set it will be
used to find the ``verilator_bin`` executable (this is the actual
Verilator binary; ``verilator`` is a Perl wrapper). If not set, the
``verilator`` script uses other methods to find ``verilator_bin``
(looking in the same directory and falling back to ``$PATH``).
* When ``make`` is run on the Makefile generated by ``verilator``: The
value of ``VERILATOR_ROOT`` (falling back to the value embedded in the
binary if not set) is used to find the include files
(``include/verilated.mk``).
If you are using a pre-compiled Verilator package, you should not need
to set ``VERILATOR_ROOT`` - the value embedded in the binary should be
correct. In fact this option *does not work* with Verilator packages
that have been installed with ``make install``. If a Verilator package
has been installed using ``./configure --prefix=/some/path && make
install`` and then moved to another location, you cannot use
``VERILATOR_ROOT`` to point to the new version.
See :ref:`Installation` for more details.
+34 -11
View File
@@ -808,6 +808,13 @@ Summary:
See also :vlopt:`--binary`.
.. option:: --main-top-name <string>
Specify the name passed to the Verilated model being constructed, in the
generated C++ main() function.
If the string ``"-"`` is used, no top level scope is added.
.. option:: --max-num-width <value>
Set the maximum number literal width (e.g., in 1024'd22 this
@@ -1101,6 +1108,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
@@ -1455,8 +1474,11 @@ Summary:
them systematically.
The generated file is in the Verilator Configuration format, see
:ref:`Configuration Files`, and can directly be consumed by
Verilator. The standard file extension is ".vlt".
:ref:`Configuration Files`. The standard file extension is ".vlt".
These files can directly be consumed by Verilator, typically by placing
the filename as part of the Verilator command line options. Waiver files
need to be listed on the command line before listing the files they are
waiving.
.. option:: -Wall
@@ -1502,10 +1524,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.
@@ -1517,7 +1539,7 @@ Summary:
Disable all code style related warning messages (note that by default, they are
already disabled). This is equivalent to ``-Wno-DECLFILENAME -Wno-DEFPARAM
-Wno-EOFNEWLINE -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY
-Wno-EOFNEWLINE -Wno-GENUNNAMED -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY
-Wno-PINNOCONNECT -Wno-SYNCASYNCNET -Wno-UNDRIVEN
-Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL
-Wno-VARHIDDEN``.
@@ -1540,16 +1562,17 @@ Summary:
Enable all lint-related warning messages (note that by default, they are already
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-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``.
``-Wwarn-ALWCOMBORDER -Wwarn-ASCRANGE -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE
-Wwarn-CASEOVERLAP -Wwarn-CASEWITHX -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CMPCONST
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-IMPLICITSTATIC -Wwarn-LATCH -Wwarn-MISINDENT
-Wwarn-NEWERSTD -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-STATICVAR -Wwarn-UNSIGNED
-Wwarn-WIDTHTRUNC -Wwarn-WIDTHEXPAND -Wwarn-WIDTHXZEXPAND``.
.. option:: -Wwarn-style
Enable all code style-related warning messages. This is equivalent to
``-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-EOFNEWLINE
-Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN
-Wwarn-GENUNNAMED -Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN
-Wwarn-UNUSEDGENVAR -Wwarn-UNUSEDPARAM -Wwarn-UNUSEDSIGNAL -Wwarn-VARHIDDEN``.
.. option:: --x-assign 0
+3 -3
View File
@@ -356,8 +356,8 @@ Why do I get "undefined reference to \`VL_RAND_RESET_I' or \`Verilated::...'"?
You need to link your compiled Verilated code against the
:code:`verilated.cpp` file found in the include directory of the Verilator
kit. This is one target in the ``$(VK_GLOBAL_OBJS)`` make variable, which
should be part of your Makefile's link rule. If you use :vlopt:`--exe`,
this is done for you.
should be part of your Makefile's link rule. If you use :vlopt:`--exe` or
:vlopt:`--binary`, this is done for you.
Is the PLI supported?
@@ -486,7 +486,7 @@ From the sc_main.cpp file, you'd then:
#include "Vour.h"
#include "Vour_our.h"
cout << "clock is " << top->our->clk << endl;
std::cout << "clock is " << top->our->clk << std::endl;
In this example, clk is a bool you can read or set as any other variable.
+4 -2
View File
@@ -126,8 +126,10 @@ In specific debug and other modes, it also creates:
- Debugging graph files (from --debug)
* - *{prefix}{misc}*\ .tree
- Debugging files (from --debug)
* - {mod_prefix}_{each_verilog_base_filename}*\ .vpp
- Pre-processed verilog (from --debug)
* - *{prefix}*\ __inputs\ .vpp
- Pre-processed verilog for all files (from --debug)
* - *{prefix}*\ _ *{each_verilog_base_filename}*\ .vpp
- Pre-processed verilog for each file (from --debug)
After running Make, the C++ compiler may produce the following:
+21 -33
View File
@@ -39,7 +39,7 @@ In brief, to install from git:
::
# Prerequisites:
#sudo apt-get install git perl python3 make autoconf g++ flex bison ccache
#sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache
#sudo apt-get install libgoogle-perftools-dev numactl perl-doc
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
@@ -104,6 +104,7 @@ for good performance:
::
sudo apt-get install ccache # If present at build, needed for run
sudo apt-get install mold # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl
The following is optional but is recommended for nicely rendered command line
@@ -124,9 +125,9 @@ Those developing Verilator itself may also want these (see internals.rst):
::
sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov
sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov
sudo apt-get install libclang-dev yapf3
sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
cpan install Pod::Perldoc
cpan install Parallel::Forker
@@ -201,8 +202,9 @@ These are the installation options:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Our personal favorite is to always run Verilator in-place from its Git
directory. This allows the easiest experimentation and upgrading, and
allows many versions of Verilator to co-exist on a system.
directory (don't run ``make install``). This allows the easiest
experimentation and upgrading, and allows many versions of Verilator to
co-exist on a system.
::
@@ -211,17 +213,18 @@ allows many versions of Verilator to co-exist on a system.
./configure
# Running will use files from $VERILATOR_ROOT, so no install needed
Note after installing (below steps), a calling program or shell must set
the environment variable :option:`VERILATOR_ROOT` to point to this Git
directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will find
the path to all needed files.
Note after installing (see `Installation`_), a calling program or shell
must set the environment variable :option:`VERILATOR_ROOT` to point to this
Git directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will
find the path to all needed files.
2. Install into a specific location
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2. Install into a Specific Prefix
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may eventually be installing onto a project/company-wide "CAD" tools
disk that may support multiple versions of every tool. Tell configure the
You may be an OS package maintainer building a Verilator package, or you
may eventually be installing onto a project/company-wide "CAD" tools disk
that may support multiple versions of every tool. Tell configure the
eventual destination directory name. We recommend that the destination
location include the Verilator version name:
@@ -232,7 +235,8 @@ location include the Verilator version name:
# For the tarball, use the version number instead of git describe
./configure --prefix /CAD_DISK/verilator/`git describe | sed "s/verilator_//"`
Note after installing (below steps), if you use `modulecmd
Note after installing (see `Installation`_), you need to add the path to
the ``bin`` directory to your ``PATH``. Or, if you use `modulecmd
<http://modules.sourceforge.net/>`__, you'll want a module file like the
following:
@@ -245,23 +249,7 @@ following:
prepend-path PKG_CONFIG_PATH $install_root/share/pkgconfig
3. Install into a Specific Path
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may eventually install Verilator into a specific installation prefix,
as most GNU tools support:
::
unset VERILATOR_ROOT # if your shell is bash
unsetenv VERILATOR_ROOT # if your shell is csh
./configure --prefix /opt/verilator-VERSION
Then after installing (below steps), you will need to add
``/opt/verilator-VERSION/bin`` to your ``$PATH`` environment variable.
4. Install System Globally
3. Install System Globally
^^^^^^^^^^^^^^^^^^^^^^^^^^
The final option is to eventually install Verilator globally, using
@@ -273,8 +261,8 @@ configure's default system paths:
unsetenv VERILATOR_ROOT # if your shell is csh
./configure
Then after installing (below), the binaries should be in a location
already in your ``$PATH`` environment variable.
Then after installing (see `Installation`_), the binaries should be in a
location already in your ``$PATH`` environment variable.
Configure
+18 -1
View File
@@ -143,7 +143,7 @@ Functional Coverage
-------------------
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
translate functional coverage points the user has inserted manually win
translate functional coverage points the user has inserted manually in
SystemVerilog code through into the Verilated model.
Currently, all functional coverage points are specified using SystemVerilog
@@ -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.
+1 -1
View File
@@ -165,7 +165,7 @@ compiled on the different target system.
To support this, none of the files that Verilator produces will reference
any configure-generated build-system-specific files, such as
:file:`config.h` (which is renamed in Verilator to :file:`config_build.h`
:file:`config.h` (which is renamed in Verilator to :file:`config_package.h`
to reduce confusion.) The disadvantage of this approach is that
:file:`include/verilatedos.h` must self-detect the requirements of the
target system, rather than using configure.
+254 -18
View File
@@ -97,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
@@ -378,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
@@ -642,6 +670,52 @@ List Of Warnings
used as a clock.
.. option:: GENUNNAMED
Warns that a generate block was unnamed and "genblk" will be used per
IEEE.
The potential issue is that adding additional generate blocks will
renumber the assigned names, which may cause eventual problems with
synthesis constraints or other tools that depend on hierarchical paths
remaining consistent.
Blocks that are empty may not be reported with this warning, as no
scopes are created for empty blocks, so there is no harm in having them
unnamed.
Disabled by default as this is a code-style warning; it will simulate
correctly.
.. code-block:: sv
:linenos:
:emphasize-lines: 2
generate
if (PARAM == 1) begin //<--- Warning
end
Results in:
.. code-block::
%Warning-GENUNNAMED: example.v:2:9: Unnamed generate block (IEEE 1800-2017 27.6)
To fix this assign a label (often with the naming convention prefix of
:code:`gen_` or :code:`g_`), for example:
.. code-block:: sv
:linenos:
:emphasize-lines: 2
generate
if (PARAM == 1) begin : gen_param_1 //<--- Repaired
end
Other tools with similar warnings: Verible's generate-label, "All
generate block statements must have a label."
.. option:: HIERBLOCK
Warns that the top module is marked as a hierarchy block by the
@@ -738,14 +812,17 @@ 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
automatic".
If the function is in a module, and does not require static behavior,
change it to "function automatic".
If the function requires static behavior, change it to "function
static".
If the function is in a module, and requires static behavior, change it
to "function static".
If the function is in a package, it defaults to static, and label the
function's variables as static.
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
@@ -845,23 +922,111 @@ List Of Warnings
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: LIFETIME
Error when a variable is referenced in a process that can outlive the process
in which it was declared. This can happen when using 'fork..join_none' or
'fork..join_any' blocks, which spawn process that can outlive their parents.
This error occurs only when Verilator can't replace the reference with a
reference to copy of this variable, local to the forked process. For example:
.. code-block:: sv
:linenos:
:emphasize-lines: 3
task foo(int local_var);
fork
#10 local_var++;
#20 $display("local_var = %d", local_var);
join_none
endtask
In the example above 'local_var' exists only within scope of 'foo', once foo
finishes, the stack frame containing 'i' gets removed. However, the process
forked from foo continues, as it contains a delay. After 10 units of time
pass, this process attempts to modify 'local_var'. However, this variable no
longer exits. It can't be made local to the forked process upon spawning, because
it's modified and can be referenced somewhere else, for example in the other
forked process, that was delayed by 20 units of time in this example. Thus,
there's no viable stack allocation for it.
In order to fix it, if the intent is not to share the variable's state outside
of the process, then create a local copy of the variable.
For example:
.. code-block:: sv
:linenos:
:emphasize-lines: 4
task foo(int local_var);
fork
#10 begin
int forked_var = local_var;
forked_var++;
end
#20 begin
// Note that we are going to print the original value here,
// as `forked_var`is a local copy that was initialized while
// `foo` was still alive.
int forked_var = local_var;
$display("forked_var = %d", forked_var)
end
join_none
endtask
If you need to share its state, another strategy is to ensure it's allocated
statically:
.. code-block:: sv
:linenos:
:emphasize-lines: 1
int static_var;
task foo();
fork
#10 static_var++;
#20 $display("static_var = %d", static_var);
join_none
endtask
However, if you need to be able to instantiate at runtime, the solution would be to
wrap it in an object, since the forked process can hold a reference to that object
and ensure that the variable stays alive this way:
.. code-block:: sv
:linenos:
:emphasize-lines: 2
class Wrapper;
int m_var;
// Here we implicitly hold a reference to `this`
task foo();
fork
#10 m_var++;
#20 $display("this.m_var = %d", m_var);
join_none
endtask
endclass
// Here we explicitly hold a handle to an object
task bar(Wrapper wrapper);
fork
#10 wrapper.m_var++;
#20 $display("wrapper.m_var = %d", wrapper.m_var);
join_none
endtask
.. option:: LITENDIAN
.. TODO better example
Warns that a packed vector is declared with big endian bit numbering
(i.e. [0:7]). Little endian bit numbering is now the overwhelming
standard, and big numbering is now thus often due to simple oversight
instead of intent.
It also warns that an instance is declared with big endian range
(i.e. [0:7] or [7]) and is connected to an N-wide signal.
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
@@ -874,6 +1039,51 @@ List Of Warnings
unsupported. Verilator uses only the typical delay value.
.. option:: MISINDENT
Warns that the indentation of a statement is misleading, suggesting the
statement is part of a previous :code:`if` or :code:`while` block while
it is not.
Verilator suppresses this check when there is an inconsistent mix of
spaces and tabs, as it cannot ensure the width of tabs. Verilator also
ignores blocks with :code:`begin`/:code:`end`, as the :code:`end`
visually indicates the earlier statement's end.
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
For example
.. code-block:: sv
:linenos:
:emphasize-lines: 3
if (something)
statement_in_if;
statement_not_in_if; //<--- Warning
Results in:
.. code-block::
%Warning-MISINDENT: example.v:3:9: Misleading indentation
To fix this repair the indentation to match the correct earlier
statement, for example:
.. code-block:: sv
:linenos:
:emphasize-lines: 3
if (something)
statement_in_if;
statement_not_in_if; //<--- Repaired
Other tools with similar warnings: GCC -Wmisleading-indentation,
clang-tidy readability-misleading-indentation.
.. option:: MODDUP
.. TODO better example
@@ -952,6 +1162,21 @@ List Of Warnings
(neither :vlopt:`--timing` nor :vlopt:`--no-timing` option was provided).
.. option:: NEWERSTD
Warns that a feature requires a newer standard of Verilog or SystemVerilog
than the one specified by the :vlopt:`--language` option. For example, unsized
unbased literals (`'0`, `'1`, `'z`, `'x`) require 1800-2005 or later.
To avoid this warning, use a Verilog or SystemVerilog standard that
supports the feature. Alternatively, modify your code to use a different
syntax that is supported by the Verilog/SystemVerilog standard specified
by the :vlopt:`--language` option.
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: NOLATCH
.. TODO better example
@@ -1302,6 +1527,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.
@@ -1813,7 +2049,7 @@ List Of Warnings
.. option:: WIDTHXZEXPAND
A more granular WIDTH warning, for when a value is xz expanded
A more granular WIDTH warning, for when a value is X/Z expanded
.. option:: WIDTHCONCAT
+39 -26
View File
@@ -628,21 +628,32 @@ 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
~~~~~~~~~~~
The visitor in ``V3Timing.cpp`` transforms each timing control into a ``co_await``.
There are two visitors in ``V3Timing.cpp``.
The first one, ``TimingSuspendableVisitor``, does not perform any AST
transformations. It is responsible for marking processes and C++ functions that
contain timing controls as suspendable. Processes that call suspendable
functions are also marked as suspendable. Functions that call, are overridden
by, or override suspendable functions are marked as suspendable as well.
The visitor keeps a dependency graph of functions and processes to handle such
cases. A function or process is dependent on a function if it calls it. A
virtual class method is dependent on another class method if it calls it,
overrides it, or is overriden by it.
The second visitor in ``V3Timing.cpp``, ``TimingControlVisitor``, uses the
information provided by ``TimingSuspendableVisitor`` and transforms each timing
control into a ``co_await``.
* event controls are turned into ``co_await`` on a trigger scheduler's
``trigger`` method. The awaited trigger scheduler is the one corresponding to
@@ -674,14 +685,9 @@ Each sub-statement of a ``fork`` is put in an ``AstBegin`` node for easier
grouping. In a later step, each of these gets transformed into a new, separate
function. See the `Forks` section for more detail.
Processes that use awaits are marked as suspendable. Later, during ``V3Sched``,
they are transformed into coroutines. Functions that use awaits get the return
type of ``VlCoroutine``. This immediately makes them coroutines. Note that if a
process calls a function that is a coroutine, the call gets wrapped in an
await, which means the process itself will be marked as suspendable. A virtual
function is a coroutine if any of its overriding or overridden functions are
coroutines. The visitor keeps a dependency graph of functions and processes to
handle such cases.
Suspendable functions get the return type of ``VlCoroutine``, which makes them
coroutines. Later, during ``V3Sched``, suspendable processes are also
transformed into coroutines.
Scheduling with timing
~~~~~~~~~~~~~~~~~~~~~~
@@ -749,9 +755,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
@@ -1509,8 +1513,19 @@ debug level 5, with the V3Width.cpp file at level 9.
--debug
-------
When you run with ``--debug``, there are two primary output file types
placed into the obj_dir, .tree and .dot files.
When you run with ``--debug``, there are three primary output file types
placed into the obj_dir, .vpp, .tree and .dot files.
.vpp Output
-----------
Verilator creates a *{mod_prefix}*\ __inputs\ .vpp file containing all the
files that were read, filtered by preprocessing. This file can be fed back
into Verilator, replacing on the command line all of the previous input
files, to enable simplification of test cases.
Verilator also creates .vpp files for each individual file passed on the
command line.
.dot Output
@@ -1807,8 +1822,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
@@ -2110,7 +2123,7 @@ Or in a hand-written C++ wrapper:
::
#ifdef TEST_VERBOSE
cout << "Read a=" << a << endl;
std::cout << "Read a=" << a << std::endl;
#endif
A filename that should be used to check the output results is given with
+38 -1
View File
@@ -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
@@ -53,6 +56,7 @@ Das
Dcache
Deadman
Debacker
Deepa
Defparams
Denio
Deprecations
@@ -96,6 +100,7 @@ Fredieu
GTKWave
Galbi
Gantt
Garnal
Gartner
Gelinek
Geoff
@@ -188,6 +193,7 @@ Laurens
Lavino
Leber
Leendert
Lem
Lesik
Liland
Liu
@@ -207,6 +213,7 @@ Matveyenko
Maupin
Mdir
Mednick
Menküc
Michiels
Microsystems
Milanovic
@@ -223,8 +230,10 @@ Muhlestein
Multithreaded
Multithreading
NOUNOPTFLAT
NaN
Nalbantis
Narayan
Nassim
Nauticus
Newgard
Nigam
@@ -238,6 +247,7 @@ Olof
Olofsson
Oyvind
PLI
Palaniappan
Patricio
Petr
Piechotka
@@ -252,6 +262,7 @@ Prateek
Pre
Preprocess
Pretet
Pretl
Priyadharshini
Pullup
Pulver
@@ -295,6 +306,7 @@ Solomatnikov
Solt
Southwell
Srini
Srinivasan
Stamness
Stephane
Stoddard
@@ -319,6 +331,7 @@ Thiede
Thierry
Thyer
Tichelaar
Timi
Tomov
Tood
Topa
@@ -343,6 +356,7 @@ Vdeeptemp
Vdly
Vemumtab
Vemuri
Venkataramanan
Veriable
Verialted
Verilate
@@ -353,6 +367,7 @@ Verilator
Verilog
Vighnesh
Viktor
Vilp
Vm
Vukobratovic
Wai
@@ -363,6 +378,7 @@ Wfuture
Whatson
Wildman
Wim
Wmisleading
Wno
Wojciech
Wolfel
@@ -376,6 +392,7 @@ Xuan
Xuanqi
Yazdanbakhsh
Yi
Yike
Yinan
Yosys
Yu
@@ -396,6 +413,7 @@ architected
args
arrarys
assertOn
astgen
async
ato
atoi
@@ -452,12 +470,14 @@ commandArgsPlusMatch
compilable
concat
concats
conf
config
const
constexpr
constpool
coredump
coroutine
coroutines
countbits
countones
cout
@@ -512,6 +532,7 @@ dumpportson
dumpvars
dut
dx
dynarray
elab
elike
elsif
@@ -520,6 +541,7 @@ endcelldefine
endfunction
endgenerate
endian
endianness
endif
endmodule
endprotect
@@ -541,6 +563,7 @@ exe
executables
expr
extern
ezchi
fanin
fasttrace
fauto
@@ -585,6 +608,7 @@ genvar
genvars
getenv
getline
ggdb
gmake
gmon
gotFinish
@@ -635,6 +659,7 @@ lcov
ld
leavinel
len
libc
libext
libgoogle
libsystemc
@@ -653,7 +678,9 @@ logicals
longint
lossy
lsb
lubc
lvalue
lvalues
lxt
macromodule
makefile
@@ -678,12 +705,15 @@ mtasks
mulithreaded
mult
multidim
multidriven
multiinterfaces
multiline
multipling
multipoint
multithread
multithreaded
multithreading
musl
mutexes
mux
myftptoyman
@@ -714,6 +744,7 @@ ortegon
oversubscription
parallelized
param
parameterization
parameterized
params
parens
@@ -762,10 +793,12 @@ pulldowns
pullup
pvalue
pwd
py
qrq
radix
randc
randcase
randstate
rarr
rdtsc
reStructuredText
@@ -807,6 +840,7 @@ specparam
splitme
spp
sqrt
srandom
src
srcdir
srcfile
@@ -838,6 +872,7 @@ svdpi
swrite
sys
systemc
tenghtt
testbench
threadsafe
threashold
@@ -869,10 +904,12 @@ typedefs
typename
uint
un
unbased
undef
undefineall
undriven
ungetc
unhandled
uniquified
unistd
unlink
@@ -909,6 +946,7 @@ vlt
vltstd
vluint
vpi
vpiDefName
vpiLeftRange
vpiModule
vpiSize
@@ -938,4 +976,3 @@ ypq
yurivict
zdave
Øyvind
+3 -1
View File
@@ -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.
+3 -1
View File
@@ -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.
+67 -71
View File
@@ -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;
}
@@ -2066,7 +2052,8 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
int zfd;
int fourpack_duo = 0;
#ifndef __MINGW32__
char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1);
int fnam_len = strlen(xc->filename) + 5 + 1;
char *fnam = (char *)malloc(fnam_len);
#endif
fixup_offs = ftello(xc->handle);
@@ -2156,7 +2143,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
fflush(xc->handle);
#ifndef __MINGW32__
sprintf(fnam, "%s.hier", xc->filename);
snprintf(fnam, fnam_len, "%s.hier", xc->filename);
unlink(fnam);
free(fnam);
#endif
@@ -2835,7 +2822,7 @@ if(ctx && name && literal_arr && val_arr && (elem_count != 0))
uint32_t i;
name_len = strlen(name);
elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count);
elem_count_len = snprintf(elem_count_buf, 16, "%" PRIu32, elem_count);
literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
@@ -3412,6 +3399,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;
@@ -3922,7 +3910,8 @@ int pass_status = 1;
if(!xc->fh)
{
fst_off_t offs_cache = ftello(xc->f);
char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1);
int fnam_len = strlen(xc->filename) + 6 + 16 + 32 + 1;
char *fnam = (char *)malloc(fnam_len);
unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
fst_off_t hl, uclen;
fst_off_t clen = 0;
@@ -3941,7 +3930,7 @@ if(!xc->fh)
htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4;
}
sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
snprintf(fnam, fnam_len, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
uclen = fstReaderUint64(xc->f);
#ifndef __MINGW32__
@@ -4140,7 +4129,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 +4141,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 +4158,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 +4230,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 +4369,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 +4391,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 +4480,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;
}
@@ -4594,15 +4587,17 @@ if(sectype == FST_BL_ZWRAPPER)
int zfd;
int flen = strlen(xc->filename);
char *hf;
int hf_len;
seclen = fstReaderUint64(xc->f);
uclen = fstReaderUint64(xc->f);
if(!seclen) return(0); /* not finished compressing, this is a failed read */
hf = (char *)calloc(1, flen + 16 + 32 + 1);
hf_len = flen + 16 + 32 + 1;
hf = (char *)calloc(1, hf_len);
sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
snprintf(hf, hf_len, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
fcomp = fopen(hf, "w+b");
if(!fcomp)
{
@@ -4974,6 +4969,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)
{
@@ -5197,16 +5193,16 @@ for(;;)
if(beg_tim)
{
if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim);
if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", beg_tim);
fstWritex(xc, wx_buf, wx_len);
if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
}
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
{
if(beg_tim == xc->blackout_times[cur_blackout])
{
wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
wx_len = snprintf(wx_buf, 32, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -5340,7 +5336,7 @@ for(;;)
clone_d[j] = srcdata[7-j];
}
}
sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.16g", d);
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
}
}
@@ -5368,7 +5364,7 @@ for(;;)
}
fstVcdID(vcdid_buf, idx+1);
wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf);
wx_len = snprintf(wx_buf, 64, "r%.16g %s\n", d, vcdid_buf);
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -5633,16 +5629,16 @@ for(;;)
}
}
if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]);
if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", time_table[i]);
fstWritex(xc, wx_buf, wx_len);
if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
{
if(time_table[i] == xc->blackout_times[cur_blackout])
{
wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
wx_len = snprintf(wx_buf, 32, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -5892,7 +5888,7 @@ for(;;)
clone_d[j] = srcdata[7-j];
}
}
sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.16g", d);
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
}
}
@@ -5918,7 +5914,7 @@ for(;;)
}
}
wx_len = sprintf(wx_buf, "r%.16g", d);
wx_len = snprintf(wx_buf, 32, "r%.16g", d);
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -6024,7 +6020,7 @@ if(xc->signal_lens[facidx] == 1)
}
}
sprintf((char *)buf, "%.16g", d);
snprintf((char *)buf, 32, "%.16g", d); /* this will write 18 bytes */
}
}
@@ -6616,7 +6612,7 @@ if(xc->signal_lens[facidx] == 1)
}
}
sprintf(buf, "r%.16g", d);
snprintf(buf, 32, "r%.16g", d); /* this will write 19 bytes */
return(buf);
}
}
+116 -45
View File
@@ -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,89 @@ 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];
}
std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
// Though not stated in IEEE, assumption is the string must be printable
const char* const stateCharsp = reinterpret_cast<const char*>(&m_state);
static_assert(sizeof(m_state) == 16, "");
std::string result{"R00112233445566770011223344556677"};
for (int i = 0; i < sizeof(m_state); ++i) {
result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15);
result[1 + i * 2 + 1] = 'a' + (stateCharsp[i] & 15);
}
return result;
}
void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
if (VL_UNLIKELY((state.length() != 1 + 2 * sizeof(m_state)) || (state[0] != 'R'))) {
VL_PRINTF_MT("%%Warning: set_randstate ignored as state string not from get_randstate\n");
return;
}
char* const stateCharsp = reinterpret_cast<char*>(&m_state);
for (int i = 0; i < sizeof(m_state); ++i) {
stateCharsp[i]
= (((state[1 + i * 2] - 'a') & 15) << 4) | ((state[1 + i * 2 + 1] - 'a') & 15);
}
}
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 +351,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 +376,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 +579,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 +706,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
@@ -1312,16 +1373,18 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
*p = t_tmp;
} else if (obits <= VL_BYTESIZE) {
CData* const p = va_arg(ap, CData*);
*p = owp[0];
*p = VL_CLEAN_II(obits, obits, owp[0]);
} else if (obits <= VL_SHORTSIZE) {
SData* const p = va_arg(ap, SData*);
*p = owp[0];
*p = VL_CLEAN_II(obits, obits, owp[0]);
} else if (obits <= VL_IDATASIZE) {
IData* const p = va_arg(ap, IData*);
*p = owp[0];
*p = VL_CLEAN_II(obits, obits, owp[0]);
} else if (obits <= VL_QUADSIZE) {
QData* const p = va_arg(ap, QData*);
*p = VL_SET_QW(owp);
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
} else {
_vl_clean_inplace_w(obits, owp);
}
}
} // switch
@@ -1651,15 +1714,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 {
@@ -1805,14 +1868,14 @@ std::string VL_TO_STRING_W(int words, const WDataInP 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 {
@@ -1833,6 +1896,12 @@ std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
return std::string{destout, len};
}
std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE {
std::string output;
for (const std::string& s : q) output += s;
return output;
}
std::string VL_PUTC_N(const std::string& lhs, IData rhs, CData ths) VL_PURE {
std::string lstring = lhs;
const int32_t rhs_s = rhs; // To signed value
@@ -1871,7 +1940,6 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
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 size_t procLen = std::min(str.length(), static_cast<size_t>(8));
const char* const datap = str.data();
int pos = static_cast<int>(str.length()) - 1;
int bit = 0;
@@ -3166,15 +3234,18 @@ void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
//===========================================================================
// VlDeleter:: Methods
void VlDeleter::deleteAll() {
void VlDeleter::deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_MT_SAFE {
while (true) {
VerilatedLockGuard lock{m_mutex};
if (m_newGarbage.empty()) break;
VerilatedLockGuard deleteLock{m_deleteMutex};
std::swap(m_newGarbage, m_toDelete);
lock.unlock(); // So destructors can enqueue new objects
{
VerilatedLockGuard lock{m_mutex};
if (m_newGarbage.empty()) break;
m_deleteMutex.lock();
std::swap(m_newGarbage, m_toDelete);
// m_mutex is unlocked here, so destructors can enqueue new objects
}
for (VlDeletable* const objp : m_toDelete) delete objp;
m_toDelete.clear();
m_deleteMutex.unlock();
}
}
+26 -21
View File
@@ -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"
@@ -142,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
@@ -159,6 +175,7 @@ public:
/// Construct mutex (without locking it)
VerilatedMutex() = default;
~VerilatedMutex() = default;
VL_UNCOPYABLE(VerilatedMutex);
const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety
/// Acquire/lock mutex
void lock() VL_ACQUIRE() VL_MT_SAFE {
@@ -202,23 +219,10 @@ public:
/// Construct and hold given mutex lock until destruction or unlock()
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
m_mutexr.lock();
mutexr.lock();
}
/// Destruct and unlock the mutex
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
/// 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
@@ -607,6 +611,7 @@ public: // But for internal use only
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
~VerilatedSyms();
VL_UNCOPYABLE(VerilatedSyms);
};
//===========================================================================
@@ -945,18 +950,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
+9 -3
View File
@@ -31,6 +31,8 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
# Compiler flags that enable coroutine support
CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
# Linker flags
CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
# Linker libraries for multithreading
CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@
@@ -77,6 +79,8 @@ VPATH += ..
VPATH += $(VERILATOR_ROOT)/include
VPATH += $(VERILATOR_ROOT)/include/vltstd
LDFLAGS += $(CFG_LDFLAGS_VERILATED)
#OPT = -ggdb -DPRINTINITSTR -DDETECTCHANGE
#OPT = -ggdb -DPRINTINITSTR
CPPFLAGS += $(OPT)
@@ -235,14 +239,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:
+6 -6
View File
@@ -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;
// std::cout << "\nch pre=" << prefix << " s=" << suffix << "\nch a="
// << old << "\nch b=" << add << "\ncho=" << result << std::endl;
return result;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
VL_REQUIRES(m_mutex) {
@@ -316,7 +316,7 @@ public:
valps[2] = page_default.c_str();
// Keys -> strings
std::string keys[VerilatedCovConst::MAX_KEYS];
std::array<std::string, VerilatedCovConst::MAX_KEYS> keys;
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) keys[i] = ckeyps[i];
}
@@ -337,7 +337,7 @@ public:
const std::string key = keys[i];
if (!keys[i].empty()) {
const std::string val = valps[i];
// cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
// std::cout << " " << __FUNCTION__ << " " << key << " = " << val << std::endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
++addKeynum;
+11 -11
View File
@@ -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 )
+21 -9
View File
@@ -152,9 +152,11 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE; // PLIi
// Base macros
// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
// Arguments must not have side effects
#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit))
// Shift appropriate word by bit. Does not account for wrapping between two words
// Argument 'bit' must not have side effects
#define VL_BITRSHIFT_W(data, bit) ((data)[VL_BITWORD_E(bit)] >> VL_BITBIT_E(bit))
// Create two 32-bit words from quadword
@@ -260,7 +262,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
@@ -758,6 +760,7 @@ static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_PURE {
static inline IData VL_CLOG2_I(IData lhs) VL_PURE {
// There are faster algorithms, or fls GCC4 builtins, but rarely used
// In C++20 there will be std::bit_width(lhs) - 1
if (VL_UNLIKELY(!lhs)) return 0;
--lhs;
int shifts = 0;
@@ -953,11 +956,19 @@ static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE
// EMIT_RULE: VL_MUL: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_DIV: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_MODDIV: oclean=dirty; lclean==clean; rclean==clean;
#define VL_DIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs))
#define VL_DIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs))
static inline IData VL_DIV_III(int lbits, IData lhs, IData rhs) {
return (rhs == 0) ? 0 : lhs / rhs;
}
static inline QData VL_DIV_QQQ(int lbits, QData lhs, QData rhs) {
return (rhs == 0) ? 0 : lhs / rhs;
}
#define VL_DIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 0))
#define VL_MODDIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs))
#define VL_MODDIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs))
static inline IData VL_MODDIV_III(int lbits, IData lhs, IData rhs) {
return (rhs == 0) ? 0 : lhs % rhs;
}
static inline QData VL_MODDIV_QQQ(int lbits, QData lhs, QData rhs) {
return (rhs == 0) ? 0 : lhs % rhs;
}
#define VL_MODDIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 1))
static inline WDataOutP VL_ADD_W(int words, WDataOutP owp, WDataInP const lwp,
@@ -2185,6 +2196,7 @@ extern IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE;
// Conversion functions
extern std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE;
extern std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE;
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
VlWide<VL_WQ_WORDS_E> lw;
VL_SET_WQ(lw, lhs);
@@ -2201,10 +2213,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);
-31
View File
@@ -1,31 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2010-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
//
//*************************************************************************
///
/// \file
/// \brief Verilated old string and data-type header
///
/// This file is deprecated, and provided for backwards compatibility.
/// Include verilated.h instead.
///
//*************************************************************************
#ifndef VERILATOR_VERILATED_HEAVY_H_
#define VERILATOR_VERILATED_HEAVY_H_
#ifdef VL_NO_LEGACY
#error "Include <verilated.h> instead of <verilated_heavy.h>"
#endif
#include "verilated.h"
#endif // Guard
+1 -1
View File
@@ -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;
}
+3 -3
View File
@@ -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); }
+145 -71
View File
@@ -26,93 +26,167 @@
// verilator lint_off TIMESCALEMOD
// verilator lint_off UNUSEDSIGNAL
package std;
// The process class is not implemented, but it's predeclared here,
// so the linter accepts references to it.
typedef class process;
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
function new(int bound = 0);
m_bound = bound;
endfunction
function new(int bound = 0);
m_bound = bound;
endfunction
function int num();
return m_queue.size();
endfunction
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
task put(T message);
`ifdef VERILATOR_TIMING
if (m_bound != 0)
wait (m_queue.size() < m_bound);
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
function int try_get(int keyCount = 1);
if (m_keyCount >= keyCount) begin
m_keyCount -= keyCount;
return 1;
end
return 0;
endfunction
endclass
class process;
typedef enum {
FINISHED = 0,
RUNNING = 1,
WAITING = 2,
SUSPENDED = 3,
KILLED = 4
} state;
`ifdef VERILATOR_TIMING
// Width visitor changes it to VlProcessRef
protected chandle m_process;
`endif
static function process self();
process p = new;
`ifdef VERILATOR_TIMING
$c(p.m_process, " = vlProcess;");
`endif
return p;
endfunction
protected function void set_status(state s);
`ifdef VERILATOR_TIMING
$c(m_process, "->state(", s, ");");
`endif
endfunction
function state status();
`ifdef VERILATOR_TIMING
return state'($c(m_process, "->state()"));
`else
return RUNNING;
`endif
endfunction
function void kill();
set_status(KILLED);
endfunction
function void suspend();
$error("std::process::suspend() not supported");
endfunction
function void resume();
set_status(RUNNING);
endfunction
task await();
`ifdef VERILATOR_TIMING
wait (status() == FINISHED || status() == KILLED);
`endif
endtask
// When really implemented, srandom must operate on the process, but for
// now rely on the srandom() that is automatically generated for all
// classes.
//
// function void srandom(int seed);
// endfunction
// The methods below work only if set_randstate is never applied to
// a state string created before another such string. Full support
// could use VlRNG class to store the state per process in VlProcess
// objects.
function string get_randstate();
string s;
s.itoa($random); // Get a random number
set_randstate(s); // Pretend it's the state of RNG
return s;
endfunction
function void set_randstate(string s);
$urandom(s.atoi()); // Set the seed using a string
endfunction
endclass
endpackage
+1 -1
View File
@@ -173,7 +173,7 @@ public:
VerilatedLockGuard lock{m_mutex};
while (m_ready.empty()) {
m_waiting = true;
m_cv.wait(lock);
m_cv.wait(m_mutex);
}
m_waiting = false;
// As noted above this is inefficient if our ready list is ever
+13 -3
View File
@@ -30,7 +30,16 @@ void VlCoroutineHandle::resume() {
// main process
if (VL_LIKELY(m_coro)) {
VL_DEBUG_IF(VL_DBG_MSGF(" Resuming: "); dump(););
m_coro();
if (m_process) { // If process state is managed with std::process
if (m_process->state() == VlProcess::KILLED) {
m_coro.destroy();
} else {
m_process->state(VlProcess::RUNNING);
m_coro();
}
} else {
m_coro();
}
m_coro = nullptr;
}
}
@@ -95,8 +104,9 @@ void VlTriggerScheduler::resume(const char* eventDescription) {
VL_DEBUG_IF(dump(eventDescription);
VL_DBG_MSGF(" Resuming processes waiting for %s\n", eventDescription););
#endif
for (auto& susp : m_ready) susp.resume();
m_ready.clear();
std::swap(m_ready, m_resumeQueue);
for (VlCoroutineHandle& coro : m_resumeQueue) coro.resume();
m_resumeQueue.clear();
commit(eventDescription);
}
+55 -36
View File
@@ -96,25 +96,38 @@ class VlCoroutineHandle final {
// MEMBERS
std::coroutine_handle<> m_coro; // The wrapped coroutine handle
VlProcessRef m_process; // Data of the suspended process, null if not needed
VlFileLineDebug m_fileline;
public:
// CONSTRUCTORS
// Construct
VlCoroutineHandle()
: m_coro{nullptr} {}
VlCoroutineHandle(std::coroutine_handle<> coro, VlFileLineDebug fileline)
VlCoroutineHandle(VlProcessRef process)
: m_coro{nullptr}
, m_process{process} {
if (m_process) m_process->state(VlProcess::WAITING);
}
VlCoroutineHandle(std::coroutine_handle<> coro, VlProcessRef process, VlFileLineDebug fileline)
: m_coro{coro}
, m_fileline{fileline} {}
, m_process{process}
, m_fileline{fileline} {
if (m_process) m_process->state(VlProcess::WAITING);
}
// Move the handle, leaving a nullptr
VlCoroutineHandle(VlCoroutineHandle&& moved)
: m_coro{std::exchange(moved.m_coro, nullptr)}
, m_process{moved.m_process}
, m_fileline{moved.m_fileline} {}
// Destroy if the handle isn't null
~VlCoroutineHandle() {
// Usually these coroutines should get resumed; we only need to clean up if we destroy a
// model with some coroutines suspended
if (VL_UNLIKELY(m_coro)) m_coro.destroy();
if (VL_UNLIKELY(m_coro)) {
m_coro.destroy();
if (m_process && m_process->state() != VlProcess::KILLED) {
m_process->state(VlProcess::FINISHED);
}
}
}
// METHODS
// Move the handle, leaving a null handle
@@ -122,7 +135,7 @@ public:
m_coro = std::exchange(moved.m_coro, nullptr);
return *this;
}
// Resume the coroutine if the handle isn't null
// Resume the coroutine if the handle isn't null and the process isn't killed
void resume();
#ifdef VL_DEBUG
void dump() const;
@@ -173,21 +186,24 @@ public:
void dump() const;
#endif
// Used by coroutines for co_awaiting a certain simulation time
auto delay(uint64_t delay, const char* filename = VL_UNKNOWN, int lineno = 0) {
auto delay(uint64_t delay, VlProcessRef process, const char* filename = VL_UNKNOWN,
int lineno = 0) {
struct Awaitable {
VlProcessRef process; // Data of the suspended process, null if not needed
VlDelayedCoroutineQueue& queue;
uint64_t delay;
VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) {
queue.push_back({delay, VlCoroutineHandle{coro, fileline}});
queue.push_back({delay, VlCoroutineHandle{coro, process, fileline}});
// Move last element to the proper place in the max-heap
std::push_heap(queue.begin(), queue.end());
}
void await_resume() const {}
};
return Awaitable{m_queue, m_context.time() + delay, VlFileLineDebug{filename, lineno}};
return Awaitable{process, m_queue, m_context.time() + delay,
VlFileLineDebug{filename, lineno}};
}
};
@@ -207,6 +223,10 @@ class VlTriggerScheduler final {
// (not resumable)
VlCoroutineVec m_ready; // Coroutines that can be resumed (all coros from m_uncommitted are
// moved here in commit())
VlCoroutineVec m_resumeQueue; // Coroutines being resumed by resume(); kept as a field to
// avoid reallocation. Resumed coroutines are moved to
// m_resumeQueue to allow adding coroutines to m_ready
// during resume(). Outside of resume() should always be empty.
public:
// METHODS
@@ -220,21 +240,23 @@ public:
void dump(const char* eventDescription) const;
#endif
// Used by coroutines for co_awaiting a certain trigger
auto trigger(const char* eventDescription = VL_UNKNOWN, const char* filename = VL_UNKNOWN,
int lineno = 0) {
auto trigger(bool commit, VlProcessRef process, const char* eventDescription = VL_UNKNOWN,
const char* filename = VL_UNKNOWN, int lineno = 0) {
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
eventDescription, filename, lineno););
struct Awaitable {
VlCoroutineVec& suspended; // Coros waiting on trigger
VlProcessRef process; // Data of the suspended process, null if not needed
VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) {
suspended.emplace_back(coro, fileline);
suspended.emplace_back(coro, process, fileline);
}
void await_resume() const {}
};
return Awaitable{m_uncommitted, VlFileLineDebug{filename, lineno}};
return Awaitable{commit ? m_ready : m_uncommitted, process,
VlFileLineDebug{filename, lineno}};
}
};
@@ -267,18 +289,19 @@ class VlDynamicTriggerScheduler final {
// with destructive post updates, e.g. named events)
// METHODS
auto awaitable(VlCoroutineVec& queue, const char* filename, int lineno) {
auto awaitable(VlProcessRef process, VlCoroutineVec& queue, const char* filename, int lineno) {
struct Awaitable {
VlProcessRef process; // Data of the suspended process, null if not needed
VlCoroutineVec& suspended; // Coros waiting on trigger
VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) {
suspended.emplace_back(coro, fileline);
suspended.emplace_back(coro, process, fileline);
}
void await_resume() const {}
};
return Awaitable{queue, VlFileLineDebug{filename, lineno}};
return Awaitable{process, queue, VlFileLineDebug{filename, lineno}};
}
public:
@@ -292,36 +315,29 @@ public:
void dump() const;
#endif
// Used by coroutines for co_awaiting trigger evaluation
auto evaluation(const char* eventDescription, const char* filename, int lineno) {
auto evaluation(VlProcessRef process, const char* eventDescription, const char* filename,
int lineno) {
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
eventDescription, filename, lineno););
return awaitable(m_suspended, filename, lineno);
return awaitable(process, m_suspended, filename, lineno);
}
// Used by coroutines for co_awaiting the trigger post update step
auto postUpdate(const char* eventDescription, const char* filename, int lineno) {
auto postUpdate(VlProcessRef process, const char* eventDescription, const char* filename,
int lineno) {
VL_DEBUG_IF(
VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting the post update step\n",
eventDescription, filename, lineno););
return awaitable(m_post, filename, lineno);
return awaitable(process, m_post, filename, lineno);
}
// Used by coroutines for co_awaiting the resumption step (in 'act' eval)
auto resumption(const char* eventDescription, const char* filename, int lineno) {
auto resumption(VlProcessRef process, const char* eventDescription, const char* filename,
int lineno) {
VL_DEBUG_IF(VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting resumption\n",
eventDescription, filename, lineno););
return awaitable(m_triggered, filename, lineno);
return awaitable(process, m_triggered, filename, lineno);
}
};
//=============================================================================
// 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.
@@ -348,24 +364,27 @@ class VlForkSync final {
public:
// Create the join object and set the counter to the specified number
void init(size_t count) { m_join.reset(new VlJoin{count, {}}); }
void init(size_t count, VlProcessRef process) { m_join.reset(new VlJoin{count, {process}}); }
// Called whenever any of the forked processes finishes. If the join counter reaches 0, the
// main process gets resumed
void done(const char* filename = VL_UNKNOWN, int lineno = 0);
// Used by coroutines for co_awaiting a join
auto join(const char* filename = VL_UNKNOWN, int lineno = 0) {
auto join(VlProcessRef process, const char* filename = VL_UNKNOWN, int lineno = 0) {
assert(m_join);
VL_DEBUG_IF(
VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno););
struct Awaitable {
VlProcessRef process; // Data of the suspended process, null if not needed
const std::shared_ptr<VlJoin> join; // Join to await on
VlFileLineDebug fileline;
bool await_ready() { return join->m_counter == 0; } // Suspend if join still exists
void await_suspend(std::coroutine_handle<> coro) { join->m_susp = {coro, fileline}; }
void await_suspend(std::coroutine_handle<> coro) {
join->m_susp = {coro, process, fileline};
}
void await_resume() const {}
};
return Awaitable{m_join, VlFileLineDebug{filename, lineno}};
return Awaitable{process, m_join, VlFileLineDebug{filename, lineno}};
}
};
+7 -4
View File
@@ -75,7 +75,7 @@ public:
// Get an element from the front of the queue. Blocks if none available
T get() VL_MT_SAFE_EXCLUDES(m_mutex) {
VerilatedLockGuard lock{m_mutex};
m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
m_cv.wait(m_mutex, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
assert(!m_queue.empty());
T value = m_queue.front();
m_queue.pop_front();
@@ -447,7 +447,9 @@ public:
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
}
VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) {
const uint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval;
QData old;
std::memcpy(&old, oldp, sizeof(old));
const uint64_t diff = old ^ newval;
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
}
VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WData* newvalp, int bits) {
@@ -460,8 +462,9 @@ public:
}
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); }
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
double old;
std::memcpy(&old, oldp, sizeof(old));
if (VL_UNLIKELY(old != newval)) fullDouble(oldp, newval);
}
};
+3 -3
View File
@@ -482,7 +482,7 @@ VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWorkerData::wa
// We have been spinning for a while, so yield the thread
VerilatedLockGuard lock{m_mutex};
m_waiting = true;
m_cv.wait(lock, [this] { return m_ready.load(std::memory_order_relaxed); });
m_cv.wait(m_mutex, [this] { return m_ready.load(std::memory_order_relaxed); });
m_waiting = false;
}
@@ -872,7 +872,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
*reinterpret_cast<QData*>(oldp) = newval;
std::memcpy(oldp, &newval, sizeof(newval));
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitQData(code, newval, bits);
}
@@ -888,7 +888,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullWData(uint32_t* oldp, const WData* newv
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) {
const uint32_t code = oldp - m_sigs_oldvalp;
*reinterpret_cast<double*>(oldp) = newval;
std::memcpy(oldp, &newval, sizeof(newval));
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
// cppcheck-suppress invalidPointerCast
emitDouble(code, newval);
+332 -21
View File
@@ -73,15 +73,45 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
#define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits
#define VL_OUTW(name, msb, lsb, words) VlWide<words> name ///< Declare output signal, 65+ bits
//===================================================================
// VlProcess stores metadata of running processes
class VlProcess final {
// MEMBERS
int m_state; // Current state of the process
public:
// TYPES
enum : int { // Type int for compatibility with $c
FINISHED = 0,
RUNNING = 1,
WAITING = 2,
SUSPENDED = 3,
KILLED = 4,
};
// CONSTRUCTORS
VlProcess()
: m_state{RUNNING} {}
// METHODS
int state() { return m_state; }
void state(int s) { m_state = s; }
};
using VlProcessRef = std::shared_ptr<VlProcess>;
inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); }
//===================================================================
// Activity trigger vector
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
@@ -91,10 +121,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 {
@@ -104,13 +142,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];
}
};
@@ -136,14 +174,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;
std::string get_randstate() const VL_MT_UNSAFE;
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;
@@ -152,6 +210,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
@@ -370,18 +433,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();
@@ -389,6 +451,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;
@@ -404,6 +470,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(); }
@@ -445,7 +517,7 @@ public:
template <typename Func>
VlQueue unique(Func with_func) const {
VlQueue out;
std::set<T_Value> saw;
std::set<decltype(with_func(0, m_deque[0]))> saw;
for (const auto& i : m_deque) {
const auto i_mapped = with_func(0, i);
const auto it = saw.find(i_mapped);
@@ -474,7 +546,7 @@ public:
VlQueue<IData> unique_index(Func with_func) const {
VlQueue<IData> out;
IData index = 0;
std::unordered_set<T_Value> saw;
std::set<decltype(with_func(0, m_deque[0]))> saw;
for (const auto& i : m_deque) {
const auto i_mapped = with_func(index, i);
auto it = saw.find(i_mapped);
@@ -788,6 +860,22 @@ public:
}
return out;
}
template <typename Func>
VlQueue<T_Value> unique(Func with_func) const {
VlQueue<T_Value> out;
T_Key default_key;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw;
for (const auto& i : m_map) {
const auto i_mapped = with_func(default_key, i.second);
const auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i.second);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
std::set<T_Key> saw;
@@ -801,6 +889,21 @@ public:
return out;
}
template <typename Func>
VlQueue<T_Key> unique_index(Func with_func) const {
VlQueue<T_Key> out;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw;
for (const auto& i : m_map) {
const auto i_mapped = with_func(i.first, i.second);
auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i.first);
}
}
return out;
}
template <typename Func>
VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
for (const auto& i : m_map)
@@ -861,6 +964,16 @@ public:
});
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element(
m_map.begin(), m_map.end(),
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
@@ -870,6 +983,16 @@ public:
});
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
m_map.begin(), m_map.end(),
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
@@ -998,9 +1121,15 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
template <class T_Value, std::size_t T_Depth>
struct VlUnpacked final {
private:
// TYPES
using T_Key = IData; // Index type, for uniformity with other containers
using Unpacked = T_Value[T_Depth];
public:
// MEMBERS
// This should be the only data member, otherwise generated static initializers need updating
T_Value m_storage[T_Depth]; // Contents of the unpacked array
Unpacked m_storage; // Contents of the unpacked array
// CONSTRUCTORS
// Default constructors and destructor are used. Note however that C++20 requires that
@@ -1011,6 +1140,7 @@ struct VlUnpacked final {
// Default copy assignment operators are used.
// METHODS
public:
// Raw access
WData* data() { return &m_storage[0]; }
const WData* data() const { return &m_storage[0]; }
@@ -1023,6 +1153,170 @@ struct VlUnpacked final {
bool neq(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(*this, that); }
// Similar to 'neq' above, *this = that used for change detection
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); }
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) { return neq(that); }
void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); }
template <typename Func>
void sort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(std::begin(m_storage), std::end(m_storage),
[=](const T_Value& a, const T_Value& b) {
// index number is meaningless with sort, as it changes
return with_func(0, a) < with_func(0, b);
});
}
// std::rbegin/std::rend not available until C++14
void rsort() {
std::sort(std::begin(m_storage), std::end(m_storage), std::greater<T_Value>());
}
template <typename Func>
void rsort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
// std::rbegin/std::rend not available until C++14, so using > below
std::sort(std::begin(m_storage), std::end(m_storage),
[=](const T_Value& a, const T_Value& b) {
// index number is meaningless with sort, as it changes
return with_func(0, a) > with_func(0, b);
});
}
void reverse() { std::reverse(std::begin(m_storage), std::end(m_storage)); }
void shuffle() { std::shuffle(std::begin(m_storage), std::end(m_storage), VlURNG{}); }
VlQueue<T_Value> unique() const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_storage) {
const auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(i);
}
}
return out;
}
template <typename Func>
VlQueue<T_Value> unique(Func with_func) const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_storage) {
const auto i_mapped = with_func(0, i);
const auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
IData index = 0;
std::set<T_Value> saw;
for (const auto& i : m_storage) {
const auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Key> unique_index(Func with_func) const {
VlQueue<T_Key> out;
IData index = 0;
std::unordered_set<T_Value> saw;
for (const auto& i : m_storage) {
const auto i_mapped = with_func(index, i);
auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) out.push_back(i);
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> out;
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) out.push_back(index);
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Value> find_first(Func with_func) const {
// Can't use std::find_if as need index number
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<T_Value>::cons(i);
++index;
}
return VlQueue<T_Value>{};
}
template <typename Func>
VlQueue<T_Key> find_first_index(Func with_func) const {
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
++index;
}
return VlQueue<T_Key>{};
}
template <typename Func>
VlQueue<T_Value> find_last(Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::cons(m_storage[i]);
}
return VlQueue<T_Value>{};
}
template <typename Func>
VlQueue<T_Key> find_last_index(Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<IData>::cons(i);
}
return VlQueue<T_Key>{};
}
// Reduction operators
VlQueue<T_Value> min() const {
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::cons(*it);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage),
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue<T_Value>::cons(*it);
}
VlQueue<T_Value> max() const {
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::cons(*it);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage),
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue<T_Value>::cons(*it);
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
@@ -1096,7 +1390,7 @@ public:
}
// Deletes all queued garbage objects.
void deleteAll() VL_MT_SAFE;
void deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_MT_SAFE;
};
//===================================================================
@@ -1166,7 +1460,8 @@ 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)
// () required here to avoid narrowing conversion warnings,
@@ -1188,6 +1483,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
@@ -1233,8 +1538,14 @@ public:
// For 'if (ptr)...'
operator bool() const { return m_objp; }
// In SV A == B iff both are handles to the same object (IEEE 1800-2017 8.4)
bool operator==(const VlClassRef& rhs) const { return m_objp == rhs.m_objp; };
bool operator!=(const VlClassRef& rhs) const { return m_objp != rhs.m_objp; };
template <typename T_OtherClass>
bool operator==(const VlClassRef<T_OtherClass>& rhs) const {
return m_objp == rhs.m_objp;
};
template <typename T_OtherClass>
bool operator!=(const VlClassRef<T_OtherClass>& rhs) const {
return m_objp != rhs.m_objp;
};
};
template <typename T, typename U>
+2 -26
View File
@@ -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
@@ -420,28 +410,14 @@ void VerilatedVcd::dumpHeader() {
if (*np == ' ') np++;
if (*np == '\t') break; // tab means signal name starts
printIndent(1);
// Find character after name end
const char* sp = np;
while (*sp && *sp != ' ' && *sp != '\t' && !(*sp & '\x80')) sp++;
printStr("$scope ");
if (*sp & '\x80') {
switch (*sp & 0x7f) {
case VLT_TRACE_SCOPE_STRUCT: printStr("struct "); break;
case VLT_TRACE_SCOPE_INTERFACE: printStr("interface "); break;
case VLT_TRACE_SCOPE_UNION: printStr("union "); break;
default: printStr("module ");
}
} else {
printStr("module ");
}
printStr("$scope module ");
for (; *np && *np != ' ' && *np != '\t'; np++) {
if (*np == '[') {
printStr("[");
} else if (*np == ']') {
printStr("]");
} else if (!(*np & '\x80')) {
} else {
*m_writep++ = *np;
}
}
+9 -9
View File
@@ -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 )
+21 -26
View File
@@ -165,6 +165,7 @@ class VerilatedVpioVarBase VL_NOT_FINAL : public VerilatedVpio {
protected:
const VerilatedVar* m_varp = nullptr;
const VerilatedScope* m_scopep = nullptr;
std::string m_fullname;
const VerilatedRange& get_range() const {
// Determine number of dimensions and return outermost
return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed();
@@ -173,11 +174,13 @@ protected:
public:
VerilatedVpioVarBase(const VerilatedVar* varp, const VerilatedScope* scopep)
: m_varp{varp}
, m_scopep{scopep} {}
, m_scopep{scopep}
, m_fullname{std::string{m_scopep->name()} + '.' + name()} {}
explicit VerilatedVpioVarBase(const VerilatedVpioVarBase* varp) {
if (varp) {
m_varp = varp->m_varp;
m_scopep = varp->m_scopep;
m_fullname = varp->m_fullname;
}
}
static VerilatedVpioVarBase* castp(vpiHandle h) {
@@ -188,11 +191,7 @@ public:
uint32_t size() const override { return get_range().elements(); }
const VerilatedRange* rangep() const override { return &get_range(); }
const char* name() const override { return m_varp->name(); }
const char* fullname() const override {
static thread_local std::string t_out;
t_out = std::string{m_scopep->name()} + "." + name();
return t_out.c_str();
}
const char* fullname() const override { return m_fullname.c_str(); }
};
class VerilatedVpioParam final : public VerilatedVpioVarBase {
@@ -646,23 +645,21 @@ public:
continue;
}
VerilatedVpiCbHolder& ho = *it++;
if (VerilatedVpioVar* const varop = VerilatedVpioVar::castp(ho.cb_datap()->obj)) {
void* const newDatap = varop->varDatap();
void* const prevDatap
= varop->prevDatap(); // Was malloced when we added the callback
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n",
varop->fullname(), *(static_cast<CData*>(newDatap)),
*(static_cast<CData*>(prevDatap)), newDatap,
prevDatap););
if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n",
ho.id(), varop->fullname(),
*(static_cast<CData*>(newDatap))););
update.insert(varop);
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
(ho.cb_rtnp())(ho.cb_datap());
called = true;
}
VerilatedVpioVar* const varop
= reinterpret_cast<VerilatedVpioVar*>(ho.cb_datap()->obj);
void* const newDatap = varop->varDatap();
void* const prevDatap = varop->prevDatap(); // Was malloced when we added the callback
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n",
varop->fullname(), *(static_cast<CData*>(newDatap)),
*(static_cast<CData*>(prevDatap)), newDatap, prevDatap););
if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n",
ho.id(), varop->fullname(),
*(static_cast<CData*>(newDatap))););
update.insert(varop);
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
(ho.cb_rtnp())(ho.cb_datap());
called = true;
}
if (was_last) break;
}
@@ -791,7 +788,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 +798,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,
@@ -2312,7 +2307,7 @@ PLI_INT32 vpi_flush(void) {
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
Verilated::runFlushCallbacks();
return 0;
return 0; // Gcc coverage bug // LCOV_EXCL_LINE
}
PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
+87 -68
View File
@@ -37,8 +37,13 @@
//=========================================================================
// Compiler pragma abstraction
#if defined(__clang__)
# define VL_CLANG_ATTR(attr) __attribute__(( attr ))
#else
# define VL_CLANG_ATTR(attr)
#endif
#ifdef __GNUC__
# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment)))
# define VL_ATTR_ALWINLINE __attribute__((always_inline)) inline
# define VL_ATTR_NOINLINE __attribute__((noinline))
# define VL_ATTR_COLD __attribute__((cold))
@@ -57,19 +62,6 @@
// All VL_ATTR_WEAK symbols must be marked with the macOS -U linker flag in verilated.mk.in
# define VL_ATTR_WEAK __attribute__((weak))
# endif
# if defined(__clang__)
# define VL_ACQUIRE(...) __attribute__((annotate("ACQUIRE"))) __attribute__((acquire_capability(__VA_ARGS__)))
# define VL_ACQUIRE_SHARED(...) __attribute__((annotate("ACQUIRE_SHARED"))) __attribute__((acquire_shared_capability(__VA_ARGS__)))
# define VL_RELEASE(...) __attribute__((annotate("RELEASE"))) __attribute__((release_capability(__VA_ARGS__)))
# define VL_RELEASE_SHARED(...) __attribute__((annotate("RELEASE_SHARED"))) __attribute__((release_shared_capability(__VA_ARGS__)))
# define VL_TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__)))
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
# define VL_CAPABILITY(x) __attribute__((capability(x)))
# define VL_REQUIRES(x) __attribute__((annotate("REQUIRES"))) __attribute__((requires_capability(x)))
# define VL_GUARDED_BY(x) __attribute__((annotate("GUARDED_BY"))) __attribute__((guarded_by(x)))
# define VL_EXCLUDES(x) __attribute__((annotate("EXCLUDES"))) __attribute__((locks_excluded(x)))
# define VL_SCOPED_CAPABILITY __attribute__((scoped_lockable))
# endif
# define VL_LIKELY(x) __builtin_expect(!!(x), 1) // Prefer over C++20 [[likely]]
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0) // Prefer over C++20 [[unlikely]]
# define VL_UNREACHABLE __builtin_unreachable() // C++23 std::unreachable()
@@ -77,10 +69,62 @@
# define VL_PREFETCH_RW(p) __builtin_prefetch((p), 1)
#endif
// Function acquires a capability/lock (-fthread-safety)
#define VL_ACQUIRE(...) \
VL_CLANG_ATTR(annotate("ACQUIRE")) \
VL_CLANG_ATTR(acquire_capability(__VA_ARGS__))
// Function acquires a shared capability/lock (-fthread-safety)
#define VL_ACQUIRE_SHARED(...) \
VL_CLANG_ATTR(annotate("ACQUIRE_SHARED")) \
VL_CLANG_ATTR(acquire_shared_capability(__VA_ARGS__))
// Function releases a capability/lock (-fthread-safety)
#define VL_RELEASE(...) \
VL_CLANG_ATTR(annotate("RELEASE")) \
VL_CLANG_ATTR(release_capability(__VA_ARGS__))
// Function releases a shared capability/lock (-fthread-safety)
#define VL_RELEASE_SHARED(...) \
VL_CLANG_ATTR(annotate("RELEASE_SHARED")) \
VL_CLANG_ATTR(release_shared_capability(__VA_ARGS__))
// Function returns bool if acquired a capability (-fthread-safety)
#define VL_TRY_ACQUIRE(...) \
VL_CLANG_ATTR(try_acquire_capability(__VA_ARGS__))
// Function returns bool if acquired shared (-fthread-safety)
#define VL_TRY_ACQUIRE_SHARED(...) \
VL_CLANG_ATTR(try_acquire_shared_capability(__VA_ARGS__))
// Function requires a capability inbound (-fthread-safety)
#define VL_CAPABILITY(x) \
VL_CLANG_ATTR(capability(x))
// Function requires not having a capability inbound (-fthread-safety)
#define VL_REQUIRES(x) \
VL_CLANG_ATTR(annotate("REQUIRES")) \
VL_CLANG_ATTR(requires_capability(x))
// Name of capability/lock (-fthread-safety)
#define VL_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("GUARDED_BY")) \
VL_CLANG_ATTR(guarded_by(x))
// The data that the annotated pointer points to is protected by the given capability.
// The pointer itself is not protected.
// Allowed on: pointer data member. (-fthread-safety)
#define VL_PT_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \
VL_CLANG_ATTR(pt_guarded_by(x))
// Name of mutex protecting this variable (-fthread-safety)
#define VL_EXCLUDES(x) \
VL_CLANG_ATTR(annotate("EXCLUDES")) \
VL_CLANG_ATTR(locks_excluded(x))
// Scoped threaded capability/lock (-fthread-safety)
#define VL_SCOPED_CAPABILITY \
VL_CLANG_ATTR(scoped_lockable)
// Annotated function returns reference to the given capability.
// Allowed on: function, method. (-fthread-safety)
#define VL_RETURN_CAPABILITY(x) \
VL_CLANG_ATTR(lock_returned(x))
// Assert that capability is already held.
// Allowed on: function, method. (-fthread-safety)
#define VL_ASSERT_CAPABILITY(x) \
VL_CLANG_ATTR(assert_capability(x))
// Defaults for unsupported compiler features
#ifndef VL_ATTR_ALIGNED
# define VL_ATTR_ALIGNED(alignment) ///< Attribute to align structure to byte alignment
#endif
#ifndef VL_ATTR_ALWINLINE
# define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing
#endif
@@ -111,19 +155,6 @@
#ifndef VL_ATTR_WEAK
# define VL_ATTR_WEAK ///< Attribute that function external that is optionally defined
#endif
#ifndef VL_CAPABILITY
# define VL_ACQUIRE(...) ///< Function acquires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function acquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if acquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if acquired shared (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
#endif
#ifndef VL_LIKELY
# define VL_LIKELY(x) (!!(x)) ///< Return boolean expression that is more often true
# define VL_UNLIKELY(x) (!!(x)) ///< Return boolean expression that is more often false
@@ -142,6 +173,7 @@
#ifndef VL_NO_LEGACY
# define VL_ATTR_ALIGNED(alignment) // Deprecated
# define VL_FUNC __func__ // Deprecated
# define VL_THREAD // Deprecated
# define VL_THREAD_LOCAL thread_local // Deprecated
@@ -149,49 +181,24 @@
#endif
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
#if defined(__clang__)
# define VL_PURE __attribute__((annotate("PURE")))
#else
# define VL_PURE
#endif
#define VL_PURE VL_CLANG_ATTR(annotate("PURE"))
// Comment tag that function is threadsafe
#if defined(__clang__)
# define VL_MT_SAFE __attribute__((annotate("MT_SAFE")))
#else
# define VL_MT_SAFE
#endif
#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE"))
// Comment tag that function is threadsafe, only if
// other threads doesn't change tree topology
#define VL_MT_STABLE VL_CLANG_ATTR(annotate("MT_STABLE"))
// Comment tag that function is threadsafe, only
// during normal operation (post-init)
#if defined(__clang__)
# define VL_MT_SAFE_POSTINIT __attribute__((annotate("MT_SAFE_POSTINIT")))
#else
# define VL_MT_SAFE_POSTINIT
#endif
#define VL_MT_SAFE_POSTINIT VL_CLANG_ATTR(annotate("MT_SAFE_POSTINIT"))
// Attribute that function is clang threadsafe and uses given mutex
#if defined(__clang__)
# define VL_MT_SAFE_EXCLUDES(mutex) __attribute__((annotate("MT_SAFE_EXCLUDES"))) VL_EXCLUDES(mutex)
#else
# define VL_MT_SAFE_EXCLUDES(mutex) VL_EXCLUDES(mutex)
#endif
#define VL_MT_SAFE_EXCLUDES(mutex) VL_CLANG_ATTR(annotate("MT_SAFE_EXCLUDES")) VL_EXCLUDES(mutex)
// Comment tag that function is not threadsafe
#if defined(__clang__)
# define VL_MT_UNSAFE __attribute__((annotate("MT_UNSAFE")))
#else
# define VL_MT_UNSAFE
#endif
#define VL_MT_UNSAFE VL_CLANG_ATTR(annotate("MT_UNSAFE"))
// Comment tag that function is not threadsafe
// protected to make sure single-caller
#if defined(__clang__)
# define VL_MT_UNSAFE_ONE __attribute__((annotate("MT_UNSAFE_ONE")))
#else
# define VL_MT_UNSAFE_ONE
#endif
#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE"))
// Comment tag that function is entry point of parallelization
#if defined(__clang__)
# define VL_MT_START __attribute__((annotate("MT_START")))
#else
# define VL_MT_START
#endif
#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START"))
#ifndef VL_NO_LEGACY
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated)
@@ -317,6 +324,7 @@ extern "C" void __gcov_dump();
// Now that C++ requires these standard types the vl types are deprecated
#include <cstdint>
#include <cinttypes>
#include <cmath>
#ifndef VL_NO_LEGACY
using vluint8_t = uint8_t; ///< 8-bit unsigned type (backward compatibility)
@@ -441,11 +449,14 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
#define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad
/// Return mask for words with 1's where relevant bits are (0=all bits)
/// Arguments must not have side effects
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
/// Return mask for quads with 1's where relevant bits are (0=all bits)
/// Arguments must not have side effects
#define VL_MASK_Q(nbits) \
(((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL)
/// Return mask for EData with 1's where relevant bits are (0=all bits)
/// Arguments must not have side effects
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
#define VL_EUL(n) VL_UL(n) // Make constant number EData sized
@@ -467,8 +478,12 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
// #defines, to avoid requiring math.h on all compile runs
#ifdef _MSC_VER
# define VL_TRUNC(n) (((n) < 0) ? std::ceil((n)) : std::floor((n)))
# define VL_ROUND(n) (((n) < 0) ? std::ceil((n)-0.5) : std::floor((n) + 0.5))
static inline double VL_TRUNC(double n) {
return (n < 0) ? std::ceil(n) : std::floor(n);
}
static inline double VL_ROUND(double n) {
return (n < 0) ? std::ceil(n-0.5) : std::floor(n + 0.5);
}
#else
# define VL_TRUNC(n) std::trunc(n)
# define VL_ROUND(n) std::round(n)
@@ -596,8 +611,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;
}
+138 -45
View File
@@ -33,10 +33,31 @@ def fully_qualified_name(node):
return [node.displayname] if node.displayname else []
# Returns True, if `class_node` contains node
# that matches `member` spelling
def check_class_member_exists(class_node, member):
for child in class_node.get_children():
if member.spelling == child.spelling:
return True
return False
# Returns Base class (if found) of `class_node`
# that is of type `base_type`
def get_base_class(class_node, base_type):
for child in class_node.get_children():
if child.kind is CursorKind.CXX_BASE_SPECIFIER:
base_class = child.type
if base_type.spelling == base_class.spelling:
return base_class
return None
@dataclass
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 +69,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 +92,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 +123,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 +227,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,7 +271,10 @@ class CallAnnotationsValidator:
self._call_location: Optional[FunctionInfo] = None
self._caller: Optional[FunctionInfo] = None
self._level: int = 0
self._constructor_context: int = 0
self._constructor_context: list[clang.cindex.Cursor] = []
def is_constructor_context(self):
return len(self._constructor_context) > 0
def compile_and_analyze_file(self, source_file: str,
compiler_args: list[str],
@@ -329,7 +364,7 @@ class CallAnnotationsValidator:
return None
refn = find_object_ref(node)
if self._constructor_context and not refn:
if self.is_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
@@ -341,20 +376,44 @@ class CallAnnotationsValidator:
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:
if refna.guarded:
is_mt_safe = True
if self.is_constructor_context() and refn.semantic_parent:
# we are in constructor, so calling local members is MT_SAFE,
# make sure object that we are calling is local to the constructor
constructor_class = self._constructor_context[
-1].semantic_parent
if refn.semantic_parent.spelling == constructor_class.spelling:
if check_class_member_exists(constructor_class, refn):
is_mt_safe = True
else:
# check if this class inherits from some base class
base_class = get_base_class(constructor_class,
refn.semantic_parent)
if base_class:
if check_class_member_exists(
base_class.get_declaration(), refn):
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
if refn.get_definition():
if refn.referenced.semantic_parent:
if refn.referenced.semantic_parent.kind in [
CursorKind.FUNCTION_DECL, CursorKind.CXX_METHOD
]:
# This is 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
else:
# Global variable in different translation unit, unsafe
pass
elif refn and refn.kind == CursorKind.CALL_EXPR:
if self._constructor_context:
if self.is_constructor_context():
# call to local function from constructor context
# safe if this function also calling local methods or
# MT-safe methods
@@ -377,6 +436,17 @@ class CallAnnotationsValidator:
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(
@@ -394,6 +464,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():
@@ -408,11 +489,18 @@ class CallAnnotationsValidator:
# 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
if ctx.is_mt_safe_context() or self.is_constructor_context():
self._constructor_context.append(refd)
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
self._constructor_context -= 1
self._constructor_context.pop()
# stable tree context
if ctx.is_stabe_tree_context():
self._constructor_context.append(refd)
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
self._constructor_context.pop()
# pure context
if ctx.is_pure_context():
@@ -428,11 +516,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)
@@ -444,47 +540,40 @@ class CallAnnotationsValidator:
or refd.kind == CursorKind.CXX_METHOD
and refd.is_static_method()):
self.process_function_call(refd, annotations)
self.iterate_children(node.get_children(),
self.dispatch_node_inside_definition)
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)
self.iterate_children(node.get_children(),
self.dispatch_node_inside_definition)
return
# Non-static class methods
if refd.kind == CursorKind.CXX_METHOD:
elif refd.kind == CursorKind.CXX_METHOD:
self.process_method_call(node, refd, annotations)
self.iterate_children(node.get_children(),
self.dispatch_node_inside_definition)
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)
self.iterate_children(node.get_children(),
self.dispatch_node_inside_definition)
return
# Constructors
if refd.kind == CursorKind.CONSTRUCTOR:
elif refd.kind == CursorKind.CONSTRUCTOR:
self.process_constructor_call(refd, annotations)
self.iterate_children(node.get_children(),
self.dispatch_node_inside_definition)
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(),
@@ -519,12 +608,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 = None
self._call_location = prev_call_location
self._caller = prev_call_location
return None
@@ -788,6 +879,8 @@ class TopDownSummaryPrinter():
name += "is mtsafe but calls non-mtsafe function(s)"
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)"
+1 -1
View File
@@ -1,6 +1,6 @@
*~
*.old
config_build.h
config_package.h
Makefile
Makefile_obj
.objcache*
+4 -2
View File
@@ -82,6 +82,7 @@ set(HEADERS
V3File.h
V3FileLine.h
V3Force.h
V3Fork.h
V3FunctionTraits.h
V3Gate.h
V3Global.h
@@ -227,6 +228,7 @@ set(COMMON_SOURCES
V3File.cpp
V3FileLine.cpp
V3Force.cpp
V3Fork.cpp
V3Gate.cpp
V3Global.cpp
V3Graph.cpp
@@ -322,7 +324,7 @@ file(TO_NATIVE_PATH ${srcdir}/../bin/verilator_includer VERILATOR_INCLUDER)
file(TO_NATIVE_PATH ${srcdir}/vlcovgen VLCOVGEN)
file(TO_NATIVE_PATH ${srcdir}/config_rev CONFIG_REV)
configure_file(config_build.h.in config_build.h @ONLY)
configure_file(config_package.h.in config_package.h @ONLY)
add_custom_command(
OUTPUT V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h
@@ -414,7 +416,7 @@ foreach(astgen_name ${ASTGENERATED_NAMES})
MAIN_DEPENDENCY ${astgen_name}.cpp
DEPENDS ${ASTGEN} V3Ast.h
COMMAND ${PYTHON3} ARGS
${ASTGEN} -I"${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp
)
list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp)
endforeach()
+1 -1
View File
@@ -95,7 +95,7 @@ clean mostlyclean distclean maintainer-clean::
-rm -f .objcache*
distclean maintainer-clean::
-rm -f Makefile Makefile_obj config_build.h
-rm -f Makefile Makefile_obj config_package.h
maintainer-clean::
-rm -f config_rev.h
+2
View File
@@ -92,6 +92,7 @@ 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
@@ -204,6 +205,7 @@ RAW_OBJS = \
V3File.o \
V3FileLine.o \
V3Force.o \
V3Fork.o \
V3Gate.o \
V3Global.o \
V3Graph.o \
+13 -10
View File
@@ -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; }
};
@@ -183,7 +183,7 @@ public:
<< " (not all control paths of combinational always assign a value)\n"
<< nodep->warnMore()
<< "... Suggest use of always_latch for intentional latches");
if (dumpGraph() >= 9) dumpDotFilePrefixed("latch_" + vrp->name());
if (dumpGraphLevel() >= 9) dumpDotFilePrefixed("latch_" + vrp->name());
}
vertp->user(false); // Clear again (see above)
vrp->varp()->isLatched(latch_detected);
@@ -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:
@@ -320,7 +320,8 @@ private:
// VISITORS
void visit(AstVarRef* nodep) override {
const AstVar* const varp = nodep->varp();
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) {
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()
&& !varp->isFuncLocalSticky()) {
m_graph.addAssignment(nodep);
}
}
@@ -329,20 +330,22 @@ 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);
} else {
iterateChildrenConst(nodep);
}
}
//--------------------
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;
@@ -652,5 +655,5 @@ public:
void V3Active::activeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("active", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeLevel() >= 3);
}
+1 -1
View File
@@ -145,5 +145,5 @@ public:
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveTopVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeLevel() >= 3);
}
+20 -10
View File
@@ -20,6 +20,7 @@
#include "V3Assert.h"
#include "V3Ast.h"
#include "V3Error.h"
#include "V3Global.h"
#include "V3Stats.h"
@@ -51,14 +52,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()) {
@@ -148,7 +157,7 @@ private:
sentreep->unlinkFrBack();
if (m_procedurep) {
// To support this need queue of asserts to activate
nodep->v3error("Unsupported: Procedural concurent assertion with"
nodep->v3error("Unsupported: Procedural concurrent assertion with"
" clocking event inside always (IEEE 1800-2917 16.14.6)");
}
}
@@ -182,7 +191,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
@@ -419,9 +428,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();
@@ -535,5 +545,5 @@ public:
void V3Assert::assertAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assert", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeLevel() >= 3);
}
-1
View File
@@ -21,7 +21,6 @@
#include "verilatedos.h"
#include "V3Ast.h"
#include "V3Error.h"
//============================================================================
+3 -3
View File
@@ -229,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(
@@ -238,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();
@@ -496,5 +496,5 @@ public:
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertPreVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeLevel() >= 3);
}
+55 -34
View File
@@ -155,7 +155,7 @@ 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.reserve(namein.length());
@@ -296,17 +296,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
@@ -345,7 +347,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;
@@ -395,7 +398,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);
}
@@ -563,8 +567,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;
}
@@ -578,7 +584,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) {
@@ -623,12 +633,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;
}
@@ -666,12 +679,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;
@@ -833,6 +846,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
@@ -907,7 +921,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);
@@ -948,13 +962,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) {
@@ -968,14 +982,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 {
@@ -1065,10 +1079,12 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
// private: Return true if the two trees are identical
if (!node1p && !node2p) return true;
if (!node1p || !node2p) return false;
if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep()
|| !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) {
return false;
}
if (node1p->type() != node2p->type()) return false;
UASSERT_OBJ(
(!node1p->dtypep() && !node2p->dtypep()) || (node1p->dtypep() && node2p->dtypep()), node1p,
"Comparison of a node with dtypep() with a node without dtypep()\n-node2=" << node2p);
if (node1p->dtypep() && !node1p->dtypep()->similarDType(node2p->dtypep())) return false;
if (!node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) return false;
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly)
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly)
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly)
@@ -1079,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()) {
@@ -1129,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");
}
}
@@ -1201,7 +1217,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
if (logsp->fail()) v3fatal("Can't write " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
if (editCountGbl() == editCountLast() && ::dumpTree() < 9) {
if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) {
*logsp << '\n';
*logsp << "No changes since last dump!\n";
} else {
@@ -1211,7 +1227,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
}
}
if (doDump && v3Global.opt.debugEmitV()) V3EmitV::debugEmitV(filename + ".v");
if (doCheck && (v3Global.opt.debugCheck() || ::dumpTree())) {
if (doCheck && (v3Global.opt.debugCheck() || ::dumpTreeLevel())) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
@@ -1342,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
@@ -1388,6 +1406,9 @@ AstNodeDType* AstNode::findQueueIndexDType() const {
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
AstNodeDType* AstNode::findStreamDType() const {
return v3Global.rootp()->typeTablep()->findStreamDType(fileline());
}
//######################################################################
// VNDeleter
+151 -91
View File
@@ -82,6 +82,17 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
// Ast<nodetypename>*' is returned.
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
// Same as VN_AS, but only checks the type in debug builds. Type checking is less critical in node
// child getters (the strongly-typed functions that wrap op*p pointers). This is because the op*p
// pointers are usually populated by code that already asserts the correct type. Having fewer type
// assertions yields better performance in release builds.
#ifdef VL_DEBUG
#define VN_DBG_AS(nodep, nodetypename) VN_AS(nodep, nodetypename)
#else
#define VN_DBG_AS(nodep, nodetypename) \
(AstNode::unsafePrivateAs<Ast##nodetypename, decltype(nodep)>(nodep))
#endif
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
#define VN_DELETED(nodep) VL_UNLIKELY((uint64_t)(nodep) == 0x1)
@@ -102,11 +113,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(); }
// ######################################################################
@@ -461,6 +472,7 @@ public:
TRIGGER_SCHEDULER,
DYNAMIC_TRIGGER_SCHEDULER,
FORK_SYNC,
PROCESS_REFERENCE,
// Unsigned and two state; fundamental types
UINT32,
UINT64,
@@ -470,7 +482,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",
@@ -493,6 +505,7 @@ public:
"VlTriggerScheduler",
"VlDynamicTriggerScheduler",
"VlFork",
"VlProcessRef",
"IData",
"QData",
"LOGIC_IMPLICIT",
@@ -500,13 +513,20 @@ public:
return names[m_e];
}
const char* dpiType() const {
static const char* const names[]
= {"%E-unk", "svBit", "char", "void*", "char",
"int", "%E-integer", "svLogic", "long long", "double",
"short", "%E-time", "const char*", "%E-untyped", "dpiScope",
"const char*", "%E-mtaskstate", "%E-triggervec", "%E-dly-sched", "%E-trig-sched",
"%E-dyn-sched", "%E-fork", "IData", "QData", "%E-logic-implct",
" MAX"};
static const char* const names[] = {"%E-unk", "svBit",
"char", "void*",
"char", "int",
"%E-integer", "svLogic",
"long long", "double",
"short", "%E-time",
"const char*", "%E-untyped",
"dpiScope", "const char*",
"%E-mtaskstate", "%E-triggervec",
"%E-dly-sched", "%E-trig-sched",
"%E-dyn-sched", "%E-fork",
"%E-proc-ref", "IData",
"QData", "%E-logic-implct",
" MAX"};
return names[m_e];
}
static void selfTest() {
@@ -545,6 +565,7 @@ public:
case TRIGGER_SCHEDULER: return 0; // opaque
case DYNAMIC_TRIGGER_SCHEDULER: return 0; // opaque
case FORK_SYNC: return 0; // opaque
case PROCESS_REFERENCE: return 0; // opaque
case UINT32: return 32;
case UINT64: return 64;
default: return 0;
@@ -584,7 +605,7 @@ public:
return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|| m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER
|| m_e == TRIGGER_SCHEDULER || m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC
|| m_e == DOUBLE || m_e == UNTYPED);
|| m_e == PROCESS_REFERENCE || m_e == DOUBLE || m_e == UNTYPED);
}
bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; }
bool isEvent() const { return m_e == EVENT; }
@@ -1097,21 +1118,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; }
@@ -1122,10 +1143,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
@@ -1373,13 +1394,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);
@@ -1387,21 +1433,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
};
//######################################################################
@@ -1426,6 +1461,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;
@@ -1545,7 +1587,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);
@@ -1601,14 +1643,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);
@@ -1655,7 +1697,7 @@ public:
static constexpr int INSTR_COUNT_PLI = 20; // PLI routines
// ACCESSORS
virtual string name() const VL_MT_SAFE { return ""; }
virtual string name() const { return ""; }
virtual string origName() const { return ""; }
virtual void name(const string& name) {
this->v3fatalSrc("name() called on object without name() method");
@@ -1663,22 +1705,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; // 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 { 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;
virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
FileLine* fileline() const VL_MT_SAFE { return m_fileline; }
void fileline(FileLine* fl) { m_fileline = fl; }
@@ -1697,25 +1740,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(); }
@@ -1724,12 +1767,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(); }
@@ -1738,12 +1781,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(); }
@@ -1752,12 +1795,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(); }
@@ -1766,12 +1809,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(); }
@@ -1795,6 +1838,7 @@ public:
// ACCESSORS for specific types
// Alas these can't be virtual or they break when passed a nullptr
inline bool isClassHandleValue() const;
inline bool isZero() const;
inline bool isOne() const;
inline bool isNeqZero() const;
@@ -1834,6 +1878,7 @@ public:
void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate
void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); }
void dtypeSetVoid() { dtypep(findVoidDType()); }
void dtypeSetStream() { dtypep(findStreamDType()); }
// Data type locators
AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); }
@@ -1845,6 +1890,7 @@ public:
AstNodeDType* findCHandleDType() const { return findBasicDType(VBasicDTypeKwd::CHANDLE); }
AstNodeDType* findEmptyQueueDType() const;
AstNodeDType* findVoidDType() const;
AstNodeDType* findStreamDType() const;
AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
@@ -1893,8 +1939,6 @@ public:
// Iterate and insert - assumes tree format
virtual void addNextStmt(AstNode* newp,
AstNode* belowp); // When calling, "this" is second argument
virtual void addBeforeStmt(AstNode* newp,
AstNode* belowp); // When calling, "this" is second argument
// METHODS - Iterate on a tree
// Clone or return nullptr if nullptr
@@ -1907,7 +1951,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;
@@ -1964,26 +2008,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'
@@ -1992,7 +2037,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;
@@ -2001,7 +2046,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;
@@ -2033,24 +2078,34 @@ public:
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
}
// For use via the VN_AS macro only
// For use via privateAs or the VN_DBG_AS macro only
template <typename T, typename E>
static T* privateAs(AstNode* nodep) VL_MT_SAFE {
static T* unsafePrivateAs(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,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return reinterpret_cast<T*>(nodep);
}
template <typename T, typename E>
static const T* privateAs(const AstNode* nodep) VL_MT_SAFE {
static const T* unsafePrivateAs(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.");
return reinterpret_cast<const T*>(nodep);
}
// For use via the VN_AS macro only
template <typename T, typename E>
static T* privateAs(AstNode* nodep) VL_PURE {
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return reinterpret_cast<const T*>(nodep);
return unsafePrivateAs<T, E>(nodep);
}
template <typename T, typename E>
static const T* privateAs(const AstNode* nodep) VL_PURE {
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return unsafePrivateAs<T, E>(nodep);
}
// Predicate that returns true if the given 'nodep' might have a descendant of type 'T_Node'.
@@ -2483,24 +2538,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);
}
+26 -18
View File
@@ -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,14 +33,18 @@ 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::isClassHandleValue() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNull())
|| VN_IS(dtypep(), ClassRefDType);
}
bool AstNode::isZero() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
}
@@ -61,12 +65,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 +82,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 +127,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(); }
@@ -150,12 +154,15 @@ AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool clea
}
AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {}
: ASTGEN_SUPER_VarRef(fl, varp, access) {}
// This form only allowed post-link (see above)
AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) {
: ASTGEN_SUPER_VarRef(fl, varscp->varp(), access) {
varScopep(varscp);
}
string AstVarRef::name() const { return varp() ? varp()->name() : "<null>"; }
bool AstVarRef::same(const AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep() && access() == samep->access());
@@ -175,7 +182,8 @@ bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
}
AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access)
: ASTGEN_SUPER_VarXRef(fl, varp, access)
, m_name{varp->name()}
, m_dotted{dotted} {
dtypeFrom(varp);
}
+137 -103
View File
@@ -63,9 +63,9 @@ public:
// 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
@@ -86,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(); }
@@ -126,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;
// 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;
};
class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
@@ -170,40 +171,37 @@ 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
// @astgen op1 := membersp : List[AstMemberDType]
private:
// TYPES
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;
AstNodeModule* m_classOrPackagep = nullptr; // Package it will be emitted with
const int m_uniqueNum;
bool m_packed;
bool m_isFourstate = false; // V3Width computes
@@ -231,7 +229,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)
@@ -241,20 +239,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; }
void clearCache() { m_members.clear(); }
void repairMemberCache();
AstMemberDType* findMember(const string& name) const {
const auto it = m_members.find(name);
return (it == m_members.end()) ? nullptr : it->second;
}
bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; }
static int lo() { return 0; }
int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange{hi(), lo()}; }
@@ -280,7 +272,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; }
@@ -336,7 +328,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; }
@@ -345,13 +337,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(); }
@@ -401,14 +393,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);
@@ -423,8 +412,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)
@@ -440,6 +429,7 @@ public:
bool isEvent() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::EVENT; }
bool isTriggerVec() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::TRIGGERVEC; }
bool isForkSync() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::FORK_SYNC; }
bool isProcessRef() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::PROCESS_REFERENCE; }
bool isDelayScheduler() const VL_MT_SAFE {
return keyword() == VBasicDTypeKwd::DELAY_SCHEDULER;
}
@@ -467,9 +457,9 @@ 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{}; }
@@ -491,13 +481,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); }
@@ -530,19 +520,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; }
};
@@ -578,13 +568,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(); }
@@ -625,18 +617,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; }
};
@@ -679,15 +673,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(); }
@@ -706,13 +700,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
@@ -756,17 +750,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; }
@@ -818,8 +814,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; }
@@ -872,7 +868,7 @@ public:
}
ASTGEN_MEMBERS_AstMemberDType;
void dumpSmall(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 hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
const char* broken() const override {
@@ -883,7 +879,10 @@ 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(); }
AstNodeUOrStructDType* getChildStructp() const;
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); }
@@ -891,10 +890,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)
@@ -931,9 +930,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 {
@@ -944,7 +945,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; }
@@ -967,8 +968,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
@@ -1022,17 +1023,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
@@ -1052,7 +1053,7 @@ private:
// Post-width typedefs are removed and point to type directly
AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef
string m_name; // Name of an AstTypedef
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Class/package in which it was defined
public:
AstRefDType(FileLine* fl, const string& name)
: ASTGEN_SUPER_RefDType(fl)
@@ -1067,6 +1068,7 @@ public:
AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp)
: ASTGEN_SUPER_RefDType(fl) {
this->typeofp(typeofp);
if (AstNodeDType* const dtp = VN_CAST(typeofp, NodeDType)) refDTypep(dtp);
}
ASTGEN_MEMBERS_AstRefDType;
// METHODS
@@ -1082,15 +1084,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();
@@ -1119,9 +1121,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); }
@@ -1163,19 +1165,49 @@ 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>); }
int widthTotalBytes() const override { return sizeof(std::map<std::string, std::string>); }
bool isCompound() const override { return true; }
};
class AstStreamDType final : public AstNodeDType {
// Stream data type, used only as data type of stream operations
// Should behave like AstPackArrayDType, but it doesn't have a size
public:
explicit AstStreamDType(FileLine* fl)
: ASTGEN_SUPER_StreamDType(fl) {
dtypep(this);
}
ASTGEN_MEMBERS_AstStreamDType;
void dumpSmall(std::ostream& str) const override;
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
bool undead() const override { return true; }
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_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
int widthAlignBytes() const override { return 1; }
int widthTotalBytes() const override { return 1; }
bool isCompound() const override { return false; }
};
class AstUnsizedArrayDType final : public AstNodeDType {
// Unsized/open-range Array data type, ie "some_dtype var_name []"
// @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width
@@ -1201,13 +1233,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(); }
@@ -1226,13 +1260,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
@@ -1266,15 +1300,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>); }
+130 -51
View File
@@ -214,7 +214,7 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
// @astgen op3 := pinsp : List[AstNodeExpr]
// @astgen op4 := scopeNamep : Optional[AstScopeName]
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the task
string m_name; // Name of variable
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
@@ -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; }
@@ -322,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 {
@@ -449,21 +449,18 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr {
VAccess m_access; // Left hand side assignment
AstVar* m_varp; // [AfterLink] Pointer to variable itself
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
string m_name; // Name of variable
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the variable
string m_selfPointer; // Output code object pointer (e.g.: 'this')
protected:
AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access)
AstNodeVarRef(VNType t, FileLine* fl, const VAccess& access)
: AstNodeExpr{t, fl}
, m_access{access}
, m_name{name} {
, m_access{access} {
varp(nullptr);
}
AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access)
: AstNodeExpr{t, fl}
, m_access{access}
, m_name{name} {
, m_access{access} {
// May have varp==nullptr
this->varp(varp);
}
@@ -474,8 +471,6 @@ public:
const char* broken() const override;
int instrCount() const override { return widthInstrs(); }
void cloneRelink() override;
string name() const override { 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
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
@@ -492,7 +487,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 =====================================================
@@ -532,7 +527,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(); }
@@ -610,7 +605,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);
@@ -644,7 +639,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
@@ -689,7 +684,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(""); }
@@ -710,7 +705,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(""); }
@@ -721,7 +716,7 @@ class AstClassOrPackageRef final : public AstNodeExpr {
private:
string m_name;
// Node not NodeModule to appease some early parser usage
AstNode* m_classOrPackageNodep; // Package hierarchy
AstNode* m_classOrPackageNodep; // Pointer to class/package referenced
public:
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
AstPin* paramsp)
@@ -746,7 +741,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;
@@ -975,6 +970,20 @@ public:
, m_num(this, 1, on) {
dtypeSetBit();
}
class All0 {};
AstConst(FileLine* fl, All0)
: ASTGEN_SUPER_Const(fl)
, m_num(this, "'0") {
initWithNumber();
fl->warnOff(V3ErrorCode::NEWERSTD, true);
}
class All1 {};
AstConst(FileLine* fl, All1)
: ASTGEN_SUPER_Const(fl)
, m_num(this, "'1") {
initWithNumber();
fl->warnOff(V3ErrorCode::NEWERSTD, true);
}
class Null {};
AstConst(FileLine* fl, Null)
: ASTGEN_SUPER_Const(fl)
@@ -990,7 +999,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(); }
@@ -1048,7 +1057,7 @@ public:
};
class AstEnumItemRef final : public AstNodeExpr {
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
AstNodeModule* m_classOrPackagep; // Package hierarchy
AstNodeModule* m_classOrPackagep; // Class/package in which it was defined
public:
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
: ASTGEN_SUPER_EnumItemRef(fl)
@@ -1058,7 +1067,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 {
@@ -1068,7 +1077,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; }
@@ -1092,7 +1101,7 @@ public:
// METHODS
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanOut() const override { return true; }
bool same(const AstNode*) const override { return true; }
};
class AstFError final : public AstNodeExpr {
@@ -1109,9 +1118,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)
@@ -1168,7 +1218,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(""); }
@@ -1365,7 +1415,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; }
};
@@ -1373,6 +1423,7 @@ class AstMemberSel final : public AstNodeExpr {
// @astgen op1 := fromp : AstNodeExpr
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
string m_name;
VAccess m_access; // Read or write, as in AstNodeVarRef
AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection
public:
AstMemberSel(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name)
@@ -1391,12 +1442,14 @@ 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; }
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool same(const AstNode* samep) const override { return true; } // dtype comparison does it
bool cleanOut() const override { return true; }
bool same(const AstNode* samep) const override;
int instrCount() const override { return widthInstrs(); }
AstVar* varp() const { return m_varp; }
void varp(AstVar* nodep) { m_varp = nodep; }
@@ -1456,7 +1509,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);
@@ -1533,7 +1586,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)
@@ -1579,6 +1632,26 @@ 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
@@ -1630,7 +1703,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();
@@ -1665,7 +1738,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(""); }
@@ -1836,7 +1909,7 @@ public:
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstStructSel final : public AstNodeExpr {
// Unpacked struct member access
// Unpacked struct/union member access
// Parents: math|stmt
// Children: varref, math
// @astgen op1 := fromp : AstNodeExpr
@@ -1850,11 +1923,14 @@ 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; }
bool cleanOut() const override {
// Not a union
return VN_IS(fromp()->dtypep()->skipRefp(), StructDType);
}
bool same(const AstNode* samep) const override {
const AstStructSel* const sp = static_cast<const AstStructSel*>(samep);
return m_name == sp->m_name;
@@ -1931,7 +2007,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
@@ -2047,14 +2123,14 @@ class AstWith final : public AstNodeExpr {
// Children: expression (equation establishing the with)
// @astgen op1 := indexArgRefp : AstLambdaArgRef
// @astgen op2 := valueArgRefp : AstLambdaArgRef
// @astgen op3 := exprp : AstNodeExpr
// @astgen op3 := exprp : List[AstNode]
public:
AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
AstNodeExpr* exprp)
: ASTGEN_SUPER_With(fl) {
this->indexArgRefp(indexArgRefp);
this->valueArgRefp(valueArgRefp);
this->exprp(exprp);
this->addExprp(exprp);
}
ASTGEN_MEMBERS_AstWith;
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -2159,7 +2235,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))";
}
@@ -2364,6 +2440,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(); }
@@ -2382,7 +2459,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 ""; }
@@ -4012,7 +4089,6 @@ public:
BROKEN_RTN(!fromp());
return nullptr;
}
void dump(std::ostream& str) const override;
};
class AstNew final : public AstNodeFTaskRef {
// New as constructor
@@ -4263,7 +4339,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 ""; }
@@ -4370,7 +4446,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 ""; }
@@ -4447,7 +4523,7 @@ 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";
@@ -4596,7 +4672,7 @@ public:
ASTGEN_MEMBERS_AstCvtPackString;
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)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
@@ -5274,15 +5350,15 @@ public:
class AstVarRef final : public AstNodeVarRef {
// A reference to a variable (lvalue or rvalue)
public:
AstVarRef(FileLine* fl, const string& name, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {}
// This form only allowed post-link because output/wire compression may
// lead to deletion of AstVar's
inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access);
// This form only allowed post-link (see above)
inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access);
ASTGEN_MEMBERS_AstVarRef;
inline string name() const override; // * = Var name
void dump(std::ostream& str) const override;
const char* broken() const override;
bool same(const AstNode* samep) const override;
inline bool same(const AstVarRef* samep) const;
inline bool sameNoLvalue(AstVarRef* samep) const;
@@ -5294,14 +5370,17 @@ public:
class AstVarXRef final : public AstNodeVarRef {
// A VarRef to something in another module before AstScope.
// Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope
string m_name;
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
public:
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, name, nullptr, access)
: ASTGEN_SUPER_VarXRef(fl, nullptr, access)
, m_name{name}
, m_dotted{dotted} {}
inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access);
ASTGEN_MEMBERS_AstVarXRef;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void dump(std::ostream& str) const override;
string dotted() const { return m_dotted; }
void dotted(const string& dotted) { m_dotted = dotted; }
+105 -125
View File
@@ -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(); }
@@ -86,6 +86,7 @@ private:
bool m_recursive : 1; // Recursive or part of recursion
bool m_underGenerate : 1; // Under generate (for warning)
bool m_virtual : 1; // Virtual method in class
bool m_needProcess : 1; // Implements part of a process that allocates std::process
VLifetime m_lifetime; // Lifetime
protected:
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
@@ -110,7 +111,8 @@ protected:
, m_pureVirtual{false}
, m_recursive{false}
, m_underGenerate{false}
, m_virtual{false} {
, m_virtual{false}
, m_needProcess{false} {
addStmtsp(stmtsp);
cname(name); // Might be overridden by dpi import/export
}
@@ -118,7 +120,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
@@ -170,6 +172,8 @@ public:
bool underGenerate() const { return m_underGenerate; }
void isVirtual(bool flag) { m_virtual = flag; }
bool isVirtual() const { return m_virtual; }
void setNeedProcess() { m_needProcess = true; }
bool needProcess() const { return m_needProcess; }
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
@@ -186,7 +190,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 {
@@ -234,7 +238,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; }
@@ -272,10 +276,13 @@ public:
class AstNodeProcedure VL_NOT_FINAL : public AstNode {
// IEEE procedure: initial, final, always
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only
bool m_suspendable = false; // Is suspendable by a Delay, EventControl, etc.
bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc.
bool m_needProcess : 1; // Implements part of a process that allocates std::process
protected:
AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp)
: AstNode{t, fl} {
m_needProcess = false;
m_suspendable = false;
addStmtsp(stmtsp);
}
@@ -286,6 +293,8 @@ public:
bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); }
bool isSuspendable() const { return m_suspendable; }
void setSuspendable() { m_suspendable = true; }
bool needProcess() const { return m_needProcess; }
void setNeedProcess() { m_needProcess = true; }
};
class AstNodeRange VL_NOT_FINAL : public AstNode {
// A range, sized or unsized
@@ -308,8 +317,6 @@ public:
// METHODS
void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
void addBeforeStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
void dump(std::ostream& str = std::cout) const override;
};
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
@@ -373,7 +380,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;
@@ -512,7 +519,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.
@@ -537,7 +544,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 {
@@ -578,6 +585,7 @@ private:
bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user)
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
bool m_dpiTraceInit : 1; // DPI trace_init
bool m_needProcess : 1; // Implements part of a process that allocates std::process
public:
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
: ASTGEN_SUPER_CFunc(fl) {
@@ -597,6 +605,7 @@ public:
m_isLoose = false;
m_isInline = false;
m_isVirtual = false;
m_needProcess = false;
m_entryPoint = false;
m_pure = false;
m_dpiContext = false;
@@ -607,7 +616,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; }
@@ -665,6 +674,8 @@ public:
void isInline(bool flag) { m_isInline = flag; }
bool isVirtual() const { return m_isVirtual; }
void isVirtual(bool flag) { m_isVirtual = flag; }
bool needProcess() const { return m_needProcess; }
void setNeedProcess() { m_needProcess = true; }
bool entryPoint() const { return m_entryPoint; }
void entryPoint(bool flag) { m_entryPoint = flag; }
bool pure() const { return m_pure; }
@@ -702,7 +713,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 {
@@ -755,7 +766,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; }
@@ -794,7 +805,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; }
@@ -809,6 +820,8 @@ class AstClassExtends final : public AstNode {
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := classOrPkgsp : Optional[AstNode]
const bool m_isImplements = false; // class implements
bool m_parameterized = false; // has parameters in its statement
public:
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements)
: ASTGEN_SUPER_ClassExtends(fl)
@@ -819,8 +832,12 @@ public:
void dump(std::ostream& str) const override;
bool hasDType() const override { return true; }
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
AstClass* classp() const; // Class being extended (after link)
// Class being extended (after link and instantiation if needed)
AstClass* classOrNullp() const;
AstClass* classp() const; // Like above, but throws error if nulll
bool isImplements() const { return m_isImplements; }
void parameterized(bool flag) { m_parameterized = flag; }
bool parameterized() const { return m_parameterized; }
};
class AstClocking final : public AstNode {
// Parents: MODULE
@@ -845,7 +862,7 @@ public:
}
ASTGEN_MEMBERS_AstClocking;
void dump(std::ostream& str) const override;
std::string name() const override { return m_name; }
std::string name() const override VL_MT_STABLE { return m_name; }
bool isDefault() const { return m_isDefault; }
bool isGlobal() const { return m_isGlobal; }
};
@@ -863,8 +880,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));
}
@@ -916,7 +933,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; }
@@ -934,7 +951,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; }
@@ -952,7 +969,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
@@ -995,7 +1012,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; }
};
@@ -1033,7 +1050,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 {
@@ -1070,7 +1087,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;
};
@@ -1092,7 +1109,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
@@ -1115,7 +1132,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
@@ -1149,9 +1166,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; }
@@ -1198,7 +1215,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 +1241,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; }
};
@@ -1250,7 +1267,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
@@ -1278,7 +1295,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 {
@@ -1356,11 +1373,12 @@ 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;
bool same(const AstNode* samep) 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; }
@@ -1495,6 +1513,7 @@ class AstTypeTable final : public AstNode {
AstEmptyQueueDType* m_emptyQueuep = nullptr;
AstQueueDType* m_queueIndexp = nullptr;
AstVoidDType* m_voidp = nullptr;
AstStreamDType* m_streamp = nullptr;
AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{};
//
using DetailedMap = std::map<VBasicTypeKey, AstBasicDType*>;
@@ -1520,6 +1539,7 @@ public:
AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl);
AstQueueDType* findQueueIndexDType(FileLine* fl);
AstVoidDType* findVoidDType(FileLine* fl);
AstStreamDType* findStreamDType(FileLine* fl);
void clearCache();
void repairCache();
void dump(std::ostream& str = std::cout) const override;
@@ -1544,9 +1564,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; }
@@ -1566,7 +1588,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 {
@@ -1586,7 +1608,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 {
@@ -1626,6 +1648,7 @@ class AstVar final : public AstNode {
bool m_usedLoopIdx : 1; // Variable subject of for unrolling
bool m_usedVirtIface : 1; // Signal used through a virtual interface
bool m_funcLocal : 1; // Local variable for a function
bool m_funcLocalSticky : 1; // As m_funcLocal but remains set if var is moved to a static
bool m_funcReturn : 1; // Return variable for a function
bool m_attrScBv : 1; // User force bit vector attribute
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
@@ -1669,6 +1692,7 @@ class AstVar final : public AstNode {
m_sigUserRdPublic = false;
m_sigUserRWPublic = false;
m_funcLocal = false;
m_funcLocalSticky = false;
m_funcReturn = false;
m_attrScBv = false;
m_attrIsolateAssign = false;
@@ -1756,7 +1780,8 @@ public:
}
ASTGEN_MEMBERS_AstVar;
void dump(std::ostream& str) const override;
string name() const override VL_MT_SAFE { return m_name; } // * = Var name
bool same(const AstNode* samep) const override;
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
string origName() const override { return m_origName; } // * = Original name
@@ -1787,17 +1812,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;
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; }
@@ -1831,7 +1856,10 @@ public:
void isContinuously(bool flag) { m_isContinuously = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; }
void funcLocal(bool flag) {
m_funcLocal = flag;
if (flag) m_funcLocalSticky = true;
}
void funcReturn(bool flag) { m_funcReturn = flag; }
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
bool hasStrengthAssignment() { return m_hasStrengthAssignment; }
@@ -1913,6 +1941,7 @@ public:
bool isStatic() const VL_MT_SAFE { return m_isStatic; }
bool isLatched() const { return m_isLatched; }
bool isFuncLocal() const { return m_funcLocal; }
bool isFuncLocalSticky() const { return m_funcLocalSticky; }
bool isFuncReturn() const { return m_funcReturn; }
bool isPullup() const { return m_isPullup; }
bool isPulldown() const { return m_isPulldown; }
@@ -1996,11 +2025,12 @@ 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 same(const AstNode* samep) 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; }
@@ -2107,15 +2137,13 @@ public:
// === AstNodeModule ===
class AstClass final : public AstNodeModule {
// @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
AstClassPackage* m_classOrPackagep = nullptr; // Package it will be emitted with
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
void insertCache(AstNode* nodep);
bool m_parameterized = false; // Parameterized class
public:
AstClass(FileLine* fl, const string& name)
@@ -2130,25 +2158,23 @@ public:
AstClassPackage* classOrPackagep() const VL_MT_SAFE { return m_classOrPackagep; }
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
AstNode* membersp() const { return stmtsp(); }
void addMembersp(AstNode* nodep) {
insertCache(nodep);
addStmtsp(nodep);
}
void clearCache() { m_members.clear(); }
void repairCache();
AstNode* findMember(const string& name) const {
const auto it = m_members.find(name);
return (it == m_members.end()) ? nullptr : it->second;
}
void addMembersp(AstNode* nodep) { addStmtsp(nodep); }
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();
static bool isCacheableChild(const AstNode* nodep);
};
class AstClassPackage final : public AstNodeModule {
// The static information portion of a class (treated similarly to a package)
@@ -2334,20 +2360,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; }
@@ -2450,7 +2476,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; }
};
@@ -2591,7 +2617,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
@@ -2633,8 +2659,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; }
@@ -2651,17 +2677,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; }
@@ -2739,46 +2761,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)
@@ -2821,7 +2803,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]
@@ -2926,7 +2908,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; }
@@ -3145,7 +3127,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; }
@@ -3274,8 +3256,6 @@ public:
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* /*samep*/) const override { return true; }
// Stop statement searchback here
void addBeforeStmt(AstNode* newp, AstNode* belowp) override;
// Stop statement searchback here
void addNextStmt(AstNode* newp, AstNode* belowp) override;
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
+103 -101
View File
@@ -103,28 +103,8 @@ int AstNodeSel::bitConst() const {
return (constp ? constp->toSInt() : 0);
}
void AstNodeUOrStructDType::repairMemberCache() {
clearCache();
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
if (m_members.find(itemp->name()) != m_members.end()) {
itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ());
} else {
m_members.emplace(itemp->name(), itemp);
}
}
}
const char* AstNodeUOrStructDType::broken() const {
std::unordered_set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) {
if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: " << it->first);
return "member broken";
}
}
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
@@ -232,6 +212,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,13 +370,15 @@ string AstVar::verilogKwd() const {
return "wreal";
} else if (varType() == VVarType::IFACEREF) {
return "ifaceref";
} else {
} else if (dtypep()) {
return dtypep()->name();
} else {
return "UNKNOWN";
}
}
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
bool asRef) const VL_MT_SAFE {
bool asRef) const {
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string ostatic;
@@ -573,7 +564,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 {
@@ -636,13 +627,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) {
@@ -704,7 +695,7 @@ 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 {
const CTypeRecursed info = cTypeRecurse(false);
return info.render(name, isRef);
}
@@ -734,9 +725,9 @@ 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);
@@ -745,7 +736,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
info.m_type += ">";
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep);
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
@@ -772,6 +763,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
info.m_type = "VlDynamicTriggerScheduler";
} else if (bdtypep->isForkSync()) {
info.m_type = "VlForkSync";
} else if (bdtypep->isProcessRef()) {
info.m_type = "VlProcessRef";
} else if (bdtypep->isEvent()) {
info.m_type = "VlEvent";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
@@ -846,7 +839,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)) {
@@ -916,10 +909,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) {
@@ -1057,6 +1050,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
return m_voidp;
}
AstStreamDType* AstTypeTable::findStreamDType(FileLine* fl) {
if (VL_UNLIKELY(!m_streamp)) {
AstStreamDType* const newp = new AstStreamDType{fl};
addTypesp(newp);
m_streamp = newp;
}
return m_streamp;
}
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* const newp = new AstQueueDType{fl, AstNode::findUInt32DType(), nullptr};
@@ -1259,44 +1261,17 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
//======================================================================
// Special walking tree inserters
void AstNode::addBeforeStmt(AstNode* newp, AstNode*) {
UASSERT_OBJ(backp(), newp, "Can't find current statement to addBeforeStmt");
// Look up; virtual call will find where to put it
this->backp()->addBeforeStmt(newp, this);
}
void AstNode::addNextStmt(AstNode* newp, AstNode*) {
UASSERT_OBJ(backp(), newp, "Can't find current statement to addNextStmt");
// Look up; virtual call will find where to put it
this->backp()->addNextStmt(newp, this);
}
void AstNodeStmt::addBeforeStmt(AstNode* newp, AstNode*) {
// Insert newp before current node
this->addHereThisAsNext(newp);
}
void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
// Insert newp after current node
this->addNextHere(newp);
}
void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
// Preconditions insert first just before themselves (the normal rule
// for other statement types)
if (belowp == precondsp()) {
// Must have been first statement in precondsp list, so newp is new first statement
belowp->addHereThisAsNext(newp);
} else if (belowp == condp()) {
// Goes before condition, IE in preconditions
addPrecondsp(newp);
} else if (belowp == stmtsp()) {
// Was first statement in body, so new front
belowp->addHereThisAsNext(newp);
} else {
belowp->v3fatalSrc("Doesn't look like this was really under the while");
}
}
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
@@ -1367,6 +1342,7 @@ void AstNode::dump(std::ostream& str) const {
void AstNodeProcedure::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isSuspendable()) str << " [SUSP]";
if (needProcess()) str << " [NPRC]";
}
void AstAlways::dump(std::ostream& str) const {
@@ -1430,29 +1406,17 @@ const char* AstClassPackage::broken() const {
void AstClassPackage::cloneRelink() {
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
}
void AstClass::insertCache(AstNode* nodep) {
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|| VN_IS(nodep, CFunc));
if (doit) {
if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
} else {
m_members.emplace(nodep->name(), nodep);
}
}
bool AstClass::isCacheableChild(const AstNode* nodep) {
return (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|| VN_IS(nodep, CFunc));
}
void AstClass::repairCache() {
clearCache();
for (auto* itemp = membersp(); itemp; itemp = itemp->nextp()) {
if (const auto* const scopep = VN_CAST(itemp, Scope)) {
for (auto* blockp = scopep->blocksp(); blockp; blockp = blockp->nextp()) {
insertCache(blockp);
}
} else {
insertCache(itemp);
}
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
@@ -1482,13 +1446,20 @@ 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.'
refp = VN_AS(childDTypep(), ClassRefDType);
AstClass* AstClassExtends::classOrNullp() const {
const AstNodeDType* const dtp = dtypep() ? dtypep() : childDTypep();
const AstClassRefDType* const refp = VN_CAST(dtp, ClassRefDType);
if (refp && !refp->paramsp()) {
// Class already resolved
return refp->classp();
} else {
return nullptr;
}
UASSERT_OBJ(refp, this, "class extends non-ref");
return refp->classp();
}
AstClass* AstClassExtends::classp() const {
AstClass* const clsp = classOrNullp();
UASSERT_OBJ(clsp, this, "Extended class is unresolved");
return clsp;
}
void AstClassRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
@@ -1652,10 +1623,25 @@ 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";
}
AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
AstNodeDType* subdtp = skipRefp();
while (AstNodeArrayDType* const asubdtp = VN_CAST(subdtp, NodeArrayDType)) {
subdtp = asubdtp->subDTypep();
}
return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr
}
bool AstMemberSel::same(const AstNode* samep) const {
const AstMemberSel* const sp = static_cast<const AstMemberSel*>(samep);
return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp())
&& name() == sp->name() && varp()->same(sp->varp());
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
str << " -> ";
@@ -1672,15 +1658,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";
@@ -1767,7 +1744,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);
@@ -1813,7 +1790,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
}
@@ -1821,6 +1798,7 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (packed()) str << " [PACKED]";
if (isFourstate()) str << " [4STATE]";
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
}
void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
@@ -2052,6 +2030,10 @@ void AstVoidDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "void";
}
void AstStreamDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "stream";
}
void AstVarScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isTrace()) str << " [T]";
@@ -2063,6 +2045,10 @@ void AstVarScope::dump(std::ostream& str) const {
str << " ->UNLINKED";
}
}
bool AstVarScope::same(const AstNode* samep) const {
const AstVarScope* const asamep = static_cast<const AstVarScope*>(samep);
return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep());
}
void AstNodeVarRef::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
@@ -2090,6 +2076,10 @@ void AstVarRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
const char* AstVarRef::broken() const {
BROKEN_RTN(!varp());
return AstNodeVarRef::broken();
}
bool AstVarRef::same(const AstNode* samep) const {
return same(static_cast<const AstVarRef*>(samep));
}
@@ -2126,12 +2116,23 @@ void AstVar::dump(std::ostream& str) const {
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
}
bool AstVar::same(const AstNode* samep) const {
const AstVar* const asamep = static_cast<const AstVar*>(samep);
return name() == asamep->name() && varType() == asamep->varType();
}
void AstScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
bool AstScope::same(const AstNode* samep) const {
const AstScope* const asamep = static_cast<const AstScope*>(samep);
return name() == asamep->name()
&& ((!aboveScopep() && !asamep->aboveScopep())
|| (aboveScopep() && asamep->aboveScopep()
&& aboveScopep()->name() == asamep->aboveScopep()->name()));
}
void AstScopeName::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (dpiExport()) str << " [DPIEX]";
@@ -2294,6 +2295,7 @@ void AstCFunc::dump(std::ostream& str) const {
if (isDestructor()) str << " [DTOR]";
if (isVirtual()) str << " [VIRT]";
if (isCoroutine()) str << " [CORO]";
if (needProcess()) str << " [NPRC]";
}
const char* AstCAwait::broken() const {
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
@@ -2313,7 +2315,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;
+21 -28
View File
@@ -72,12 +72,12 @@ private:
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
string dot(const string& a, const string& b) {
if (a == "") return b;
if (b == "") return a;
return a + "__DOT__" + b;
}
@@ -123,30 +123,22 @@ 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("");
}
@@ -186,7 +178,10 @@ private:
m_ftaskp = nodep;
m_liftedp = nullptr;
iterateChildren(nodep);
renameAndStaticsRecurse(nodep);
nodep->foreach([&](AstInitialStatic* const initp) {
initp->unlinkFrBack();
m_ftaskp->addHereThisAsNext(initp);
});
if (m_liftedp) {
// Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced
if (AstNode* const stmtsp = nodep->stmtsp()) {
@@ -196,7 +191,6 @@ private:
nodep->addStmtsp(m_liftedp);
m_liftedp = nullptr;
}
m_staticFuncVars.clear();
m_ftaskp = nullptr;
}
}
@@ -235,11 +229,11 @@ private:
void visit(AstVar* nodep) override {
// If static variable, move it outside a function.
if (nodep->lifetime().isStatic() && m_ftaskp) {
const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name();
const std::string newName
= m_ftaskp->name() + "__Vstatic__" + dot(m_unnamedScope, nodep->name());
nodep->name(newName);
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
m_staticFuncVars.insert(nodep);
nodep->funcLocal(false);
} else if (m_unnamedScope != "") {
// Rename it
@@ -288,7 +282,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);
@@ -350,7 +344,6 @@ private:
void visit(AstVarRef* nodep) override {
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef " << nodep << endl);
nodep->name(nodep->varp()->name());
}
iterateChildren(nodep);
}
@@ -381,5 +374,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
{ BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeLevel() >= 3);
}
+11 -9
View File
@@ -38,17 +38,19 @@ 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:
// AstFTask::user1() -> int. Number of references
const VNUser1InUse m_inuser1;
// STATE
// STATE - across all visitors
std::vector<AstCFunc*> m_cfuncsp; // List of all tasks
// STATE - for current visit position (use VL_RESTORER)
int m_likely = false; // Excuses for branch likely taken
int m_unlikely = false; // Excuses for branch likely not taken
std::vector<AstCFunc*> m_cfuncsp; // List of all tasks
// METHODS
@@ -71,12 +73,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 +93,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 +116,7 @@ public:
// CONSTRUCTORS
explicit BranchVisitor(AstNetlist* nodep) {
reset();
iterateChildren(nodep);
iterateChildrenConst(nodep);
calc_tasks();
}
~BranchVisitor() override = default;
+7 -2
View File
@@ -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
+3
View File
@@ -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();
};
+4 -3
View File
@@ -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);
@@ -201,7 +202,7 @@ private:
public:
// CONSTRUCTORS
CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
explicit CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
~CCtorsVisitor() override = default;
};
@@ -256,5 +257,5 @@ void V3CCtors::cctorsAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
evalAsserts();
{ CCtorsVisitor{v3Global.rootp()}; }
V3Global::dumpCheckGlobalTree("cctors", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeLevel() >= 3);
}
+30 -7
View File
@@ -45,12 +45,16 @@ class CUseVisitor final : public VNVisitor {
const VNUser1InUse m_inuser1;
// MEMBERS
bool m_impOnly = false; // In details needed only for implementation
AstNodeModule* const m_modp; // Current module
std::set<std::pair<VUseType, std::string>> m_didUse; // What we already used
bool m_dtypesImplOnly = false;
// METHODS
void addNewUse(AstNode* nodep, VUseType useType, const string& name) {
if (m_dtypesImplOnly
&& (useType == VUseType::INT_INCLUDE || useType == VUseType::INT_FWD_CLASS))
return;
if (m_didUse.emplace(useType, name).second) {
AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name};
m_modp->addStmtsp(newp);
@@ -61,12 +65,29 @@ class CUseVisitor final : public VNVisitor {
// VISITORS
void visit(AstClassRefDType* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
// Need to include extends() when we implement, but no need for pointers to know
VL_RESTORER(m_impOnly);
addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
}
void visit(AstCFunc* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateAndNextNull(nodep->argsp());
{
m_impOnly = true;
iterateChildren(nodep->classp()); // This also gets all extend classes
VL_RESTORER(m_dtypesImplOnly);
m_dtypesImplOnly = true;
iterateAndNextNull(nodep->initsp());
iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->finalsp());
}
}
void visit(AstCReturn* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (m_dtypesImplOnly) {
for (AstNode* exprp = nodep->op1p(); exprp; exprp = exprp->nextp()) {
if (exprp->dtypep()) iterate(exprp->dtypep());
}
} else {
iterateChildren(nodep);
}
}
void visit(AstNodeDType* nodep) override {
@@ -79,6 +100,8 @@ class CUseVisitor final : public VNVisitor {
if (stypep && stypep->classOrPackagep()) {
addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name());
iterateChildren(stypep);
} else if (AstClassRefDType* const classp = VN_CAST(nodep->skipRefp(), ClassRefDType)) {
addNewUse(nodep, VUseType::INT_FWD_CLASS, classp->name());
}
}
void visit(AstNode* nodep) override {
@@ -115,5 +138,5 @@ void V3CUse::cUseAll() {
// for each output file and put under that
CUseVisitor{modp};
}
V3Global::dumpCheckGlobalTree("cuse", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeLevel() >= 3);
}
+6 -6
View File
@@ -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;
};
@@ -566,7 +566,7 @@ public:
void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("case", 0, dumpTreeLevel() >= 3);
}
void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
+28 -2
View File
@@ -122,6 +122,31 @@ private:
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
}
void visit(AstNodeCond* nodep) override {
// All class types are castable to each other. If they are of different types,
// a compilation error will be thrown, so an explicit cast is required. Types were
// already checked by V3Width and dtypep of a condition operator is a type of their
// common base class, so both classes can be safetly casted.
const AstClassRefDType* const thenClassDtypep
= VN_CAST(nodep->thenp()->dtypep(), ClassRefDType);
const AstClassRefDType* const elseClassDtypep
= VN_CAST(nodep->elsep()->dtypep(), ClassRefDType);
const bool castRequired = thenClassDtypep && elseClassDtypep
&& (thenClassDtypep->classp() != elseClassDtypep->classp());
if (castRequired) {
const AstClass* const commonBaseClassp
= VN_AS(nodep->dtypep(), ClassRefDType)->classp();
if (thenClassDtypep->classp() != commonBaseClassp) {
AstNodeExpr* thenp = nodep->thenp()->unlinkFrBack();
nodep->thenp(new AstCCast{thenp->fileline(), thenp, nodep});
}
if (elseClassDtypep->classp() != commonBaseClassp) {
AstNodeExpr* elsep = nodep->elsep()->unlinkFrBack();
nodep->elsep(new AstCCast{elsep->fileline(), elsep, nodep});
}
}
visit(static_cast<AstNodeTriop*>(nodep));
}
void visit(AstNodeTriop* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
@@ -161,7 +186,8 @@ private:
&& !VN_IS(backp, NodeCCall) && !VN_IS(backp, CMethodHard) && !VN_IS(backp, SFormatF)
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, StructSel) && !VN_IS(backp, RedXor)
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()
&& !nodep->varp()->basicp()->isForkSync())
&& !nodep->varp()->basicp()->isForkSync()
&& !nodep->varp()->basicp()->isProcessRef())
&& backp->width() && castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
@@ -208,5 +234,5 @@ public:
void V3Cast::castAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CastVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("cast", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeLevel() >= 3);
}
+12 -7
View File
@@ -27,6 +27,7 @@
#include "V3Ast.h"
#include "V3Global.h"
#include "V3UniqueNames.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -41,6 +42,7 @@ private:
// MEMBERS
string m_prefix; // String prefix to add to name based on hier
V3UniqueNames m_names; // For unique naming of structs and unions
AstNodeModule* m_modp = nullptr; // Current module
AstNodeModule* m_classPackagep = nullptr; // Package moving into
const AstScope* m_classScopep = nullptr; // Package moving scopes into
@@ -62,8 +64,10 @@ private:
AstClassPackage* const packagep
= new AstClassPackage{nodep->fileline(), nodep->origName()};
packagep->name(nodep->name() + "__Vclpkg");
nodep->editCountInc();
nodep->classOrPackagep(packagep);
packagep->classp(nodep);
packagep->timeunit(nodep->timeunit());
v3Global.rootp()->addModulesp(packagep);
// Add package to hierarchy
AstCell* const cellp = new AstCell{packagep->fileline(),
@@ -102,7 +106,6 @@ private:
m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep);
}
nodep->repairCache();
}
void visit(AstNodeModule* nodep) override {
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
@@ -177,14 +180,15 @@ private:
}
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
// Give it a pointer to its package and a final name
dtypep->classOrPackagep(m_modp);
dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct")
+ cvtToStr(dtypep->uniqueNum()));
// Give struct a pointer to its package and a final name
dtypep->editCountInc();
dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp);
dtypep->name(
m_names.get(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct")));
for (const AstMemberDType* itemp = dtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstNodeUOrStructDType* const subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
AstNodeUOrStructDType* const subp = itemp->getChildStructp();
// 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);
@@ -193,6 +197,7 @@ private:
void visit(AstTypedef* nodep) override {
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType);
if (dtypep && !dtypep->packed()) {
@@ -243,5 +248,5 @@ public:
void V3Class::classAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClassVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("class", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("class", 0, dumpTreeLevel() >= 3);
}
+7 -2
View File
@@ -95,6 +95,7 @@ private:
|| VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|| VN_IS(nodep->dtypep()->skipRefp(), QueueDType)
|| VN_IS(nodep->dtypep()->skipRefp(), StreamDType)
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) {
} else {
@@ -298,7 +299,11 @@ private:
}
void visit(AstWith* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->exprp());
setClean(nodep, true);
}
void visit(AstCReturn* nodep) override {
iterateChildren(nodep);
ensureClean(nodep->lhsp());
setClean(nodep, true);
}
void visit(AstIntfRef* nodep) override {
@@ -325,5 +330,5 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CleanVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clean", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeLevel() >= 3);
}
+6 -4
View File
@@ -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
@@ -222,5 +224,5 @@ public:
void V3Clock::clockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clock", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("clock", 0, dumpTreeLevel() >= 3);
}
+1 -1
View File
@@ -238,5 +238,5 @@ public:
void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
CombineVisitor::apply(nodep);
V3Global::dumpCheckGlobalTree("combine", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("combine", 0, dumpTreeLevel() >= 3);
}
+11 -8
View File
@@ -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);
@@ -63,9 +63,10 @@ static void makeVlToString(AstIface* nodep) {
}
static void makeVlToString(AstNodeUOrStructDType* nodep) {
AstNodeModule* const modp = nodep->classOrPackagep();
UASSERT_OBJ(modp, nodep, "Unlinked struct package");
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);
@@ -81,11 +82,13 @@ static void makeVlToString(AstNodeUOrStructDType* nodep) {
}
stmt += VIdProtect::protect(itemp->prettyName()) + ":\" + ";
if (VN_IS(itemp->dtypep()->skipRefp(), BasicDType) && itemp->isWide()) {
stmt += "VL_TO_STRING_W";
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
} else {
stmt += "VL_TO_STRING";
stmt += "VL_TO_STRING(";
}
stmt += "(obj." + itemp->nameProtect() + ");\n";
stmt += "obj." + itemp->nameProtect() + ");\n";
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
}
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "out += \"}\";\n"});
@@ -137,7 +140,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});
@@ -172,5 +175,5 @@ void V3Common::commonAll() {
if (!dtypep->packed()) makeVlToString(dtypep);
}
}
V3Global::dumpCheckGlobalTree("common", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("common", 0, dumpTreeLevel() >= 3);
}
+15 -6
View File
@@ -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
+1
View File
@@ -23,6 +23,7 @@
#include "V3Ast.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Mutex.h"
//######################################################################
+175 -105
View File
@@ -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);
@@ -2167,7 +2166,12 @@ private:
AstNodeExpr* const srcp = nodep->rhsp()->unlinkFrBack();
// Connect the rhs to the stream operator and update its width
VN_AS(streamp, StreamL)->lhsp(srcp);
streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED);
if (VN_IS(srcp->dtypep(), DynArrayDType) || VN_IS(srcp->dtypep(), QueueDType)
|| VN_IS(srcp->dtypep(), UnpackArrayDType)) {
streamp->dtypeSetStream();
} else {
streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED);
}
// Shrink the RHS if necessary
if (sWidth > dWidth) {
streamp = new AstSel{streamp->fileline(), streamp, sWidth - dWidth, dWidth};
@@ -2265,7 +2269,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);
@@ -2747,52 +2751,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();
}
};
@@ -2817,9 +2843,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
@@ -2839,35 +2864,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: ");
}
}
@@ -2975,6 +3018,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);
@@ -3025,7 +3069,7 @@ private:
&& nodep->displayType() == VDisplayType::DT_WRITE)))
return false;
if ((prevp->filep() && !nodep->filep()) || (!prevp->filep() && nodep->filep())
|| !prevp->filep()->sameTree(nodep->filep()))
|| (prevp->filep() && nodep->filep() && !prevp->filep()->sameTree(nodep->filep())))
return false;
if (!prevp->fmtp() || prevp->fmtp()->nextp() || !nodep->fmtp() || nodep->fmtp()->nextp())
return false;
@@ -3188,7 +3232,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;
}
@@ -3207,7 +3251,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
@@ -3366,9 +3410,9 @@ private:
TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)");
TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->castNot()->lhsp(), $elsep, $thenp}");
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero, !$elsep.isClassHandleValue}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, !$thenp.isClassHandleValue, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b
TREEOP ("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())");
// Prefer constants on left, since that often needs a shift, it lets
// constant red remove the shift
@@ -3611,6 +3655,7 @@ private:
public:
// Processing Mode Enum
enum ProcMode : uint8_t {
PROC_PARAMS_NOWARN,
PROC_PARAMS,
PROC_GENERATE,
PROC_LIVE,
@@ -3626,16 +3671,18 @@ public:
, m_concswapNames{globalPass ? ("__Vconcswap_" + cvtToStr(s_globalPassNum++)) : ""} {
// clang-format off
switch (pmode) {
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true;
m_required = true; break;
case PROC_GENERATE: m_doV = true; m_doNConst = true; m_params = true;
m_required = true; m_doGenerate = true; break;
case PROC_LIVE: break;
case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break;
case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break;
case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break;
case PROC_CPP: m_doV = false; m_doNConst = true; m_doCpp = true; break;
default: v3fatalSrc("Bad case"); break;
case PROC_PARAMS_NOWARN: m_doV = true; m_doNConst = true; m_params = true;
m_required = false; break;
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true;
m_required = true; break;
case PROC_GENERATE: m_doV = true; m_doNConst = true; m_params = true;
m_required = true; m_doGenerate = true; break;
case PROC_LIVE: break;
case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break;
case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break;
case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break;
case PROC_CPP: m_doV = false; m_doNConst = true; m_doCpp = true; break;
default: v3fatalSrc("Bad case"); break;
}
// clang-format on
}
@@ -3683,6 +3730,29 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
return nodep;
}
//! Constify this cell node's parameter list if possible
//! @return Pointer to the edited node.
AstNode* V3Const::constifyParamsNoWarnEdit(AstNode* nodep) {
// if (debug() > 0) nodep->dumpTree("- forceConPRE : ");
// Resize even if the node already has a width, because buried in the tree
// we may have a node we just created with signing, etc, that isn't sized yet.
// Make sure we've sized everything first
nodep = V3Width::widthParamsEdit(nodep);
ConstVisitor visitor{ConstVisitor::PROC_PARAMS_NOWARN, /* globalPass: */ false};
if (AstVar* const varp = VN_CAST(nodep, Var)) {
// If a var wants to be constified, it's really a param, and
// we want the value to be constant. We aren't passed just the
// init value because we need widthing above to handle the var's type.
if (varp->valuep()) visitor.mainAcceptEdit(varp->valuep());
} else {
nodep = visitor.mainAcceptEdit(nodep);
}
// Because we do edits, nodep links may get trashed and core dump this.
// if (debug() > 0) nodep->dumpTree("- forceConDONE: ");
return nodep;
}
//! Force this cell node's parameter list to become a constant inside generate.
//! If we are inside a generated "if", "case" or "for", we don't want to
//! trigger warnings when we deal with the width. It is possible that these
@@ -3720,7 +3790,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3);
}
void V3Const::constifyCpp(AstNetlist* nodep) {
@@ -3729,7 +3799,7 @@ void V3Const::constifyCpp(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTreeLevel() >= 3);
}
AstNode* V3Const::constifyEdit(AstNode* nodep) {
@@ -3753,7 +3823,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3);
}
void V3Const::constifyAll(AstNetlist* nodep) {
@@ -3763,7 +3833,7 @@ void V3Const::constifyAll(AstNetlist* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3);
}
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {
+4
View File
@@ -30,6 +30,10 @@ public:
static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) {
return VN_AS(constifyParamsEdit(static_cast<AstNode*>(exprp)), NodeExpr);
}
static AstNode* constifyParamsNoWarnEdit(AstNode* nodep);
static AstNodeExpr* constifyParamsNoWarnEdit(AstNodeExpr* exprp) {
return VN_AS(constifyParamsNoWarnEdit(static_cast<AstNode*>(exprp)), NodeExpr);
}
static AstNode* constifyGenerateParamsEdit(AstNode* nodep);
// Only do constant pushing, without removing dead logic
static void constifyAllLive(AstNetlist* nodep);
+1 -1
View File
@@ -567,5 +567,5 @@ public:
void V3Coverage::coverage(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coverage", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("coverage", 0, dumpTreeLevel() >= 3);
}
+1 -1
View File
@@ -117,5 +117,5 @@ public:
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageJoinVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeLevel() >= 3);
}
+30 -25
View File
@@ -62,9 +62,10 @@ private:
// TYPES
using AssignMap = std::multimap<AstVarScope*, AstNodeAssign*>;
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
// STATE - across all visitors
const bool m_elimUserVars; // Allow removal of user's vars
const bool m_elimDTypes; // Allow removal of DTypes
const bool m_elimCells; // Allow removal of Cells
// List of all encountered to avoid another loop through tree
std::vector<AstVar*> m_varsp;
std::vector<AstNode*> m_dtypesp;
@@ -73,13 +74,14 @@ private:
std::vector<AstCell*> m_cellsp;
std::vector<AstClass*> m_classesp;
std::vector<AstTypedef*> m_typedefsp;
AssignMap m_assignMap; // List of all simple assignments for each variable
const bool m_elimUserVars; // Allow removal of user's vars
const bool m_elimDTypes; // Allow removal of DTypes
const bool m_elimCells; // Allow removal of Cells
bool m_sideEffect = false; // Side effects discovered in assign RHS
// STATE - for current visit position (use VL_RESTORER)
bool m_inAssign = false; // Currently in an assign
AstNodeModule* m_modp = nullptr; // Current module
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
// METHODS
void checkAll(AstNode* nodep) {
@@ -107,18 +109,16 @@ private:
void visit(AstNodeModule* nodep) override {
if (m_modp) m_modp->user1Inc(); // e.g. Class under Package
VL_RESTORER(m_modp);
{
m_modp = nodep;
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
if (AstClass* const classp = VN_CAST(nodep, Class)) {
if (classp->extendsp()) classp->extendsp()->user1Inc();
if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc();
m_classesp.push_back(classp);
// TODO we don't reclaim dead classes yet - graph implementation instead?
classp->user1Inc();
}
m_modp = nodep;
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
if (AstClass* const classp = VN_CAST(nodep, Class)) {
if (classp->extendsp()) classp->extendsp()->user1Inc();
if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc();
m_classesp.push_back(classp);
// TODO we don't reclaim dead classes yet - graph implementation instead?
classp->user1Inc();
}
}
}
@@ -282,9 +282,13 @@ private:
// See if simple assignments to variables may be eliminated because
// that variable is never used.
// Similar code in V3Life
VL_RESTORER(m_sideEffect);
const bool assignInAssign = m_inAssign; // Might be Assign(..., ExprStmt(Assign), ...)
{
VL_RESTORER(m_inAssign);
VL_RESTORER(m_sideEffect);
m_inAssign = true;
m_sideEffect = false;
if (assignInAssign) m_sideEffect = true;
iterateAndNextNull(nodep->rhsp());
checkAll(nodep);
// Has to be direct assignment without any EXTRACTing.
@@ -299,6 +303,7 @@ private:
}
iterateNull(nodep->timingControlp());
}
if (assignInAssign) m_sideEffect = true; // Parent assign shouldn't optimize
}
//-----
@@ -539,29 +544,29 @@ void V3Dead::deadifyModules(AstNetlist* nodep) {
{
DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTree() >= 6);
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeLevel() >= 6);
}
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeLevel() >= 3);
}
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeLevel() >= 3);
}
void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeLevel() >= 3);
}
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeLevel() >= 3);
}
+30 -28
View File
@@ -92,21 +92,23 @@ private:
const VNUser4InUse m_inuser4;
const VNUser5InUse m_inuser5;
// STATE
// STATE - across all visitors
std::unordered_map<const AstVarScope*, int> m_scopeVecMap; // Next var number for each scope
std::set<AstSenTree*> m_timingDomains; // Timing resume domains
using VarMap = std::map<const std::pair<AstNodeModule*, std::string>, AstVar*>;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
// STATE - for current visit position (use VL_RESTORER)
AstActive* m_activep = nullptr; // Current activate
const AstCFunc* m_cfuncp = nullptr; // Current public C Function
AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments
AstNodeProcedure* m_procp = nullptr; // Current process
std::set<AstSenTree*> m_timingDomains; // Timing resume domains
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
bool m_inInitial = false; // True in static initializers and initial blocks
bool m_inSuspendableOrFork = false; // True in suspendable processes and forks
bool m_ignoreBlkAndNBlk = false; // Suppress delayed assignment BLKANDNBLK
using VarMap = std::map<const std::pair<AstNodeModule*, std::string>, AstVar*>;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
std::unordered_map<const AstVarScope*, int> m_scopeVecMap; // Next var number for each scope
// METHODS
@@ -262,8 +264,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 +284,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 +303,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 +323,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
@@ -424,10 +426,8 @@ private:
}
void visit(AstCFunc* nodep) override {
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
m_cfuncp = nodep;
iterateChildren(nodep);
}
void visit(AstActive* nodep) override {
m_activep = nodep;
@@ -443,10 +443,12 @@ private:
void visit(AstNodeProcedure* nodep) override {
VL_RESTORER(m_inSuspendableOrFork);
m_inSuspendableOrFork = nodep->isSuspendable();
m_procp = nodep;
m_timingDomains.clear();
iterateChildren(nodep);
m_procp = nullptr;
{
VL_RESTORER(m_procp);
m_procp = nodep;
m_timingDomains.clear();
iterateChildren(nodep);
}
if (m_timingDomains.empty()) return;
if (auto* const actp = VN_AS(nodep->user3p(), Active)) {
// Merge all timing domains (and possibly the active's domain) to create a sentree for
@@ -474,14 +476,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 +574,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(),
@@ -616,10 +620,8 @@ private:
}
void visit(AstWhile* nodep) override {
VL_RESTORER(m_inLoop);
{
m_inLoop = true;
iterateChildren(nodep);
}
m_inLoop = true;
iterateChildren(nodep);
}
//--------------------
@@ -639,5 +641,5 @@ public:
void V3Delayed::delayedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DelayedVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("delayed", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("delayed", 0, dumpTreeLevel() >= 3);
}
+1 -1
View File
@@ -166,5 +166,5 @@ public:
void V3Depth::depthAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("depth", 0, dumpTree() >= 6);
V3Global::dumpCheckGlobalTree("depth", 0, dumpTreeLevel() >= 6);
}
+3 -2
View File
@@ -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
@@ -126,5 +127,5 @@ public:
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthBlockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTreeLevel() >= 3);
}
+3 -3
View File
@@ -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: ");
@@ -285,5 +285,5 @@ public:
void V3Descope::descopeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DescopeVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("descope", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("descope", 0, dumpTreeLevel() >= 3);
}
+15 -11
View File
@@ -334,17 +334,20 @@ class AstToDfgVisitor final : public VNVisitor {
const uint32_t bEnd = b.m_lsb + bWidth;
const uint32_t overlapEnd = std::min(aEnd, bEnd) - 1;
varp->varp()->v3warn( //
MULTIDRIVEN,
"Bits [" //
<< overlapEnd << ":" << b.m_lsb << "] of signal "
<< varp->varp()->prettyNameQ()
<< " have multiple combinational drivers\n"
<< a.m_fileline->warnOther() << "... Location of first driver\n"
<< a.m_fileline->warnContextPrimary() << '\n'
<< b.m_fileline->warnOther() << "... Location of other driver\n"
<< b.m_fileline->warnContextSecondary() << varp->varp()->warnOther()
<< "... Only the first driver will be respected");
if (a.m_fileline->operatorCompare(*b.m_fileline) != 0) {
varp->varp()->v3warn( //
MULTIDRIVEN,
"Bits [" //
<< overlapEnd << ":" << b.m_lsb << "] of signal "
<< varp->varp()->prettyNameQ()
<< " have multiple combinational drivers\n"
<< a.m_fileline->warnOther() << "... Location of first driver\n"
<< a.m_fileline->warnContextPrimary() << '\n'
<< b.m_fileline->warnOther() << "... Location of other driver\n"
<< b.m_fileline->warnContextSecondary()
<< varp->varp()->warnOther()
<< "... Only the first driver will be respected");
}
// If the first driver completely covers the range of the second driver,
// we can just delete the second driver completely, otherwise adjust the
@@ -437,6 +440,7 @@ class AstToDfgVisitor final : public VNVisitor {
void visit(AstCell* nodep) override { markReferenced(nodep); }
void visit(AstNodeProcedure* nodep) override { markReferenced(nodep); }
void visit(AstVar* nodep) override {
if (nodep->isSc()) return;
// No need to (and in fact cannot) handle variables with unsupported dtypes
if (!DfgVertex::isSupportedDType(nodep->dtypep())) return;
// Mark ports as having external references
+1 -2
View File
@@ -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;
}
+6 -6
View File
@@ -237,7 +237,7 @@ void V3DfgOptimizer::extract(AstNetlist* netlistp) {
UINFO(2, __FUNCTION__ << ": " << endl);
// Extract more optimization candidates
DataflowExtractVisitor::apply(netlistp);
V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeLevel() >= 3);
}
void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
@@ -267,7 +267,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
// Build the DFG of this module
const std::unique_ptr<DfgGraph> dfg{V3DfgPasses::astToDfg(*modp, ctx)};
if (dumpDfg() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-input");
if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-input");
// Extract the cyclic sub-graphs. We do this because a lot of the optimizations assume a
// DAG, and large, mostly acyclic graphs could not be optimized due to the presence of
@@ -284,7 +284,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
// For each cyclic component
for (auto& component : cyclicComponents) {
if (dumpDfg() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
// TODO: Apply optimizations safe for cyclic graphs
// Add back under the main DFG (we will convert everything back in one go)
dfg->addGraph(*component);
@@ -292,7 +292,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
// For each acyclic component
for (auto& component : acyclicComponents) {
if (dumpDfg() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
// Optimize the component
V3DfgPasses::optimize(*component, ctx);
// Add back under the main DFG (we will convert everything back in one go)
@@ -300,9 +300,9 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
}
// Convert back to Ast
if (dumpDfg() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized");
if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized");
AstModule* const resultModp = V3DfgPasses::dfgToAst(*dfg, ctx);
UASSERT_OBJ(resultModp == modp, modp, "Should be the same module");
}
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeLevel() >= 3);
}
+3 -3
View File
@@ -285,7 +285,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
const auto apply = [&](int dumpLevel, const string& name, std::function<void()> pass) {
pass();
if (dumpDfg() >= dumpLevel) {
if (dumpDfgLevel() >= dumpLevel) {
const string strippedName = VString::removeWhitespace(name);
const string label
= ctx.prefix() + "pass-" + cvtToStr(passNumber) + "-" + strippedName;
@@ -294,7 +294,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
++passNumber;
};
if (dumpDfg() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "input");
if (dumpDfgLevel() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "input");
apply(3, "input ", [&]() {});
apply(4, "inlineVars ", [&]() { inlineVars(dfg); });
apply(4, "cse0 ", [&]() { cse(dfg, ctx.m_cseContext0); });
@@ -304,5 +304,5 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
apply(4, "cse1 ", [&]() { cse(dfg, ctx.m_cseContext1); });
}
apply(4, "removeVars ", [&]() { removeVars(dfg, ctx.m_removeVarsContext); });
if (dumpDfg() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "optimized");
if (dumpDfgLevel() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "optimized");
}
+2 -2
View File
@@ -123,9 +123,9 @@ struct V3DfgPeepholeContext final {
const std::string m_label; // Label to apply to stats
// Enable flags for each optimization
bool m_enabled[VDfgPeepholePattern::_ENUM_END];
std::array<bool, VDfgPeepholePattern::_ENUM_END> m_enabled;
// Count of applications for each optimization (for statistics)
VDouble0 m_count[VDfgPeepholePattern::_ENUM_END];
std::array<VDouble0, VDfgPeepholePattern::_ENUM_END> m_count;
explicit V3DfgPeepholeContext(const std::string& label);
~V3DfgPeepholeContext();
+1 -1
View File
@@ -100,5 +100,5 @@ void V3DupFinder::dumpFile(const string& filename, bool tree) {
}
void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) {
if (dump()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
if (dumpLevel()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
}
+30 -29
View File
@@ -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()) {
@@ -73,6 +79,10 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
args += prefixNameProtect(EmitCParentModule::get(nodep));
args += "* vlSelf";
}
if (nodep->needProcess()) {
if (!args.empty()) args += ", ";
args += "VlProcessRef vlProcess";
}
if (!nodep->argTypes().empty()) {
if (!args.empty()) args += ", ";
args += nodep->argTypes();
@@ -95,8 +105,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 +124,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 +139,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,25 +227,16 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
}
}
void EmitCBaseVisitor::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)) {
if (usep->useType() == useType) {
if (usep->useType().isInclude()) {
puts("#include \"" + prefixNameProtect(usep) + ".h\"\n");
}
if (usep->useType().isFwdClass()) {
puts("class " + prefixNameProtect(usep) + ";\n");
}
nl = "\n";
}
}
}
puts(nl);
void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) {
bool nl = false;
forModCUse(modp, useType, [&](string entry) {
puts(entry);
nl = true;
});
if (nl) puts("\n");
}
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;
+59 -37
View File
@@ -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());
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,18 +72,68 @@ 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);
void emitVarDecl(const AstVar* nodep, bool asRef = false);
template <typename F>
static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) {
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
if (usep->useType() == useType) {
if (usep->useType().isInclude()) {
action("#include \"" + prefixNameProtect(usep) + ".h\"\n");
}
if (usep->useType().isFwdClass()) {
action("class " + prefixNameProtect(usep) + ";\n");
}
}
}
}
}
void emitModCUse(const AstNodeModule* modp, VUseType useType);
void emitTextSection(const AstNodeModule* modp, VNType type);
// CONSTRUCTORS
EmitCBaseVisitor() = default;
~EmitCBaseVisitor() override = default;
EmitCBaseVisitorConst() = default;
~EmitCBaseVisitorConst() override = default;
};
#endif // guard
+3 -3
View File
@@ -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("}");
+1 -1
View File
@@ -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)) {

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