Compare commits

...
144 Commits
Author SHA1 Message Date
Wilson Snyder 935032366f Version bump 2021-12-05 11:10:19 -05:00
Yutetsu TAKATSUKASA 1160dddc6d Fix bit op tree optimization (#3221)
* Add a test to reproduce #3197

* Fix #3197. Optimize correctly even if a variable is >32

* Quick exit instead of continue. No functional change is intended.

* Delete comment-out line.

* update per review comment
2021-11-30 23:20:00 +09:00
Wilson Snyder 293a5f402b Fix timescale portability on Arm64 (#3222). 2021-11-28 15:47:19 -05:00
Wilson Snyder ca09f73446 Tests: Fix open test on some automount cloud providers 2021-11-28 15:40:35 -05:00
Wilson Snyder e814855357 Tests: Skip gdb tests if no gdb 2021-11-28 15:33:33 -05:00
Wilson Snyder 692306ef44 Optimize $random concatenates/selects (#3114). 2021-11-28 14:17:28 -05:00
Wilson Snyder ffdc0afe5f Disable unintended debug message 2021-11-28 14:10:50 -05:00
Wilson Snyder 98037cad56 Internals: Optimize VL_RANDOM to have unclean output 2021-11-28 14:00:19 -05:00
Wilson Snyder 61e3536163 Internals: Remove some unused arguments. 2021-11-28 13:44:16 -05:00
Wilson Snyder a1a186a86c Internals: Remove some unused arguments. 2021-11-28 13:07:37 -05:00
Wilson Snyder 04e0c7e4f1 Support tracing through --hierarchical/--lib-create libraries (#3200). 2021-11-27 17:07:27 -05:00
Wilson Snyder 833686446c Commentary, ChangeLog up to date 2021-11-27 09:05:51 -05:00
Wilson Snyder c6dae40cf6 Support task name in $display %m (#3211). 2021-11-26 20:38:48 -05:00
Wilson Snyder cd737065f2 Internals: More const. No functional change intended. 2021-11-26 17:55:36 -05:00
Wilson Snyder 010084201a Internals: Remove dead code. 2021-11-26 16:15:08 -05:00
Wilson Snyder 60f7eff701 Remove dead statistic. 2021-11-26 16:10:16 -05:00
Wilson Snyder d1862e25eb Internals: Cleanup some constructor-constructor assigns. No functional change intended. 2021-11-26 16:05:07 -05:00
Wilson Snyder b0018fd680 Internals: Remove dead output variable. No functional change. 2021-11-26 15:13:36 -05:00
Wilson Snyder 2742a8c813 Internals: No need for variable name on immediate visitors. No functional change intended. 2021-11-26 10:52:45 -05:00
Wilson Snyder 05e12ab60e Internals: More const. No functional change intended. 2021-11-26 10:52:45 -05:00
Michaël Lefebvre 9bda2cb4ad Fix some SliceSels not being constants (#3186) (#3218). 2021-11-26 10:51:11 -05:00
Wilson Snyder 393b9e435d Internals: Revert previous commit const for clang. 2021-11-25 09:47:06 -05:00
Wilson Snyder e87a726989 Internals: More const. No functional change intended. 2021-11-25 09:05:50 -05:00
Wilson Snyder 62387a0e32 Fix display of empty string constant (#3207) (#3215). 2021-11-25 08:03:27 -05:00
Wilson Snyder 31079ca8b5 Fix $size on dynamic strings (#3216). 2021-11-25 07:50:47 -05:00
Wilson Snyder 4184ad1921 Commentary 2021-11-23 18:27:40 -05:00
Wilson Snyder e7ebe0e280 Fix $fopen etc on integer arrays (#3214). 2021-11-23 18:22:16 -05:00
Wilson Snyder c14bbb9421 Fix incorrect width after and-or optimization (#3208). 2021-11-23 18:15:21 -05:00
Wilson Snyder b1b92b7dd4 Fix hang on recursive definition error (#3199). 2021-11-23 07:27:41 -05:00
Julie Schwartz a14394dbb5 Commentary: remove duplicate/wrong change-log entry (#3212) 2021-11-18 05:15:02 -05:00
Wilson Snyder 96b7831243 Commentary: C++14 moves to 2023. 2021-11-17 18:56:11 -05:00
Wilson Snyder 1e440765c0 Commentary, about previous commit: Fix display of signed without format (#3204). 2021-11-17 18:52:53 -05:00
Wilson Snyder 2ccf49031b Fix $display of signed/unsigned without format (#3207). 2021-11-17 18:50:52 -05:00
Wilson Snyder 0abc856be9 Fix %0 format on $value$plusargs. 2021-11-17 17:54:07 -05:00
Wilson Snyder d2a8fa7440 Fix display of empty string constant (#3207). 2021-11-17 17:46:08 -05:00
Wilson Snyder 106d635d0f Fix vluint64 portability (#3150). 2021-11-17 07:10:48 -05:00
Wilson Snyder cff9f8143e Commentary 2021-11-17 07:06:43 -05:00
Wilson Snyder cfa401e01d Internals: Add lib-create const and improve comments. 2021-11-14 12:01:02 -05:00
Wilson Snyder d6195e354f Add some missing COLD attributes. 2021-11-14 11:05:20 -05:00
Wilson Snyder c0892dd11c When using --lib-create, disable tracing hash/internals. Partial (#3200). 2021-11-14 10:16:59 -05:00
Wilson Snyder 899de9a282 Add --lib-create, similar to --protect-lib but without protections (#3200). 2021-11-14 09:39:31 -05:00
Wilson Snyder 4b593f8eb3 Commentary 2021-11-14 09:01:03 -05:00
Wilson Snyder 28b6e79cf7 Tests: Rename t_lib_prot tests in prep for new options. 2021-11-14 08:58:04 -05:00
Wilson Snyder fe5822ba54 Commentary 2021-11-13 15:01:27 -05:00
Wilson Snyder c496649c49 Internals: Remove unused DfaGraph code. 2021-11-13 14:48:21 -05:00
Wilson Snyder 37e3c6da70 Internals: Add more const. No functional change intended. 2021-11-13 13:50:44 -05:00
Wilson Snyder 4cb5c1e1db Internals: More const. No functional change. 2021-11-13 11:38:12 -05:00
Wilson Snyder b7a7504ba5 Internals: More obvious debug filename. 2021-11-13 11:35:03 -05:00
Wilson Snyder 3a5cbd5b67 Internals: Untabify some embedded tabs. 2021-11-13 10:46:25 -05:00
Wilson Snyder 27883b52d6 Internals: Add const 2021-11-13 10:42:26 -05:00
Wilson Snyder b95ee84343 Commentary 2021-11-13 10:41:00 -05:00
Geza Lore 185e5d8f42 Make 'bit', 'logic' and 'time' types unsigned by default
IEEE 1800-2017 6.11.3 says these types are unsigned. Until now these
types were treated as not having a signedness (NOSIGN), and nodes having
these types were later resolved by V3Width to be unsigned. This is a bit
problematic when creating nodes of these types after V3Width. Treating
these types as unsigned from the get go is fine, and actually improves
generated code slightly.
2021-11-09 21:54:21 +00:00
Geza Lore 987ce927eb Remove unused code. No functional change. 2021-11-09 19:46:19 +00:00
Yutetsu TAKATSUKASA b08c694cd6 Fix wrong bit op tree optimization (#3185)
* Add a test to reproduce bug3182. Run the same HDL with -Oo to confirm the result is same.

* Hopefully fix #3182. The result can be 0 only when polarity is true (no AstNot is found during traversal).
2021-11-06 12:31:50 +09:00
Geza Lore e69a8e838d Improve memory usage of V3Partition. Only performance change intended. (#3192) 2021-11-05 22:08:54 -04:00
Wilson Snyder 61612582e6 Improve memory usage of V3Partition. Only performance change intended. 2021-11-04 07:39:28 -04:00
Wilson Snyder 8b00939f0c Improve performance of V3Scoreboard. Only performance change intended. 2021-11-03 22:16:18 -04:00
Wilson Snyder da5644211f Improve memory usage of V3Partition. Only performance change intended. 2021-11-03 22:01:40 -04:00
Wilson Snyder c1d7bfa617 Internals: Skip some asserts in fastpath partitioning. 2021-11-03 19:19:23 -04:00
Wilson Snyder c26ce25cea Internals: Add more const. No functional change. 2021-11-03 17:49:19 -04:00
Wilson Snyder 758264dc77 Fix nested generate if genblk naming (#3189). 2021-11-01 08:59:00 -04:00
Wilson Snyder 304697d133 Commentary 2021-11-01 08:57:43 -04:00
Teng Huang fdbf465eda Fix array method names with parens (#3181) (#3183) 2021-10-26 12:20:45 -04:00
Wilson Snyder 90102d9867 Commentary 2021-10-25 21:02:02 -04:00
Wilson Snyder a1bb471aca Internals: Iterate sentree in clocker to avoid confusing iterateChildren. No functional change intended. 2021-10-25 20:19:49 -04:00
Wilson Snyder 4ef37d9411 Commentary 2021-10-25 19:53:41 -04:00
Yutetsu TAKATSUKASA f3b10df454 Skip merging assign statements if a variable is marked split_var to fix #3177 (#3179)
* add tests to reproduce #3177.

Any random test circuits can be added to t_split_var_4.v later because it uses CRC to check the result while
t_split_var_0.v has just barrel shifters.

* Fix #3177. Don't merge assign statements if a variable is marked split_var.
2021-10-25 20:56:59 +09:00
Geza Lore f5a226a183 Partial clean up of V3Order. No functional change intended.
This is a partial cleanup of V3Order with the aim of increasing clarity:
- Split the initial OrderGraph building and the actual ordering process
into separate classes (OrderVisitor -> OrderBuildVisitor + OrderProcess)
- Remove all the historical cruft from the graph building phase (now in
OrderBuildVisitor), and add more assertions for assumptions.
- Change the dot styling of OrderGraph to use shapes and more easily
distinguishable colors.
- Expand vague comments, remove incorrect comments, and add more.
- Replace some old code with cleaner C++11 constructs.
- Move code about a bit so logically connected sections are closer to
each other, scope some definitions where they are used rather than file
scope.
- The actual ordering process (now in OrderProcess) is still largely
unchanged.

The generated code is identical to before (within the limits of the
exiting non-determinism).
2021-10-24 16:49:05 +01:00
Geza Lore 5515eed0b6 Make AstTopScope accessible from AstNetlist
AstTopScope is a singleton node and making it accessible without a
traversal simplifies some code and decouple some other.
2021-10-24 13:00:29 +01:00
Geza Lore 381c87a1eb Remove VN_CAST_CONST and VN_AS_CONST.
The _CONST suffix on these macros is only lexical notation, pointer
constness can be preserved by overloading the underlying
implementations appropriately. Given that the compiler will catch
invalid const usage (trying to assign a non-const pointer to a const
pointer variable, etc.), and that the declarations of symbols should
make their constness obvious, I see no reason to keep the _CONST
flavours.
2021-10-24 11:43:48 +01:00
github action 20e896ec21 Apply 'make format' 2021-10-22 18:51:57 +00:00
Geza Lore 70603bb752 Add static assertions for unnecessary VN_IS/VN_AS/VN_CAST
Fail at compile time if the result of these macros can be statically
determined (i.e.: they aways succeed or always fail). Remove unnecessary
casts discovered. No functional change.
2021-10-22 19:39:24 +01:00
Geza Lore 7cb6dc664e Generate YYSTYPE members with astgen
In preparation for strengthening Ast type system. No functional change.
2021-10-22 19:27:32 +01:00
Geza Lore dae9fa5053 Use VN_AS wherever possible and obvious. No functional change. 2021-10-22 14:06:00 +01:00
Wilson Snyder aa1a0b0f13 Tests: Fix numactl on WSL2 2021-10-19 21:24:22 -04:00
Wilson Snyder 371bf01957 Tests: Fix numactl on WSL2 2021-10-19 21:21:52 -04:00
Wilson Snyder ef7759a522 Commentary re: WSL2 2021-10-19 20:34:13 -04:00
Wilson Snyder 0ef9087f89 Commentary 2021-10-17 14:51:50 -04:00
Wilson Snyder 00059987a1 devel release 2021-10-17 14:47:19 -04:00
Wilson Snyder 8f090176a6 Version bump 2021-10-17 14:36:23 -04:00
Wilson Snyder 43e8263d1f Commentary 2021-10-17 14:35:34 -04:00
Geza Lore ac622f9db8 Introduce VN_AS for downcasting to known AstNode subtype.
VN_AS should be used over VN_CAST in code where the author knows up
front (i.e.: statically) what the true type of the node is. This has
multiple benefits over VN_CAST:
- In the debug build: Asserts node type is as expected
- In the optimized build: It is faster as no superfluous type test
- And (I would argue most importantly) it documents intent in the code

No current instances of VN_CAST changed in this patch
2021-10-16 23:52:31 +01:00
Wilson Snyder 749a66b7a2 Add assertion on mix of combo/posedge (#3170) 2021-10-16 18:14:32 -04:00
Geza Lore fc80ace6e4 Reduce size of astgen generated implementation boilerplate.
Rely on C++ templates instead for simplicity. No functional change.
2021-10-16 20:15:51 +01:00
Wilson Snyder b8f6b262e4 Fix false EOFNEWLINE warning when DOS carriage returns present (#3171). 2021-10-13 21:21:51 -04:00
Wilson Snyder b64e89f7ed Fix calling new with arguments in same class (#3166). 2021-10-12 21:22:59 -04:00
Wilson Snyder c3bec344a4 Fix missing install of vl_file_copy/vl_hier_graph (#3165). 2021-10-12 20:20:45 -04:00
Iru Cai 9731ec76e3 Fix $urandom_range when the range is 0 ... UINT_MAX (#3161) 2021-10-11 06:45:19 -06:00
Matthew Ballance a9646cf45c Fix constructor-parameter argument comma-separation in C++ (#3162) 2021-10-09 17:19:31 -06:00
Wilson Snyder 5f597dd9fc Tests: Improve internal coverage holes 2021-10-05 22:02:37 -04:00
Wilson Snyder 7d57c3ca78 Internals: Remove dead code. 2021-10-05 22:02:23 -04:00
Wilson Snyder 4739956cfe Internals: Add missing const. No functional change. 2021-10-05 21:20:22 -04:00
Wilson Snyder e202a6324a Tests: Improve internal coverage holes 2021-10-05 21:09:57 -04:00
Wilson Snyder 66d70c8b37 Internal coverage: Fix some test runs having conflicting sources. 2021-10-05 20:22:29 -04:00
Wilson Snyder 02aa639425 Internals: Add some const etc. No functional change. 2021-10-05 19:42:31 -04:00
Wilson Snyder 55da66164b Fix verilator_gantt time on Arm. 2021-10-04 22:13:34 -04:00
Wilson Snyder 2560fc867f verilator_gantt: Fix reading broken /cpu/procinfo reports 2021-10-02 11:10:43 -04:00
Wilson Snyder f5c9deecb8 Tests: Add verilator_gantt no-proc test. 2021-10-02 10:05:59 -04:00
github action 20af8a36a7 Apply 'make format' 2021-09-28 11:29:21 +00:00
Zhanglei Wang 1c1c805b07 Fix internal error on bad widths (#3140) (#3145) 2021-09-28 07:28:02 -04:00
Wilson Snyder 9029da5ab8 Add profile-guided optmization of mtasks (#3150). 2021-09-26 22:51:11 -04:00
Wilson Snyder def7c8fe4d Commentary 2021-09-26 16:21:58 -04:00
Wilson Snyder 9184c4f501 Fix cygwin compile error due to missing -std=gnu++14 (#3149) 2021-09-26 16:19:46 -04:00
Wilson Snyder 44809f1843 Remove unused CFG_CXXFLAGS_STD_OLDEST 2021-09-26 16:01:25 -04:00
Wilson Snyder 87ced0cc3e Fix crash on clang 12/13 (#3148). 2021-09-25 17:10:57 -04:00
Wilson Snyder 741bb5328e verilator_gantt: Fix argument report omitting last digits 2021-09-24 21:11:15 -04:00
Wilson Snyder 33650336f5 Commentary 2021-09-24 08:49:16 -04:00
Wilson Snyder bbce1dc256 Commentary 2021-09-24 08:48:20 -04:00
Wilson Snyder 8ab51dbf22 Verilator_gantt: remove ASCII graphics 2021-09-24 08:48:20 -04:00
Wilson Snyder fd4595d6b4 verilator_gantt: Add eval count to report 2021-09-24 08:48:20 -04:00
github action 204804ae52 Apply 'make format' 2021-09-24 03:00:42 +00:00
Wilson Snyder c2819923c5 Verilator_gantt now shows the predicted mtask times, eval times, and additional statistics. 2021-09-23 22:59:36 -04:00
Wilson Snyder 68f1432a68 Gantt: Subtract common start in slowpath to reduce collection measurement error. 2021-09-23 19:43:20 -04:00
Keith Colbert 0defb61a18 Fix --waiver-output for multiline warnings (#2429) (#3141) 2021-09-22 07:42:59 -04:00
Wilson Snyder 0fc805202c Commentary (#3139) 2021-09-21 18:15:56 -04:00
Wilson Snyder a7374e84a2 Tests: Some coverage improvements 2021-09-20 18:20:48 -04:00
Wilson Snyder 76681fd931 Commentary 2021-09-17 20:18:47 -04:00
Wilson Snyder 2418df7bb2 Commentary 2021-09-17 20:03:45 -04:00
Wilson Snyder 97d8d32049 Commentary 2021-09-17 18:52:12 -04:00
Wilson Snyder 08c8b0d7d6 Fix removing if statement with side effect in condition (#3131). 2021-09-13 15:52:53 -04:00
Wilson Snyder 81fd3e4732 Commentary 2021-09-13 15:47:03 -04:00
Wilson Snyder d384a69877 Fix display has no time units on class function (#3116). 2021-09-08 19:31:46 -04:00
github action a8b480559d Apply 'make format' 2021-09-08 22:46:27 +00:00
Wilson Snyder f1b8b1d99b Format: perltidy spacing cleanup. No functional change. 2021-09-08 18:45:25 -04:00
Wilson Snyder f67637144f Internals: Some verilog.y format cleanups. No functional change. 2021-09-08 08:34:53 -04:00
Wilson Snyder 4b274a8d4d Convert verilator_gantt to python 2021-09-08 08:16:31 -04:00
Wilson Snyder c678e7ec3e Format: perltidy spacing cleanup. No functional change. 2021-09-07 23:50:28 -04:00
Wilson Snyder 2a79e46c46 Tests: Fix t_dist_fixme to detect later files. 2021-09-07 19:27:46 -04:00
Wilson Snyder d09b6a7d2c Include processor information in verilator_gantt data file. 2021-09-05 11:56:28 -04:00
Wilson Snyder 35eac0c457 Commentary: Fix profcfunc naming. 2021-09-05 11:33:20 -04:00
Wilson Snyder cac0b0f316 Tests: Fix t_gantt_io 2021-09-04 16:51:55 -04:00
Wilson Snyder 8519dc1383 Tests: Skip unstability 2021-09-04 13:48:16 -04:00
Wilson Snyder 72f198d79e Tests: Add t_gantt_io test 2021-09-04 12:44:13 -04:00
Wilson Snyder 1cb8091125 verilator_profcfunc: Also allow eval_step. 2021-09-04 12:28:26 -04:00
Wilson Snyder 18c543f2f2 Convert verilator_difftree to Python 2021-09-04 09:31:22 -04:00
Wilson Snyder 496b9f9c63 Tests: Add difftree test. 2021-09-04 08:27:59 -04:00
Wilson Snyder 1ee46ac5e1 Convert verilator_profcfunc to python. 2021-09-04 08:21:09 -04:00
Wilson Snyder f37c875be8 Internal: Remove fixme 2021-09-04 08:07:48 -04:00
Wilson Snyder 56dc66d842 Fix verilator_profcfunc profile accounting (#3115). 2021-09-03 19:59:10 -04:00
Wilson Snyder 7ae54ef973 Commentary 2021-09-02 09:00:01 -04:00
Iru Cai 4ed00c563c Support displaying x and z in $display task (#3107) (#3109) 2021-09-02 08:10:52 -04:00
Daniel Bates a49bfe871c Docs: Fix typo in coverage instructions (#3111) 2021-09-02 07:41:10 -04:00
Wilson Snyder 6d97fea2f5 Internals: Cleanup some const, etc. No functional change. 2021-09-01 22:15:38 -04:00
Wilson Snyder da833d55fe devel release 2021-09-01 21:08:17 -04:00
617 changed files with 18837 additions and 8850 deletions
+2
View File
@@ -13,4 +13,6 @@ Can you attach an example that shows the issue? (Must be openly licensed, ideal
What 'verilator --version' are you using? Did you try it with the git master version?
What OS and distribution are you using?
Would you be willing to try to fix Verilator yourself with assistance?
+1
View File
@@ -39,3 +39,4 @@ verilator-config-version.cmake
**/__pycache__/*
**/_build/*
**/obj_dir/*
/.vscode/
+57
View File
@@ -8,6 +8,63 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 4.216 2021-12-05
==========================
**Major:**
* Add --lib-create, similar to --protect-lib but without protections.
* Support tracing through --hierarchical/--lib-create libraries (#3200).
**Minor:**
* Internal code cleanups and improvements. [Geza Lore]
* Improve --thread verilation-time performance.
* Support task name in $display %m (#3211). [Julie Schwartz]
* Make 'bit', 'logic' and 'time' types unsigned by default. [Geza Lore]
* Optimize $random concatenates/selects (#3114).
* Fix array method names with parenthesis (#3181) (#3183). [Teng Huang]
* Fix split_var assign merging (#3177) (#3179). [Yutetsu TAKATSUKASA]
* Fix wrong bit op tree optimization (#3185). [Yutetsu TAKATSUKASA]
* Fix some SliceSels not being constants (#3186) (#3218). [Michaël Lefebvre]
* Fix nested generate if genblk naming (#3189). [yanx21]
* Fix hang on recursive definition error (#3199). [Jonathan Kimmitt]
* Fix display of signed without format (#3204). [Julie Schwartz]
* Fix display of empty string constant (#3207) (#3215). [Julie Schwartz]
* Fix incorrect width after and-or optimization (#3208). [Julie Schwartz]
* Fix $fopen etc on integer arrays (#3214). [adrienlemasle]
* Fix $size on dynamic strings (#3216).
* Fix %0 format on $value$plusargs (#3217).
* Fix timescale portability on Arm64 (#3222).
Verilator 4.214 2021-10-17
==========================
**Major:**
* Add profile-guided optmization of mtasks (#3150).
**Minor:**
* Verilator_gantt has removed the ASCII graphics, use the VCD output instead.
* Verilator_gantt now shows the predicted mtask times, eval times, and additional statistics.
* Verilator_gantt data files now include processor information, to allow later processing.
* Support displaying x and z in $display task (#3107) (#3109). [Iru Cai]
* Fix verilator_profcfunc profile accounting (#3115).
* Fix display has no time units on class function (#3116). [Damien Pretet]
* Fix removing if statement with side effect in condition (#3131). [Alexander Grobman]
* Fix --waiver-output for multiline warnings (#2429) (#3141). [Keith Colbert]
* Fix internal error on bad widths (#3140) (#3145). [Zhanglei Wang]
* Fix crash on clang 12/13 (#3148). [Kouping Hsu]
* Fix cygwin compile error due to missing -std=gnu++14 (#3149). [Sun Kim]
* Fix $urandom_range when the range is 0 ... UINT_MAX (#3161). [Iru Cai]
* Fix constructor-parameter argument comma-separation in C++ (#3162). [Matthew Ballance]
* Fix missing install of vl_file_copy/vl_hier_graph (#3165). [Popolon]
* Fix calling new with arguments in same class (#3166). [Matthew Ballance]
* Fix false EOFNEWLINE warning when DOS carriage returns present (#3171).
Verilator 4.212 2021-09-01
==========================
+8 -20
View File
@@ -118,23 +118,6 @@ INFOS = verilator.html verilator.pdf
INFOS_OLD = README README.html README.pdf
INST_PROJ_FILES = \
bin/verilator \
bin/verilator_ccache_report \
bin/verilator_coverage \
bin/verilator_gantt \
bin/verilator_includer \
bin/verilator_profcfunc \
include/verilated.mk \
include/*.[chv]* \
include/gtkwave/*.[chv]* \
include/vltstd/*.[chv]* \
INST_PROJ_BIN_FILES = \
bin/verilator_bin$(EXEEXT) \
bin/verilator_bin_dbg$(EXEEXT) \
bin/verilator_coverage_bin_dbg$(EXEEXT) \
EXAMPLES_FIRST = \
examples/make_hello_c \
examples/make_hello_sc \
@@ -142,7 +125,7 @@ EXAMPLES_FIRST = \
EXAMPLES = $(EXAMPLES_FIRST) $(filter-out $(EXAMPLES_FIRST), $(sort $(wildcard examples/*)))
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_gantt.1 verilator_profcfunc.1
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1
default: all
all: all_nomsg msg_test
@@ -224,8 +207,10 @@ VL_INST_INC_SRCDIR_FILES = \
include/vltstd/*.[chv]* \
VL_INST_DATA_SRCDIR_FILES = \
examples/*/*.[chv]* examples/*/Makefile* \
examples/*/CMakeLists.txt
examples/*/*.[chv]* \
examples/*/CMakeLists.txt \
examples/*/Makefile* \
examples/*/vl_* \
installbin:
$(MKINSTALLDIRS) $(DESTDIR)$(bindir)
@@ -369,6 +354,9 @@ clang-format:
PY_PROGRAMS = \
bin/verilator_ccache_report \
bin/verilator_difftree \
bin/verilator_gantt \
bin/verilator_profcfunc \
examples/xml_py/vl_file_copy \
examples/xml_py/vl_hier_graph \
docs/guide/conf.py \
+35 -34
View File
@@ -34,11 +34,11 @@ my $opt_quiet_exit;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
pod2usage(-exitstatus=>2, -verbose=>0);
pod2usage(-exitstatus => 2, -verbose => 0);
}
# Insert debugging options up front
push @ARGV, (split ' ',$ENV{VERILATOR_TEST_FLAGS}||"");
push @ARGV, (split ' ', $ENV{VERILATOR_TEST_FLAGS} || "");
# We sneak a look at the flags so we can do some pre-environment checks
# All flags will hit verilator...
@@ -46,7 +46,7 @@ foreach my $sw (@ARGV) {
push @Opt_Verilator_Sw, $sw;
}
Getopt::Long::config("no_auto_abbrev","pass_through");
Getopt::Long::config("no_auto_abbrev", "pass_through");
if (! GetOptions(
# Major operating modes
"help" => \&usage,
@@ -60,7 +60,7 @@ if (! GetOptions(
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
pod2usage(-exitstatus => 2, -verbose => 0);
}
if ($opt_gdbbt && !gdb_works()) {
@@ -73,12 +73,12 @@ if ($opt_gdbbt && !gdb_works()) {
# Starting with that, escape all special chars for the shell;
# The shell will undo the escapes and the verilator binary should
# then see exactly the contents of @Opt_Verilator_Sw.
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
my @quoted_sw = map { sh_escape($_) } @Opt_Verilator_Sw;
if ($opt_gdb) {
# Generic GDB interactive
run (aslr_off()
.($ENV{VERILATOR_GDB}||"gdb")
." ".verilator_bin()
. ($ENV{VERILATOR_GDB} || "gdb")
. " " . verilator_bin()
# Note, uncomment to set breakpoints before running:
# ." -ex 'break main'"
@@ -87,42 +87,41 @@ if ($opt_gdb) {
# escapes as you would expect in a double-quoted string.
# That's not true for a single-quoted string, where \'
# actually terminates the string -- not what we want!
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt'");
. " -ex \"run " . join(' ', @quoted_sw) . "\""
. " -ex 'set width 0'"
. " -ex 'bt'");
} elsif ($opt_rr) {
# Record with rr
run (aslr_off()
."rr record ".verilator_bin()
." ".join(' ', @quoted_sw));
. "rr record " . verilator_bin()
. " " . join(' ', @quoted_sw));
} elsif ($opt_gdbbt && $Debug) {
# Run under GDB to get gdbbt
run (aslr_off()
."gdb"
." ".verilator_bin()
." --batch --quiet --return-child-result"
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt' -ex 'quit'");
. "gdb"
. " " . verilator_bin()
. " --batch --quiet --return-child-result"
. " -ex \"run " . join(' ', @quoted_sw)."\""
. " -ex 'set width 0'"
. " -ex 'bt' -ex 'quit'");
} elsif ($Debug) {
# Debug
run(aslr_off()
.verilator_bin()." ".join(' ',@quoted_sw));
run(aslr_off() . verilator_bin() . " " . join(' ', @quoted_sw));
} else {
# Normal, non gdb
run(verilator_bin()." ".join(' ',@quoted_sw));
run(verilator_bin() . " " . join(' ', @quoted_sw));
}
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
pod2usage(-verbose => 2, -exitval => 0, -output => \*STDOUT);
}
sub debug {
shift;
my $level = shift;
$Debug = $level||3;
$Debug = $level || 3;
}
#######################################################################
@@ -163,13 +162,13 @@ sub verilator_bin {
sub gdb_works {
$! = undef; # Cleanup -x
system("gdb /bin/echo"
." --batch-silent --quiet --return-child-result"
." -ex 'run -n'" # `echo -n`
." -ex 'set width 0'"
." -ex 'bt'"
." -ex 'quit'");
. " --batch-silent --quiet --return-child-result"
. " -ex 'run -n'" # `echo -n`
. " -ex 'set width 0'"
. " -ex 'bt'"
. " -ex 'quit'");
my $status = $?;
return $status==0;
return $status == 0;
}
sub aslr_off {
@@ -185,7 +184,7 @@ sub run {
# Run command, check errors
my $command = shift;
$! = undef; # Cleanup -x
print "\t$command\n" if $Debug>=3;
print "\t$command\n" if $Debug >= 3;
system($command);
my $status = $?;
if ($status) {
@@ -193,7 +192,7 @@ sub run {
warn "%Error: verilator: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: export VERILATOR_ROOT=" . ($ENV{VERILATOR_ROOT} || "") . "\n";
warn "%Error: $command\n";
}
if ($status & 127) {
@@ -201,13 +200,13 @@ sub run {
|| ($status & 127) == 8 # SIGFPA
|| ($status & 127) == 11) { # SIGSEGV
warn "%Error: Verilator internal fault, sorry. "
."Suggest trying --debug --gdbbt\n" if !$Debug;
. "Suggest trying --debug --gdbbt\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator aborted. "
."Suggest trying --debug --gdbbt\n" if !$Debug;
. "Suggest trying --debug --gdbbt\n" if !$Debug;
} else {
warn "%Error: Verilator threw signal $status. "
."Suggest trying --debug --gdbbt\n" if !$Debug;
. "Suggest trying --debug --gdbbt\n" if !$Debug;
}
}
if (!$opt_quiet_exit && ($status != 256 || $Debug)) { # i.e. not normal exit(1)
@@ -337,6 +336,7 @@ detailed descriptions of these arguments.
-LDFLAGS <flags> Linker pre-object arguments for makefile
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
--lib-create <name> Create a DPI library
+libext+<ext>+[ext]... Extensions for finding modules
--lint-only Lint, but do not make output
-MAKEFLAGS <flags> Arguments to pass to make during --build
@@ -448,6 +448,7 @@ description of these arguments.
+verilator+prof+threads+file+<filename> Set profile filename
+verilator+prof+threads+start+<value> Set profile starting point
+verilator+prof+threads+window+<value> Set profile duration
+verilator+prof+vlt+file+<filename> Set profile guided filename
+verilator+rand+reset+<value> Set random reset technique
+verilator+seed+<value> Set random seed
+verilator+V Verbose version and config
+9 -9
View File
@@ -30,7 +30,7 @@ $Debug = 0;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
pod2usage(-exitstatus=>2, -verbose=>0);
pod2usage(-exitstatus => 2, -verbose => 0);
}
# We sneak a look at the flags so we can do some pre-environment checks
@@ -40,7 +40,7 @@ foreach my $sw (@ARGV) {
push @Opt_Verilator_Sw, $sw;
}
Getopt::Long::config("no_auto_abbrev","pass_through");
Getopt::Long::config("no_auto_abbrev", "pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
@@ -49,23 +49,23 @@ if (! GetOptions (
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
pod2usage(-exitstatus => 2, -verbose => 0);
}
# Normal, non gdb
run(verilator_coverage_bin()
." ".join(' ',@Opt_Verilator_Sw));
. " " . join(' ', @Opt_Verilator_Sw));
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
pod2usage(-verbose => 2, -exitval => 0, -output => \*STDOUT);
}
sub debug {
shift;
my $level = shift;
$Debug = $level||3;
$Debug = $level || 3;
}
#######################################################################
@@ -107,7 +107,7 @@ sub run {
# Run command, check errors
my $command = shift;
$! = undef; # Cleanup -x
print "\t$command\n" if $Debug>=3;
print "\t$command\n" if $Debug >= 3;
system($command);
my $status = $?;
if ($status) {
@@ -115,11 +115,11 @@ sub run {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: export VERILATOR_ROOT=" . ($ENV{VERILATOR_ROOT} || "") . "\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
+106 -200
View File
@@ -1,233 +1,139 @@
#!/usr/bin/env perl
# See copyright, etc in below POD section.
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0116
######################################################################
use warnings;
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw($Debug);
import argparse
import collections
import glob
import os.path
import re
import sys
#======================================================================
# main
$Debug = 0;
my $Opt_A;
my $Opt_B;
my $Opt_Lineno = 1;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"lineno!" => \$Opt_Lineno,
)) {
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
}
def diff(a, b):
defined $Opt_A or die "%Error: No old diff filename\n";
defined $Opt_B or die "%Error: No new diff filename\n";
if not os.path.exists(a):
sys.exit("%Error: No old diff filename found: " + a)
if not os.path.exists(b):
sys.exit("%Error: No new diff filename found: " + b)
-e $Opt_A or die "%Error: No old diff filename found: $Opt_A\n";
-e $Opt_B or die "%Error: No new diff filename found: $Opt_B\n";
if os.path.isdir(a) and os.path.isdir(b):
diff_dir(a, b)
elif os.path.isfile(a) and os.path.isfile(b):
diff_file(a, b)
else:
sys.exit("%Error: Mix of files and dirs")
if (-d $Opt_A && -d $Opt_B) {
diff_dir($Opt_A, $Opt_B);
} elsif (-f $Opt_A && -f $Opt_B) {
diff_file($Opt_A, $Opt_B);
} else {
die "%Error: Mix of files and dirs\n";
}
sub diff_dir {
my $a = shift;
my $b = shift;
def diff_dir(a, b):
# Diff all files under two directories
my %files;
files = collections.defaultdict(lambda: {})
foreach my $fn (glob("$a/*.tree")) {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{a} = $fn;
}
foreach my $fn (glob("$b/*.tree")) {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{b} = $fn;
}
my $any;
foreach my $base (sort (keys %files)) {
my $a = $files{$base}{a};
my $b = $files{$base}{b};
next if !$a || !$b;
print "="x70,"\n";
print "= $a <-> $b\n";
diff_file($a,$b);
$any = 1;
}
$any or warn("%Warning: No .tree files found that have similar base names:\n "
.join("\n ", sort keys %files),"\n");
}
for fn in glob.glob(a + "/*.tree"):
base = re.sub(r'.*/', '', fn)
files[base]['a'] = fn
for fn in glob.glob(b + "/*.tree"):
base = re.sub(r'.*/', '', fn)
files[base]['b'] = fn
sub diff_file {
my $a = shift;
my $b = shift;
anyfile = False
for base in sorted(files.keys()):
a = files[base]['a']
b = files[base]['b']
if not a or not b:
continue
print("=" * 70)
print("= %s <-> %s" % (a, b))
diff_file(a, b)
anyfile = True
if not anyfile:
sys.stderr.write(
"%Warning: No .tree files found that have similar base names\n")
def diff_file(a, b):
# Compare the two tree files
(my $short_a = $a) =~ s/[^a-zA-Z0-9.]+/_/g;
(my $short_b = $b) =~ s/[^a-zA-Z0-9.]+/_/g;
my $tmp_a = "/tmp/${$}_${short_a}.a";
my $tmp_b = "/tmp/${$}_${short_b}.b";
short_a = re.sub(r'[^a-zA-Z0-9.]+', '_', a)
short_b = re.sub(r'[^a-zA-Z0-9.]+', '_', b)
tmp_a = "/tmp/%s_%s.a" % (os.getpid(), short_a)
tmp_b = "/tmp/%s_%s.b" % (os.getpid(), short_b)
my $vera = version_from($a);
my $verb = version_from($b);
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|| ($vera >= 0x3900 && $verb < 0x3900));
# Version conversion deprecated, but for future...
# vera = version_from(a)
# verb = version_from(b)
# verCvt = ((vera < 0x3900 and verb >= 0x3900)
# or (vera >= 0x3900 and verb < 0x3900))
filter($a, $tmp_a, $verCvt);
filter($b, $tmp_b, $verCvt);
system("diff -u $tmp_a $tmp_b");
unlink $tmp_a;
unlink $tmp_b;
}
filterf(a, tmp_a)
filterf(b, tmp_b)
os.system("diff -u " + tmp_a + " " + tmp_b)
os.unlink(tmp_a)
os.unlink(tmp_b)
sub version_from {
my $fn = shift;
def version_from(filename):
# Return dump format
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
while (defined (my $line=$f1->getline())) {
last if $. > 10;
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
}
return 1.0;
}
with open(filename) as fh:
lineno = 0
for line in fh:
if lineno > 10:
break
match = re.search(r'format (0x[0-9.]+)', line)
if match:
return hex(match.group(1))
return 1.0
sub filter {
my $fn1 = shift;
my $fn2 = shift;
my $verCvt = shift;
def filterf(fn1, fn2):
# Remove hex numbers before diffing
my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,";
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
while (defined (my $line=$f1->getline())) {
same_line:
next if $line =~ / This=/;
$line =~ s/0x[a-f0-9]+/0x/g;
$line =~ s/<e[0-9]+\#?>/<e>/g;
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
if ($verCvt) {
next if $line =~ /^ NETLIST/;
if ($line =~ /: ([A-Z]+) /) {
my $type = $1;
next if $type =~ 'DTYPE';
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
$line =~ /^(\s+\S+:) /; my $prefix = $1;
while (defined ($line=$f1->getline())) {
next if $line =~ /^\s+[a-z]/; # Table body
next if $line =~ /^${prefix}[0-9]:/;
goto same_line;
}
next;
}
}
}
print $f2 $line;
}
$f1->close;
$f2->close;
}
with open(fn1) as fh1:
with open(fn2, "w") as fh2:
for line in fh1:
if re.search(r' This=', line):
continue
line = re.sub(r'0x[a-f0-9]+', '0x', line)
line = re.sub(r'<e[0-9]+\#?>', '<e>', line)
if not Args.no_lineno:
line = re.sub(r'{[a-z]*\d+}', '{}', line)
fh2.write(line)
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
######################################################################
######################################################################
sub debug {
$Debug = 1;
}
sub parameter {
my $param = shift;
if (!defined $Opt_A) {
$Opt_A = $param;
} elsif (!defined $Opt_B) {
$Opt_B = $param;
} else {
die "%Error: Unknown parameter: $param\n";
}
}
#######################################################################
sub run {
# Run a system command, check errors
my $command = shift;
print "\t$command\n";
system "$command";
my $status = $?;
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
}
#######################################################################
__END__
=pod
=head1 NAME
verilator_difftree - Compare two Verilator debugging trees
=head1 SYNOPSIS
verilator_difftree .../a/a.tree .../b/a.tree
verilator_difftree .../a .../b
=head1 DESCRIPTION
Verilator_difftree is used for debugging Verilator tree output files. It
performs a diff between two files, or all files common between two
parser = argparse.ArgumentParser(
allow_abbrev=False,
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""Compare two Verilator debugging trees""",
epilog=
"""Verilator_difftree is used for debugging Verilator tree output files.
It performs a diff between two files, or all files common between two
directories, ignoring irrelevant pointer differences.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=item --nolineno
Do not show differences in line numbering.
=back
=head1 DISTRIBUTION
The latest version is available from L<https://verilator.org>.
For documentation see
https://verilator.org/guide/latest/exe_verilator_difftree.html
Copyright 2005-2021 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
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
=head1 AUTHORS
parser.add_argument('--debug',
action='store_const',
const=9,
help='enable debug')
parser.add_argument('--no-lineno',
action='store_false',
help='do not show differences in line numbering')
parser.add_argument('filea', help='input file a to diff')
parser.add_argument('fileb', help='input file b to diff')
Wilson Snyder <[email protected]>
=head1 SEE ALSO
C<verilator>
and L<https://verilator.org/verilator_doc.html> for detailed documentation.
=cut
Args = parser.parse_args()
diff(Args.filea, Args.fileb)
######################################################################
### Local Variables:
### compile-command: "$V4/bin/verilator_difftree {$V4D,$V4}/test_regress/obj_dir/t_EXAMPLE/V*_03_*.tree"
### End:
# Local Variables:
# compile-command: "./verilator_difftree ../test_regress/t/t_difftree.{a,b}.tree"
# End:
+428 -511
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -10,11 +10,11 @@
require 5.005;
use warnings;
print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
print "// DESCR" . "IPTION: Generated by verilator_includer via makefile\n";
foreach my $param (@ARGV) {
if ($param =~ /^-D([^=]+)=(.*)/) {
print "#define $1 $2\n"
print "#define $1 $2\n";
} else {
print "#include \"$param\"\n"
print "#include \"$param\"\n";
}
}
+173 -217
View File
@@ -1,248 +1,204 @@
#!/usr/bin/env perl
# See copyright, etc in below POD section.
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0116,R0914,R0912,R0915,eval-used
######################################################################
require 5.006_001;
use warnings;
use Getopt::Long;
use IO::File;
use Pod::Usage;
eval { use Data::Dumper; $Data::Dumper::Indent = 1; }; # Debug, ok if missing
use strict;
use vars qw($Debug);
import argparse
import collections
import re
# from pprint import pprint
#======================================================================
######################################################################
#======================================================================
# main
def profcfunc(filename):
funcs = {}
$Debug = 0;
my $Opt_File;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
}
with open(filename) as fh:
defined $Opt_File or die "%Error: No filename given\n";
for line in fh:
# %time cumesec selfsec calls {stuff} name
match = re.match(
r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
line)
if match:
pct = float(match.group(1))
sec = float(match.group(2))
calls = float(match.group(3))
func = match.group(4)
if func not in funcs:
funcs[func] = {'pct': 0, 'sec': 0, 'calls': 0}
funcs[func]['pct'] += pct
funcs[func]['sec'] += sec
funcs[func]['calls'] += calls
continue
profcfunc($Opt_File);
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
$Debug = 1;
}
sub parameter {
my $param = shift;
if (!defined $Opt_File) {
$Opt_File = $param;
} else {
die "%Error: Unknown parameter: $param\n";
}
}
#######################################################################
sub profcfunc {
my $filename = shift;
# Remove hex numbers before diffing
my $fh = IO::File->new ($filename) or die "%Error: $! $filename,";
my %funcs;
while (defined (my $line=$fh->getline())) {
# %time cumesec selfsec calls {stuff} name
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
$funcs{$func}{pct} += $pct;
$funcs{$func}{sec} += $sec;
$funcs{$func}{calls} += $calls;
}
# Older gprofs have no call column for single-call functions
# %time cumesec selfsec {stuff} name
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
my $pct=$1; my $sec=$2; my $calls=1; my $func=$3;
$funcs{$func}{pct} += $pct;
$funcs{$func}{sec} += $sec;
$funcs{$func}{calls} += $calls;
}
}
$fh->close;
# Older gprofs have no call column for single-call functions
# %time cumesec selfsec {stuff} name
match = re.match(
r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
line)
if match:
pct = float(match.group(1))
sec = float(match.group(2))
calls = 1
func = match.group(3)
if func not in funcs:
funcs[func] = {'pct': 0, 'sec': 0, 'calls': 0}
funcs[func]['pct'] += pct
funcs[func]['sec'] += sec
funcs[func]['calls'] += calls
continue
# Find modules
my %pointer_mods;
my %verilated_mods;
foreach my $func (keys %funcs) {
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
$verilated_mods{$1} = qr/^$1/;
$pointer_mods{$2} = $1;
}
}
#print Dumper(\%pointer_mods, \%verilated_mods);
verilated_mods = {}
for func in funcs:
match = re.search(r'(.*)::eval(_step)?\(', func)
if match:
prefix = match.group(1)
if Args.debug:
print("-got _eval %s prefix=%s" % (func, prefix))
verilated_mods[prefix] = re.compile(r'^' + prefix)
# pprint(verilated_mods)
# Resort by Verilog name
my %vfuncs;
my %groups;
foreach my $func (keys %funcs) {
my $pct = $funcs{$func}{pct};
my $vfunc = $func;
my $design;
# Sort by Verilog name
vfuncs = {}
groups = {}
groups['type'] = collections.defaultdict(lambda: 0)
groups['design'] = collections.defaultdict(lambda: 0)
groups['module'] = collections.defaultdict(lambda: 0)
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
$design = $pointer_mods{$1};
}
for func in funcs:
pct = funcs[func]['pct']
vfunc = func
foreach my $vde (keys %verilated_mods) {
last if $design;
if ($func =~ /$verilated_mods{$vde}/) {
$design=$vde;
last;
}
}
funcarg = re.sub(r'^.*\(', '', func)
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
$vfunc = sprintf("VBlock %s:%d", $1, $2);
$groups{type}{"Verilog Blocks under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$1} += $pct;
} else {
if ($design) {
$vfunc = sprintf("VCommon %s", $func);
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
$groups{design}{'C++'} += $pct;
$groups{module}{'C++'} += $pct;
}
}
$vfuncs{$vfunc} = $funcs{$func};
}
design = None
for vde in verilated_mods:
if verilated_mods[vde].match(func) or verilated_mods[vde].match(
funcarg):
design = vde
break
vdesign = "-"
prof_match = re.search(r'__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(', vfunc)
if design and prof_match:
linefunc = prof_match.group(1)
lineno = int(prof_match.group(2))
vfunc = "VBlock %s:%d" % (linefunc, lineno)
vdesign = design
groups['type']["Verilog Blocks under " + design] += pct
groups['design'][design] += pct
groups['module'][linefunc] += pct
elif design:
vfunc = "VCommon " + func
vdesign = design
groups['type']["Common code under " + design] += pct
groups['design'][design] += pct
groups['module'][design + " common code"] += pct
elif re.match(r'(VL_[A-Z0-9_]+|_?vl_[a-zA-Z0-9_]+|Verilated)', vfunc):
vfunc = "VLib " + func
groups['type']['VLib'] += pct
groups['design']['VLib'] += pct
groups['module']['VLib'] += pct
elif re.match(r'^_mcount_private', vfunc):
vfunc = "Prof " + func
groups['type']['Prof'] += pct
groups['design']['Prof'] += pct
groups['module']['Prof'] += pct
else:
vfunc = "C++ " + func
groups['type']['C++'] += pct
groups['design']['C++'] += pct
groups['module']['C++'] += pct
if vfunc not in vfuncs:
vfuncs[vfunc] = funcs[func]
vfuncs[vfunc]['design'] = vdesign
else:
vfuncs[vfunc]['pct'] += funcs[func]['pct']
vfuncs[vfunc]['calls'] += funcs[func]['calls']
vfuncs[vfunc]['sec'] += funcs[func]['sec']
for ftype in ['type', 'design', 'module']:
missing = 100
for item in groups[ftype].keys():
missing -= groups[ftype][item]
groups[ftype]["\377Unaccounted for/rounding error"] = missing
print("Overall summary by %s:" % ftype)
print(" %-6s %s" % ("% time", ftype))
for what in sorted(groups[ftype].keys()):
# \377 used to establish sort order
pwhat = re.sub(r'^\377', '', what)
print(" %6.2f %s" % (groups[ftype][what], pwhat))
print()
design_width = 1
for func in vfuncs:
if design_width < len(vfuncs[func]['design']):
design_width = len(vfuncs[func]['design'])
print("Verilog code profile:")
print(" These are split into three categories:")
print(" C++: Time in non-Verilated C++ code")
print(" Prof: Time in profile overhead")
print(" VBlock: Time attributable to a block in a" +
" Verilog file and line")
print(" VCommon: Time in a Verilated module," +
" due to all parts of the design")
print(" VLib: Time in Verilated common libraries," +
" called by the Verilated code")
print()
print(" % cumulative self ")
print((" time seconds seconds calls %-" + str(design_width) +
"s type filename and line number") % "design")
cume = 0
for func in sorted(vfuncs.keys(),
key=lambda f: vfuncs[f]['sec'],
reverse=True):
cume += vfuncs[func]['sec']
print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") %
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'],
vfuncs[func]['calls'], vfuncs[func]['design'], func))
foreach my $type (qw(type design module)) {
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
}
if ($missing) {
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
}
######################################################################
######################################################################
print("Overall summary by $type:\n");
printf(" %-6s %s\n","% time",$type);
foreach my $what (sort (keys %{$groups{$type}})) {
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
}
print("\n");
}
print("Verilog code profile:\n");
print(" These are split into three categories:\n");
print(" C++: Time in non-Verilated C++ code\n");
print(" Prof: Time in profile overhead\n");
print(" VBlock: Time attributable to a block in a Verilog file and line\n");
print(" VCommon: Time in a Verilated module, due to all parts of the design\n");
print(" VLib: Time in Verilated common libraries, called by the Verilated code\n");
print("\n");
print(" % cumulative self \n");
print(" time seconds seconds calls type filename and line number\n");
my $cume = 0;
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|| $a cmp $b}
(keys %vfuncs)) {
$cume += $vfuncs{$func}{sec};
printf +("%6.2f %9.2f %8.2f %8d %s\n",
$vfuncs{$func}{pct},
$cume, $vfuncs{$func}{sec},
$vfuncs{$func}{calls},
$func);
}
}
#######################################################################
__END__
=pod
=head1 NAME
verilator_profcfunc - Read gprof report created with --prof-cfuncs
=head1 SYNOPSIS
verilator --prof-cfuncs ....
gcc ....
{run executable}
gprof
verilator_profcfuncs gprof.out
=head1 DESCRIPTION
Verilator_profcfunc reads a profile report created by gprof. The names of
parser = argparse.ArgumentParser(
allow_abbrev=False,
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""Read gprof report created with --prof-cfuncs""",
epilog=
"""Verilator_profcfunc reads a profile report created by gprof. The names of
the functions are then transformed, assuming the user used Verilator's
--prof-cfuncs, and a report printed showing the percentage of time, etc,
in each Verilog block.
For documentation see
L<https://verilator.org/guide/latest/exe_verilator_profcfuncs.html>.
https://verilator.org/guide/latest/exe_verilator_profcfunc.html
=head1 ARGUMENT SUMMARY
<filename> Input file (gprof.out)
--help Display this help
=head1 DISTRIBUTION
The latest version is available from L<https://verilator.org>.
Copyright 2007-2021 by Wilson Snyder. This program is free software; you
Copyright 2002-2021 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
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
=head1 SEE ALSO
parser.add_argument('--debug',
action='store_const',
const=9,
help='enable debug')
parser.add_argument('filename', help='input gprof output to process')
C<verilator>
and L<https://verilator.org/guide/latest/exe_verilator_profcfuncs.html> for
detailed documentation.
=cut
Args = parser.parse_args()
profcfunc(Args.filename)
######################################################################
### Local Variables:
### compile-command: "$V4/bin/verilator_profcfunc $V4/test_c/obj_dir/V*_03_*.tree $V4N/test_c/obj_dir/V*_03_*.tree"
### End:
# Local Variables:
# compile-command: "./verilator_profcfunc ../test_regress/t/t_profcfunc.gprof"
# End:
+8 -12
View File
@@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.212 2021-09-01],
AC_INIT([Verilator],[4.216 2021-12-05],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
@@ -347,22 +347,18 @@ AC_SUBST(CFG_CXXFLAGS_PROFILE)
# Flag to select newest language standard supported
# Macros work such that first option that passes is the one we take
# Currently enabled c++14 due to packaged SystemC dependency
# c++17 is the newest that Verilator supports
# c++03 is the oldest that Verilator supports
# c++14 is the newest that Verilator is regressed to support
# c++11 is the oldest that Verilator supports
# gnu is requried for Cygwin to compile verilated.h successfully
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20)
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++20)
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17)
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++17)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++14)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++14)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++11)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++11)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++03)
AC_SUBST(CFG_CXXFLAGS_STD_NEWEST)
# And likewise oldest standard (same list above, backwards)
# This is used for internal testing
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++03)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++11)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++14)
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++17)
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++20)
AC_SUBST(CFG_CXXFLAGS_STD_OLDEST)
# Flags for compiling Verilator internals including parser, and Verilated files
# These turn on extra warnings and are only used with 'configure --enable-ccwarn'
+7
View File
@@ -11,6 +11,7 @@ Andreas Kuster
Chris Randall
Conor McCullough
Dan Petrisko
Daniel Bates
David Horton
David Metz
David Stanford
@@ -30,6 +31,7 @@ Harald Heckmann
Howard Su
Huang Rui
HyungKi Jeong
Iru Cai
Ivan Vnučec
Iztok Jeras
James Hanlon
@@ -43,9 +45,11 @@ John Coiner
John Demme
Jonathan Drolet
Josh Redford
Julie Schwartz
Julien Margetts
Kaleb Barrett
Kanad Kanhere
Keith Colbert
Kevin Kiningham
Krzysztof Bieganski
Kuba Ober
@@ -60,6 +64,7 @@ Marshal Qiao
Martin Schmidt
Matthew Ballance
Michael Killough
Michaël Lefebvre
Mike Popoloski
Miodrag Milanović
Morten Borup Petersen
@@ -85,6 +90,7 @@ Sergi Granell
Stefan Wallentowitz
Stephen Henry
Steven Hugg
Teng Huang
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
@@ -101,3 +107,4 @@ Yossi Nivin
Yuri Victorovich
Yutetsu TAKATSUKASA
Yves Mathieu
Zhanglei Wang
+6
View File
@@ -0,0 +1,6 @@
.. comment: generated by t_lint_didnotconverge_bad
.. code-block:: sv
:linenos:
always_comb b = ~a;
always_comb a = b;
+7
View File
@@ -0,0 +1,7 @@
.. comment: generated by t_lint_didnotconverge_bad
.. code-block::
-V{t#,#}+ Vt_lint_didnotconverge_bad___024root___change_request
-V{t#,#}+ Vt_lint_didnotconverge_bad___024root___change_request_1
-V{t#,#} CHANGE: t/t_lint_didnotconverge_bad.v:14: a
%Error: t/t_lint_didnotconverge_bad.v:7: Verilated model didn't converge
+4
View File
@@ -0,0 +1,4 @@
.. comment: generated by t_lint_didnotconverge_nodbg_bad
.. code-block::
%Error: t/t_lint_didnotconverge_bad.v:7: Verilated model didn't converge
+5
View File
@@ -0,0 +1,5 @@
.. comment: generated by t_lint_stmtdly_bad
.. code-block:: sv
:emphasize-lines: 1
#100 $finish; //<--- Warning
+4
View File
@@ -0,0 +1,4 @@
.. comment: generated by t_lint_stmtdly_bad
.. code-block::
%Warning-STMTDLY: example.v:1:8 Unsupported: Ignoring delay on this delayed statement.
+1 -1
View File
@@ -1,4 +1,4 @@
# pylint: disable=C0103,C0114,C0116,E0402,W0622
# pylint: disable=C0103,C0114,C0116,C0301,E0402,W0622
#
# Configuration file for Verilator's Sphinx documentation builder.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
+1 -1
View File
@@ -9,7 +9,7 @@ The following deprecated items are scheduled for future removal:
C++11 compiler support
Verilator currently requires C++11 or newer compilers. Verilator will
require C++14 or newer compilers for both compiling Verilator and
compiling Verilated models no sooner than January 2022.
compiling Verilated models no sooner than January 2023.
Verilated_heavy.h
The legacy "verilated_heavy.h" include was replaced with just including
+6
View File
@@ -62,6 +62,12 @@ Summary:
makes sense for a single-clock-domain module where it's typical to want
to capture one posedge eval() and one negedge eval().
.. option:: +verilator+prof+vlt+file+<filename>
When a model was Verilated using :vlopt:`--prof-threads`, sets the
profile-guided optimization data runtime filename to dump to. Defaults
to :file:`profile.vlt`.
.. option:: +verilator+rand+reset+<value>
When a model was Verilated using :vlopt:`--x-initial unique
+63 -51
View File
@@ -158,41 +158,26 @@ Summary:
.. option:: --clk <signal-name>
Sometimes it is quite difficult for Verilator to distinguish clock
signals from other data signals. Occasionally the clock signals can end
up in the checking list of signals which determines if further
evaluation is needed. This will heavily degrade the performance of a
Verilated model.
With :vlopt:`--clk`, the specified signal-name is taken as a root clock
into the model, then Verilator will mark the signal as clocker and
propagate the clocker attribute automatically to other signals derived
from that. In this way, Verilator will try to avoid taking the clocker
signal into checking list.
into the model; Verilator will mark the signal as clocker and
propagate the clocker attribute automatically to other signals downstream in
that clock tree.
Note signal-name is specified by the RTL hierarchy path. For example,
v.foo.bar. If the signal is the input to top-module, the directly the
signal name. If you find it difficult to find the exact name, try to use
a :option:`/*verilator&32;clocker*/` metacomment in RTL file to mark the
The provided signal-name is specified using a RTL hierarchy path. For
example, v.foo.bar. If the signal is the input to top-module, then
directly provide the signal name. Alternatively, use a
:option:`/*verilator&32;clocker*/` metacomment in RTL file to mark the
signal directly.
If clock signals are assigned to vectors and then later used
individually, Verilator will attempt to decompose the vector and connect
the single-bit clock signals directly. This should be transparent to
the user.
If clock signals are assigned to vectors and then later used as
individual bits, Verilator will attempt to decompose the vector and
connect the single-bit clock signals.
.. option:: --make <build-tool>
Generates a script for the specified build tool.
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
Both can be specified together. If no build tool is specified, gmake is
assumed. The executable of gmake can be configured via environment
variable "MAKE".
When using :vlopt:`--build` Verilator takes over the responsibility of
building the model library/executable. For this reason :option:`--make`
cannot be specified when using :vlopt:`--build`.
The clocker attribute is useful in cases where Verilator does not
properly distinguish clock signals from other data signals. Using
clocker will cause the signal indicated to be considered a clock, and
remove it from the combinatorial logic reevaluation checking code. This
may greatly improve performance.
.. option:: --compiler <compiler-name>
@@ -590,6 +575,23 @@ Summary:
"+libext+" is fairly standard across Verilog tools. Defaults to
".v+.sv".
.. option:: --lib-create <name>
Produces C++, Verilog wrappers and a Makefile which can in turn produce
a DPI library which can be used by Verilator or other simulators along
with the corresponding Verilog wrapper. The Makefile will build both a
static and dynamic version of the library named :file:`lib<name>.a` and
:file:`lib<name>.so` respectively. This is done because some simulators
require a dynamic library, but the static library is arguably easier to
use if possible. :vlopt:`--protect-lib` implies :vlopt:`--protect-ids`.
When using :vlopt:`--lib-create` it is advised to also use
:vlopt:`--timescale-override /1fs <--timescale-override>` to ensure the
model has a time resolution that is always compatible with the time
precision of the upper instantiating module.
See also :vlopt:`--protect-lib`.
.. option:: --lint-only
Check the files for lint violations only, do not create any other
@@ -601,6 +603,19 @@ Summary:
If the design is not to be completely Verilated see also the
:vlopt:`--bbox-sys` and :vlopt:`--bbox-unsup` options.
.. option:: --make <build-tool>
Generates a script for the specified build tool.
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
Both can be specified together. If no build tool is specified, gmake is
assumed. The executable of gmake can be configured via environment
variable "MAKE".
When using :vlopt:`--build` Verilator takes over the responsibility of
building the model library/executable. For this reason :option:`--make`
cannot be specified when using :vlopt:`--build`.
.. option:: -MAKEFLAGS <string>
When using :vlopt:`--build`, add the specified argument to the invoked
@@ -816,7 +831,7 @@ Summary:
When compiling the C++ code, enable the compiler's profiling flag
(e.g. :code:`g++ -pg`). See :ref:`Profiling`.
Using :vlopt:`--prof-cfuncs` also enables :vlopt:`prof-c`.
Using :vlopt:`--prof-cfuncs` also enables :vlopt:`--prof-c`.
.. option:: --prof-cfuncs
@@ -828,12 +843,12 @@ Summary:
came from. This allows gprof or oprofile reports to be correlated with
the original Verilog source statements. See :ref:`Profiling`.
Using :vlopt:`--prof-cfuncs` also enables :vlopt:`prof-c`.
Using :vlopt:`--prof-cfuncs` also enables :vlopt:`--prof-c`.
.. option:: --prof-threads
Enable gantt chart data collection for threaded builds. See :ref:`Thread
Profiling`.
Profiling` and :ref:`Thread PGO`.
.. option:: --protect-key <key>
@@ -874,24 +889,15 @@ Summary:
.. option:: --protect-lib <name>
Produces C++, Verilog wrappers and a Makefile which can in turn produce
a DPI library which can be used by Verilator or other simulators along
with the corresponding Verilog wrapper. The Makefile will build both a
static and dynamic version of the library named :file:`lib<name>.a` and
:file:`lib<name>.so` respectively. This is done because some simulators
require a dynamic library, but the static library is arguably easier to
use if possible. :vlopt:`--protect-lib` implies :vlopt:`--protect-ids`.
Produces a DPI library similar to :vlopt:`--lib-create`, but hides
internal design details. :vlopt:`--protect-lib` implies
:vlopt:`--protect-ids`, and :vlopt:`--lib-create`.
This allows for the secure delivery of sensitive IP without the need for
encrypted RTL (i.e. IEEE P1735). See :file:`examples/make_protect_lib`
in the distribution for a demonstration of how to build and use the DPI
library.
When using :vlopt:`--protect-lib` it is advised to also use
:vlopt:`--timescale-override /1fs <--timescale-override>` to ensure the
model has a time resolution that is always compatible with the time
precision of the upper instantiating module.
.. option:: --private
Opposite of :vlopt:`--public`. Is the default; this option exists for
@@ -1167,9 +1173,9 @@ Summary:
.. option:: --trace-underscore
Enable tracing of signals that start with an underscore. Normally, these
signals are not output during tracing. See also
:vlopt:`--coverage-underscore` option.
Enable tracing of signals or modules that start with an
underscore. Normally, these signals are not output during tracing. See
also :vlopt:`--coverage-underscore` option.
.. option:: -U<var>
@@ -1506,9 +1512,9 @@ The grammar of configuration commands is as follows:
.. option:: no_clocker -module "<modulename>" [-function "<funcname>"] -var "<signame>"
Indicate the signal is used as clock or not. This information is used by
Verilator to mark the signal as clocker and propagate the clocker
attribute automatically to derived signals. See :vlopt:`--clk`.
Indicates that the signal is used as clock or not. This information is
used by Verilator to mark the signal and any derrived signals as
clocker. See :vlopt:`--clk`.
Same as :option:`/*verilator&32;clocker*/` metacomment.
@@ -1612,6 +1618,12 @@ The grammar of configuration commands is as follows:
:option:`/*verilator&32;public_flat*/`, etc, metacomments. See
e.g. :ref:`VPI Example`.
.. option:: profile_data -mtask "<mtask_hash>" -cost <cost_value>
Feeds profile-guided optimization data into the Verilator algorithms in
order to improve model runtime performance. This option is not expected
to be used by users directly. See :ref:`Thread PGO`.
.. option:: sc_bv -module "<modulename>" [-task "<taskname>"] -var "<signame>"
.. option:: sc_bv -module "<modulename>" [-function "<funcname>"] -var "<signame>"
+38 -27
View File
@@ -10,42 +10,60 @@ starts and ends, and showing when each thread is busy or idle.
For an overview of use of verilator_gantt, see :ref:`Profiling`.
Gantt Chart Contents
--------------------
Gantt Chart VCD
---------------
The generated Gantt chart has time on the X-axis. Times shown are to the
scale printed, i.e. a certain about of time for each character width. The
Y-axis shows threads, each thread's execution is shown on one line. That
line shows "[" at the position in time when it executes.
Verilated_gnatt creates a value change dump (VCD) format dump file which
may be viewed in a waveform viewer (e.g. C<GTKWave>):
Following the "[" is the CPU number the task executed on, followed by zero
or more "-" to make the width of the characters match the scaled execution
time, followed by a "]". If the scale is too small, the CPU number and
mtask number will not be printed. If the scale is very small, a "&"
indicates multiple mtasks started at that time position.
.. figure:: figures/fig_gantt_min.png
Example verilator_gantt output, as viewed with GTKWave.
The viewed waveform chart has time on the X-axis, with one unit for each
time tick of the system's high-performance counter.
Also creates a value change dump (VCD) format dump file which may be viewed
in a waveform viewer (e.g. C<GTKWave>). See below.
Gantt Chart VCD Signals
-----------------------
In waveforms there are the following signals. Most signals the "decimal"
format will remove the leading zeros and make the traces easier to read.
In waveforms there are the following signals. In GTKWave, using a data
format of "decimal" will remove the leading zeros and make the traces
easier to read.
parallelism
evals
Increments each time when eval_step was measured to be active. This
allow visualization of how much time eval_step was active.
eval_loop
Increments each time when the evaluation loop within eval_step was
measured to be active. For best performance there is only a single
evaluation loop within each eval_step call, that is the eval_loop
waveform looks identical to the evals waveform.
measured_parallelism
The number of mtasks active at this time, for best performance this will
match the thread count. You may want to use an "analog step" format to
match the thread count. In GTKWave, use a data format of "analog step" to
view this signal.
predicted_parallelism
The number of mtasks Verilator predicted would be active at this time,
for best performance this will match the thread count. In GTKWave, use a
data format of "analog step" to view this signal.
cpu#_thread
For the given CPU number, the thread number executing.
For the given CPU number, the thread number measured to be executing.
mtask#_cpu
For the given mtask id, the CPU it is executing on.
For the given mtask id, the CPU it was measured to execute on.
thread#_mtask
For the given thread number, the mtask id executing.
For the given thread number, the mtask id it was executing.
predicted_thread#_mtask
For the given thread number, the mtask id Verilator predicted would be
executing.
verilator_gantt Arguments
-------------------------
@@ -60,13 +78,6 @@ The filename to read data from, defaults to "profile_threads.dat".
Displays a help summary, the program version, and exits.
.. option:: --scale <n>
Sets the number of time units per character on the X-axis of the generated
Gantt chart. (On x86, time units are rdtsc ticks.) Defaults to 0, which
will automatically compute a reasonable scale where no two mtasks need to
fit into same character width's worth of scaled time.
.. option:: --no-vcd
Disables creating a .vcd file.
@@ -1,20 +1,24 @@
.. Copyright 2003-2021 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
verilator_profcfuncs
====================
verilator_profcfunc
===================
Verilator_profcfunc reads a profile report created by gprof. The names of
the functions are then transformed, assuming the user used Verilator's
--prof-cfuncs, and a report printed showing the percentage of time, etc, in
each Verilog block.
For an overview of use of verilator_profcfuncs, see :ref:`Profiling`.
Due to rounding errors in gprof reports, the input report's percentages may
not total to 100%. In the verilator_profcfunc report this will get
reported as a rounding error.
verilator_profcfuncs Arguments
------------------------------
For an overview of use of verilator_profcfunc, see :ref:`Profiling`.
.. program:: verilator_profcfuncs
verilator_profcfunc Arguments
-----------------------------
.. program:: verilator_profcfunc
.. option:: <filename>
+1 -1
View File
@@ -15,5 +15,5 @@ options to each executable.
exe_verilator.rst
exe_verilator_coverage.rst
exe_verilator_gantt.rst
exe_verilator_profcfuncs.rst
exe_verilator_profcfunc.rst
exe_sim.rst
+18 -4
View File
@@ -48,6 +48,14 @@ or "`ifdef`"'s may break other tools.
Verilog functions where the variable is flattened out, and also enable
other optimizations.
Verilator does not use any text inside the quotes for
ordering/scheduling. If you need the $c to be called at a specific
time, e.g. when a variable changes, then the $c must be under an
appropriate sensitivity statement, e.g. :code:`always @(posedge clk)
$c("func()")` to call it on every edge, or e.g. :code:`always @*
c("func(",a,")")` to call it when :code:`a` changes (the latter working
because :code:`a` is outside the quotes).
If you will be reading or writing any Verilog variables inside the C++
functions, the Verilog signals must be declared with
:option:`/*verilator&32;public*/` metacomments.
@@ -176,10 +184,9 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;no_clocker*/
Used after a signal declaration to indicate the signal is used as clock
or not. This information is used by Verilator to mark the signal as
clocker and propagate the clocker attribute automatically to derived
signals. See :vlopt:`--clk`.
Specifies that the signal is used as clock or not. This information is
used by Verilator to mark the signal and any derrived signals as
clocker. See :vlopt:`--clk`.
Same as :option:`clocker` and :option:`no_clocker` in configuration
files.
@@ -482,6 +489,13 @@ or "`ifdef`"'s may break other tools.
Verilator) text that should be passed through to the XML output as a tag,
for use by downstream applications.
.. option:: /*verilator&32;trace_init_task*/
Attached to a DPI import to indicate that function should be called when
initializing tracing. This attribute is indented only to be used
internally in code that Verilator generates when :vlopt:`--lib-create`
or :vlopt:`--hierarchical` is used along with :vlopt:`--trace`.
.. option:: /*verilator&32;tracing_off*/
Disable waveform tracing for all future signals that are declared in
+4 -2
View File
@@ -35,8 +35,10 @@ simulators.
Does Verilator run under Windows?
"""""""""""""""""""""""""""""""""
Yes, using Cygwin. Verilated output also compiles under Microsoft Visual
C++, but this is not tested every release.
Yes, ideally run Ubuntu under Windows Subsystem for Linux (WSL2).
Alternatively use Cygwin, though this tends to be slower and is not
regurally tested. Verilated output also compiles under Microsoft Visual
C++, but this is also not regurally tested.
Can you provide binaries?
Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 37 KiB

+21 -1
View File
@@ -74,7 +74,7 @@ For --cc/--sc, it creates:
- DPI import and export declarations (from --dpi)
* - *{prefix}*\ __Dpi.cpp
- Global DPI export wrappers (from --dpi)
* - *{prefix}*\ __Dpi_Export\ *{__n}\ .cpp
* - *{prefix}*\ __Dpi_Export\ *{__n}*\ .cpp
- DPI export wrappers scoped to this particular model (from --dpi)
* - *{prefix}*\ __Inlines.h
- Inline support functions
@@ -145,3 +145,23 @@ After running Make, the C++ compiler may produce the following:
- Intermediate dependencies
* - *{prefix}{misc}*\ .o
- Intermediate objects
The Verilated executable may produce the following:
.. list-table::
* - coverage.dat
- Code coverage output, and default input filename for :command:`verilator_coverage`
* - gmon.out
- GCC/clang code profiler output, often fed into :command:`verilator_profcfunc`
* - profile.vlt
- -profile data file for :ref:`Thread PGO`
* - profile_threads.dat
- -profile-threads data file for :command:`verilator_gnatt`
Verilator_gantt may produce the following:
.. list-table::
* - profile_threads.vcd
- Gantt report waveform output
+10 -10
View File
@@ -51,15 +51,15 @@ In brief, to install from git:
unsetenv VERILATOR_ROOT # For csh; ignore error if on bash
unset VERILATOR_ROOT # For bash
cd verilator
git pull # Make sure git repository is up-to-date
git tag # See what versions exist
git pull # Make sure git repository is up-to-date
git tag # See what versions exist
#git checkout master # Use development branch (e.g. recent bug fixes)
#git checkout stable # Use most recent stable release
#git checkout v{version} # Switch to specified release version
autoconf # Create ./configure script
./configure # Configure and create Makefile
make -j # Build Verilator itself
autoconf # Create ./configure script
./configure # Configure and create Makefile
make -j `nproc` # Build Verilator itself (if error, try just 'make')
sudo make install
@@ -78,10 +78,10 @@ OS Requirements
Verilator is developed and has primary testing on Ubuntu, with additional
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
Linux, HPUX and Solaris. It should run with minor porting on any
GNU/Linux-ish platform. Verilator also works on Windows under Cygwin, and
Windows under MinGW (gcc -mno-cygwin). Verilated output (not Verilator
itself) compiles under all the options above, plus using MSVC++.
Linux, and other flavors of GNU/Linux-ish platforms. Verilator also works
on Windows Subsystem for Linux (WSL2), Windows under Cygwin, and Windows
under MinGW (gcc -mno-cygwin). Verilated output (not Verilator itself)
compiles under all the options above, plus using MSVC++.
Install Prerequisites
@@ -287,7 +287,7 @@ Compile Verilator:
::
make -j
make -j `nproc` # Or if error on `nproc`, the number of CPUs in system
Test
+126 -6
View File
@@ -26,7 +26,8 @@ risk of reset bugs in trade for performance; see the above documentation
for these options.
If using Verilated multithreaded, use ``numactl`` to ensure you are using
non-conflicting hardware resources. See :ref:`Multithreading`.
non-conflicting hardware resources. See :ref:`Multithreading`. Also
consider using profile-guided optimization, see :ref:`Thread PGO`.
Minor Verilog code changes can also give big wins. You should not have any
UNOPTFLAT warnings from Verilator. Fixing these warnings can result in
@@ -93,9 +94,7 @@ cases, for example regressions, it is usually worth spending extra
compilation time to reduce total CPU time.
If you will be running many simulations on a single model, you can
investigate profile guided optimization. With GCC, using GCC's
"-fprofile-arcs", then GCC's "-fbranch-probabilities" will yield another
15% or so.
investigate profile guided optimization. See :ref:`Compiler PGO`.
Modern compilers also support link-time optimization (LTO), which can help
especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
@@ -230,7 +229,7 @@ coverage point insertions into the model and collect the coverage data.
To get the coverage data from the model, in the user wrapper code,
typically at the end once a test passes, call
:code:`Verilated::coveragep()->write` with an argument of the filename for
:code:`Verilated::threadContextp()->coveragep()->write` with an argument of the filename for
the coverage data file to write coverage data to (typically
"logs/coverage.dat").
@@ -298,6 +297,9 @@ With the :vlopt:`--prof-threads` option, Verilator will:
* Add code to save profiling data in non-human-friendly form to the file
specified with :vlopt:`+verilator+prof+threads+file+\<filename\>`.
* Add code to save profiling data for thread profile-guided
optimization. See :ref:`Thread PGO`.
The :command:`verilator_gantt` program may then be run to transform the
saved profiling file into a nicer visual format and produce some related
statistics.
@@ -306,7 +308,7 @@ statistics.
Example verilator_gantt output, as viewed with GTKWave.
The parallelism shows the number of CPUs being used at a given moment.
The measured_parallelism shows the number of CPUs being used at a given moment.
The cpu_thread section shows which thread is executing on each of the physical CPUs.
@@ -314,6 +316,7 @@ statistics.
For more information see :command:`verilator_gantt`.
.. _Profiling ccache efficiency:
Profiling ccache efficiency
@@ -377,3 +380,120 @@ For example:
os >> main_time;
os >> *topp;
}
Profile-Guided Optimization
===========================
Profile-guided optimization is the technique where profiling data is
collected by running your simulation executable, then this information is
used to guide the next Verilation or compilation.
There are two forms of profile-guided optimizations. Unfortunately for
best results they must each be performed from the highest level code to the
lowest, which means performing them separately and in this order:
* :ref:`Thread PGO`
* :ref:`Compiler PGO`
Other forms of PGO may be supported in the future, such as clock and reset
toggle rate PGO, branch prediction PGO, statement execution time PGO, or
others as they prove beneficial.
.. _Thread PGO:
Thread Profile-Guided Optimization
----------------------------------
Verilator supports thread profile-guided optimization (Thread PGO) to
improve multithreaded performance.
When using multithreading, Verilator computes how long macro tasks take and
tries to balance those across threads. (What is a macro-task? See the
Verilator internals document (:file:`docs/internals.rst` in the
distribution.) If the estimations are incorrect, the threads will not be
balanced, leading to decreased performance. Thread PGO allows collecting
profiling data to replace the estimates and better optimize these
decisions.
To use Thread PGO, Verilate the model with the :vlopt:`--prof-threads`
option.
Run the model executable. When the executable exits, it will create a
profile.vlt file.
Rerun Verilator, optionally omitting the :vlopt:`--prof-threads` option,
and adding the profile.vlt generated earlier to the command line.
Note there is no Verilator equivalent to GCC's --fprofile-use. Verilator's
profile data file (profile.vlt) can be placed on the verilator command line
directly without any prefix.
If results from multiple simulations are to be used in generating the
optimization, multiple simulation's profile.vlt may be concatenated
externally, or each of the files may be fed as separate command line
options into Verilator. Verilator will simply sum the profile results, so
a longer running test will have proportionally more weight for optimization
than a shorter running test.
If you provide any profile feedback data to Verilator, and it cannot use
it, it will issue the :option:`PROFOUTOFDATE` warning that threads were
scheduled using estimated costs. This usually indicates that the profile
data was generated from different Verilog source code than Verilator is
currently running against. Therefore, repeat the data collection phase to
create new profiling data, then rerun Verilator with the same input source
files and that new profiling data.
.. _Compiler PGO:
Compiler Profile-Guided Optimization
------------------------------------
GCC and Clang support compiler profile-guided optimization (PGO). This
optimizes any C/C++ program including Verilated code. Using compiler PGO
typically yields improvements of 5-15% on both single-threaded and
multi-threaded models.
To use compiler PGO with GCC or Clang, please see the appropriate compiler
documentation. The process in GCC 10 was as follows:
1. Compile the Verilated model with the compiler's "-fprofile-generate"
flag:
.. code-block:: bash
verilator [whatever_flags] --make \
-CFLAGS -fprofile-generate -LDFLAGS -fprofile-generate
or, if calling make yourself, add -fprofile-generate appropriately to your
Makefile.
2. Run your simulation. This will create \*.gcda file(s) in the same
directory as the source files.
3. Recompile the model with -fprofile-use. The compiler will read the
\*.gcda file(s).
For GCC:
.. code-block:: bash
verilator [whatever_flags] --build \
-CFLAGS "-fprofile-use -fprofile-correction"
For Clang:
.. code-block:: bash
llvm-profdata merge -output default.profdata *.profraw
verilator [whatever_flags] --build \
-CFLAGS "-fprofile-use -fprofile-correction"
or, if calling make yourself, add these CFLAGS switches appropriately to
your Makefile.
Clang and GCC also support -fauto-profile which uses sample-based
feedback-directed optimization. See the appropriate compiler
documentation.
+3 -4
View File
@@ -70,10 +70,9 @@ Verilator is run in hierarchical mode on the whole SoC. Verilator will
make two models, one for the CPU hierarchy block, and one for the SoC. The
Verialted code for the SoC will automatically call the CPU Verilated model.
The current hierarchical Verilation is based on protect-lib. Each hierarchy
block is Verilated to a protect-lib. User modules of the hierarchy blocks
will see a tiny wrapper generated by protect-lib instead of the actual
design.
The current hierarchical Verilation is based on :vlopt:`--lib-create`. Each
hierarchy block is Verilated into a library. User modules of the hierarchy
blocks will see a tiny wrapper generated by :vlopt:`--lib-create`.
Usage
+85 -36
View File
@@ -130,9 +130,10 @@ List Of Warnings
.. option:: BADSTDPRAGMA
Error that a pragma is badly formed, when that pragma is defined by IEEE1800-2017.
For example, an empty `pragma line, or an incorrect specified '`pragma protect'.
Note that 3rd party pragmas not defined by IEEE1800-2017 are ignored.
Error that a pragma is badly formed, when that pragma is defined by IEEE
1800-2017. For example, an empty pragma line, or an incorrect specified
'pragma protect'. Note that 3rd party pragmas not defined by IEEE
1800-2017 are ignored.
.. option:: BLKANDNBLK
@@ -481,39 +482,44 @@ List Of Warnings
Faulty example:
.. code-block:: sv
.. include:: ../../docs/gen/ex_DIDNOTCONVERGE_faulty.rst
always_comb b = ~a;
always_comb a = b
Results in at runtime (not when Verilated):
This code will toggle forever, and thus to prevent an infinite loop, the
executable will give the didn't converge error.
.. include:: ../../docs/gen/ex_DIDNOTCONVERGE_nodbg_msg.rst
To debug this, first review any UNOPTFLAT warnings that were ignored.
Though typically it is safe to ignore UNOPTFLAT (at a performance cost),
at the time of issuing a UNOPTFLAT Verilator did not know if the logic
would eventually converge and assumed it would.
This is because the signals keep toggling even with out time
passing. Thus to prevent an infinite loop, the Verilated executable
gives the DIDNOTCONVERGE error.
To debug this, first review any UNOPT or UNOPTFLAT warnings that were
ignored. Though typically it is safe to ignore UNOPTFLAT (at a
performance cost), at the time of issuing a UNOPTFLAT Verilator did not
know if the logic would eventually converge and assumed it would.
Next, run Verilator with :vlopt:`--prof-cfuncs -CFLAGS -DVL_DEBUG
<--prof-cfuncs>`. Rerun the test. Now just before the convergence
error you should see additional output similar to this:
.. code-block::
.. include:: ../../docs/gen/ex_DIDNOTCONVERGE_msg.rst
CHANGE: filename.v:1: b
CHANGE: filename.v:2: a
This means that signal b and signal a keep changing, inspect the code
that modifies these signals. Note if many signals are getting printed
then most likely all of them are oscillating. It may also be that
e.g. "a" may be oscillating, then "a" feeds signal "c" which then is
also reported as oscillating.
The CHANGE line means that on the given filename and line number that
drove a signal, the signal 'a' kept changing. Inspect the code that
modifies these signals. Note if many signals are getting printed then
most likely all of them are oscillating. It may also be that e.g. "a"
may be oscillating, then "a" feeds signal "c" which then is also
reported as oscillating.
One way DIDNOTCONVERGE may occur is flops are built out of gate
primitives. error. Verilator does not support building flops or latches
out of gate primitives, and any such code must change to use behavioral
primitives. Verilator does not support building flops or latches out of
gate primitives, and any such code must change to use behavioral
constructs (e.g. always_ff and always_latch).
Another way DIDNOTCONVERGE may occur is if # delays are used to generate
clocks. Verilator ignores the delays and gives an :option:`ASSIGNDLY`
or :option:`STMTDLY` warning. If these were suppressed, due to the
absense of the delay, the code may now oscillate.
Finally, rare, more difficult cases can be debugged like a C++ program;
either enter :command:`gdb` and use its tracing facilities, or edit the
generated C++ code to add appropriate prints to see what is going on.
@@ -572,7 +578,7 @@ List Of Warnings
must end in newline, as otherwise for example :command:`cat` with the
file as an argument may produce undesirable results.
Repair by adding a newline to the end of the file.
Repair by appending a newline to the end of the file.
Disabled by default as this is a code style warning; it will simulate
correctly.
@@ -792,8 +798,8 @@ List Of Warnings
.. TODO better example
Warns that a module has multiple definitions. Generally this indicates
a coding error, or a mistake in a library file and it's good practice to
have one module per file (and only put each file once on the command
a coding error, or a mistake in a library file, and it's good practice
to have one module per file (and only put each file once on the command
line) to avoid these issues. For some gate level netlists duplicates
are sometimes unavoidable, and MODDUP should be disabled.
@@ -1005,9 +1011,25 @@ List Of Warnings
a var/reg must be used as the target of procedural assignments.
.. option:: PROFOUTOFDATE
Warns that threads were scheduled using estimated costs, despite the
fact that data was provided from profile-guided optimization (see
:ref:`Thread PGO`) as fed into Verilator using the
:option:`profile_data` configuration file option. This usually
indicates that the profile data was generated from different Verilog
source code than Verilator is currently running against.
It is recommended to create new profiling data, then rerun Verilator
with the same input source files and that new profiling data.
Ignoring this warning may only slow simulations, it will simulate
correctly.
.. option:: PROTECTED
Warning that a '`pragma protected' section was encountered. The code
Warning that a 'pragma protected' section was encountered. The code
inside the protected region will be partly checked for correctness, but is
otherwise ignored.
@@ -1183,9 +1205,25 @@ List Of Warnings
Faulty example:
.. code-block:: sv
.. include:: ../../docs/gen/ex_STMTDLY_faulty.rst
#100 $finish; //<--- Warning
Results in:
.. include:: ../../docs/gen/ex_STMTDLY_msg.rst
This is a warning because Verilator does not support delayed statements.
It will simply ignore all such delays. In many cases ignoring a delay
might be harmless, but if the delayed statement is, as in this example,
used to cause some important action at a later time, it might be an
important difference.
Some possible work arounds:
* Move the delayed statement into the C++ wrapper file, where the
stimulus and clock generation can be done in C++.
* Convert the statement into a FSM, or other statement that tests
against $time.
.. option:: SYMRSVDWORD
@@ -1353,7 +1391,9 @@ List Of Warnings
Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
synthesis which analyzes interconnection per-bit, but is circular to
simulation which analyzes per-bus:
simulation which analyzes per-bus.
Faulty example:
.. code-block:: sv
@@ -1466,9 +1506,16 @@ List Of Warnings
Error that a construct might be legal according to IEEE but is not
currently supported by Verilator.
A typical workaround is to recode the construct into a simpler and more
common alternative language construct.
Alternatively, check if the construct is supported by other tools, and
if so please consider submitting a github pull request against the
Verilator sources to implement the missing unsupported feature.
This error may be ignored with :vlopt:`--bbox-unsup`, however this will
make the design simulate incorrectly; see the details under
:vlopt:`--bbox-unsup`.
make the design simulate incorrectly and is only intended for lint
usage; see the details under :vlopt:`--bbox-unsup`.
.. option:: UNUSED
@@ -1598,7 +1645,7 @@ List Of Warnings
* A part select has a different size then needed to index into the
packed or unpacked array (etc).
Verilator for attempts to track the minimum width of unsized constants
Verilator attempts to track the minimum width of unsized constants
and will suppress the warning when the minimum width is appropriate to
fit the required size.
@@ -1607,11 +1654,13 @@ List Of Warnings
The recommendation is to fix these issues by:
* Resizing the variable or constant. E.g. :code:`2'd2` instead of :code:`3'd2`.
* Resizing the variable or constant to match the needed size for the
expression. E.g. :code:`2'd2` instead of :code:`3'd2`.
* Using :code:`'0` or :code:`'1`.
* Using :code:`'0` or :code:`'1` which automatically resize in an
expression.
* Using part select to narrow a variable. E.g. :code:`too_wide[1:0]`.
* Using part selects to narrow a variable. E.g. :code:`too_wide[1:0]`.
* Using concatenate to widen a variable. E.g. :code:`{1'b1, too_narrow}`.
+3
View File
@@ -405,6 +405,9 @@ routines in the sources to rely more heavily on randomness, and
generally try harder not to keep input nodes together when we have the
option to scramble things.
Profile-guided optimization make this a bit better, by adjusting mtask
scheduling, but this does not yet guide the packing into mtasks.
Performance Regression
""""""""""""""""""""""
-1
View File
@@ -676,7 +676,6 @@ prev
printf
printtimescale
profcfunc
profcfuncs
prototyptes
ps
pthread
+1 -1
View File
@@ -99,7 +99,7 @@ run:
@echo "-- DONE --------------------"
@echo "Note: Once this example is understood, see examples/cmake_tracing_sc."
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
clean mostlyclean distclean maintainer-clean:
@rm -rf build logs
+1 -1
View File
@@ -40,7 +40,7 @@ default:
obj_dir/Vtop
@echo "-- DONE --------------------"
@echo "Note: Once this example is understood, see examples/make_tracing_c."
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
######################################################################
+2 -1
View File
@@ -4,7 +4,8 @@
// any use, without warranty, 2017 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// See also the EXAMPLE section in the verilator manpage/document.
// See also https://verilator.org/guide/latest/examples.html"
module top;
initial begin
$display("Hello World!");
+1 -1
View File
@@ -49,7 +49,7 @@ run:
obj_dir/Vtop
@echo "-- DONE --------------------"
@echo "Note: Once this example is understood, see examples/make_tracing_sc."
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
######################################################################
+2 -1
View File
@@ -4,7 +4,8 @@
// any use, without warranty, 2017 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// See also the EXAMPLE section in the verilator manpage/document.
// See also https://verilator.org/guide/latest/examples.html"
module top;
initial begin
$display("Hello World!");
+2 -1
View File
@@ -4,7 +4,8 @@
// any use, without warranty, 2019 by Todd Strader.
// SPDX-License-Identifier: CC0-1.0
// See also the EXAMPLE section in the verilator manpage/document.
// See also https://verilator.org/guide/latest/examples.html"
module top (input clk);
integer cyc = 0;
+47 -42
View File
@@ -25,7 +25,7 @@
//=========================================================================
// Internal note:
//
// verilated.o may exist both in protect-lib (incrementally linked .a/.so)
// verilated.o may exist both in --lib-create (incrementally linked .a/.so)
// and the main module. Both refer the same instance of static
// variables/VL_THREAD_LOCAL in verilated.o such as Verilated, or
// VerilatedImpData. This is important to share that state, but the
@@ -208,7 +208,7 @@ void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char
std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
va_list aq;
va_copy(aq, ap);
size_t len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
const size_t len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
va_end(aq);
if (VL_UNLIKELY(len < 1)) return "";
@@ -308,27 +308,22 @@ vluint64_t vl_rand64() VL_MT_SAFE {
return result;
}
#ifndef VL_NO_LEGACY
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
// LCOV_EXCL_START
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = vl_rand64();
outwp[VL_WORDS_I(obits) - 1] = vl_rand64() & VL_MASK_E(obits);
for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = vl_rand64();
// Last word is unclean
return outwp;
}
// LCOV_EXCL_STOP
#endif
IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE {
IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE {
Verilated::threadContextp()->randSeed(static_cast<int>(seed));
return VL_RANDOM_I(obits);
return VL_RANDOM_I();
}
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
if (Verilated::threadContextp()->randReset() == 0) return 0;
IData data = ~0;
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
data = VL_RANDOM_I(obits);
data = VL_RANDOM_I();
}
data &= VL_MASK_I(obits);
return data;
@@ -337,7 +332,7 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
if (Verilated::threadContextp()->randReset() == 0) return 0;
QData data = ~0ULL;
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
data = VL_RANDOM_Q(obits);
data = VL_RANDOM_Q();
}
data &= VL_MASK_Q(obits);
return data;
@@ -387,7 +382,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw - 1; j >= 0; --j) {
vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
const vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]);
k = unw64 - static_cast<vluint64_t>(owp[j]) * static_cast<vluint64_t>(rwp[0]);
}
@@ -444,7 +439,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i = 0; i < vw; ++i) {
vluint64_t p = qhat * vn[i]; // Multiply by estimate
const vluint64_t p = qhat * vn[i]; // Multiply by estimate
t = un[i + j] - k - (p & 0xFFFFFFFFULL); // Subtract
un[i + j] = t;
k = (p >> 32ULL) - (t >> 32ULL);
@@ -698,8 +693,8 @@ std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t w
}
}
} else {
double shiftd = vl_time_multiplier(shift);
double scaled = ld * shiftd;
const double shiftd = vl_time_multiplier(shift);
const double scaled = ld * shiftd;
const double fracDiv = vl_time_multiplier(fracDigits);
const double whole = scaled / fracDiv;
if (!fracDigits) {
@@ -749,7 +744,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
} else { // Format character
inPct = false;
char fmt = pos[0];
const char fmt = pos[0];
switch (fmt) {
case '0': // FALLTHRU
case '1': // FALLTHRU
@@ -809,7 +804,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
output += _vl_vsformat_time(t_tmp, d, timeunit, left, width);
} else {
const size_t len = pos - pctp + 1;
std::string fmts{pctp, len};
const std::string fmts{pctp, len};
VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d);
output += t_tmp;
}
@@ -869,7 +864,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
digits = append.length();
}
int needmore = width - digits;
const int needmore = width - digits;
std::string padding;
if (needmore > 0) {
if (pctp && pctp[0] && pctp[1] == '0') { // %0
@@ -892,7 +887,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
append = VL_DECIMAL_NW(lbits, lwp);
digits = append.length();
}
int needmore = width - digits;
const int needmore = width - digits;
std::string padding;
if (needmore > 0) {
if (pctp && pctp[0] && pctp[1] == '0') { // %0
@@ -953,7 +948,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
case 'x':
for (; lsb >= 0; --lsb) {
lsb = (lsb / 4) * 4; // Next digit
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
output += "0123456789abcdef"[charval];
}
break;
@@ -1027,7 +1022,7 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp,
}
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
const std::string& fstr, char* beginp, std::size_t n,
bool inhibit = false) {
const bool inhibit = false) {
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized
// specifically for block reads of N bytes (read operations are not demarcated by
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
@@ -1041,9 +1036,7 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
IData ld) VL_MT_SAFE {
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1);
}
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) { VL_ASSIGNBIT_WI(lsb, owp, ld & 1); }
}
static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp,
size_t posstart, size_t posend) VL_MT_SAFE {
@@ -1100,16 +1093,16 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_skipspace(fp, floc, fromp, fstr);
} else if (!inPct) { // Expected Format
_vl_vsss_skipspace(fp, floc, fromp, fstr);
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c != pos[0]) goto done;
_vl_vsss_advance(fp, floc);
} else { // Format character
// Skip loading spaces
inPct = false;
char fmt = pos[0];
const char fmt = pos[0];
switch (fmt) {
case '%': {
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c != '%') goto done;
_vl_vsss_advance(fp, floc);
break;
@@ -1139,7 +1132,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
switch (fmt) {
case 'c': {
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF) goto done;
_vl_vsss_advance(fp, floc);
owp[0] = c;
@@ -1292,7 +1285,7 @@ void _vl_vint_to_string(int obits, char* destoutp, const WDataInP sourcep) VL_MT
char* destp = destoutp;
for (; lsb >= 0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff;
const IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff;
if (!start || charval) {
*destp++ = (charval == 0) ? ' ' : charval;
start = false; // Drop leading 0s
@@ -1530,16 +1523,16 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
// Prep for reading
IData read_count = 0;
IData read_elements = 0;
int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
const int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
int shift = start_shift;
// Read the data
// We process a character at a time, as then we don't need to deal
// with changing buffer sizes dynamically, etc.
while (true) {
int c = std::fgetc(fp);
const int c = std::fgetc(fp);
if (VL_UNLIKELY(c == EOF)) break;
// Shift value in
IData entry = read_elements + start - array_lsb;
const IData entry = read_elements + start - array_lsb;
if (width <= 8) {
CData* const datap = &(reinterpret_cast<CData*>(memp))[entry];
if (shift == start_shift) *datap = 0;
@@ -1600,6 +1593,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else if (inPct && posp[0] == '0') { // %0
} else { // Format character
switch (std::tolower(*posp)) {
case '%':
@@ -1727,14 +1721,14 @@ std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_MT_SAFE {
// See also _vl_vint_to_string
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
int obits = lwords * VL_EDATASIZE;
const int obits = lwords * VL_EDATASIZE;
int lsb = obits - 1;
bool start = true;
char* destp = destout;
size_t len = 0;
for (; lsb >= 0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
if (!start || charval) {
*destp++ = (charval == 0) ? ' ' : charval;
++len;
@@ -2068,7 +2062,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary
VL_FATAL_MT(filename.c_str(), rmem.linenum(), "",
"$readmem file address beyond bounds of array");
} else {
QData entry = addr - array_lsb;
const QData entry = addr - array_lsb;
if (bits <= 8) {
CData* const datap = &(reinterpret_cast<CData*>(memp))[entry];
rmem.setData(datap, value);
@@ -2103,7 +2097,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary
QData start, // First array row address to write
QData end // Last address to write, or ~0 when not specified
) VL_MT_SAFE {
QData addr_max = array_lsb + depth - 1;
const QData addr_max = array_lsb + depth - 1;
if (start < static_cast<QData>(array_lsb)) start = array_lsb;
if (end > addr_max) end = addr_max;
@@ -2258,6 +2252,7 @@ VerilatedContext::VerilatedContext()
Verilated::lastContextp(this);
Verilated::threadContextp(this);
m_ns.m_profThreadsFilename = "profile_threads.dat";
m_ns.m_profVltFilename = "profile.vlt";
m_fdps.resize(31);
std::fill(m_fdps.begin(), m_fdps.end(), static_cast<FILE*>(nullptr));
m_fdFreeMct.resize(30);
@@ -2340,6 +2335,14 @@ std::string VerilatedContext::profThreadsFilename() const VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
return m_ns.m_profThreadsFilename;
}
void VerilatedContext::profVltFilename(const std::string& flag) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_ns.m_profVltFilename = flag;
}
std::string VerilatedContext::profVltFilename() const VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
return m_ns.m_profVltFilename;
}
void VerilatedContext::randReset(int val) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_s.m_randReset = val;
@@ -2495,6 +2498,8 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
profThreadsWindow(std::atol(value.c_str()));
} else if (commandArgVlValue(arg, "+verilator+prof+threads+file+", value /*ref*/)) {
profThreadsFilename(value);
} else if (commandArgVlValue(arg, "+verilator+prof+vlt+file+", value /*ref*/)) {
profVltFilename(value);
} else if (commandArgVlValue(arg, "+verilator+rand+reset+", value /*ref*/)) {
randReset(std::atoi(value.c_str()));
} else if (commandArgVlValue(arg, "+verilator+seed+", value /*ref*/)) {
@@ -2816,7 +2821,7 @@ size_t VerilatedVarProps::totalSize() const {
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
int indxAdj = indx - low(dim);
const int indxAdj = indx - low(dim);
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
size_t slicesz = entSize();
@@ -2861,7 +2866,7 @@ void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const
void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE {
// Slowpath - called once/scope*export at construction
// Insert a exported function into scope table
int funcnum = VerilatedImp::exportInsert(namep);
const int funcnum = VerilatedImp::exportInsert(namep);
if (!finalize) {
// Need two passes so we know array size to create
// Alternative is to dynamically stretch the array, which is more code, and slower.
@@ -2903,7 +2908,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, boo
} else {
// We could have a linked list of ranges, but really this whole thing needs
// to be generalized to support structs and unions, etc.
std::string msg
const std::string msg
= std::string{"Unsupported multi-dimensional public varInsert: "} + namep;
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
@@ -2950,7 +2955,7 @@ void VerilatedScope::scopeDump() const {
VerilatedImp::exportName(i));
}
}
if (VerilatedVarNameMap* const varsp = this->varsp()) {
if (const VerilatedVarNameMap* const varsp = this->varsp()) {
for (const auto& i : *varsp) VL_PRINTF_MT(" VAR %p: %s\n", &(i.second), i.first);
}
}
+4 -1
View File
@@ -346,6 +346,7 @@ protected:
vluint32_t m_profThreadsWindow = 2; // +prof+threads window size
// Slow path
std::string m_profThreadsFilename; // +prof+threads filename
std::string m_profVltFilename; // +prof+vlt filename
} m_ns;
mutable VerilatedMutex m_argMutex; // Protect m_argVec, m_argVecLoaded
@@ -358,7 +359,7 @@ protected:
} m_args VL_GUARDED_BY(m_argMutex);
// Implementation details
std::unique_ptr<VerilatedContextImpData> m_impdatap;
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
// Coverage access
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()
@@ -522,6 +523,8 @@ public: // But for internal use only
vluint32_t profThreadsWindow() const VL_MT_SAFE { return m_ns.m_profThreadsWindow; }
void profThreadsFilename(const std::string& flag) VL_MT_SAFE;
std::string profThreadsFilename() const VL_MT_SAFE;
void profVltFilename(const std::string& flag) VL_MT_SAFE;
std::string profVltFilename() const VL_MT_SAFE;
// Internal: Find scope
const VerilatedScope* scopeFind(const char* namep) const VL_MT_SAFE;
-2
View File
@@ -23,8 +23,6 @@ CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
CFG_CXXFLAGS_PROFILE = @CFG_CXXFLAGS_PROFILE@
# Select newest language
CFG_CXXFLAGS_STD_NEWEST = @CFG_CXXFLAGS_STD_NEWEST@
# Select oldest language (for Verilator internal testing only)
CFG_CXXFLAGS_STD_OLDEST = @CFG_CXXFLAGS_STD_OLDEST@
# Compiler flags to use to turn off unused and generated code warnings, such as -Wno-div-by-zero
CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
# Compiler flags that turn on extra warnings
+9 -8
View File
@@ -206,9 +206,9 @@ private:
}
// Forward to . so we have a whole word
std::string suffix = *bpost ? std::string{bpost + 1} : "";
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
std::string out = prefix + "*" + suffix;
const std::string out = prefix + "*" + suffix;
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
// <<"\ncho="<<out<<endl;
@@ -219,7 +219,7 @@ private:
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
// We don't compare keys, only values
std::string val = m_indexValues[itemp->m_vals[i]];
const std::string val = m_indexValues[itemp->m_vals[i]];
if (std::string::npos != val.find(match)) { // Found
return true;
}
@@ -302,7 +302,7 @@ public:
// First two key/vals are filename
ckeyps[0] = "filename";
valps[0] = m_insertFilenamep;
std::string linestr = vlCovCvtToStr(m_insertLineno);
const std::string linestr = vlCovCvtToStr(m_insertLineno);
ckeyps[1] = "lineno";
valps[1] = linestr.c_str();
// Default page if not specified
@@ -342,7 +342,7 @@ public:
m_insertp->m_vals[addKeynum] = valueIndex(val);
++addKeynum;
if (VL_UNCOVERABLE(!legalKey(key))) {
std::string msg
const std::string msg
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
+ key); // LCOV_EXCL_LINE
VL_FATAL_MT("", 0, "", msg.c_str());
@@ -364,7 +364,7 @@ public:
std::ofstream os{filename};
if (os.fail()) {
std::string msg = std::string{"%Error: Can't write '"} + filename + "'";
const std::string msg = std::string{"%Error: Can't write '"} + filename + "'";
VL_FATAL_MT("", 0, "", msg.c_str());
return;
}
@@ -380,8 +380,9 @@ public:
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
std::string val = m_indexValues[itemp->m_vals[i]];
const std::string key
= VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
const std::string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
+4 -4
View File
@@ -68,7 +68,7 @@ svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1));
}
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); }
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(bit, dp, s); }
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
// Verilator doesn't support X/Z so only aval
dp[VL_BITWORD_I(bit)].aval = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
@@ -428,13 +428,13 @@ void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
switch (varp->udims()) {
case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
case 2: {
int indx2 = va_arg(ap, int);
const int indx2 = va_arg(ap, int);
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
break;
}
case 3: {
int indx2 = va_arg(ap, int);
int indx3 = va_arg(ap, int);
const int indx2 = va_arg(ap, int);
const int indx3 = va_arg(ap, int);
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
break;
}
+122 -127
View File
@@ -73,18 +73,20 @@ extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
/// Print a debug message from internals with standard prefix, with printf style format
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
#ifndef VL_NO_LEGACY
// EMIT_RULE: VL_RANDOM: oclean=dirty
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp);
#endif
extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE;
extern IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE;
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
vluint64_t rnd = vl_rand64();
const vluint64_t rnd = vl_rand64();
if (VL_LIKELY(hi > lo)) {
// (hi - lo + 1) can be zero when hi is UINT_MAX and lo is zero
if (VL_UNLIKELY(hi - lo + 1 == 0)) return rnd;
// Modulus isn't very fast but it's common that hi-low is power-of-two
return (rnd % (hi - lo + 1)) + lo;
} else {
if (VL_UNLIKELY(lo - hi + 1 == 0)) return rnd;
return (rnd % (lo - hi + 1)) + hi;
}
}
@@ -360,13 +362,13 @@ vluint64_t vl_time_pow10(int n) VL_PURE;
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits))
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (obits), (owp), (lwp))
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (owp), (lwp))
static inline WDataOutP _vl_clean_inplace_w(int obits, WDataOutP owp) VL_MT_SAFE {
const int words = VL_WORDS_I(obits);
owp[words - 1] &= VL_MASK_E(obits);
return owp;
}
static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
static inline WDataOutP VL_CLEAN_WW(int obits, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
const int words = VL_WORDS_I(obits);
for (int i = 0; (i < (words - 1)); ++i) owp[i] = lwp[i];
owp[words - 1] = lwp[words - 1] & VL_MASK_E(obits);
@@ -394,37 +396,37 @@ static inline WDataOutP VL_ASSIGN_W(int obits, WDataOutP owp, WDataInP const lwp
}
// EMIT_RULE: VL_ASSIGNBIT: rclean=clean;
static inline void VL_ASSIGNBIT_II(int, int bit, CData& lhsr, IData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_II(int bit, CData& lhsr, IData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_II(int, int bit, SData& lhsr, IData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_II(int bit, SData& lhsr, IData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_II(int, int bit, IData& lhsr, IData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_II(int bit, IData& lhsr, IData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_QI(int bit, QData& lhsr, QData rhs) VL_PURE {
lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)];
static inline void VL_ASSIGNBIT_WI(int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
const EData orig = owp[VL_BITWORD_E(bit)];
owp[VL_BITWORD_E(bit)] = ((orig & ~(VL_EUL(1) << VL_BITBIT_E(bit)))
| (static_cast<EData>(rhs) << VL_BITBIT_E(bit)));
}
// Alternative form that is an instruction faster when rhs is constant one.
static inline void VL_ASSIGNBIT_IO(int, int bit, CData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_IO(int bit, CData& lhsr) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_IO(int, int bit, SData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_IO(int bit, SData& lhsr) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_IO(int, int bit, IData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_IO(int bit, IData& lhsr) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_QO(int bit, QData& lhsr) VL_PURE {
lhsr = (lhsr | (1ULL << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
const EData orig = owp[VL_BITWORD_E(bit)];
owp[VL_BITWORD_E(bit)] = (orig | (VL_EUL(1) << VL_BITBIT_E(bit)));
}
@@ -585,9 +587,9 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp,
// REDUCTION OPERATORS
// EMIT_RULE: VL_REDAND: oclean=clean; lclean==clean; obits=1;
#define VL_REDAND_II(obits, lbits, lhs) ((lhs) == VL_MASK_I(lbits))
#define VL_REDAND_IQ(obits, lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
static inline IData VL_REDAND_IW(int, int lbits, WDataInP const lwp) VL_MT_SAFE {
#define VL_REDAND_II(lbits, lhs) ((lhs) == VL_MASK_I(lbits))
#define VL_REDAND_IQ(lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_MT_SAFE {
const int words = VL_WORDS_I(lbits);
EData combine = lwp[0];
for (int i = 1; i < words - 1; ++i) combine &= lwp[i];
@@ -693,11 +695,11 @@ static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_MT_SAFE {
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
const int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
if (ctrlSum == 3) {
return VL_COUNTONES_I(lhs);
} else if (ctrlSum == 0) {
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
const IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
return VL_COUNTONES_I(~lhs & mask);
} else {
return (lbits == 32) ? 32 : lbits;
@@ -768,7 +770,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
const EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
for (int i = words - 1; i >= 0; --i) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
@@ -859,52 +861,52 @@ static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) V
return 0; // ==
}
#define VL_LTS_IWW(obits, lbits, rbbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) < 0)
#define VL_LTES_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) <= 0)
#define VL_GTS_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) > 0)
#define VL_GTES_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) >= 0)
#define VL_LTS_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) < 0)
#define VL_LTES_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) <= 0)
#define VL_GTS_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) > 0)
#define VL_GTES_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) >= 0)
static inline IData VL_GTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_GTS_III(int lbits, IData lhs, IData rhs) VL_PURE {
// For lbits==32, this becomes just a single instruction, otherwise ~5.
// GCC 3.3.4 sign extension bugs on AMD64 architecture force us to use quad logic
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed > rhs_signed;
}
static inline IData VL_GTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_GTS_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed > rhs_signed;
}
static inline IData VL_GTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_GTES_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed >= rhs_signed;
}
static inline IData VL_GTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_GTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed >= rhs_signed;
}
static inline IData VL_LTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_LTS_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed < rhs_signed;
}
static inline IData VL_LTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_LTS_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed < rhs_signed;
}
static inline IData VL_LTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_LTES_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed <= rhs_signed;
}
static inline IData VL_LTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_LTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed <= rhs_signed;
@@ -940,7 +942,7 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp
static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE {
EData carry = 1;
for (int i = 0; i < words; ++i) {
EData word = ~owp_lwp[i] + carry;
const EData word = ~owp_lwp[i] + carry;
carry = (word < ~owp_lwp[i]);
owp_lwp[i] = word;
}
@@ -999,18 +1001,18 @@ static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP const lwp,
return owp;
}
static inline IData VL_MULS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_MULS_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
const vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
return lhs_signed * rhs_signed;
}
static inline QData VL_MULS_QQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline QData VL_MULS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed * rhs_signed;
}
static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP const lwp,
static inline WDataOutP VL_MULS_WWW(int lbits, WDataOutP owp, WDataInP const lwp,
WDataInP const rwp) VL_MT_SAFE {
const int words = VL_WORDS_I(lbits);
// cppcheck-suppress variableScope
@@ -1019,13 +1021,13 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
WData rwstore[VL_MULS_MAX_WORDS];
WDataInP lwusp = lwp;
WDataInP rwusp = rwp;
EData lneg = VL_SIGN_E(lbits, lwp[words - 1]);
const EData lneg = VL_SIGN_E(lbits, lwp[words - 1]);
if (lneg) { // Negate lhs
lwusp = lwstore;
VL_NEGATE_W(words, lwstore, lwp);
lwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
}
EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
const EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
if (rneg) { // Negate rhs
rwusp = rwstore;
VL_NEGATE_W(words, rwstore, rwp);
@@ -1218,31 +1220,27 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp, boo
// INTERNAL: Stuff LHS bit 0++ into OUTPUT at specified offset
// ld may be "dirty", output is clean
static inline void _vl_insert_II(int, CData& lhsr, IData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_II(CData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
const IData cleanmask = VL_MASK_I(rbits);
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_II(int, SData& lhsr, IData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_II(SData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
const IData cleanmask = VL_MASK_I(rbits);
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_II(int, IData& lhsr, IData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_II(IData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
const IData cleanmask = VL_MASK_I(rbits);
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_QQ(int, QData& lhsr, QData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_QQ(QData& lhsr, QData ld, int hbit, int lbit, int rbits) VL_PURE {
const QData cleanmask = VL_MASK_Q(rbits);
const QData insmask = (VL_MASK_Q(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_WI(int, WDataOutP owp, IData ld, int hbit, int lbit,
static inline void _vl_insert_WI(WDataOutP owp, IData ld, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
const int hoffset = VL_BITBIT_E(hbit);
const int loffset = VL_BITBIT_E(lbit);
@@ -1275,7 +1273,7 @@ static inline void _vl_insert_WI(int, WDataOutP owp, IData ld, int hbit, int lbi
// INTERNAL: Stuff large LHS bit 0++ into OUTPUT at specified offset
// lwp may be "dirty"
static inline void _vl_insert_WW(int, WDataOutP owp, WDataInP const lwp, int hbit, int lbit,
static inline void _vl_insert_WW(WDataOutP owp, WDataInP const lwp, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
const int hoffset = VL_BITBIT_E(hbit);
const int loffset = VL_BITBIT_E(lbit);
@@ -1331,19 +1329,19 @@ static inline void _vl_insert_WW(int, WDataOutP owp, WDataInP const lwp, int hbi
}
}
static inline void _vl_insert_WQ(int obits, WDataOutP owp, QData ld, int hbit, int lbit,
static inline void _vl_insert_WQ(WDataOutP owp, QData ld, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> lwp;
VL_SET_WQ(lwp, ld);
_vl_insert_WW(obits, owp, lwp, hbit, lbit, rbits);
_vl_insert_WW(owp, lwp, hbit, lbit, rbits);
}
// EMIT_RULE: VL_REPLICATE: oclean=clean>width32, dirty<=width32; lclean=clean; rclean==clean;
// RHS MUST BE CLEAN CONSTANT.
#define VL_REPLICATE_IOI(obits, lbits, rbits, ld, rep) (-(ld)) // Iff lbits==1
#define VL_REPLICATE_QOI(obits, lbits, rbits, ld, rep) (-(static_cast<QData>(ld))) // Iff lbits==1
#define VL_REPLICATE_IOI(lbits, ld, rep) (-(ld)) // Iff lbits==1
#define VL_REPLICATE_QOI(lbits, ld, rep) (-(static_cast<QData>(ld))) // Iff lbits==1
static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) VL_PURE {
static inline IData VL_REPLICATE_III(int lbits, IData ld, IData rep) VL_PURE {
IData returndata = ld;
for (unsigned i = 1; i < rep; ++i) {
returndata = returndata << lbits;
@@ -1351,7 +1349,7 @@ static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) V
}
return returndata;
}
static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) VL_PURE {
static inline QData VL_REPLICATE_QII(int lbits, IData ld, IData rep) VL_PURE {
QData returndata = ld;
for (unsigned i = 1; i < rep; ++i) {
returndata = returndata << lbits;
@@ -1359,27 +1357,27 @@ static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) V
}
return returndata;
}
static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld,
static inline WDataOutP VL_REPLICATE_WII(int lbits, WDataOutP owp, IData ld,
IData rep) VL_MT_SAFE {
owp[0] = ld;
for (unsigned i = 1; i < rep; ++i) {
_vl_insert_WI(obits, owp, ld, i * lbits + lbits - 1, i * lbits);
_vl_insert_WI(owp, ld, i * lbits + lbits - 1, i * lbits);
}
return owp;
}
static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld,
static inline WDataOutP VL_REPLICATE_WQI(int lbits, WDataOutP owp, QData ld,
IData rep) VL_MT_SAFE {
VL_SET_WQ(owp, ld);
for (unsigned i = 1; i < rep; ++i) {
_vl_insert_WQ(obits, owp, ld, i * lbits + lbits - 1, i * lbits);
_vl_insert_WQ(owp, ld, i * lbits + lbits - 1, i * lbits);
}
return owp;
}
static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp,
WDataInP const lwp, IData rep) VL_MT_SAFE {
static inline WDataOutP VL_REPLICATE_WWI(int lbits, WDataOutP owp, WDataInP const lwp,
IData rep) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i];
for (unsigned i = 1; i < rep; ++i) {
_vl_insert_WW(obits, owp, lwp, i * lbits + lbits - 1, i * lbits);
_vl_insert_WW(owp, lwp, i * lbits + lbits - 1, i * lbits);
}
return owp;
}
@@ -1388,7 +1386,7 @@ static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP ow
// Special "fast" versions for slice sizes that are a power of 2. These use
// shifts and masks to execute faster than the slower for-loop approach where a
// subset of bits is copied in during each iteration.
static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_log2) VL_PURE {
static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_PURE {
// Pre-shift bits in most-significant slice:
//
// If lbits is not a multiple of the slice size (i.e., lbits % rd != 0),
@@ -1426,7 +1424,7 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_
return ret >> (VL_IDATASIZE - lbits);
}
static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_log2) VL_PURE {
static inline QData VL_STREAML_FAST_QQI(int lbits, QData ld, IData rd_log2) VL_PURE {
// Pre-shift bits in most-significant slice (see comment in VL_STREAML_FAST_III)
QData ret = ld;
if (rd_log2) {
@@ -1458,7 +1456,7 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
}
// Regular "slow" streaming operators
static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_PURE {
static inline IData VL_STREAML_III(int lbits, IData ld, IData rd) VL_PURE {
IData ret = 0;
// Slice size should never exceed the lhs width
const IData mask = VL_MASK_I(rd);
@@ -1470,7 +1468,7 @@ static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_P
return ret;
}
static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_PURE {
static inline QData VL_STREAML_QQI(int lbits, QData ld, IData rd) VL_PURE {
QData ret = 0;
// Slice size should never exceed the lhs width
const QData mask = VL_MASK_Q(rd);
@@ -1482,7 +1480,7 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_P
return ret;
}
static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP const lwp,
static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const lwp,
IData rd) VL_MT_SAFE {
VL_ZERO_W(lbits, owp);
// Slice size should never exceed the lhs width
@@ -1493,7 +1491,8 @@ static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WData
for (int sbit = 0; sbit < ssize && sbit < lbits - istart; ++sbit) {
// Extract a single bit from lwp and shift it to the correct
// location for owp.
EData bit = (VL_BITRSHIFT_W(lwp, (istart + sbit)) & 1) << VL_BITBIT_E(ostart + sbit);
const EData bit = (VL_BITRSHIFT_W(lwp, (istart + sbit)) & 1)
<< VL_BITBIT_E(ostart + sbit);
owp[VL_BITWORD_E(ostart + sbit)] |= bit;
}
}
@@ -1519,63 +1518,63 @@ static inline WDataOutP VL_CONCAT_WII(int obits, int lbits, int rbits, WDataOutP
IData rd) VL_MT_SAFE {
owp[0] = rd;
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WWI(int obits, int lbits, int rbits, WDataOutP owp,
WDataInP const lwp, IData rd) VL_MT_SAFE {
owp[0] = rd;
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WIW(int obits, int lbits, int rbits, WDataOutP owp, IData ld,
WDataInP const rwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WIQ(int obits, int lbits, int rbits, WDataOutP owp, IData ld,
QData rd) VL_MT_SAFE {
VL_SET_WQ(owp, rd);
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WQI(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
IData rd) VL_MT_SAFE {
owp[0] = rd;
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WQQ(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
QData rd) VL_MT_SAFE {
VL_SET_WQ(owp, rd);
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WWQ(int obits, int lbits, int rbits, WDataOutP owp,
WDataInP const lwp, QData rd) VL_MT_SAFE {
VL_SET_WQ(owp, rd);
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WQW(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
WDataInP const rwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WWW(int obits, int lbits, int rbits, WDataOutP owp,
WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
return owp;
}
@@ -1610,7 +1609,7 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits, int, int, WDataOutP owp, WDataI
for (int i = word_shift; i < VL_WORDS_I(obits); ++i) owp[i] = lwp[i - word_shift];
} else {
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, obits - 1, rd);
_vl_insert_WW(owp, lwp, obits - 1, rd);
}
return owp;
}
@@ -1763,7 +1762,8 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits, int lbits, int, WDataOutP owp,
owp[lmsw] &= VL_MASK_E(lbits);
} else {
const int loffset = rd & VL_SIZEBITS_E;
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
const int nbitsonright
= VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
// Middle words
const int words = VL_WORDS_I(obits - rd);
for (int i = 0; i < words; ++i) {
@@ -1832,14 +1832,13 @@ static inline QData VL_SHIFTRS_QQQ(int obits, int lbits, int rbits, QData lhs, Q
// Bit selection
// EMIT_RULE: VL_BITSEL: oclean=dirty; rclean==clean;
#define VL_BITSEL_IIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QQII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_IQII(obits, lbits, rbits, zbits, lhs, rhs) (static_cast<IData>((lhs) >> (rhs)))
#define VL_BITSEL_IIII(lbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QIII(lbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QQII(lbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_IQII(lbits, lhs, rhs) (static_cast<IData>((lhs) >> (rhs)))
static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP const lwp,
IData rd) VL_MT_SAFE {
int word = VL_BITWORD_E(rd);
static inline IData VL_BITSEL_IWII(int lbits, WDataInP const lwp, IData rd) VL_MT_SAFE {
const int word = VL_BITWORD_E(rd);
if (VL_UNLIKELY(rd > static_cast<IData>(lbits))) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
// We return all 1's as that's more likely to find bugs (?) than 0's.
@@ -1850,27 +1849,24 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP const lwp,
// EMIT_RULE: VL_RANGE: oclean=lclean; out=dirty
// <msb> & <lsb> MUST BE CLEAN (currently constant)
#define VL_SEL_IIII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_QQII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_IQII(obits, lbits, rbits, tbits, lhs, lsb, width) \
(static_cast<IData>((lhs) >> (lsb)))
#define VL_SEL_IIII(lbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_QQII(lbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_IQII(lbits, lhs, lsb, width) (static_cast<IData>((lhs) >> (lsb)))
static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP const lwp, IData lsb,
IData width) VL_MT_SAFE {
int msb = lsb + width - 1;
static inline IData VL_SEL_IWII(int lbits, WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
const int msb = lsb + width - 1;
if (VL_UNLIKELY(msb >= lbits)) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
} else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast<int>(lsb))) {
return VL_BITRSHIFT_W(lwp, lsb);
} else {
// 32 bit extraction may span two words
int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word
const int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word
return ((lwp[VL_BITWORD_E(msb)] << nbitsfromlow) | VL_BITRSHIFT_W(lwp, lsb));
}
}
static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, IData lsb,
IData width) VL_MT_SAFE {
static inline QData VL_SEL_QWII(int lbits, WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
const int msb = lsb + width - 1;
if (VL_UNLIKELY(msb > lbits)) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
@@ -1883,7 +1879,7 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, ID
return (hi << nbitsfromlow) | lo;
} else {
// 64 bit extraction may span three words
int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb);
const int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb);
const QData hi = (lwp[VL_BITWORD_E(msb)]);
const QData mid = (lwp[VL_BITWORD_E(lsb) + 1]);
const QData lo = VL_BITRSHIFT_W(lwp, lsb);
@@ -1891,8 +1887,8 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, ID
}
}
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP owp,
WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataInP const lwp,
IData lsb, IData width) VL_MT_SAFE {
const int msb = lsb + width - 1;
const int word_shift = VL_BITWORD_E(lsb);
if (VL_UNLIKELY(msb > lbits)) { // Outside bounds,
@@ -1924,7 +1920,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP ow
// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
// This does not need to support subnormals as they are sub-integral
lhs = VL_ROUND(lhs);
@@ -1941,8 +1937,8 @@ static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
if (lhs < 0) out = -out;
return out;
}
static inline IData VL_RTOIROUND_I_D(int bits, double lhs) VL_PURE {
return static_cast<IData>(VL_RTOIROUND_Q_D(bits, lhs));
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE {
return static_cast<IData>(VL_RTOIROUND_Q_D(lhs));
}
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
@@ -1956,7 +1952,7 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
if (lsb < 0) {
VL_SET_WQ(owp, mantissa >> -lsb);
} else if (lsb < obits) {
_vl_insert_WQ(obits, owp, mantissa, lsb + 52, lsb);
_vl_insert_WQ(owp, mantissa, lsb + 52, lsb);
}
if (lhs < 0) VL_NEGATE_INPLACE_W(VL_WORDS_I(obits), owp);
return owp;
@@ -1968,48 +1964,48 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
// EMIT_RULE: VL_ASSIGNRANGE: rclean=dirty;
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, CData& lhsr,
IData rhs) VL_PURE {
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, SData& lhsr,
IData rhs) VL_PURE {
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, IData& lhsr,
IData rhs) VL_PURE {
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_QIII(int rbits, int obits, int lsb, QData& lhsr,
IData rhs) VL_PURE {
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_QQII(int rbits, int obits, int lsb, QData& lhsr,
QData rhs) VL_PURE {
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_QIIQ(int rbits, int obits, int lsb, QData& lhsr,
QData rhs) VL_PURE {
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
// static inline void VL_ASSIGNSEL_IIIW(int obits, int lsb, IData& lhsr, WDataInP const rwp)
// VL_MT_SAFE { Illegal, as lhs width >= rhs width
static inline void VL_ASSIGNSEL_WIII(int rbits, int obits, int lsb, WDataOutP owp,
IData rhs) VL_MT_SAFE {
_vl_insert_WI(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_WI(owp, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_WIIQ(int rbits, int obits, int lsb, WDataOutP owp,
QData rhs) VL_MT_SAFE {
_vl_insert_WQ(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_WQ(owp, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_WIIW(int rbits, int obits, int lsb, WDataOutP owp,
WDataInP const rwp) VL_MT_SAFE {
_vl_insert_WW(obits, owp, rwp, lsb + obits - 1, lsb, rbits);
_vl_insert_WW(owp, rwp, lsb + obits - 1, lsb, rbits);
}
//======================================================================
// Triops
static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, WDataOutP owp, int cond,
WDataInP const w1p, WDataInP const w2p) VL_MT_SAFE {
static inline WDataOutP VL_COND_WIWW(int obits, WDataOutP owp, int cond, WDataInP const w1p,
WDataInP const w2p) VL_MT_SAFE {
const int words = VL_WORDS_I(obits);
for (int i = 0; i < words; ++i) owp[i] = cond ? w1p[i] : w2p[i];
return owp;
@@ -2184,15 +2180,14 @@ inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
return lhs + rhs;
}
inline std::string VL_REPLICATEN_NNQ(int, int, int, const std::string& lhs, IData rep) VL_PURE {
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;
}
inline std::string VL_REPLICATEN_NNI(int obits, int lbits, int rbits, const std::string& lhs,
IData rep) VL_PURE {
return VL_REPLICATEN_NNQ(obits, lbits, rbits, lhs, rep);
inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE {
return VL_REPLICATEN_NNQ(lhs, rep);
}
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
@@ -2217,31 +2212,31 @@ extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suff
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, SData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = VL_SET_QW(rwp);
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, double& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = VL_CVT_D_Q(VL_SET_QW(rwp));
return got;
}
+5 -5
View File
@@ -277,7 +277,7 @@ public: // But only for verilated*.cpp
IData fdNewMcd(const char* filenamep) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
const VerilatedLockGuard lock{m_fdMutex};
if (m_fdFreeMct.empty()) return 0;
IData idx = m_fdFreeMct.back();
const IData idx = m_fdFreeMct.back();
m_fdFreeMct.pop_back();
m_fdps[idx] = std::fopen(filenamep, "w");
if (VL_UNLIKELY(!m_fdps[idx])) return 0;
@@ -299,7 +299,7 @@ public: // But only for verilated*.cpp
m_fdFree[i] = id;
}
}
IData idx = m_fdFree.back();
const IData idx = m_fdFree.back();
m_fdFree.pop_back();
m_fdps[idx] = fp;
return (idx | (1UL << 31)); // bit 31 indicates not MCD
@@ -334,7 +334,7 @@ public: // But only for verilated*.cpp
const VerilatedLockGuard lock{m_fdMutex};
if (VL_BITISSET_I(fdi, 31)) {
// Non-MCD case
IData idx = VL_MASK_I(31) & fdi;
const IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(idx >= m_fdps.size())) return;
if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr
if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free
@@ -549,8 +549,8 @@ public: // But only for verilated*.cpp
const VerilatedLockGuard lock{s().m_exportMutex};
const auto& it = s().m_exportMap.find(namep);
if (VL_LIKELY(it != s().m_exportMap.end())) return it->second;
std::string msg = (std::string{"%Error: Testbench C called "} + namep
+ " but no such DPI export function name exists in ANY model");
const std::string msg = (std::string{"%Error: Testbench C called "} + namep
+ " but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return -1;
}
+113
View File
@@ -0,0 +1,113 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Code available from: https://verilator.org
//
// Copyright 2012-2021 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 general profiling header
///
/// This file is not part of the Verilated public-facing API.
/// It is only for internal use by Verilated library routines.
///
//=============================================================================
#ifndef VERILATOR_VERILATED_PROFILER_H_
#define VERILATOR_VERILATED_PROFILER_H_
#include "verilatedos.h"
#include "verilated.h" // for VerilatedMutex and clang annotations
// Profile record, private class used only by this header
class VerilatedProfilerRec final {
const std::string m_name; // Hashed name of mtask/etc
const size_t m_counterNumber = 0; // Which counter has data
public:
// METHODS
VerilatedProfilerRec(size_t counterNumber, const std::string& name)
: m_name{name}
, m_counterNumber{counterNumber} {}
VerilatedProfilerRec() = default;
size_t counterNumber() const { return m_counterNumber; }
std::string name() const { return m_name; }
};
// Create some number of bucketed profilers
template <std::size_t T_Entries> class VerilatedProfiler final {
// Counters are stored packed, all together, versus in VerilatedProfilerRec to
// reduce cache effects
std::array<vluint64_t, T_Entries> m_counters{}; // Time spent on this record
std::deque<VerilatedProfilerRec> m_records; // Record information
public:
// METHODS
VerilatedProfiler() = default;
~VerilatedProfiler() = default;
void write(const char* modelp, const std::string& filename) VL_MT_SAFE;
void addCounter(size_t counter, const std::string& name) {
VL_DEBUG_IF(assert(counter < T_Entries););
m_records.emplace_back(VerilatedProfilerRec{counter, name});
}
void startCounter(size_t counter) {
vluint64_t val;
VL_RDTSC(val);
// -= so when we add end time in stopCounter, we already subtracted
// out, without needing to hold another temporary
m_counters[counter] -= val;
}
void stopCounter(size_t counter) {
vluint64_t val;
VL_RDTSC(val);
m_counters[counter] += val;
}
};
template <std::size_t T_Entries>
void VerilatedProfiler<T_Entries>::write(const char* modelp,
const std::string& filename) VL_MT_SAFE {
static VerilatedMutex s_mutex;
const VerilatedLockGuard lock{s_mutex};
// On the first call we create the file. On later calls we append.
// So when we have multiple models in an executable, possibly even
// running on different threads, each will have a different symtab so
// each will collect is own data correctly. However when each is
// destroid we need to get all the data, not keep overwriting and only
// get the last model's data.
static bool s_firstCall = true;
VL_DEBUG_IF(VL_DBG_MSGF("+prof+vlt+file writing to '%s'\n", filename.c_str()););
FILE* fp = nullptr;
if (!s_firstCall) fp = std::fopen(filename.c_str(), "a");
if (VL_UNLIKELY(!fp))
fp = std::fopen(filename.c_str(), "w"); // firstCall, or doesn't exist yet
if (VL_UNLIKELY(!fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "+prof+vlt+file file not writable");
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
return; // LCOV_EXCL_LINE
}
s_firstCall = false;
// TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc.
fprintf(fp, "// Verilated model profile-guided optimization data dump file\n");
fprintf(fp, "`verilator_config\n");
for (const auto& it : m_records) {
const std::string& name = it.name();
fprintf(fp, "profile_data -model \"%s\" -mtask \"%s\" -cost 64'd%" VL_PRI64 "u\n", modelp,
name.c_str(), m_counters[it.counterNumber()]);
}
std::fclose(fp);
}
#endif
+2 -2
View File
@@ -192,7 +192,7 @@ void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(!isOpen())) return;
vluint8_t* wp = m_bufp;
const vluint8_t* wp = m_bufp;
while (true) {
const ssize_t remaining = (m_cp - wp);
if (remaining == 0) break;
@@ -204,7 +204,7 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string{__FUNCTION__} + ": " + std::strerror(errno);
const std::string msg = std::string{__FUNCTION__} + ": " + std::strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
+1 -1
View File
@@ -279,7 +279,7 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, const std::string& rhs) {
vluint32_t len = rhs.length();
const vluint32_t len = rhs.length();
os << len;
return os.write(rhs.data(), len);
}
+5 -5
View File
@@ -192,8 +192,8 @@ public:
class VerilatedDpiOpenVar final {
// MEMBERS
const VerilatedVarProps* m_propsp; // Variable properties
void* m_datap; // Location of data (local to thread always, so safe)
const VerilatedVarProps* const m_propsp; // Variable properties
void* const m_datap; // Location of data (local to thread always, so safe)
public:
// CONSTRUCTORS
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
@@ -230,10 +230,10 @@ public:
class VerilatedVar final : public VerilatedVarProps {
// MEMBERS
void* m_datap; // Location of data
const char* m_namep; // Name - slowpath
void* const m_datap; // Location of data
const char* const m_namep; // Name - slowpath
protected:
bool m_isParam;
const bool m_isParam;
friend class VerilatedScope;
// CONSTRUCTORS
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
+34 -7
View File
@@ -25,6 +25,7 @@
#include "verilated_threads.h"
#include <cstdio>
#include <fstream>
//=============================================================================
// Globals
@@ -145,7 +146,7 @@ void VlThreadPool::profileAppendAll(const VlProfileRec& rec) VL_MT_SAFE_EXCLUDES
}
}
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed)
void VlThreadPool::profileDump(const char* filenamep, vluint64_t tickStart, vluint64_t tickEnd)
VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
@@ -159,7 +160,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed)
// TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc.
fprintf(fp, "VLPROFTHREAD 1.0 # Verilator thread profile dump version 1.0\n");
fprintf(fp, "VLPROFTHREAD 1.1 # Verilator thread profile dump version 1.1\n");
fprintf(fp, "VLPROF arg --threads %" VL_PRI64 "u\n", vluint64_t(m_workers.size() + 1));
fprintf(fp, "VLPROF arg +verilator+prof+threads+start+%" VL_PRI64 "u\n",
Verilated::threadContextp()->profThreadsStart());
@@ -167,6 +168,16 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed)
Verilated::threadContextp()->profThreadsWindow());
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n", VlMTaskVertex::yields());
// Copy /proc/cpuinfo into this output so verilator_gantt can be run on
// a different machine
{
const std::unique_ptr<std::ifstream> ifp{new std::ifstream("/proc/cpuinfo")};
if (!ifp->fail()) {
std::string line;
while (std::getline(*ifp, line)) { fprintf(fp, "VLPROFPROC %s\n", line.c_str()); }
}
}
vluint32_t thread_id = 0;
for (const auto& pi : m_allProfiles) {
++thread_id;
@@ -177,20 +188,36 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed)
case VlProfileRec::TYPE_BARRIER: //
printing = true;
break;
case VlProfileRec::TYPE_EVAL:
if (!printing) break;
fprintf(fp,
"VLPROF eval start %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
" cpu %u on thread %u\n",
ei.m_startTime - tickStart, (ei.m_endTime - ei.m_startTime), ei.m_cpu,
thread_id);
break;
case VlProfileRec::TYPE_EVAL_LOOP:
if (!printing) break;
fprintf(fp,
"VLPROF eval_loop start %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
" cpu %u on thread %u\n",
ei.m_startTime - tickStart, (ei.m_endTime - ei.m_startTime), ei.m_cpu,
thread_id);
break;
case VlProfileRec::TYPE_MTASK_RUN:
if (!printing) break;
fprintf(fp,
"VLPROF mtask %d"
" start %" VL_PRI64 "u end %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
" predict_time %u cpu %u on thread %u\n",
ei.m_mtaskId, ei.m_startTime, ei.m_endTime,
(ei.m_endTime - ei.m_startTime), ei.m_predictTime, ei.m_cpu, thread_id);
" start %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
" predict_start %u predict_cost %u cpu %u on thread %u\n",
ei.m_mtaskId, ei.m_startTime - tickStart, (ei.m_endTime - ei.m_startTime),
ei.m_predictStart, ei.m_predictCost, ei.m_cpu, thread_id);
break;
default: assert(false); break; // LCOV_EXCL_LINE
}
}
}
fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n", ticksElapsed);
fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n", tickEnd - tickStart);
std::fclose(fp);
}
+28 -12
View File
@@ -131,21 +131,36 @@ public:
class VlProfileRec final {
protected:
friend class VlThreadPool;
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
VlProfileE m_type = TYPE_BARRIER; // Record type
vluint32_t m_mtaskId = 0; // Mtask we're logging
vluint32_t m_predictTime = 0; // How long scheduler predicted would take
vluint64_t m_startTime = 0; // Tick at start of execution
enum VlProfileE { TYPE_MTASK_RUN, TYPE_EVAL, TYPE_EVAL_LOOP, TYPE_BARRIER };
// Layout below allows efficient packing.
// Leave endTime first, so no math needed to calculate address in endRecord
vluint64_t m_endTime = 0; // Tick at end of execution
vluint64_t m_startTime = 0; // Tick at start of execution
vluint32_t m_mtaskId = 0; // Mtask we're logging
vluint32_t m_predictStart = 0; // Time scheduler predicted would start
vluint32_t m_predictCost = 0; // How long scheduler predicted would take
VlProfileE m_type = TYPE_BARRIER; // Record type
unsigned m_cpu; // Execution CPU number (at start anyways)
public:
class Barrier {};
VlProfileRec() = default;
explicit VlProfileRec(Barrier) { m_cpu = getcpu(); }
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
void startEval(vluint64_t time) {
m_type = VlProfileRec::TYPE_EVAL;
m_startTime = time;
m_cpu = getcpu();
}
void startEvalLoop(vluint64_t time) {
m_type = VlProfileRec::TYPE_EVAL_LOOP;
m_startTime = time;
m_cpu = getcpu();
}
void startRecord(vluint64_t time, vluint32_t mtask, vluint32_t predictStart,
vluint32_t predictCost) {
m_type = VlProfileRec::TYPE_MTASK_RUN;
m_mtaskId = mtask;
m_predictTime = predict;
m_predictStart = predictStart;
m_predictCost = predictCost;
m_startTime = time;
m_cpu = getcpu();
}
@@ -202,12 +217,12 @@ private:
// Store the size atomically, so we can spin wait
std::atomic<size_t> m_ready_size;
VlThreadPool* m_poolp; // Our associated thread pool
VlThreadPool* const m_poolp; // Our associated thread pool
bool m_profiling; // Is profiling enabled?
const bool m_profiling; // Is profiling enabled?
std::atomic<bool> m_exiting; // Worker thread should exit
std::thread m_cthread; // Underlying C++ thread record
VerilatedContext* m_contextp; // Context for spawned thread
VerilatedContext* const m_contextp; // Context for spawned thread
VL_UNCOPYABLE(VlWorkerThread);
@@ -259,7 +274,7 @@ class VlThreadPool final {
// MEMBERS
std::vector<VlWorkerThread*> m_workers; // our workers
bool m_profiling; // is profiling enabled?
const bool m_profiling; // is profiling enabled?
// Support profiling -- we can append records of profiling events
// to this vector with very low overhead, and then dump them out
@@ -292,7 +307,8 @@ public:
return &(t_profilep->back());
}
void profileAppendAll(const VlProfileRec& rec) VL_MT_SAFE_EXCLUDES(m_mutex);
void profileDump(const char* filenamep, vluint64_t ticksElapsed) VL_MT_SAFE_EXCLUDES(m_mutex);
void profileDump(const char* filenamep, vluint64_t tickStart, vluint64_t tickEnd)
VL_MT_SAFE_EXCLUDES(m_mutex);
// In profiling mode, each executing thread must call
// this once to setup profiling state:
void setupProfilingClientThread() VL_MT_SAFE_EXCLUDES(m_mutex);
+3 -3
View File
@@ -267,7 +267,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flushBase() {
// Callbacks to run on global events
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
// This calls 'flush' on the derived classo (which must then get any mutex)
// This calls 'flush' on the derived class (which must then get any mutex)
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
}
@@ -481,8 +481,8 @@ void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>
VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
std::string msg = (std::string{"Internal: "} + __FILE__ + "::" + __FUNCTION__
+ " called with already open file");
const std::string msg = (std::string{"Internal: "} + __FILE__ + "::" + __FUNCTION__
+ " called with already open file");
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
} // LCOV_EXCL_STOP
cbVec.push_back(cbRec);
+5 -5
View File
@@ -79,10 +79,10 @@ public:
// Readmem/Writemem operation classes
class VlReadMem final {
bool m_hex; // Hex format
int m_bits; // Bit width of values
const bool m_hex; // Hex format
const int m_bits; // Bit width of values
const std::string& m_filename; // Filename
QData m_end; // End address (as specified by user)
const QData m_end; // End address (as specified by user)
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to read
int m_linenum; // Line number last read from file
@@ -96,8 +96,8 @@ public:
};
class VlWriteMem final {
bool m_hex; // Hex format
int m_bits; // Bit width of values
const bool m_hex; // Hex format
const int m_bits; // Bit width of values
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to write
public:
+4 -4
View File
@@ -281,7 +281,7 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
// minsize is size of largest write. We buffer at least 8 times as much data,
// writing when we are 3/4 full (with thus 2*minsize remaining free)
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
char* oldbufp = m_wrBufp;
const char* oldbufp = m_wrBufp;
m_wrChunkSize = minsize * 2;
m_wrBufp = new char[m_wrChunkSize * 8];
std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
@@ -298,7 +298,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
// When it gets nearly full we dump it using this routine which calls write()
// This is much faster than using buffered I/O
if (VL_UNLIKELY(!isOpen())) return;
char* wp = m_wrBufp;
const char* wp = m_wrBufp;
while (true) {
const ssize_t remaining = (m_writep - wp);
if (remaining == 0) break;
@@ -311,7 +311,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg
const std::string msg
= std::string{"VerilatedVcd::bufferFlush: "} + std::strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
closeErr();
@@ -386,7 +386,7 @@ void VerilatedVcd::dumpHeader() {
const std::string& decl = i.second;
// Determine difference between the old and new names
const char* hiername = hiernamestr.c_str();
const char* const hiername = hiernamestr.c_str();
const char* lp = lastName;
const char* np = hiername;
lastName = hiername;
+1 -1
View File
@@ -74,7 +74,7 @@ private:
int m_modDepth = 0; // Depth of module hierarchy
char* m_wrBufp; // Output buffer
char* m_wrFlushp; // Output buffer flush trigger location
const char* m_wrFlushp; // Output buffer flush trigger location
char* m_writep; // Write pointer into output buffer
vluint64_t m_wrChunkSize; // Output buffer size
vluint64_t m_wroteBytes = 0; // Number of bytes written to this file
+45 -45
View File
@@ -123,8 +123,8 @@ public:
class VerilatedVpioTimedCb final : public VerilatedVpio {
// A handle to a timed callback created with vpi_register_cb
// User can call vpi_remove_cb or vpi_release_handle on it
vluint64_t m_id; // Unique id/sequence number to find schedule's event
QData m_time;
const vluint64_t m_id; // Unique id/sequence number to find schedule's event
const QData m_time;
public:
VerilatedVpioTimedCb(vluint64_t id, QData time)
@@ -141,8 +141,8 @@ public:
class VerilatedVpioReasonCb final : public VerilatedVpio {
// A handle to a non-timed callback created with vpi_register_cb
// User can call vpi_remove_cb or vpi_release_handle on it
vluint64_t m_id; // Unique id/sequence number to find schedule's event
PLI_INT32 m_reason; // VPI callback reason code
const vluint64_t m_id; // Unique id/sequence number to find schedule's event
const PLI_INT32 m_reason; // VPI callback reason code
public:
// cppcheck-suppress uninitVar // m_value
@@ -158,7 +158,7 @@ public:
};
class VerilatedVpioConst final : public VerilatedVpio {
vlsint32_t m_num;
const vlsint32_t m_num;
public:
explicit VerilatedVpioConst(vlsint32_t num)
@@ -219,7 +219,7 @@ public:
};
class VerilatedVpioRange final : public VerilatedVpio {
const VerilatedRange* m_range;
const VerilatedRange* const m_range;
public:
explicit VerilatedVpioRange(const VerilatedRange* range)
@@ -235,7 +235,7 @@ public:
class VerilatedVpioRangeIter final : public VerilatedVpio {
// Only supports 1 dimension
const VerilatedRange* m_range;
const VerilatedRange* const m_range;
bool m_done = false;
public:
@@ -258,7 +258,7 @@ public:
class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio {
protected:
const VerilatedScope* m_scopep;
const VerilatedScope* const m_scopep;
public:
explicit VerilatedVpioScope(const VerilatedScope* scopep)
@@ -352,7 +352,7 @@ public:
};
class VerilatedVpioVarIter final : public VerilatedVpio {
const VerilatedScope* m_scopep;
const VerilatedScope* const m_scopep;
VerilatedVarNameMap::const_iterator m_it;
bool m_started = false;
@@ -389,9 +389,9 @@ public:
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
const vpiHandle m_handle;
const VerilatedVar* m_varp;
const VerilatedVar* const m_varp;
vlsint32_t m_iteration;
vlsint32_t m_direction;
const vlsint32_t m_direction;
bool m_done = false;
public:
@@ -413,7 +413,7 @@ public:
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
const vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
iterationInc();
return result;
}
@@ -457,7 +457,7 @@ public:
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
const VerilatedScope* modp = *m_it++;
const VerilatedScope* const modp = *m_it++;
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
};
@@ -595,7 +595,7 @@ public:
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); true;) {
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
bool was_last = it == last;
const bool was_last = it == last;
if (VL_UNLIKELY(it->invalid())) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
if (was_last) break;
@@ -1111,7 +1111,7 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
#define SELF_CHECK_RESULT_CSTR(got, exp) \
if (0 != std::strcmp((got), (exp))) { \
std::string msg \
const std::string msg \
= std::string{"%Error: "} + "GOT = '" + (got) + "'" + " EXP = '" + (exp) + "'"; \
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
}
@@ -1305,7 +1305,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
QData time = 0;
if (cb_data_p->time) time = VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
const QData abstime = VL_TIME_Q() + time;
vluint64_t id = VerilatedVpiImp::nextCallbackId();
const vluint64_t id = VerilatedVpiImp::nextCallbackId();
VerilatedVpioTimedCb* const vop = new VerilatedVpioTimedCb{id, abstime};
VerilatedVpiImp::cbTimedAdd(id, cb_data_p, abstime);
return vop->castVpiHandle();
@@ -1410,7 +1410,7 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
// Memory words are not indexable
VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(vop)) return nullptr;
const VerilatedVpioVar* const varop = VerilatedVpioVar::castp(object);
if (VL_LIKELY(varop)) {
@@ -1442,10 +1442,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
VL_VPI_ERROR_RESET_();
switch (type) {
case vpiLeftRange: {
if (VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
} else if (VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
} else if (const VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
}
@@ -1455,10 +1455,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
return nullptr;
}
case vpiRightRange: {
if (VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
} else if (VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
} else if (const VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
}
@@ -1468,18 +1468,18 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
return nullptr;
}
case vpiIndex: {
VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return nullptr;
const vlsint32_t val = vop->index();
return (new VerilatedVpioConst{val})->castVpiHandle();
}
case vpiScope: {
VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioScope{vop->scopep()})->castVpiHandle();
}
case vpiParent: {
VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioVar{vop->varp(), vop->scopep()})->castVpiHandle();
}
@@ -1697,7 +1697,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
// Maximum required size is for binary string, one byte per bit plus null termination
static VL_THREAD_LOCAL char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// cppcheck-suppress variableScope
static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
const static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
// This may cause backward compatibility issues with older code.
if (valuep->format == vpiVectorVal) {
@@ -1718,14 +1718,14 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT64) {
QData data = *(reinterpret_cast<QData*>(varDatap));
const QData data = *(reinterpret_cast<QData*>(varDatap));
t_out[1].aval = static_cast<IData>(data >> 32ULL);
t_out[1].bval = 0;
t_out[0].aval = static_cast<IData>(data);
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_WDATA) {
int words = VL_WORDS_I(varp->packed().elements());
const int words = VL_WORDS_I(varp->packed().elements());
if (VL_UNCOVERABLE(words >= VL_VALUE_STRING_MAX_WORDS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value with more than VL_VALUE_STRING_MAX_WORDS; increase and "
@@ -1741,7 +1741,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
} else if (valuep->format == vpiBinStrVal) {
valuep->value.str = t_outStr;
int bits = varp->packed().elements();
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (bits > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@@ -1754,7 +1754,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
VL_VALUE_STRING_MAX_WORDS, bits);
}
for (i = 0; i < bits; ++i) {
char val = (datap[i >> 3] >> (i & 7)) & 1;
const char val = (datap[i >> 3] >> (i & 7)) & 1;
t_outStr[bits - i - 1] = val ? '1' : '0';
}
t_outStr[i] = '\0';
@@ -1763,7 +1763,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
valuep->value.str = t_outStr;
int chars = (varp->packed().elements() + 2) / 3;
const int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (chars > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@@ -1788,7 +1788,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
if (i == (chars - 1)) {
// most signifcant char, mask off non existant bits when vector
// size is not a multiple of 3
unsigned int rem = varp->packed().elements() % 3;
const unsigned int rem = varp->packed().elements() % 3;
if (rem) {
// generate bit mask & zero non existant bits
val &= (1 << rem) - 1;
@@ -1821,7 +1821,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
} else if (valuep->format == vpiHexStrVal) {
valuep->value.str = t_outStr;
int chars = (varp->packed().elements() + 3) >> 2;
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (chars > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@@ -1855,7 +1855,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
} else {
valuep->value.str = t_outStr;
int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (bytes > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@@ -1899,13 +1899,13 @@ void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
VL_VPI_ERROR_RESET_();
if (VL_UNLIKELY(!valuep)) return;
if (VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
return;
} else if (const VerilatedVpioParam* const vop = VerilatedVpioParam::castp(object)) {
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
return;
} else if (VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
} else if (const VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
if (valuep->format == vpiIntVal) {
valuep->value.integer = vop->num();
return;
@@ -1970,9 +1970,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (valuep->format == vpiBinStrVal) {
const int bits = vop->varp()->packed().elements();
const int len = std::strlen(valuep->value.str);
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
for (int i = 0; i < bits; ++i) {
char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
const char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
// zero bits 7:1 of byte when assigning to bit 0, else
// or in 1 if bit set
if (i & 7) {
@@ -1986,7 +1986,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
const int chars = (vop->varp()->packed().elements() + 2) / 3;
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
const int len = std::strlen(valuep->value.str);
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
div_t idx;
datap[0] = 0; // reset zero'th byte
for (int i = 0; i < chars; ++i) {
@@ -1997,7 +1997,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
idx = div(i * 3, 8);
if (i < len) {
// ignore illegal chars
char digit = valuep->value.str[len - i - 1];
const char digit = valuep->value.str[len - i - 1];
if (digit >= '0' && digit <= '7') {
val.half = digit - '0';
} else {
@@ -2064,8 +2064,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
}
} else if (valuep->format == vpiHexStrVal) {
const int chars = (vop->varp()->packed().elements() + 3) >> 2;
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
char* val = valuep->value.str;
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
const char* val = valuep->value.str;
// skip hex ident if one is detected at the start of the string
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2;
const int len = std::strlen(val);
@@ -2073,7 +2073,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
char hex;
// compute hex digit value
if (i < len) {
char digit = val[len - i - 1];
const char digit = val[len - i - 1];
if (digit >= '0' && digit <= '9') {
hex = digit - '0';
} else if (digit >= 'a' && digit <= 'f') {
@@ -2105,7 +2105,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (valuep->format == vpiStringVal) {
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
const int len = std::strlen(valuep->value.str);
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
for (int i = 0; i < bytes; ++i) {
// prepend with 0 values before placing string the least significant bytes
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
@@ -2167,7 +2167,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
return;
} else if (time_p->type == vpiScaledRealTime) {
double dtime = VL_TIME_D();
if (VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object)) {
if (const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object)) {
const int scalePow10
= Verilated::threadContextp()->timeprecision() - vop->scopep()->timeunit();
const double scale = vl_time_multiplier(scalePow10); // e.g. 0.0001
@@ -2287,7 +2287,7 @@ PLI_INT32 vpi_release_handle(vpiHandle object) {
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) VL_MT_SAFE {
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();
const auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();
vlog_info_p->argc = argc_argv.first;
vlog_info_p->argv = argc_argv.second;
vlog_info_p->product = const_cast<PLI_BYTE8*>(Verilated::productName());
+8 -2
View File
@@ -333,7 +333,8 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
# include <stdint.h> // Linux and most flavors
# include <sys/types.h> // __WORDSIZE
# include <unistd.h> // ssize_t
typedef char vlsint8_t; ///< 8-bit signed type
// Arm64 gcc 9.3.0 defaults to unsigned char, not signed char
typedef signed char vlsint8_t; ///< 8-bit signed type
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
typedef short vlsint16_t; ///< 16-bit signed type
typedef uint16_t vluint16_t; ///< 16-bit unsigned type
@@ -472,7 +473,12 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
(val) = ((vluint64_t)lo) | (((vluint64_t)hi) << 32); \
}
#elif defined(__aarch64__)
# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r"(val));
// 1 GHz virtual system timer on SBSA level 5 compliant systems, else often 100 MHz
# define VL_RDTSC(val) \
{ \
asm volatile("isb" : : : "memory"); \
asm volatile("mrs %[rt],CNTVCT_EL0" : [rt] "=r"(val)); \
}
#else
// We just silently ignore unknown OSes, as only leads to missing statistics
# define VL_RDTSC(val) (val) = 0;
-4
View File
@@ -23,10 +23,6 @@ source_globs("include/*/*.c")
# Note *'s are removed when using fastcov
remove_source("/usr/*")
remove_source("*/include/sysc/*")
remove_source("*/V3ClkGater.cpp")
remove_source("*/V3ClkGater.h")
remove_source("*/V3GraphDfa.cpp")
remove_source("*/V3GraphDfa.h")
remove_source("*/V3Lexer_pregen.yy.cpp")
remove_source("*/V3PreLex_pregen.yy.cpp")
remove_source("*/verilog.c")
-1
View File
@@ -203,7 +203,6 @@ RAW_OBJS = \
V3Graph.o \
V3GraphAlg.o \
V3GraphAcyc.o \
V3GraphDfa.o \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hash.o \
+34 -34
View File
@@ -50,8 +50,8 @@ public:
enum VertexType : uint8_t { VT_BLOCK, VT_BRANCH, VT_OUTPUT };
private:
string m_name; // Only used for .dot file generation
VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
const string m_name; // Only used for .dot file generation
const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
string typestr() const { // "
switch (m_type) {
@@ -108,9 +108,10 @@ protected:
}
break;
case LatchDetectGraphVertex::VT_BRANCH: // (AND of both sibling)
// A BRANCH vertex always has exactly 2 siblings
LatchDetectGraphVertex* ifp = castVertexp(vertexp->outBeginp()->top());
LatchDetectGraphVertex* elsp = castVertexp(vertexp->outBeginp()->outNextp()->top());
// A BRANCH vertex always has exactly 2 siblings
LatchDetectGraphVertex* const ifp = castVertexp(vertexp->outBeginp()->top());
LatchDetectGraphVertex* const elsp
= castVertexp(vertexp->outBeginp()->outNextp()->top());
result = latchCheckInternal(ifp) && latchCheckInternal(elsp);
break;
}
@@ -151,7 +152,7 @@ public:
// Add a new output variable vertex and store a pointer to it in the user1 field of the
// variables AstNode
LatchDetectGraphVertex* addOutputVertex(AstVarRef* nodep) {
LatchDetectGraphVertex* outVertexp
LatchDetectGraphVertex* const outVertexp
= new LatchDetectGraphVertex{this, nodep->name(), LatchDetectGraphVertex::VT_OUTPUT};
nodep->varp()->user1p(outVertexp);
m_outputs.push_back(nodep);
@@ -172,7 +173,7 @@ public:
void latchCheck(AstNode* nodep, bool latch_expected) {
bool latch_detected = false;
for (const auto& vrp : m_outputs) {
LatchDetectGraphVertex* vertp = castVertexp(vrp->varp()->user1p());
LatchDetectGraphVertex* const vertp = castVertexp(vrp->varp()->user1p());
vertp->user(true); // Identify the output vertex we are checking paths _to_
if (!latchCheckInternal(castVertexp(verticesBeginp()))) latch_detected = true;
if (latch_detected && !latch_expected) {
@@ -262,7 +263,7 @@ public:
// Return a sentree in this scope that matches given sense list.
AstActive* activep = nullptr;
AstSenTree* activeSenp = m_activeSens.find(sensesp);
AstSenTree* const activeSenp = m_activeSens.find(sensesp);
if (activeSenp) {
const auto it = m_activeMap.find(activeSenp);
UASSERT(it != m_activeMap.end(), "Corrupt active map");
@@ -271,7 +272,7 @@ public:
// Not found, form a new one
if (!activep) {
AstSenTree* newsenp = sensesp->cloneTree(false);
AstSenTree* const newsenp = sensesp->cloneTree(false);
activep = new AstActive(fl, "sequent", newsenp);
activep->sensesStorep(activep->sensesp());
UINFO(8, " New ACTIVE " << activep << endl);
@@ -298,20 +299,20 @@ private:
// NODE STATE
// Input:
// AstVar::user1p // V2LatchGraphVertex* The vertex handling this node
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
LatchDetectGraph m_graph; // Graph used to detect latches in combo always
// VISITORS
virtual void visit(AstVarRef* nodep) {
AstVar* varp = nodep->varp();
const AstVar* const varp = nodep->varp();
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) {
m_graph.addAssignment(nodep);
}
}
virtual void visit(AstNodeIf* nodep) {
if (!nodep->isBoundsCheck()) {
LatchDetectGraphVertex* parentp = m_graph.currentp();
LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
LatchDetectGraphVertex* const parentp = m_graph.currentp();
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
m_graph.addPathVertex(branchp, "IF");
iterateAndNextNull(nodep->ifsp());
m_graph.addPathVertex(branchp, "ELSE");
@@ -340,9 +341,9 @@ public:
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
private:
CheckType m_check; // Combo logic or other
AstNode* m_alwaysp; // Always we're under
AstNode* m_assignp = nullptr; // In assign
const CheckType m_check; // Combo logic or other
const AstNode* const m_alwaysp; // Always we're under
const AstNode* m_assignp = nullptr; // In assign
// VISITORS
virtual void visit(AstAssignDly* nodep) override {
if (m_check != CT_SEQ) {
@@ -355,7 +356,7 @@ private:
} else if (m_check == CT_LATCH) {
// Suppress. Shouldn't matter that the interior of the latch races
} else if (!(VN_IS(nodep->lhsp(), VarRef)
&& VN_CAST(nodep->lhsp(), VarRef)->varp()->isLatched())) {
&& VN_AS(nodep->lhsp(), VarRef)->varp()->isLatched())) {
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
" (non flop or latch) block\n"
<< nodep->warnMore()
@@ -363,8 +364,8 @@ private:
// Conversely, we could also suggest latches use delayed assignments, as
// recommended by Cliff Cummings?
}
AstNode* newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack());
AstNode* const newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack());
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@@ -377,7 +378,7 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
AstVar* varp = nodep->varp();
const AstVar* const varp = nodep->varp();
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
&& !varp->isTemp()) {
// Allow turning off warnings on the always, or the variable also
@@ -437,29 +438,29 @@ private:
virtual void visit(AstInitial* nodep) override {
// Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl);
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
AstActive* const wantactivep = m_namer.getIActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignAlias* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignW* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstCoverToggle* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " COVERTOGGLE " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
@@ -470,7 +471,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
if (!m_scopeFinalp) {
m_scopeFinalp = new AstCFunc(
nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep());
@@ -489,8 +490,7 @@ private:
// METHODS
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
// Move always to appropriate ACTIVE based on its sense list
if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem)
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
if (oldsensesp && oldsensesp->sensesp() && oldsensesp->sensesp()->isNever()) {
// Never executing. Kill it.
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
@@ -540,14 +540,14 @@ private:
// Warn and/or convert any delayed assignments
if (combo && !sequent) {
ActiveLatchCheckVisitor latchvisitor{nodep, kwd};
const ActiveLatchCheckVisitor latchvisitor{nodep, kwd};
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_LATCH};
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_LATCH};
} else {
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_COMBO};
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_COMBO};
}
} else if (!combo && sequent) {
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_SEQ};
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_SEQ};
}
}
virtual void visit(AstAlways* nodep) override {
@@ -578,7 +578,7 @@ private:
}
virtual void visit(AstSenItem* nodep) override {
if (nodep->varrefp()) {
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) {
if (basicp->isEventValue()) {
// Events need to be treated as active high so we only activate on event being
// 1
@@ -620,6 +620,6 @@ public:
void V3Active::activeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveVisitor visitor{nodep}; } // Destruct before checking
{ ActiveVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+8 -16
View File
@@ -42,22 +42,15 @@ private:
// AstNode::user() bool. True if processed
// Each call to V3Const::constify
// AstNode::user4() Used by V3Const::constify, called below
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstTopScope* m_topscopep = nullptr; // Top scope for adding sentrees under
SenTreeFinder m_finder; // Find global sentree's and add them
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstTopScope* nodep) override {
m_topscopep = nodep;
m_finder.init(m_topscopep);
iterateChildren(nodep);
m_topscopep = nullptr;
}
virtual void visit(AstNodeModule* nodep) override {
// Create required actives and add to module
// We can start ordering at a module, or a scope
@@ -68,10 +61,9 @@ private:
UINFO(4, " ACTIVE " << nodep << endl);
// Remove duplicate clocks and such; sensesp() may change!
V3Const::constifyExpensiveEdit(nodep);
AstSenTree* sensesp = nodep->sensesp();
AstSenTree* const sensesp = nodep->sensesp();
UASSERT_OBJ(sensesp, nodep, "nullptr");
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
if (sensesp->sensesp() && sensesp->sensesp()->isNever()) {
// Never executing. Kill it.
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
@@ -80,16 +72,16 @@ private:
}
// Copy combo tree to settlement tree with duplicated statements
if (sensesp->hasCombo()) {
AstSenTree* newsentreep = new AstSenTree(
AstSenTree* const newsentreep = new AstSenTree(
nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
AstActive* newp = new AstActive(nodep->fileline(), "settle", newsentreep);
AstActive* const newp = new AstActive(nodep->fileline(), "settle", newsentreep);
newp->sensesStorep(newsentreep);
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
nodep->addNextHere(newp);
}
// Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(sensesp);
AstSenTree* const wantp = m_finder.getSenTree(sensesp);
UINFO(4, " lookdone\n");
if (wantp != sensesp) {
// Move the active's contents to the other active
@@ -136,6 +128,6 @@ public:
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveTopVisitor visitor{nodep}; } // Destruct before checking
{ ActiveTopVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+43 -42
View File
@@ -20,7 +20,6 @@
#include "V3Global.h"
#include "V3Assert.h"
#include "V3Ast.h"
#include "V3GraphDfa.h"
#include "V3Stats.h"
//######################################################################
@@ -31,11 +30,11 @@ private:
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user() -> bool. True if processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp = nullptr; // Last module
AstBegin* m_beginp = nullptr; // Last begin
const AstBegin* m_beginp = nullptr; // Last begin
unsigned m_monitorNum = 0; // Global $monitor numbering (not per module)
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
@@ -56,14 +55,14 @@ private:
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
// cppcheck-suppress nullPointer
AstNode* timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
AstNode* const timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
if (AstNode* const timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
nodep->fmtp()->addExprsp(timenewp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
nodep->fmtp()->scopeNamep(new AstScopeName{nodep->fileline(), true});
}
}
AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) {
@@ -89,8 +88,8 @@ private:
AstNode* newIfAssertOn(AstNode* nodep, bool force) {
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
FileLine* fl = nodep->fileline();
AstNode* newp = new AstIf(
FileLine* const fl = nodep->fileline();
AstNode* const newp = new AstIf(
fl,
(force ? new AstConst(fl, AstConst::BitTrue())
: // If assertions are off, have constant propagation rip them out later
@@ -106,10 +105,10 @@ private:
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
// Like newFireAssert() but omits the asserts-on check
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message,
nullptr, nullptr);
AstDisplay* const dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR,
message, nullptr, nullptr);
dispp->fmtp()->timeunit(m_modp->timeunit());
AstNode* bodysp = dispp;
AstNode* const bodysp = dispp;
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
bodysp->addNext(new AstStop(nodep->fileline(), true));
return bodysp;
@@ -124,8 +123,8 @@ private:
void newPslAssertion(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
AstNode* propp = nodep->propp()->unlinkFrBackWithNext();
AstSenTree* sentreep = nodep->sentreep();
AstNode* const propp = nodep->propp()->unlinkFrBackWithNext();
AstSenTree* const sentreep = nodep->sentreep();
const string& message = nodep->name();
AstNode* passsp = nodep->passsp();
if (passsp) passsp->unlinkFrBackWithNext();
@@ -141,13 +140,13 @@ private:
AstNode* bodysp = nullptr;
bool selfDestruct = false;
AstIf* ifp = nullptr;
if (AstCover* snodep = VN_CAST(nodep, Cover)) {
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
++m_statCover;
if (!v3Global.opt.coverageUser()) {
selfDestruct = true;
} else {
// V3Coverage assigned us a bucket to increment.
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
AstCoverInc* const covincp = VN_AS(snodep->coverincp(), CoverInc);
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
if (message != "") covincp->declp()->comment(message);
@@ -199,13 +198,13 @@ private:
virtual void visit(AstIf* nodep) override {
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
const AstNodeIf* ifp = nodep;
AstNode* propp = nullptr;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
// nextIf statement. Otherwise it will be null.
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
const AstNodeIf* const nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
iterateAndNextNull(ifp->condp());
// Recurse into the true case.
@@ -217,7 +216,7 @@ private:
}
// Build a bitmask of the true predicates
AstNode* predp = ifp->condp()->cloneTree(false);
AstNode* const predp = ifp->condp()->cloneTree(false);
if (propp) {
propp = new AstConcat(nodep->fileline(), predp, propp);
} else {
@@ -230,7 +229,7 @@ private:
ifp = nextifp;
} while (ifp);
AstNode* newifp = nodep->cloneTree(false);
AstNode* const newifp = nodep->cloneTree(false);
const bool allow_none = nodep->unique0Pragma();
// Empty case means no property
@@ -238,10 +237,11 @@ private:
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
AstNode* ohot = ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* checkifp
AstNode* const ohot
= ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* const checkifp
= new AstIf(nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep, "'unique if' statement violated"), newifp);
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
@@ -258,7 +258,7 @@ private:
if (!nodep->user1SetOnce()) {
bool has_default = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) has_default = true;
}
if (nodep->fullPragma() || nodep->priorityPragma()) {
@@ -279,10 +279,10 @@ private:
} else {
AstNode* propp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
AstNode* onep;
if (AstInsideRange* rcondp = VN_CAST(icondp, InsideRange)) {
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
onep = rcondp->newAndFromInside(nodep->exprp(),
rcondp->lhsp()->cloneTree(true),
rcondp->rhsp()->cloneTree(true));
@@ -306,11 +306,11 @@ private:
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
const bool allow_none = has_default || nodep->unique0Pragma();
AstNode* ohot
AstNode* const ohot
= (allow_none
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* ifp = new AstIf(
AstIf* const ifp = new AstIf(
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep,
"synthesis parallel_case, but multiple matches found"),
@@ -329,22 +329,22 @@ private:
if (nodep->ticksp()) {
UASSERT_OBJ(VN_IS(nodep->ticksp(), Const), nodep,
"Expected constant ticks, checked in V3Width");
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
ticks = VN_AS(nodep->ticksp(), Const)->toUInt();
}
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
AstNode* inp = nodep->exprp()->unlinkFrBack();
AstVar* invarp = nullptr;
AstSenTree* sentreep = nodep->sentreep();
AstSenTree* const sentreep = nodep->sentreep();
sentreep->unlinkFrBack();
AstAlways* alwaysp
AstAlways* const alwaysp
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
m_modp->addStmtp(alwaysp);
for (uint32_t i = 0; i < ticks; ++i) {
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
inp->dtypep());
AstVar* const outvarp = new AstVar(
nodep->fileline(), AstVarType::MODULETEMP,
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep());
m_modp->addStmtp(outvarp);
AstNode* assp = new AstAssignDly(
AstNode* const assp = new AstAssignDly(
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
alwaysp->addStmtp(assp);
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
@@ -378,15 +378,15 @@ private:
new AstConst{fl, monNum}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);"
AstNode* stmtsp = nodep;
AstIf* ifp = new AstIf{
AstNode* const stmtsp = nodep;
AstIf* const ifp = new AstIf{
fl,
new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)},
new AstEq{fl, new AstConst{fl, monNum},
newMonitorNumVarRefp(nodep, VAccess::READ)}},
stmtsp, nullptr};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
m_modp->addStmtp(newp);
} else if (nodep->displayType() == AstDisplayType::DT_STROBE) {
nodep->displayType(AstDisplayType::DT_DISPLAY);
@@ -401,10 +401,11 @@ private:
new AstConst{fl, AstConst::BitTrue{}}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
AstNode* stmtsp = nodep;
AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
AstNode* const stmtsp = nodep;
AstIf* const ifp
= new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitFalse{}}});
m_modp->addStmtp(newp);
@@ -474,6 +475,6 @@ public:
void V3Assert::assertAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertVisitor visitor{nodep}; } // Destruct before checking
{ AssertVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+11 -11
View File
@@ -97,10 +97,10 @@ private:
virtual void visit(AstFell* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* past = new AstPast(fl, exprp, nullptr);
AstNode* const past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
exprp->dtypeSetBit();
@@ -116,10 +116,10 @@ private:
virtual void visit(AstRose* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* past = new AstPast(fl, exprp, nullptr);
AstNode* const past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
exprp->dtypeSetBit();
@@ -130,9 +130,9 @@ private:
virtual void visit(AstStable* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
AstNode* past = new AstPast(fl, exprp, nullptr);
AstNode* const past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstEq(fl, past, exprp->cloneTree(false));
exprp->dtypeSetBit();
@@ -144,15 +144,15 @@ private:
virtual void visit(AstImplication* nodep) override {
if (nodep->sentreep()) return; // Already processed
FileLine* fl = nodep->fileline();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
FileLine* const fl = nodep->fileline();
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp);
AstNode* past = new AstPast(fl, lhsp, nullptr);
AstNode* const past = new AstPast(fl, lhsp, nullptr);
past->dtypeFrom(lhsp);
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
AstNode* const exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@@ -205,6 +205,6 @@ public:
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertPreVisitor visitor{nodep}; } // Destruct before checking
{ AssertPreVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+61 -60
View File
@@ -95,7 +95,7 @@ AstNode* AstNode::abovep() const {
// Avoid supporting at other locations as would require walking
// list which is likely to cause performance issues.
UASSERT_OBJ(!m_nextp || firstAbovep(), this, "abovep() not allowed when in midlist");
const AstNode* firstp = firstAbovep() ? this : m_headtailp;
const AstNode* const firstp = firstAbovep() ? this : m_headtailp;
return firstp->backp();
}
@@ -230,7 +230,8 @@ string AstNode::prettyTypeName() const {
//######################################################################
// Insertion
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next){
inline void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int lineno,
bool next){
#ifdef VL_DEBUG
// Called on all major tree changers.
// Only for use for those really nasty bugs relating to internals
@@ -254,8 +255,8 @@ inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next){
AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
// Add to m_nextp, returns this
UDEBUGONLY(UASSERT_OBJ(newp, nodep, "Null item passed to addNext"););
nodep->debugTreeChange("-addNextThs: ", __LINE__, false);
newp->debugTreeChange("-addNextNew: ", __LINE__, true);
debugTreeChange(nodep, "-addNextThs: ", __LINE__, false);
debugTreeChange(newp, "-addNextNew: ", __LINE__, true);
if (!nodep) { // verilog.y and lots of other places assume this
return newp;
} else {
@@ -276,8 +277,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
oldtailp->m_nextp = newp;
newp->m_backp = oldtailp;
// New tail needs the head
AstNode* newtailp = newp->m_headtailp;
AstNode* headp = oldtailp->m_headtailp;
AstNode* const newtailp = newp->m_headtailp;
AstNode* const headp = oldtailp->m_headtailp;
oldtailp->m_headtailp = nullptr; // May be written again as new head
newp->m_headtailp = nullptr; // May be written again as new tail
newtailp->m_headtailp = headp;
@@ -285,7 +286,7 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
newp->editCountInc();
if (oldtailp->m_iterpp) *(oldtailp->m_iterpp) = newp; // Iterate on new item
}
nodep->debugTreeChange("-addNextOut:", __LINE__, true);
debugTreeChange(nodep, "-addNextOut:", __LINE__, true);
return nodep;
}
@@ -300,15 +301,15 @@ void AstNode::addNextHere(AstNode* newp) {
// New could be head of single node, or list
UASSERT(newp, "Null item passed to addNext");
UASSERT(!newp->backp(), "New node (back) already assigned?");
this->debugTreeChange("-addHereThs: ", __LINE__, false);
newp->debugTreeChange("-addHereNew: ", __LINE__, true);
debugTreeChange(this, "-addHereThs: ", __LINE__, false);
debugTreeChange(newp, "-addHereNew: ", __LINE__, true);
newp->editCountInc();
AstNode* addlastp = newp->m_headtailp; // Last node in list to be added
AstNode* const addlastp = newp->m_headtailp; // Last node in list to be added
UASSERT(!addlastp->m_nextp, "Headtailp tail isn't at the tail");
// Forward links
AstNode* oldnextp = this->m_nextp;
AstNode* const oldnextp = this->m_nextp;
this->m_nextp = newp;
addlastp->m_nextp = oldnextp; // Perhaps null if 'this' is not list
@@ -317,7 +318,7 @@ void AstNode::addNextHere(AstNode* newp) {
newp->m_backp = this;
// Head/tail
AstNode* oldheadtailp = this->m_headtailp;
AstNode* const oldheadtailp = this->m_headtailp;
// (!oldheadtailp) // this was&is middle of list
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not
@@ -339,7 +340,7 @@ void AstNode::addNextHere(AstNode* newp) {
}
if (this->m_iterpp) *(this->m_iterpp) = newp; // Iterate on new item
this->debugTreeChange("-addHereOut: ", __LINE__, true);
debugTreeChange(this, "-addHereOut: ", __LINE__, true);
}
void AstNode::setOp1p(AstNode* newp) {
@@ -347,12 +348,12 @@ void AstNode::setOp1p(AstNode* newp) {
UDEBUGONLY(UASSERT_OBJ(!m_op1p, this, "Adding to non-empty, non-list op1"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_nextp, newp, "Adding list to non-list op1"););
this->debugTreeChange("-setOp1pThs: ", __LINE__, false);
newp->debugTreeChange("-setOp1pNew: ", __LINE__, true);
debugTreeChange(this, "-setOp1pThs: ", __LINE__, false);
debugTreeChange(newp, "-setOp1pNew: ", __LINE__, true);
m_op1p = newp;
newp->editCountInc();
newp->m_backp = this;
this->debugTreeChange("-setOp1pOut: ", __LINE__, false);
debugTreeChange(this, "-setOp1pOut: ", __LINE__, false);
}
void AstNode::setOp2p(AstNode* newp) {
@@ -360,12 +361,12 @@ void AstNode::setOp2p(AstNode* newp) {
UDEBUGONLY(UASSERT_OBJ(!m_op2p, this, "Adding to non-empty, non-list op2"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_nextp, newp, "Adding list to non-list op2"););
this->debugTreeChange("-setOp2pThs: ", __LINE__, false);
newp->debugTreeChange("-setOp2pNew: ", __LINE__, true);
debugTreeChange(this, "-setOp2pThs: ", __LINE__, false);
debugTreeChange(newp, "-setOp2pNew: ", __LINE__, true);
m_op2p = newp;
newp->editCountInc();
newp->m_backp = this;
this->debugTreeChange("-setOp2pOut: ", __LINE__, false);
debugTreeChange(this, "-setOp2pOut: ", __LINE__, false);
}
void AstNode::setOp3p(AstNode* newp) {
@@ -373,12 +374,12 @@ void AstNode::setOp3p(AstNode* newp) {
UDEBUGONLY(UASSERT_OBJ(!m_op3p, this, "Adding to non-empty, non-list op3"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_nextp, newp, "Adding list to non-list op3"););
this->debugTreeChange("-setOp3pThs: ", __LINE__, false);
newp->debugTreeChange("-setOp3pNew: ", __LINE__, true);
debugTreeChange(this, "-setOp3pThs: ", __LINE__, false);
debugTreeChange(newp, "-setOp3pNew: ", __LINE__, true);
m_op3p = newp;
newp->editCountInc();
newp->m_backp = this;
this->debugTreeChange("-setOp3pOut: ", __LINE__, false);
debugTreeChange(this, "-setOp3pOut: ", __LINE__, false);
}
void AstNode::setOp4p(AstNode* newp) {
@@ -386,12 +387,12 @@ void AstNode::setOp4p(AstNode* newp) {
UDEBUGONLY(UASSERT_OBJ(!m_op4p, this, "Adding to non-empty, non-list op4"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
UDEBUGONLY(UASSERT_OBJ(!newp->m_nextp, newp, "Adding list to non-list op4"););
this->debugTreeChange("-setOp4pThs: ", __LINE__, false);
newp->debugTreeChange("-setOp4pNew: ", __LINE__, true);
debugTreeChange(this, "-setOp4pThs: ", __LINE__, false);
debugTreeChange(newp, "-setOp4pNew: ", __LINE__, true);
m_op4p = newp;
newp->editCountInc();
newp->m_backp = this;
this->debugTreeChange("-setOp4pOut: ", __LINE__, false);
debugTreeChange(this, "-setOp4pOut: ", __LINE__, false);
}
void AstNode::addOp1p(AstNode* newp) {
@@ -453,11 +454,11 @@ void AstNRelinker::dump(std::ostream& str) const {
}
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
this->debugTreeChange("-unlinkWNextThs: ", __LINE__, true);
AstNode* oldp = this;
debugTreeChange(this, "-unlinkWNextThs: ", __LINE__, true);
AstNode* const oldp = this;
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
oldp->editCountInc();
AstNode* backp = oldp->m_backp;
AstNode* const backp = oldp->m_backp;
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
@@ -486,7 +487,7 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
AstNode* oldtailp = oldp;
while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp;
// Create new head/tail of old list
AstNode* oldheadp = oldtailp->m_headtailp;
AstNode* const oldheadp = oldtailp->m_headtailp;
oldheadp->m_headtailp = oldp->m_backp;
oldheadp->m_headtailp->m_headtailp = oldheadp;
// Create new head/tail of extracted list
@@ -508,16 +509,16 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
// Iterator fixup
if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr;
oldp->m_iterpp = nullptr;
oldp->debugTreeChange("-unlinkWNextOut: ", __LINE__, true);
debugTreeChange(oldp, "-unlinkWNextOut: ", __LINE__, true);
return oldp;
}
AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
this->debugTreeChange("-unlinkFrBkThs: ", __LINE__, true);
AstNode* oldp = this;
debugTreeChange(this, "-unlinkFrBkThs: ", __LINE__, true);
AstNode* const oldp = this;
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
oldp->editCountInc();
AstNode* backp = oldp->m_backp;
AstNode* const backp = oldp->m_backp;
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
@@ -559,7 +560,7 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
this->v3fatalSrc("Unlink of node with back not pointing to it.");
}
if (oldp->m_nextp) {
AstNode* newheadp = oldp->m_nextp;
AstNode* const newheadp = oldp->m_nextp;
newheadp->m_backp = backp;
newheadp->m_headtailp = oldp->m_headtailp;
newheadp->m_headtailp->m_headtailp = newheadp;
@@ -572,7 +573,7 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
oldp->m_backp = nullptr;
oldp->m_headtailp = this;
oldp->m_iterpp = nullptr;
oldp->debugTreeChange("-unlinkFrBkOut: ", __LINE__, true);
debugTreeChange(oldp, "-unlinkFrBkOut: ", __LINE__, true);
return oldp;
}
@@ -581,7 +582,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
UINFO(0, " EDIT: relink: ");
dumpPtrs();
}
AstNode* newp = this;
AstNode* const newp = this;
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
UASSERT(!newp->backp(), "New node already linked?");
newp->editCountInc();
@@ -591,9 +592,9 @@ void AstNode::relink(AstNRelinker* linkerp) {
cout << endl;
}
AstNode* backp = linkerp->m_backp;
this->debugTreeChange("-relinkNew: ", __LINE__, true);
backp->debugTreeChange("-relinkTre: ", __LINE__, true);
AstNode* const backp = linkerp->m_backp;
debugTreeChange(this, "-relinkNew: ", __LINE__, true);
debugTreeChange(backp, "-relinkTre: ", __LINE__, true);
switch (linkerp->m_chg) {
case AstNRelinker::RELINK_NEXT: backp->addNextHere(newp); break;
@@ -618,7 +619,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
}
// Empty the linker so not used twice accidentally
linkerp->m_backp = nullptr;
this->debugTreeChange("-relinkOut: ", __LINE__, true);
debugTreeChange(this, "-relinkOut: ", __LINE__, true);
}
void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set to newp
@@ -630,10 +631,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
// Likewise there may be a old list.
// Insert the whole old list following the new node's list.
// Thus a unlink without next, followed by relink, gives the same list.
AstNode* newlistlastp = newp->m_headtailp;
AstNode* const newlistlastp = newp->m_headtailp;
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp,
"Headtailp tail isn't at the tail");
AstNode* oldlistlastp = pointpr->m_headtailp;
AstNode* const oldlistlastp = pointpr->m_headtailp;
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp,
"Old headtailp tail isn't at the tail");
// Next links
@@ -670,7 +671,7 @@ void AstNode::swapWith(AstNode* bp) {
AstNode* AstNode::cloneTreeIter() {
// private: Clone single node and children
AstNode* newp = this->clone();
AstNode* const newp = this->clone();
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList());
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
@@ -687,7 +688,7 @@ AstNode* AstNode::cloneTreeIterList() {
AstNode* newtailp = nullptr;
// Audited to make sure this is never nullptr
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
AstNode* newp = oldp->cloneTreeIter();
AstNode* const newp = oldp->cloneTreeIter();
newp->m_headtailp = nullptr;
newp->m_backp = newtailp;
if (newtailp) newtailp->m_nextp = newp;
@@ -700,7 +701,7 @@ AstNode* AstNode::cloneTreeIterList() {
}
AstNode* AstNode::cloneTree(bool cloneNextLink) {
this->debugTreeChange("-cloneThs: ", __LINE__, cloneNextLink);
debugTreeChange(this, "-cloneThs: ", __LINE__, cloneNextLink);
cloneClearTree();
AstNode* newp;
if (cloneNextLink && this->m_nextp) {
@@ -712,7 +713,7 @@ AstNode* AstNode::cloneTree(bool cloneNextLink) {
}
newp->m_backp = nullptr;
newp->cloneRelinkTree();
newp->debugTreeChange("-cloneOut: ", __LINE__, true);
debugTreeChange(newp, "-cloneOut: ", __LINE__, true);
return newp;
}
@@ -764,7 +765,7 @@ void AstNode::deleteTree() {
// deleteTree always deletes the next link, because you must have called
// unlinkFromBack or unlinkFromBackWithNext as appropriate before calling this.
UASSERT(!m_backp, "Delete called on node with backlink still set");
this->debugTreeChange("-delTree: ", __LINE__, true);
debugTreeChange(this, "-delTree: ", __LINE__, true);
this->editCountInc();
// MUST be depth first!
deleteTreeIter();
@@ -776,14 +777,14 @@ void AstNode::deleteTree() {
#ifdef VL_LEAK_CHECKS
void* AstNode::operator new(size_t size) {
// Optimization note: Aligning to cache line is a loss, due to lost packing
AstNode* objp = static_cast<AstNode*>(::operator new(size));
const AstNode* const objp = static_cast<AstNode*>(::operator new(size));
V3Broken::addNewed(objp);
return objp;
}
void AstNode::operator delete(void* objp, size_t size) {
if (!objp) return;
AstNode* nodep = static_cast<AstNode*>(objp);
const AstNode* const nodep = static_cast<AstNode*>(objp);
V3Broken::deleted(nodep);
::operator delete(objp);
}
@@ -876,7 +877,7 @@ void AstNode::iterateAndNextConst(AstNVisitor& v) {
// Keep following the current list even if edits change it
AstNode* nodep = this;
do {
AstNode* nnextp = nodep->m_nextp;
AstNode* const nnextp = nodep->m_nextp;
ASTNODE_PREFETCH(nnextp);
nodep->accept(v);
nodep = nnextp;
@@ -897,7 +898,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
} else if (!nodep->backp()) {
// Calling on standalone tree; insert a shim node so we can keep
// track, then delete it on completion
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
AstBegin* const tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
{
VL_DO_DANGLING(tempp->stmtsp()->accept(v),
nodep); // nodep to null as may be replaced
@@ -993,8 +994,8 @@ void AstNode::checkTreeIter(AstNode* backp) {
void AstNode::checkTreeIterList(AstNode* backp) {
// private: Check a (possible) list of nodes, this is always the head of the list
// Audited to make sure this is never nullptr
AstNode* headp = this;
AstNode* tailp = this;
AstNode* const headp = this;
const AstNode* tailp = this;
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
nodep->checkTreeIter(backp);
UASSERT_OBJ(headp == this || !nextp(), this,
@@ -1142,7 +1143,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
checkTree();
// Broken isn't part of check tree because it can munge iterp's
// set by other steps if it is called in the middle of other operations
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
if (AstNetlist* const netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
}
}
@@ -1163,7 +1164,7 @@ string AstNode::locationStr() const {
return ""; // LCOV_EXCL_LINE
}
const AstScope* scopep;
if ((scopep = VN_CAST_CONST(backp, Scope))) {
if ((scopep = VN_CAST(backp, Scope))) {
// The design is flattened and there are no useful scopes
// This is probably because of inlining
if (scopep->isTop()) break;
@@ -1177,10 +1178,10 @@ string AstNode::locationStr() const {
while (backp) {
const AstModule* modp;
const AstNodeVarRef* nvrp;
if ((modp = VN_CAST_CONST(backp, Module)) && !modp->hierName().empty()) {
if ((modp = VN_CAST(backp, Module)) && !modp->hierName().empty()) {
str += modp->hierName();
return str;
} else if ((nvrp = VN_CAST_CONST(backp, NodeVarRef))) {
} else if ((nvrp = VN_CAST(backp, NodeVarRef))) {
const string prettyName = nvrp->prettyName();
// VarRefs have not been flattened yet and do not contain location information
if (prettyName != nvrp->name()) {
@@ -1275,9 +1276,9 @@ AstNodeDType* AstNode::findVoidDType() const {
}
//######################################################################
// AstNVisitor
// AstNDeleter
void AstNVisitor::doDeletes() {
for (AstNode* nodep : m_deleteps) nodep->deleteTree();
void AstNDeleter::doDeletes() {
for (AstNode* const nodep : m_deleteps) nodep->deleteTree();
m_deleteps.clear();
}
+122 -65
View File
@@ -56,19 +56,28 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
// For broken() function, return error string if a base of this class has a match
#define BROKEN_BASE_RTN(test) \
do { \
const char* reasonp = (test); \
const char* const reasonp = (test); \
if (VL_UNCOVERABLE(reasonp)) return reasonp; \
} while (false)
// (V)erilator (N)ode is: True if AstNode is of a a given AstType
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename>(nodep))
// (V)erilator (N)ode is: Returns true if and only if AstNode is of the given AstNode subtype,
// and not nullptr.
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode cast: Cast to given type if can; effectively
// dynamic_cast<nodetypename>(nodep)
#define VN_CAST(nodep, nodetypename) (AstNode::privateCast<Ast##nodetypename>(nodep))
#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateConstCast<Ast##nodetypename>(nodep))
// (V)erilator (N)ode cast: Similar to dynamic_cast, but more efficient, use this instead.
// Cast to given type if node is of such type, otherwise returns nullptr. If 'nodep' is nullptr,
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*',
// a 'const Ast<nodetypename>*' is returned.
#define VN_CAST(nodep, nodetypename) \
(AstNode::privateCast<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode deleted: Reference to deleted child (for assertions only)
// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Use this to
// downcast instead of VN_CAST when you know the true type of the node. If 'nodep' is nullptr,
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*', a 'const
// Ast<nodetypename>*' is returned.
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
#define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
//######################################################################
@@ -495,7 +504,8 @@ public:
}
bool isUnsigned() const {
return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64;
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64 || m_e == BIT || m_e == LOGIC
|| m_e == TIME;
}
bool isFourstate() const {
return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
@@ -508,9 +518,6 @@ public:
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
}
bool isSloppy() const { // Don't be as anal about width warnings
return !(m_e == LOGIC || m_e == BIT);
}
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
return (m_e == LOGIC || m_e == BIT);
}
@@ -1001,7 +1008,7 @@ public:
// MEMBERS
void init(int hi, int lo, bool littleEndian) {
if (lo > hi) {
int t = hi;
const int t = hi;
hi = lo;
lo = t;
}
@@ -1020,9 +1027,6 @@ public:
int hiMaxSelect() const {
return (lo() < 0 ? hi() - lo() : hi());
} // Maximum value a [] select may index
bool representableByWidth() const { // Could be represented by just width=1, or [width-1:0]
return (!m_ranged || (m_right == 0 && m_left >= 1));
}
void dump(std::ostream& str) const {
if (ranged()) {
str << "[" << left() << ":" << right() << "]";
@@ -1073,11 +1077,11 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
class VBasicTypeKey final {
public:
int m_width; // From AstNodeDType: Bit width of operation
int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
VSigning m_numeric; // From AstNodeDType: Node is signed
AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
const int m_width; // From AstNodeDType: Bit width of operation
const int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
const VSigning m_numeric; // From AstNodeDType: Node is signed
const AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
bool operator==(const VBasicTypeKey& rhs) const {
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
@@ -1242,31 +1246,39 @@ public:
// clang-format on
//######################################################################
// AstNVisitor -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
// Node deleter, deletes all enqueued AstNode* on destruction, or when
// explicitly told to do so. This is useful when the deletion of removed
// nodes needs to be deferred to a later time, because pointers to the
// removed nodes might still exist.
class AstNVisitor VL_NOT_FINAL {
private:
class AstNDeleter VL_NOT_FINAL {
// MEMBERS
std::vector<AstNode*> m_deleteps; // Nodes to delete when doDeletes() called
protected:
friend class AstNode;
std::vector<AstNode*> m_deleteps; // Nodes to delete
public:
// METHODS
/// At the end of the visitor (or doDeletes()), delete this pushed node
/// along with all children and next(s). This is often better to use
/// than an immediate deleteTree, as any pointers into this node will
/// persist for the lifetime of the visitor
// Enqueue node for deletion on next 'doDelete' (or destruction)
void pushDeletep(AstNode* nodep) {
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
m_deleteps.push_back(nodep);
}
/// Call deleteTree on all previously pushDeletep()'ed nodes
// Delete all previously pushed nodes (by callint deleteTree)
void doDeletes();
// Do the deletions on destruction
virtual ~AstNDeleter() { doDeletes(); }
};
//######################################################################
// AstNVisitor -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
class AstNVisitor VL_NOT_FINAL : public AstNDeleter {
friend class AstNode;
public:
virtual ~AstNVisitor() { doDeletes(); }
/// Call visit()s on nodep
void iterate(AstNode* nodep);
/// Call visit()s on nodep
@@ -1437,7 +1449,7 @@ private:
public:
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
// cppcheck-suppress functionConst
void debugTreeChange(const char* prefix, int lineno, bool next);
static void debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next);
protected:
// CONSTRUCTORS
@@ -1838,16 +1850,62 @@ protected:
private:
void iterateListBackwards(AstNVisitor& v);
// CONVERSION
// For internal use only.
template <typename T> inline static bool privateTypeTest(const AstNode* nodep);
template <typename TargetType, typename DeclType> constexpr static bool uselessCast() {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
return std::is_base_of<TargetType, NonCV>::value;
}
template <typename TargetType, typename DeclType> constexpr static bool impossibleCast() {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
return !std::is_base_of<NonCV, TargetType>::value;
}
public:
// These for use by VN_IS macro only
template <class T> static bool privateIs(const AstNode* nodep);
// For use via the VN_IS macro only
template <typename T, typename E> inline static bool privateIs(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_IS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_IS, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep);
}
// These for use by VN_CAST macro only
template <class T> static T* privateCast(AstNode* nodep);
// For use via the VN_CAST macro only
template <typename T, typename E> inline static T* privateCast(AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_CAST, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
}
template <typename T, typename E> inline static const T* privateCast(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_CAST, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
}
// These for use by VN_CAST_CONST macro only
template <class T> static const T* privateConstCast(const AstNode* nodep);
// For use via the VN_AS macro only
template <typename T, typename E> inline static T* privateAs(AstNode* nodep) {
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> inline static const T* privateAs(const AstNode* nodep) {
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<const T*>(nodep);
}
};
// Specialisations of privateIs/privateCast
@@ -1896,7 +1954,7 @@ public:
virtual bool cleanOut() const = 0; // True if output has extra upper bits zero
// Someday we will generically support data types on every math node
// Until then isOpaque indicates we shouldn't constant optimize this node type
bool isOpaque() { return VN_IS(this, CvtPackString); }
bool isOpaque() const { return VN_IS(this, CvtPackString); }
};
class AstNodeTermop VL_NOT_FINAL : public AstNodeMath {
@@ -2085,9 +2143,7 @@ public:
AstNode* expr1p() const { return op2p(); } // op2 = If true...
AstNode* expr2p() const { return op3p(); } // op3 = If false...
virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
virtual string emitC() override {
return "VL_COND_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)";
}
virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
virtual bool cleanOut() const override { return false; } // clean if e1 & e2 clean
virtual bool cleanLhs() const override { return true; }
virtual bool cleanRhs() const override { return false; }
@@ -2140,7 +2196,7 @@ public:
AstNode* fromp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
AstNode* thsp() const { return op3p(); }
AstAttrOf* attrp() const { return VN_CAST(op4p(), AttrOf); }
AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); }
void fromp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
@@ -2278,7 +2334,7 @@ public:
virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
AstNode* exprp() const { return op1p(); } // op1 = case condition <expression>
AstCaseItem* itemsp() const {
return VN_CAST(op2p(), CaseItem);
return VN_AS(op2p(), CaseItem);
} // op2 = list of case expressions
AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's
void addItemsp(AstNode* nodep) { addOp2p(nodep); }
@@ -2492,10 +2548,10 @@ public:
// For basicp() we reuse the size to indicate a "fake" basic type of same size
virtual AstBasicDType* basicp() const override {
return (isFourstate()
? VN_CAST(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType)
: VN_CAST(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType));
? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType)
: VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType));
}
virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
@@ -2511,7 +2567,7 @@ public:
virtual string name() const override { return m_name; }
virtual void name(const string& flag) override { m_name = flag; }
AstMemberDType* membersp() const {
return VN_CAST(op1p(), MemberDType);
return VN_AS(op1p(), MemberDType);
} // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; }
@@ -2554,18 +2610,18 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
virtual bool same(const AstNode* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
&& rangenp()->sameTree(asamep->rangenp()));
} // HashedDT doesn't recurse, so need to check children
virtual bool similarDType(AstNodeDType* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return (asamep && type() == samep->type() && hi() == asamep->hi()
&& rangenp()->sameTree(asamep->rangenp())
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
virtual AstNodeDType* subDTypep() const override {
return m_refDTypep ? m_refDTypep : childDTypep();
@@ -2573,7 +2629,7 @@ public:
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Array(s) of variable
AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Array(s) of variable
void rangep(AstRange* nodep);
// METHODS
virtual AstBasicDType* basicp() const override {
@@ -2647,7 +2703,7 @@ public:
virtual const char* broken() const override;
virtual int instrCount() const override { return INSTR_COUNT_CALL; }
virtual bool same(const AstNode* samep) const override {
const AstNodeCCall* asamep = static_cast<const AstNodeCCall*>(samep);
const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
}
AstNode* exprsp() const { return op2p(); } // op2 = expressions to print
@@ -2679,6 +2735,7 @@ private:
bool m_dpiContext : 1; // DPI import context
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
bool m_dpiTask : 1; // DPI import task (vs. void function)
bool m_dpiTraceInit : 1; // DPI trace_init
bool m_isConstructor : 1; // Class constructor
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
@@ -2702,6 +2759,7 @@ protected:
, m_dpiContext{false}
, m_dpiOpenChild{false}
, m_dpiTask{false}
, m_dpiTraceInit{false}
, m_isConstructor{false}
, m_isHideLocal{false}
, m_isHideProtected{false}
@@ -2736,7 +2794,7 @@ public:
AstNode* stmtsp() const { return op3p(); } // op3 = List of statements
void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
// op4 = scope name
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
// MORE ACCESSORS
void dpiOpenParentInc() { ++m_dpiOpenParent; }
void dpiOpenParentClear() { m_dpiOpenParent = 0; }
@@ -2764,6 +2822,8 @@ public:
bool dpiOpenChild() const { return m_dpiOpenChild; }
void dpiTask(bool flag) { m_dpiTask = flag; }
bool dpiTask() const { return m_dpiTask; }
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
bool dpiTraceInit() const { return m_dpiTraceInit; }
void isConstructor(bool flag) { m_isConstructor = flag; }
bool isConstructor() const { return m_isConstructor; }
bool isHideLocal() const { return m_isHideLocal; }
@@ -2816,7 +2876,6 @@ public:
return m_taskp && m_taskp->isGateOptimizable();
}
string dotted() const { return m_dotted; } // * = Scope name or ""
string prettyDotted() const { return prettyName(dotted()); }
string inlinedDots() const { return m_inlinedDots; }
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable
@@ -2834,7 +2893,7 @@ public:
AstNode* pinsp() const { return op3p(); }
void addPinsp(AstNode* nodep) { addOp3p(nodep); }
// op4 = scope tracking
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
};
@@ -2844,7 +2903,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
// excluding $unit package stuff
private:
string m_name; // Name of the module
string m_origName; // Name of the module, ignoring name() changes, for dot lookup
const string m_origName; // Name of the module, ignoring name() changes, for dot lookup
string m_hierName; // Hierarchical name for errors, etc.
bool m_modPublic : 1; // Module has public references
bool m_modTrace : 1; // Tracing this module
@@ -2855,7 +2914,6 @@ private:
bool m_recursive : 1; // Recursive module
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
int m_level = 0; // 1=top module, 2=cell off top module, ...
int m_typeNum = 0; // Incrementing implicit type number
VLifetime m_lifetime; // Lifetime
VTimescale m_timeunit; // Global time unit
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
@@ -2880,7 +2938,7 @@ public:
virtual string name() const override { return m_name; }
virtual bool timescaleMatters() const = 0;
AstNode* stmtsp() const { return op2p(); } // op2 = List of statements
AstActive* activesp() const { return VN_CAST(op3p(), Active); } // op3 = List of i/sblocks
AstActive* activesp() const { return VN_AS(op3p(), Active); } // op3 = List of i/sblocks
// METHODS
void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
void addStmtp(AstNode* nodep) { addNOp2p(nodep); }
@@ -2895,7 +2953,6 @@ public:
void level(int level) { m_level = level; }
int level() const { return m_level; }
bool isTop() const { return level() == 1; }
int typeNumGetInc() { return ++m_typeNum; }
void modPublic(bool flag) { m_modPublic = flag; }
bool modPublic() const { return m_modPublic; }
void modTrace(bool flag) { m_modTrace = flag; }
+6 -6
View File
@@ -34,7 +34,7 @@ inline int AstNode::widthInstrs() const {
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
}
inline bool AstNode::isDouble() const {
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble();
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
}
inline bool AstNode::isString() const {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
@@ -42,19 +42,19 @@ inline bool AstNode::isString() const {
inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
inline bool AstNode::isZero() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero());
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
}
inline bool AstNode::isNeqZero() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero());
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNeqZero());
}
inline bool AstNode::isOne() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne());
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne());
}
inline bool AstNode::isAllOnes() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes());
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnes());
}
inline bool AstNode::isAllOnesV() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV());
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnesV());
}
inline bool AstNode::sameTree(const AstNode* node2p) const {
return sameTreeIter(this, node2p, true, false);
+82 -104
View File
@@ -44,7 +44,7 @@ const char* AstIfaceRefDType::broken() const {
}
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
return ((m_cellp && m_cellp->modp()) ? VN_CAST(m_cellp->modp(), Iface) : m_ifacep);
return ((m_cellp && m_cellp->modp()) ? VN_AS(m_cellp->modp(), Iface) : m_ifacep);
}
const char* AstNodeVarRef::broken() const {
@@ -73,13 +73,13 @@ const char* AstAddrOfCFunc::broken() const {
}
int AstNodeSel::bitConst() const {
AstConst* constp = VN_CAST(bitp(), Const);
const AstConst* const constp = VN_AS(bitp(), Const);
return (constp ? constp->toSInt() : 0);
}
void AstNodeUOrStructDType::repairMemberCache() {
clearCache();
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
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 {
@@ -90,7 +90,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
const char* AstNodeUOrStructDType::broken() const {
std::unordered_set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
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) {
@@ -197,30 +197,6 @@ AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
}
AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstGteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstGteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstGteS(fl, lhsp, rhsp);
} else {
return new AstGte(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstLteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstLteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstLteS(fl, lhsp, rhsp);
} else {
return new AstLte(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
@@ -238,11 +214,11 @@ AstExecGraph::AstExecGraph(FileLine* fileline)
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
AstNode* ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
AstNode* bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
AstNode* const ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
AstNode* const bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
AstNode* newp = new AstAnd(fileline(), ap, bp);
AstNode* const newp = new AstAnd(fileline(), ap, bp);
return newp;
}
@@ -250,11 +226,11 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
bool success = false;
if (literal[0] == '"') {
// This is a string
string v = literal.substr(1, literal.find('"', 1) - 1);
const string v = literal.substr(1, literal.find('"', 1) - 1);
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
} else if (literal.find_first_of(".eEpP") != string::npos) {
// This may be a real
double v = VString::parseDouble(literal, &success);
const double v = VString::parseDouble(literal, &success);
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
}
if (!success) {
@@ -266,7 +242,7 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
// the string after the number, this is invalid C and we try
// the Verilog literal parser.
char* endp;
int v = strtol(literal.c_str(), &endp, 0);
const int v = strtol(literal.c_str(), &endp, 0);
if ((v != 0) && (endp[0] == 0)) { // C literal
return new AstConst(fl, AstConst::Signed32(), v);
} else { // Try a Verilog literal (fatals if not)
@@ -360,7 +336,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string AstVar::vlEnumType() const {
string arg;
AstBasicDType* bdtypep = basicp();
const AstBasicDType* const bdtypep = basicp();
const bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING;
if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
return "VLVT_PTR";
@@ -401,7 +377,7 @@ string AstVar::vlEnumDir() const {
out += "|VLVF_PUB_RD";
}
//
if (AstBasicDType* bdtypep = basicp()) {
if (const AstBasicDType* const bdtypep = basicp()) {
if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY";
}
return out;
@@ -413,7 +389,7 @@ string AstVar::vlPropDecl(const string& propName) const {
std::vector<int> ulims; // Unpacked dimension limits
for (const AstNodeDType* dtp = dtypep(); dtp;) {
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
ulims.push_back(adtypep->declRange().left());
ulims.push_back(adtypep->declRange().right());
dtp = adtypep->subDTypep();
@@ -499,7 +475,7 @@ public:
string convert(const AstVar* varp) const {
if (varp->isDpiOpenArray()) {
return openArray(varp);
} else if (const AstBasicDType* basicp = varp->basicp()) {
} else if (const AstBasicDType* const basicp = varp->basicp()) {
if (basicp->isDpiBitVec() || basicp->isDpiLogicVec()) {
return bitLogicVector(varp, basicp->isDpiBitVec());
} else {
@@ -539,9 +515,9 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
string AstVar::dpiTmpVarType(const string& varName) const {
class converter final : public dpiTypesToStringConverter {
string m_name;
const string m_name;
string arraySuffix(const AstVar* varp, size_t n) const {
if (AstUnpackArrayDType* unpackp
if (AstUnpackArrayDType* const unpackp
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
// Convert multi dimensional unpacked array to 1D array
if (n == 0) n = 1;
@@ -607,15 +583,15 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
// See if this is a SC assignment; if so return that type
// Historically sc variables are identified by a variable
// attribute. TODO it would better be a data type attribute.
if (AstVar* anodep = VN_CAST(nodep, Var)) {
if (AstVar* const anodep = VN_CAST(nodep, Var)) {
if (anodep->isSc()) {
return anodep;
} else {
return nullptr;
}
} else if (VN_IS(nodep, VarRef)) {
if (VN_CAST(nodep, VarRef)->varp()->isSc()) {
return VN_CAST(nodep, VarRef)->varp();
if (VN_AS(nodep, VarRef)->varp()->isSc()) {
return VN_AS(nodep, VarRef)->varp();
} else {
return nullptr;
}
@@ -666,29 +642,29 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
// Legacy compound argument currently just passed through and unused
CTypeRecursed info;
const AstNodeDType* dtypep = this->skipRefp();
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const AstNodeDType* const dtypep = this->skipRefp();
if (const auto* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, QueueDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (adtypep->isCompound()) compound = true;
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
info.m_type = "VlUnpacked<" + sub.m_type;
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
info.m_type += ">";
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
} 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
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
@@ -728,7 +704,7 @@ uint32_t AstNodeDType::arrayUnpackedElements() {
uint32_t entries = 1;
for (AstNodeDType* dtypep = this; dtypep;) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep();
} else {
@@ -745,7 +721,7 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
uint32_t unpacked = 0;
for (AstNodeDType* dtypep = this; dtypep;) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if (VN_IS(adtypep, PackArrayDType)) {
++packed;
} else {
@@ -753,11 +729,11 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
}
dtypep = adtypep->subDTypep();
continue;
} else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) {
} else if (const AstQueueDType* const qdtypep = VN_CAST(dtypep, QueueDType)) {
unpacked++;
dtypep = qdtypep->subDTypep();
continue;
} else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
} else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
} else if (VN_IS(dtypep, StructDType)) {
packed++;
@@ -769,7 +745,7 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
int AstNodeDType::widthPow2() const {
// I.e. width 30 returns 32, width 32 returns 32.
uint32_t width = this->width();
const uint32_t width = this->width();
for (int p2 = 30; p2 >= 0; p2--) {
if (width > (1UL << p2)) return (1UL << (p2 + 1));
}
@@ -777,11 +753,11 @@ int AstNodeDType::widthPow2() const {
}
bool AstNodeDType::isLiteralType() const {
if (auto* const dtypep = VN_CAST_CONST(skipRefp(), BasicDType)) {
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
return dtypep->keyword().isLiteralType();
} else if (auto* const dtypep = VN_CAST_CONST(skipRefp(), UnpackArrayDType)) {
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
return dtypep->basicp()->isLiteralType();
} else if (auto* const dtypep = VN_CAST_CONST(skipRefp(), StructDType)) {
} else if (const auto* const dtypep = VN_CAST(skipRefp(), StructDType)) {
// Currently all structs are packed, later this can be expanded to
// 'forall members _.isLiteralType()'
return dtypep->packed();
@@ -795,25 +771,25 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
// Else AstArraySel etc; search for the base
while (nodep) {
if (VN_IS(nodep, ArraySel)) {
nodep = VN_CAST(nodep, ArraySel)->fromp();
nodep = VN_AS(nodep, ArraySel)->fromp();
continue;
} else if (VN_IS(nodep, Sel)) {
nodep = VN_CAST(nodep, Sel)->fromp();
nodep = VN_AS(nodep, Sel)->fromp();
continue;
} else if (overMembers && VN_IS(nodep, MemberSel)) {
nodep = VN_CAST(nodep, MemberSel)->fromp();
nodep = VN_AS(nodep, MemberSel)->fromp();
continue;
}
// AstNodeSelPre stashes the associated variable under an ATTROF
// of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
else if (VN_IS(nodep, AttrOf)) {
nodep = VN_CAST(nodep, AttrOf)->fromp();
nodep = VN_AS(nodep, AttrOf)->fromp();
continue;
} else if (VN_IS(nodep, NodePreSel)) {
if (VN_CAST(nodep, NodePreSel)->attrp()) {
nodep = VN_CAST(nodep, NodePreSel)->attrp();
if (VN_AS(nodep, NodePreSel)->attrp()) {
nodep = VN_AS(nodep, NodePreSel)->attrp();
} else {
nodep = VN_CAST(nodep, NodePreSel)->fromp();
nodep = VN_AS(nodep, NodePreSel)->fromp();
}
continue;
} else {
@@ -854,7 +830,7 @@ string AstScope::nameDotless() const {
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
out += textp->text();
}
// TOP will be replaced by top->name()
@@ -865,7 +841,7 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
}
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
out += textp->text();
}
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
@@ -879,28 +855,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
bool AstSenTree::hasClocked() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isClocked()) return true;
}
return false;
}
bool AstSenTree::hasSettle() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isSettle()) return true;
}
return false;
}
bool AstSenTree::hasInitial() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isInitial()) return true;
}
return false;
}
bool AstSenTree::hasCombo() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isCombo()) return true;
}
return false;
@@ -918,7 +894,7 @@ void AstTypeTable::clearCache() {
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
}
}
@@ -926,7 +902,7 @@ void AstTypeTable::repairCache() {
// After we mass-change widthMin in V3WidthCommit, we need to correct the table.
clearCache();
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) {
(void)findInsertSameDType(bdtypep);
}
}
@@ -934,7 +910,7 @@ void AstTypeTable::repairCache() {
AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
if (VL_UNLIKELY(!m_emptyQueuep)) {
AstEmptyQueueDType* newp = new AstEmptyQueueDType{fl};
AstEmptyQueueDType* const newp = new AstEmptyQueueDType{fl};
addTypesp(newp);
m_emptyQueuep = newp;
}
@@ -943,7 +919,7 @@ AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
if (VL_UNLIKELY(!m_voidp)) {
AstVoidDType* newp = new AstVoidDType{fl};
AstVoidDType* const newp = new AstVoidDType{fl};
addTypesp(newp);
m_voidp = newp;
}
@@ -952,7 +928,7 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
AstQueueDType* const newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
addTypesp(newp);
m_queueIndexp = newp;
}
@@ -962,11 +938,11 @@ AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
//
AstBasicDType* new1p = new AstBasicDType(fl, kwd);
AstBasicDType* const new1p = new AstBasicDType(fl, kwd);
// Because the detailed map doesn't update this map,
// check the detailed map for this same node
// Also adds this new node to the detailed map
AstBasicDType* newp = findInsertSameDType(new1p);
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
} else {
@@ -979,8 +955,8 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd)
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width,
int widthMin, VSigning numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
} else {
@@ -992,8 +968,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
const VNumRange& range, int widthMin,
VSigning numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
} else {
@@ -1003,8 +979,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
}
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange());
const VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange());
DetailedMap& mapr = m_detailedMap;
const auto it = mapr.find(key);
if (it != mapr.end()) return it->second;
@@ -1041,10 +1017,8 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
// - the default/inititem children might be in different order yet still yield the same table
// See note in AstInitArray::same about the same. This function instead compares by initializer
// value, rather than by tree structure.
const AstUnpackArrayDType* const aDTypep = VN_CAST(ap->dtypep(), UnpackArrayDType);
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
UASSERT_STATIC(aDTypep, "Bad type in array initializer");
UASSERT_STATIC(bDTypep, "Bad type in array initializer");
const AstUnpackArrayDType* const aDTypep = VN_AS(ap->dtypep(), UnpackArrayDType);
const AstUnpackArrayDType* const bDTypep = VN_AS(bp->dtypep(), UnpackArrayDType);
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) { // Element types differ
return false;
}
@@ -1063,14 +1037,14 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
}
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
AstNode* const defaultp = initp->defaultp();
const AstNode* const defaultp = initp->defaultp();
// Verify initializer is well formed
UASSERT_OBJ(VN_IS(initp->dtypep(), UnpackArrayDType), initp,
"Const pool table must have AstUnpackArrayDType dtype");
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
"Const pool table default must be Const");
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {
AstNode* const valuep = VN_CAST(nodep, InitItem)->valuep();
const AstNode* const valuep = VN_AS(nodep, InitItem)->valuep();
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
}
// Try to find an existing table with the same content
@@ -1078,7 +1052,7 @@ AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
const auto& er = m_tables.equal_range(hash.value());
for (auto it = er.first; it != er.second; ++it) {
AstVarScope* const varScopep = it->second;
const AstInitArray* const init2p = VN_CAST(varScopep->varp()->valuep(), InitArray);
const AstInitArray* const init2p = VN_AS(varScopep->varp()->valuep(), InitArray);
if (sameInit(initp, init2p)) {
return varScopep; // Found identical table
}
@@ -1107,7 +1081,7 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
const auto& er = m_consts.equal_range(hash.value());
for (auto it = er.first; it != er.second; ++it) {
AstVarScope* const varScopep = it->second;
const AstConst* const init2p = VN_CAST(varScopep->varp()->valuep(), Const);
const AstConst* const init2p = VN_AS(varScopep->varp()->valuep(), Const);
if (sameInit(initp, init2p)
&& (mergeDType || varScopep->dtypep()->sameTree(initp->dtypep()))) {
return varScopep; // Found identical constant
@@ -1218,7 +1192,7 @@ void AstNode::dump(std::ostream& str) const {
} else {
str << " @dt=" << nodeAddr(dtypep()) << "@";
}
if (AstNodeDType* dtp = dtypep()) dtp->dumpSmall(str);
if (AstNodeDType* const dtp = dtypep()) dtp->dumpSmall(str);
} else { // V3Broken will throw an error
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
}
@@ -1284,9 +1258,8 @@ const char* AstClassPackage::broken() const {
return nullptr;
}
void AstClass::insertCache(AstNode* nodep) {
const bool doit
= (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_CAST(nodep, NodeFTask)->isExternProto()));
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()));
if (doit) {
if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
@@ -1312,9 +1285,9 @@ void AstClass::dump(std::ostream& str) const {
if (isVirtual()) str << " [VIRT]";
}
AstClass* AstClassExtends::classp() const {
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
refp = VN_CAST(childDTypep(), ClassRefDType);
refp = VN_AS(childDTypep(), ClassRefDType);
}
UASSERT_OBJ(refp, this, "class extends non-ref");
return refp->classp();
@@ -1338,7 +1311,7 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const {
}
void AstDisplay::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
// str<<" "<<displayType().ascii();
// str << " " << displayType().ascii();
}
void AstEnumItemRef::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
@@ -1501,7 +1474,7 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (generic()) str << " [GENERIC]";
if (AstNodeDType* dtp = virtRefDTypep()) {
if (AstNodeDType* const dtp = virtRefDTypep()) {
str << " refdt=" << nodeAddr(dtp);
dtp->dumpSmall(str);
}
@@ -1515,7 +1488,7 @@ void AstNodeDType::dumpSmall(std::ostream& str) const {
}
void AstNodeArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
if (auto* adtypep = VN_CAST_CONST(this, UnpackArrayDType)) {
if (auto* const adtypep = VN_CAST(this, UnpackArrayDType)) {
// uc = packed compound object, u = unpacked POD
str << (adtypep->isCompound() ? "uc" : "u");
} else {
@@ -1551,7 +1524,7 @@ std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
std::vector<AstUnpackArrayDType*> dims;
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
dims.push_back(unpackp);
if (AstNodeDType* subp = unpackp->subDTypep()) {
if (AstNodeDType* const subp = unpackp->subDTypep()) {
unpackp = VN_CAST(subp, UnpackArrayDType);
} else {
unpackp = nullptr;
@@ -1608,7 +1581,7 @@ void AstMTaskBody::dump(std::ostream& str) const {
void AstTypeTable::dump(std::ostream& str) const {
this->AstNode::dump(str);
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
if (AstBasicDType* subnodep = m_basicps[i]) {
if (AstBasicDType* const subnodep = m_basicps[i]) {
str << '\n'; // Newline from caller, so newline first
str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii();
str << " -> ";
@@ -1618,7 +1591,7 @@ void AstTypeTable::dump(std::ostream& str) const {
{
const DetailedMap& mapr = m_detailedMap;
for (const auto& itr : mapr) {
AstBasicDType* dtypep = itr.second;
AstBasicDType* const dtypep = itr.second;
str << '\n'; // Newline from caller, so newline first
str << "\t\tdetailed -> ";
dtypep->dump(str);
@@ -1727,6 +1700,11 @@ void AstScope::dump(std::ostream& str) const {
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
void AstScopeName::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (dpiExport()) str << " [DPIEX]";
if (forFormat()) str << " [FMT]";
}
void AstSenTree::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isMulti()) str << " [MULTI]";
+197 -185
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -103,7 +103,7 @@ public:
// Get a reference to the user data
T_Data& operator()(const T_Node* nodep) {
T_Data* userp = getUserp(nodep);
T_Data* const userp = getUserp(nodep);
UASSERT_OBJ(userp, nodep, "Missing User data on const AstNode");
return *userp;
}
+20 -11
View File
@@ -41,7 +41,7 @@ private:
// NODE STATE
// Entire netlist:
// AstNodeFTask::user1 -> bool, 1=processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
bool m_anyFuncInBegin = false;
public:
@@ -59,10 +59,11 @@ public:
class BeginVisitor final : public AstNVisitor {
private:
// STATE
BeginState* m_statep; // Current global state
BeginState* const m_statep; // Current global state
AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
string m_displayScope; // Name of %m in $display/AstScopeName
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth = 0; // Current if depth
@@ -111,9 +112,11 @@ private:
// naming; so that any begin's inside the function will rename
// inside the function.
// Process children
VL_RESTORER(m_displayScope);
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
m_displayScope = dot(m_displayScope, nodep->name());
m_namedScope = "";
m_unnamedScope = "";
m_ftaskp = nodep;
@@ -134,6 +137,7 @@ private:
virtual void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep << endl);
VL_RESTORER(m_displayScope);
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
@@ -145,11 +149,14 @@ private:
while ((pos = dottedname.find("__DOT__")) != string::npos) {
const string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
if (nodep->name() != "") {
m_displayScope = dot(m_displayScope, ident);
m_namedScope = dot(m_namedScope, ident);
}
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(
AstCellInline* const inlinep = new AstCellInline(
nodep->fileline(), m_unnamedScope, "__BEGIN__", m_modp->timeunit());
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
@@ -162,7 +169,7 @@ private:
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
if (AstNode* const stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
@@ -220,11 +227,13 @@ private:
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's
if (m_namedScope != "") {
// DPI svGetScope doesn't include function name, but %m does
const string scname = nodep->forFormat() ? m_displayScope : m_namedScope;
if (!scname.empty()) {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
AstNode* const afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__") + m_namedScope));
nodep->scopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
if (afterp) nodep->scopeAttrp(afterp);
}
iterateChildren(nodep);
@@ -308,8 +317,8 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
BeginState state;
{ BeginVisitor bvisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor brvisitor(nodep, &state); }
{ BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+2 -2
View File
@@ -40,7 +40,7 @@ private:
// NODE STATE
// Entire netlist:
// AstFTask::user1() -> int. Number of references
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
int m_likely = false; // Excuses for branch likely taken
@@ -123,5 +123,5 @@ public:
void V3Branch::branchAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
BranchVisitor visitor{nodep};
{ BranchVisitor{nodep}; }
}
+7 -6
View File
@@ -191,13 +191,13 @@ private:
void processEnter(AstNode* nodep) {
nodep->brokenState(m_brokenCntCurrentUnder);
const char* whyp = nodep->broken();
const char* const whyp = nodep->broken();
UASSERT_OBJ(!whyp, nodep,
"Broken link in node (or something without maybePointedTo): " << whyp);
if (nodep->dtypep()) {
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
UASSERT_OBJ(nodep->dtypep(), nodep,
"Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
}
if (v3Global.assertDTypesResolved()) {
@@ -210,7 +210,8 @@ private:
}
UASSERT_OBJ(!nodep->getChildDTypep(), nodep,
"childDTypep() non-null on node after should have removed");
if (const AstNodeDType* dnodep = VN_CAST(nodep, NodeDType)) checkWidthMin(dnodep);
if (const AstNodeDType* const dnodep = VN_CAST(nodep, NodeDType))
checkWidthMin(dnodep);
}
checkWidthMin(nodep);
}
@@ -242,7 +243,7 @@ private:
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
&& !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstScope* nodep) override {
@@ -342,8 +343,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
UINFO(1, "Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
} else {
inBroken = true;
BrokenMarkVisitor mvisitor{nodep};
BrokenCheckVisitor cvisitor{nodep};
const BrokenMarkVisitor mvisitor{nodep};
const BrokenCheckVisitor cvisitor{nodep};
s_allocTable.checkForLeaks();
s_linkableTable.clear();
s_brokenCntGlobal.inc();
+5 -4
View File
@@ -39,7 +39,7 @@ public:
enum en : uint8_t { MODULE, CLASS, COVERAGE };
private:
enum en m_e;
const enum en m_e;
public:
// cppcheck-suppress noExplicitConstructor
@@ -139,7 +139,8 @@ void V3CCtors::evalAsserts() {
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* const varp = VN_CAST(np, Var)) {
if (varp->isPrimaryInish() && !varp->isSc()) {
if (AstBasicDType* basicp = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
if (const AstBasicDType* const basicp
= VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
const int storedWidth = basicp->widthAlignBytes() * 8;
const int lastWordWidth = varp->width() % storedWidth;
if (lastWordWidth != 0) {
@@ -175,7 +176,7 @@ void V3CCtors::cctorsAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
evalAsserts();
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
modp = VN_AS(modp->nextp(), NodeModule)) {
// Process each module in turn
{
V3CCtorsBuilder var_reset{modp, "_ctor_var_reset",
@@ -200,7 +201,7 @@ void V3CCtors::cctorsAll() {
}
}
}
if (AstClass* const classp = VN_CAST(modp, Class)) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
AstCFunc* const funcp = new AstCFunc{modp->fileline(), "~", nullptr, ""};
funcp->isDestructor(true);
funcp->isStatic(false);
+2 -2
View File
@@ -39,7 +39,7 @@
class CUseVisitor final : public AstNVisitor {
// NODE STATE
// AstNode::user1() -> bool. True if already visited
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// MEMBERS
bool m_impOnly = false; // In details needed only for implementation
@@ -100,7 +100,7 @@ void V3CUse::cUseAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
// Call visitor separately for each module, so visitor state is cleared
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
modp = VN_AS(modp->nextp(), NodeModule)) {
// Insert under this module; someday we should e.g. make Ast
// for each output file and put under that
CUseVisitor{modp};
+44 -42
View File
@@ -52,20 +52,20 @@
class CaseLintVisitor final : public AstNVisitor {
private:
AstNodeCase* m_caseExprp
const AstNodeCase* m_caseExprp
= nullptr; // Under a CASE value node, if so the relevant case statement
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstNodeCase* nodep) override {
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) {
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
// Detect multiple defaults
bool hitDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) {
if (hitDefault) {
itemp->v3error("Multiple default statements in case statement.");
@@ -79,7 +79,7 @@ private:
m_caseExprp = nodep;
iterate(nodep->exprp());
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
iterateAndNextNull(itemp->condsp());
}
m_caseExprp = nullptr;
@@ -91,11 +91,11 @@ private:
if (VN_IS(m_caseExprp, GenCase)) {
nodep->v3error("Use of x/? constant in generate case statement, "
"(no such thing as 'generate casez')");
} else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) {
} else if (VN_IS(m_caseExprp, Case) && VN_AS(m_caseExprp, Case)->casex()) {
// Don't sweat it, we already complained about casex in general
} else if (VN_IS(m_caseExprp, Case)
&& (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
&& (VN_AS(m_caseExprp, Case)->casez()
|| VN_AS(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isAnyX()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)");
@@ -122,12 +122,12 @@ private:
// NODE STATE
// Cleared each Case
// AstIf::user3() -> bool. Set true to indicate clone not needed
AstUser3InUse m_inuser3;
const AstUser3InUse m_inuser3;
// STATE
VDouble0 m_statCaseFast; // Statistic tracking
VDouble0 m_statCaseSlow; // Statistic tracking
AstNode* m_alwaysp = nullptr; // Always in which case is located
const AstNode* m_alwaysp = nullptr; // Always in which case is located
// Per-CASE
int m_caseWidth = 0; // Width of valueItems
@@ -145,7 +145,7 @@ private:
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (icondp->isDouble()) opaque = true;
@@ -159,7 +159,7 @@ private:
return false; // Too wide for analysis
}
UINFO(8, "Simple case statement: " << nodep << endl);
uint32_t numCases = 1UL << m_caseWidth;
const uint32_t numCases = 1UL << m_caseWidth;
// Zero list of items for each value
for (uint32_t i = 0; i < numCases; ++i) m_valueItem[i] = nullptr;
// Now pick up the values for each assignment
@@ -167,20 +167,20 @@ private:
bool reportedOverlap = false;
bool reportedSubcase = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
// if (debug() >= 9) icondp->dumpTree(cout, " caseitem: ");
AstConst* iconstp = VN_CAST(icondp, Const);
AstConst* const iconstp = VN_AS(icondp, Const);
UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this");
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
V3Number nummask(itemp, iconstp->width());
nummask.opBitsNonX(iconstp->num());
uint32_t mask = nummask.toUInt();
const uint32_t mask = nummask.toUInt();
V3Number numval(itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
uint32_t val = numval.toUInt();
const uint32_t val = numval.toUInt();
uint32_t firstOverlap = 0;
bool foundOverlap = false;
@@ -190,7 +190,7 @@ private:
if (!m_valueItem[i]) {
m_valueItem[i] = itemp;
foundHit = true;
} else if (!foundOverlap && !itemp->ignoreOverlap()) {
} else if (!foundOverlap) {
firstOverlap = i;
foundOverlap = true;
m_caseNoOverlapsAllCovered = false;
@@ -244,7 +244,7 @@ private:
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch
for (uint32_t i = 0; i < numCases; ++i) {
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->bodysp();
}
return true; // All is fine
}
@@ -289,10 +289,11 @@ private:
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// new AstConst(cexprp->fileline(), nummask));
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
AstNode* eqp
AstNode* const and1p
= new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
AstNode* const eqp
= new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p);
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
AstIf* const ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
ifp->user3(1); // So we don't bother to clone it
return ifp;
}
@@ -302,11 +303,11 @@ private:
// CASEx(cexpr,....
// -> tree of IF(msb, IF(msb-1, 11, 10)
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
if (debug() >= 9) { // LCOV_EXCL_START
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (AstNode* itemp = m_valueItem[i]) {
if (const AstNode* const itemp = m_valueItem[i]) {
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
}
}
@@ -335,13 +336,13 @@ private:
// -> IF((cexpr==icond1),istmts1,
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
// ,istmts2, istmts3
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
// We'll do this in two stages. First stage, convert the conditions to
// the appropriate IF AND terms.
if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: ");
bool hadDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (!itemp->condsp()) {
// Default clause. Just make true, we'll optimize it away later
itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue()));
@@ -355,7 +356,7 @@ private:
icondp->unlinkFrBack();
AstNode* condp = nullptr; // Default is to use and1p/and2p
AstConst* iconstp = VN_CAST(icondp, Const);
AstConst* const iconstp = VN_CAST(icondp, Const);
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
VL_DO_DANGLING(icondp->deleteTree(), icondp);
@@ -363,7 +364,7 @@ private:
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::BitFalse());
} else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) {
} else if (AstInsideRange* const irangep = VN_CAST(icondp, InsideRange)) {
// Similar logic in V3Width::visit(AstInside)
condp = irangep->newAndFromInside(cexprp, irangep->lhsp()->unlinkFrBack(),
irangep->rhsp()->unlinkFrBack());
@@ -373,18 +374,19 @@ private:
nummask.opBitsNonX(iconstp->num());
V3Number numval(itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
AstNode* const and1p
= new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* const and2p = new AstAnd(
itemp->fileline(), new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
VL_DO_DANGLING(icondp->deleteTree(), icondp);
VL_DANGLING(iconstp);
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
AstNode* and1p = cexprp->cloneTree(false);
AstNode* and2p = icondp;
AstNode* const and1p = cexprp->cloneTree(false);
AstNode* const and2p = icondp;
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
}
if (!ifexprp) {
@@ -416,16 +418,16 @@ private:
AstIf* groupnextp = nullptr;
AstIf* itemnextp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
itemp = VN_AS(itemp->nextp(), CaseItem)) {
AstNode* const istmtsp = itemp->bodysp(); // Maybe null -- no action.
if (istmtsp) istmtsp->unlinkFrBackWithNext();
// Expressioned clause
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
AstNode* const ifexprp = itemp->condsp()->unlinkFrBack();
{ // Prepare for next group
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = nullptr;
AstIf* newp
AstIf* const newp
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), nullptr, nullptr);
if (groupnextp) {
groupnextp->addElsesp(newp);
@@ -434,7 +436,7 @@ private:
}
groupnextp = newp;
} else { // Continue group, modify if condition to OR in this new condition
AstNode* condp = groupnextp->condp()->unlinkFrBack();
AstNode* const condp = groupnextp->condp()->unlinkFrBack();
groupnextp->condp(
new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true)));
}
@@ -446,7 +448,7 @@ private:
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::BitTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
AstIf* const newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
if (itemnextp) {
itemnextp->addElsesp(newp);
} else {
@@ -474,7 +476,7 @@ private:
// covered, we're done with it.
// Else, convert to a normal statement parallel with the case statement.
if (nodep->notParallelp() && !noOverlapsAllCovered) {
AstNode* parp = nodep->notParallelp()->unlinkFrBackWithNext();
AstNode* const parp = nodep->notParallelp()->unlinkFrBackWithNext();
nodep->addNextHere(parp);
}
}
@@ -530,10 +532,10 @@ public:
void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor visitor{nodep}; } // Destruct before checking
{ CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
CaseLintVisitor visitor{nodep};
{ CaseLintVisitor{nodep}; }
}
+3 -3
View File
@@ -54,7 +54,7 @@ private:
// NODE STATE
// Entire netlist:
// AstNode::user() // bool. Indicates node is of known size
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
@@ -155,7 +155,7 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
AstNode* const backp = nodep->backp();
const AstNode* const backp = nodep->backp();
if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath)
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) && backp->width()
&& castSize(nodep) != castSize(nodep->varp())) {
@@ -203,6 +203,6 @@ public:
void V3Cast::castAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CastVisitor visitor{nodep}; } // Destruct before checking
{ CastVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+39 -36
View File
@@ -50,8 +50,8 @@ public:
// Graph support classes
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
AstScope* m_scopep;
AstNode* m_nodep;
AstScope* const m_scopep;
AstNode* const m_nodep;
AstSenTree* m_srcDomainp = nullptr;
AstSenTree* m_dstDomainp = nullptr;
bool m_srcDomainSet : 1;
@@ -84,7 +84,7 @@ public:
};
class CdcVarVertex final : public CdcEitherVertex {
AstVarScope* m_varScp;
AstVarScope* const m_varScp;
int m_cntAsyncRst = 0;
bool m_fromFlop = false;
@@ -217,15 +217,15 @@ private:
// AstVarScope::user2 -> bool Used in sensitivity list
// {statement}Node::user1p -> CdcLogicVertex* for this statement
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
AstScope* m_scopep = nullptr; // Current scope being processed
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeModule* m_modp = nullptr; // Current module
AstSenTree* m_domainp = nullptr; // Current sentree
bool m_inDly = false; // In delayed assign
int m_inSenItem = 0; // Number of senitems
@@ -266,7 +266,7 @@ private:
if (varscp->varp()->isPrimaryIO()) {
// Create IO vertex - note it's relative to the pointed to var, not where we are
// now This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp
CdcLogicVertex* const ioVertexp
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), nullptr);
if (varscp->varp()->isWritable()) {
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
@@ -337,7 +337,7 @@ private:
int filelineWidth() {
if (!m_filelineWidth) {
CdcWidthVisitor visitor{v3Global.rootp()};
const CdcWidthVisitor visitor{v3Global.rootp()};
m_filelineWidth = visitor.maxWidth();
}
return m_filelineWidth;
@@ -351,12 +351,12 @@ private:
// userClearVertices is very slow, so we use a generation count instead
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (vvertexp->cntAsyncRst()) {
m_userGeneration++; // Effectively a userClearVertices()
UINFO(8, " Trace One async: " << vvertexp << endl);
// Twice, as we need to detect, then propagate
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
CdcEitherVertex* const markp = traceAsyncRecurse(vvertexp, false);
if (markp) { // Mark is non-nullptr if something bad on this path
UINFO(9, " Trace One bad! " << vvertexp << endl);
m_userGeneration++; // Effectively a userClearVertices()
@@ -381,17 +381,18 @@ private:
// Clear out in prep for marking next path
if (!mark) vertexp->asyncPath(false);
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Any logic considered bad, at the moment, anyhow
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
// And keep tracing back so the user can understand what's up
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
} else if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true);
// If primary I/O, it's ok here back
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
// Show the source "input" statement if it exists
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return nullptr;
@@ -399,7 +400,8 @@ private:
// Also ok if from flop, but partially trace the flop so more obvious to users
if (vvertexp->fromFlop()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return nullptr;
@@ -407,8 +409,8 @@ private:
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const submarkp = traceAsyncRecurse(eFromVertexp, mark);
if (submarkp && !mark_outp) mark_outp = submarkp;
}
@@ -417,14 +419,14 @@ private:
}
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
AstNode* nodep = vertexp->varScp();
const AstNode* const nodep = vertexp->varScp();
*m_ofp << "\n";
*m_ofp << "\n";
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
if (!eToVertexp) targetp = eToVertexp;
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
if (vvertexp->isFlop() // IE the target flop that is upsetting us
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
targetp = eToVertexp;
@@ -452,14 +454,14 @@ private:
const string cont = prefix + sep;
string nextsep = " ";
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
}
// Dump single variable/logic block
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
AstNode* nodep = vertexp->nodep();
string front
AstNode* const nodep = vertexp->nodep();
const string front
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
if (VN_IS(nodep, VarScope)) {
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
@@ -473,7 +475,7 @@ private:
if (level)
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Now that we've printed a path with this hazard, don't bother to print any more
// Otherwise, we'd get a path for almost every destination flop
vvertexp->clearHazard();
@@ -499,7 +501,7 @@ private:
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
m_graph.userClearVertices(); // user1: bool - was analyzed
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
UINFO(9, " Trace One edge: " << vvertexp << endl);
edgeDomainRecurse(vvertexp, traceDests, 0);
}
@@ -514,8 +516,8 @@ private:
std::deque<string> report; // Sort output by name
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
AstVar* varp = vvertexp->varScp()->varp();
if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
const AstVar* const varp = vvertexp->varScp()->varp();
{
string what = "wire";
if (varp->isPrimaryIO()) what = varp->direction().prettyName();
@@ -558,11 +560,11 @@ private:
} // Fully computed
std::set<AstSenTree*> senouts; // List of all sensitivities for new signal
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (vvertexp) {} // Unused
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
} else if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
// If primary I/O, give it domain of the input
AstVar* varp = vvertexp->varScp()->varp();
const AstVar* const varp = vvertexp->varScp()->varp();
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
senouts.insert(new AstSenTree(
varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
@@ -572,13 +574,14 @@ private:
// Now combine domains of sources/dests
if (traceDests) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
}
} else {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
}
@@ -599,7 +602,7 @@ private:
}
}
// If multiple domains need to do complicated optimizations
if (senedited) senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree);
if (senedited) senoutp = VN_AS(V3Const::constifyExpensiveEdit(senoutp), SenTree);
if (traceDests) {
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->dstDomainp(senoutp);
@@ -653,9 +656,9 @@ private:
virtual void visit(AstNodeVarRef* nodep) override {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
AstVarScope* const varscp = nodep->varScopep();
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
CdcVarVertex* varvertexp = makeVarVertex(varscp);
CdcVarVertex* const varvertexp = makeVarVertex(varscp);
UINFO(5, " VARREF to " << varscp << endl);
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
@@ -758,5 +761,5 @@ public:
void V3Cdc::cdcAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
CdcVisitor visitor{nodep};
{ CdcVisitor{nodep}; }
}
+10 -10
View File
@@ -71,7 +71,7 @@ public:
// Each change detection function needs at least one AstChangeDet
// to ensure that V3EmitC outputs the necessary code.
maybeCreateMidChg();
m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr, false});
m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr});
}
void maybeCreateMidChg() {
// Don't create an extra function call if splitting is disabled
@@ -94,7 +94,7 @@ public:
if (!m_tlChgFuncp->stmtsp()) {
m_tlChgFuncp->addStmtsp(new AstCReturn{m_scopetopp->fileline(), callp});
} else {
AstCReturn* const returnp = VN_CAST(m_tlChgFuncp->stmtsp(), CReturn);
AstCReturn* const returnp = VN_AS(m_tlChgFuncp->stmtsp(), CReturn);
UASSERT_OBJ(returnp, m_scopetopp, "Lost CReturn in top change function");
// This is currently using AstLogOr which will shortcut the
// evaluation if any function returns true. This is likely what
@@ -146,7 +146,7 @@ private:
m_statep->maybeCreateChgFuncp();
AstChangeDet* const changep = new AstChangeDet{
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true), false};
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true)};
m_statep->m_chgFuncp->addStmtsp(changep);
AstAssign* const initp = new AstAssign{m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
m_varEqnp->cloneTree(true)};
@@ -154,7 +154,7 @@ private:
// Later code will expand words which adds to GCC compile time,
// so add penalty based on word width also
EmitCBaseCounterVisitor visitor{initp};
const EmitCBaseCounterVisitor visitor{initp};
m_statep->m_numStmts += visitor.count() + m_varEqnp->widthWords();
}
@@ -214,8 +214,8 @@ public:
m_detects = 0;
{
AstVar* const varp = m_vscp->varp();
string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
+ varp->shortName()};
const string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
+ varp->shortName()};
// Create: VARREF(_last)
// ASSIGN(VARREF(_last), VARREF(var))
// ...
@@ -247,17 +247,17 @@ private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1() -> bool. True indicates processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
ChangedState* m_statep; // Shared state across visitors
ChangedState* const m_statep; // Shared state across visitors
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void genChangeDet(AstVarScope* vscp) {
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
ChangedInsertVisitor visitor{vscp, m_statep};
{ ChangedInsertVisitor{vscp, m_statep}; }
}
// VISITORS
@@ -304,7 +304,7 @@ void V3Changed::changedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
ChangedState state;
ChangedVisitor visitor{nodep, &state};
ChangedVisitor{nodep, &state};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+16 -12
View File
@@ -32,11 +32,11 @@
class ClassVisitor final : public AstNVisitor {
private:
// MEMBERS
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep = nullptr; // Package moving scopes into
const AstScope* m_classScopep = nullptr; // Package moving scopes into
AstScope* m_packageScopep = nullptr; // Class package scope
AstNodeFTask* m_ftaskp = nullptr; // Current task
const AstNodeFTask* m_ftaskp = nullptr; // Current task
std::vector<std::pair<AstNode*, AstScope*>> m_moves;
// NODE STATE
@@ -53,27 +53,30 @@ private:
v3Global.rootp()->addModulep(nodep);
// Make containing package
// Note origName is the same as the class origName so errors look correct
AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName());
AstClassPackage* const packagep
= new AstClassPackage(nodep->fileline(), nodep->origName());
packagep->name(nodep->name() + "__Vclpkg");
nodep->classOrPackagep(packagep);
packagep->classp(nodep);
v3Global.rootp()->addModulep(packagep);
// Add package to hierarchy
AstCell* cellp = new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
packagep->name(), nullptr, nullptr, nullptr);
AstCell* const cellp
= new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
packagep->name(), nullptr, nullptr, nullptr);
cellp->modp(packagep);
v3Global.rootp()->topModulep()->addStmtp(cellp);
// Find class's scope
// Alternative would be to move this and related to V3Scope
AstScope* classScopep = nullptr;
const AstScope* classScopep = nullptr;
for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) {
if ((classScopep = VN_CAST(itp, Scope))) break;
}
UASSERT_OBJ(classScopep, nodep, "No scope under class");
// Add scope
AstScope* scopep = new AstScope(nodep->fileline(), packagep, classScopep->name(),
classScopep->aboveScopep(), classScopep->aboveCellp());
AstScope* const scopep
= new AstScope(nodep->fileline(), packagep, classScopep->name(),
classScopep->aboveScopep(), classScopep->aboveCellp());
packagep->addStmtp(scopep);
// Iterate
VL_RESTORER(m_prefix);
@@ -141,8 +144,9 @@ public:
if (VN_IS(moved.first, NodeFTask)) {
moved.second->addActivep(moved.first->unlinkFrBack());
} else if (VN_IS(moved.first, Var)) {
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
moved.second->addVarp(scopep->unlinkFrBack());
AstVarScope* const scopep = VN_AS(moved.first->user1p(), VarScope);
scopep->unlinkFrBack();
moved.second->addVarp(scopep);
}
}
}
@@ -153,6 +157,6 @@ public:
void V3Class::classAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClassVisitor visitor{nodep}; } // Destruct before checking
{ ClassVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+10 -10
View File
@@ -42,15 +42,15 @@ private:
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
// AstNode::user2() -> bool. True indicates widthMin has been propagated
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
// TYPES
enum CleanState : uint8_t { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
// STATE
AstNodeModule* m_modp = nullptr;
const AstNodeModule* m_modp = nullptr;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -67,16 +67,16 @@ private:
}
void setCppWidth(AstNode* nodep) {
nodep->user2(true); // Don't resize it again
AstNodeDType* old_dtypep = nodep->dtypep();
AstNodeDType* const old_dtypep = nodep->dtypep();
const int width = cppWidth(nodep); // widthMin is unchanged
if (old_dtypep->width() != width) {
// Since any given dtype's cppWidth() is the same, we can just
// remember one conversion for each, and reuse it
if (AstNodeDType* new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
if (AstNodeDType* const new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
nodep->dtypep(new_dtypep);
} else {
nodep->dtypeChgWidth(width, nodep->widthMin());
AstNodeDType* new_dtypep2 = nodep->dtypep();
AstNodeDType* const new_dtypep2 = nodep->dtypep();
UASSERT_OBJ(new_dtypep2 != old_dtypep, nodep,
"Dtype didn't change when width changed");
old_dtypep->user3p(new_dtypep2); // Remember for next time
@@ -126,7 +126,7 @@ private:
computeCppWidth(nodep);
V3Number mask(nodep, cppWidth(nodep));
mask.setMask(nodep->widthMin());
AstNode* cleanp
AstNode* const cleanp
= new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), mask), nodep);
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
relinkHandle.relink(cleanp);
@@ -138,7 +138,7 @@ private:
void ensureCleanAndNext(AstNode* nodep) {
// Editing list, careful looping!
for (AstNode* exprp = nodep; exprp;) {
AstNode* nextp = exprp->nextp();
AstNode* const nextp = exprp->nextp();
ensureClean(exprp);
exprp = nextp;
}
@@ -314,6 +314,6 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CleanVisitor visitor{nodep}; } // Destruct before checking
{ CleanVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+37 -36
View File
@@ -73,11 +73,11 @@ private:
// NODE STATE
// Cleared each Module:
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstTopScope* m_topScopep = nullptr; // Current top scope
const AstTopScope* m_topScopep = nullptr; // Current top scope
AstScope* m_scopep = nullptr; // Current scope
AstCFunc* m_evalFuncp = nullptr; // Top eval function we are creating
AstCFunc* m_initFuncp = nullptr; // Top initial function we are creating
@@ -92,30 +92,30 @@ private:
AstVarScope* getCreateLastClk(AstVarScope* vscp) {
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
AstVar* varp = vscp->varp();
const AstVar* const varp = vscp->varp();
if (!varp->width1()) {
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
<< varp->prettyNameQ());
}
string newvarname
const string newvarname
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1);
AstVar* const newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1);
newvarp->noReset(true); // Reset by below assign
m_modp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
vscp->user1p(newvscp);
m_scopep->addVarp(newvscp);
// Add init
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
AstNode* newinitp = new AstAssign(
AstNode* const newinitp = new AstAssign(
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
addToInitial(newinitp);
// At bottom, assign them
AstAssign* finalp = new AstAssign(vscp->fileline(),
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
AstAssign* const finalp = new AstAssign(
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_evalFuncp->addFinalsp(finalp);
//
UINFO(4, "New Last: " << newvscp << endl);
@@ -136,16 +136,17 @@ private:
"Unsupported: Complicated event expression in sensitive activity list");
return nullptr;
}
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
UASSERT_OBJ(nodep->varrefp(), nodep, "No clock found on sense item");
AstVarScope* const clkvscp = nodep->varrefp()->varScopep();
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstNot(nodep->fileline(),
@@ -153,7 +154,7 @@ private:
VAccess::READ)),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
newp = new AstXor(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
@@ -171,7 +172,7 @@ private:
AstNode* createSenseEquation(AstSenItem* nodesp) {
// Nodep may be a list of elements; we need to walk it
AstNode* senEqnp = nullptr;
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
AstNode* const senOnep = createSenItemEquation(senp);
if (senEqnp) {
// Add new OR to the sensitivity list equation
@@ -183,9 +184,9 @@ private:
return senEqnp;
}
AstIf* makeActiveIf(AstSenTree* sensesp) {
AstNode* senEqnp = createSenseEquation(sensesp->sensesp());
AstNode* const senEqnp = createSenseEquation(sensesp->sensesp());
UASSERT_OBJ(senEqnp, sensesp, "No sense equation, shouldn't be in sequent activation.");
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
AstIf* const newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
return newifp;
}
void clearLastSen() {
@@ -214,11 +215,11 @@ private:
AstCFunc* funcp = nullptr;
// Unlink all statements, then add item by item to new sub-functions
AstBegin* tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext()};
AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext()};
if (ofuncp->finalsp()) tempp->addStmtsp(ofuncp->finalsp()->unlinkFrBackWithNext());
while (tempp->stmtsp()) {
AstNode* itemp = tempp->stmtsp()->unlinkFrBack();
AstNode* const itemp = tempp->stmtsp()->unlinkFrBack();
const int stmts = EmitCBaseCounterVisitor(itemp).count();
if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) {
// Make a new function
@@ -230,7 +231,7 @@ private:
funcp->slow(ofuncp->slow());
m_topScopep->scopep()->addActivep(funcp);
//
AstCCall* callp = new AstCCall{funcp->fileline(), funcp};
AstCCall* const callp = new AstCCall{funcp->fileline(), funcp};
ofuncp->addStmtsp(callp);
func_stmts = 0;
}
@@ -288,7 +289,7 @@ private:
// UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
iterateChildren(nodep);
if (AstNode* movep = nodep->finalClksp()) {
if (AstNode* const movep = nodep->finalClksp()) {
UASSERT_OBJ(m_topScopep, nodep, "Final clocks under non-top scope");
movep->unlinkFrBackWithNext();
m_evalFuncp->addFinalsp(movep);
@@ -296,7 +297,7 @@ private:
m_scopep = nullptr;
}
virtual void visit(AstNodeProcedure* nodep) override {
if (AstNode* stmtsp = nodep->bodysp()) {
if (AstNode* const stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
nodep->addNextHere(stmtsp);
}
@@ -306,12 +307,12 @@ private:
// nodep->dumpTree(cout, "ct:");
// COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
AstNode* incp = nodep->incp()->unlinkFrBack();
AstNode* origp = nodep->origp()->unlinkFrBack();
AstNode* changeWrp = nodep->changep()->unlinkFrBack();
AstNode* changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changeRdp),
incp, nullptr);
AstNode* const incp = nodep->incp()->unlinkFrBack();
AstNode* const origp = nodep->origp()->unlinkFrBack();
AstNode* const changeWrp = nodep->changep()->unlinkFrBack();
AstNode* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
AstIf* const newp = new AstIf(
nodep->fileline(), new AstXor(nodep->fileline(), origp, changeRdp), incp, nullptr);
// We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though versus a potential memory miss.
// We'll go with the miss.
@@ -324,7 +325,7 @@ private:
// Link to global function
if (nodep->formCallTree()) {
UINFO(4, " formCallTree " << nodep << endl);
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
AstCCall* const callp = new AstCCall(nodep->fileline(), nodep);
m_finalFuncp->addStmtsp(callp);
}
}
@@ -352,7 +353,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (m_mtaskBodyp) {
UINFO(4, " TR ACTIVE " << nodep << endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
UASSERT_OBJ(!nodep->hasInitial(), nodep,
"Initial block should not have clock sensitivity");
@@ -377,7 +378,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else {
UINFO(4, " ACTIVE " << nodep << endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
// Remember the latest sensitivity so we can compare it next time
UASSERT_OBJ(!nodep->hasInitial(), nodep,
@@ -411,8 +412,8 @@ private:
}
}
virtual void visit(AstExecGraph* nodep) override {
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
for (m_mtaskBodyp = VN_AS(nodep->op1p(), MTaskBody); m_mtaskBodyp;
m_mtaskBodyp = VN_AS(m_mtaskBodyp->nextp(), MTaskBody)) {
clearLastSen();
iterate(m_mtaskBodyp);
}
@@ -443,6 +444,6 @@ public:
void V3Clock::clockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClockVisitor visitor{nodep}; } // Destruct before checking
{ ClockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+5 -5
View File
@@ -121,7 +121,7 @@ class CombineVisitor final : CombBaseVisitor {
private:
// NODE STATE
// Entire netlist:
AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
const AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
// AstUser4InUse part of V3Hasher in V3DupFinder
// STATE
@@ -132,7 +132,7 @@ private:
// METHODS
void walkEmptyFuncs() {
for (const auto& itr : m_dupFinder) {
AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc);
AstCFunc* const oldfuncp = VN_AS(itr.second, CFunc);
UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash");
if (!oldfuncp->emptyBody()) continue;
UASSERT_OBJ(!oldfuncp->dontCombine(), oldfuncp,
@@ -152,14 +152,14 @@ private:
// Do non-slow first as then favors naming functions based on fast name
for (const bool slow : {false, true}) {
for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) {
AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc);
AstCFunc* const newfuncp = VN_AS(newIt->second, CFunc);
UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash");
if (newfuncp->user3()) continue; // Already replaced
if (newfuncp->slow() != slow) continue;
auto oldIt = newIt;
++oldIt; // Skip over current position
for (; oldIt != m_dupFinder.end(); ++oldIt) {
AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc);
AstCFunc* const oldfuncp = VN_AS(oldIt->second, CFunc);
UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash");
UASSERT_OBJ(newfuncp != oldfuncp, newfuncp,
"Same function hashed multiple times");
@@ -223,6 +223,6 @@ public:
void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CombineVisitor visitor{nodep}; } // Destruct before checking
{ CombineVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+2 -2
View File
@@ -64,7 +64,7 @@ static void makeToStringMiddle(AstClass* nodep) {
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "std::string out;\n"});
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (auto* const varp = VN_CAST(itemp, Var)) {
if (const auto* const varp = VN_CAST(itemp, Var)) {
if (!varp->isParam()) {
string stmt = "out += \"";
stmt += comma;
@@ -109,7 +109,7 @@ void V3Common::commonAll() {
// NODE STATE
// Entire netlist:
// AstClass::user1() -> bool. True if class needs to_string dumper
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// Create ToString methods
makeVlToString(classp);
makeToString(classp);
+42 -12
View File
@@ -24,6 +24,7 @@
#include <map>
#include <set>
#include <string>
#include <unordered_map>
//######################################################################
// Resolve wildcards in files, modules, ftasks or variables
@@ -102,7 +103,7 @@ public:
// Apply all attributes to the variable
void apply(AstVar* varp) {
for (const_iterator it = begin(); it != end(); ++it) {
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
AstNode* const newp = new AstAttrOf(varp->fileline(), it->m_type);
varp->addAttrsp(newp);
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, nullptr));
@@ -189,13 +190,13 @@ public:
void apply(AstNodeModule* modp) {
if (m_inline) {
AstPragmaType type
const AstPragmaType type
= m_inlineValue ? AstPragmaType::INLINE_MODULE : AstPragmaType::NO_INLINE_MODULE;
AstNode* nodep = new AstPragma(modp->fileline(), type);
AstNode* const nodep = new AstPragma(modp->fileline(), type);
modp->addStmtp(nodep);
}
for (auto it = m_modPragmas.cbegin(); it != m_modPragmas.cend(); ++it) {
AstNode* nodep = new AstPragma(modp->fileline(), *it);
AstNode* const nodep = new AstPragma(modp->fileline(), *it);
modp->addStmtp(nodep);
}
}
@@ -222,9 +223,9 @@ using V3ConfigModuleResolver = V3ConfigWildcardResolver<V3ConfigModule>;
// lint/coverage/tracing on/off
class V3ConfigIgnoresLine final {
public:
int m_lineno; // Line number to make change at
V3ErrorCode m_code; // Error code
bool m_on; // True to enable message
const int m_lineno; // Line number to make change at
const V3ErrorCode m_code; // Error code
const bool m_on; // True to enable message
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
: m_lineno{lineno}
, m_code{code}
@@ -346,6 +347,9 @@ using V3ConfigFileResolver = V3ConfigWildcardResolver<V3ConfigFile>;
class V3ConfigResolver final {
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
std::unordered_map<string, std::unordered_map<string, vluint64_t>>
m_profileData; // Access to profile_data records
FileLine* m_profileFileLine = nullptr;
static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow)
V3ConfigResolver() = default;
@@ -356,6 +360,20 @@ public:
V3ConfigModuleResolver& modules() { return m_modules; }
V3ConfigFileResolver& files() { return m_files; }
void addProfileData(FileLine* fl, const string& model, const string& key, vluint64_t cost) {
if (!m_profileFileLine) m_profileFileLine = fl;
if (cost == 0) cost = 1; // Cost 0 means delete (or no data)
m_profileData[model][key] += cost;
}
vluint64_t getProfileData(const string& model, const string& key) const {
const auto mit = m_profileData.find(model);
if (mit == m_profileData.cend()) return 0;
const auto it = mit->second.find(key);
if (it == mit->second.cend()) return 0;
return it->second;
}
FileLine* getProfileDataFileLine() const { return m_profileFileLine; } // Maybe null
};
V3ConfigResolver V3ConfigResolver::s_singleton;
@@ -392,10 +410,6 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int
}
}
void V3Config::addModulePragma(const string& module, AstPragmaType pragma) {
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
}
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
if (ftask.empty()) {
V3ConfigResolver::s().modules().at(module).setInline(on);
@@ -408,6 +422,15 @@ void V3Config::addInline(FileLine* fl, const string& module, const string& ftask
}
}
void V3Config::addModulePragma(const string& module, AstPragmaType pragma) {
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
}
void V3Config::addProfileData(FileLine* fl, const string& model, const string& key,
vluint64_t cost) {
V3ConfigResolver::s().addProfileData(fl, model, key, cost);
}
void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& var, AstAttrType attr, AstSenTree* sensep) {
// Semantics: sensep only if public_flat_rw
@@ -479,7 +502,7 @@ void V3Config::applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp) {
const string& modname = modulep->name();
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
if (!modp) return;
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
const V3ConfigFTask* const ftp = modp->ftasks().resolve(ftaskp->name());
if (ftp) ftp->apply(ftaskp);
}
@@ -497,6 +520,13 @@ void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar
if (vp) vp->apply(varp);
}
vluint64_t V3Config::getProfileData(const string& model, const string& key) {
return V3ConfigResolver::s().getProfileData(model, key);
}
FileLine* V3Config::getProfileDataFileLine() {
return V3ConfigResolver::s().getProfileDataFileLine();
}
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());
if (!filep) return false;
+8 -2
View File
@@ -33,17 +33,23 @@ public:
static void addCoverageBlockOff(const string& file, int lineno);
static void addCoverageBlockOff(const string& module, const string& blockname);
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
static void addModulePragma(const string& module, AstPragmaType pragma);
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
static void addModulePragma(const string& module, AstPragmaType pragma);
static void addProfileData(FileLine* fl, const string& model, const string& key,
vluint64_t cost);
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
static void addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& signal, AstAttrType type, AstSenTree* nodep);
static void applyCase(AstCase* nodep);
static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep);
static void applyIgnores(FileLine* filelinep);
static void applyModule(AstNodeModule* modulep);
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
static vluint64_t getProfileData(const string& model, const string& key);
static FileLine* getProfileDataFileLine();
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
};
+444 -395
View File
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -43,7 +43,7 @@ private:
using LinenoSet = std::set<int>;
struct ToggleEnt {
string m_comment; // Comment for coverage dump
const string m_comment; // Comment for coverage dump
AstNode* m_varRefp; // How to get to this element
AstNode* m_chgRefp; // How to get to this element
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
@@ -73,7 +73,7 @@ private:
// NODE STATE
// Entire netlist:
// AstIf::user1() -> bool. True indicates ifelse processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
CheckState m_state; // State save-restored on each new coverage scope/block
@@ -116,20 +116,20 @@ private:
// Someday the user might be allowed to specify a different page suffix
const string page = page_prefix + "/" + m_modp->prettyName();
AstCoverDecl* declp = new AstCoverDecl(fl, page, comment, linescov, offset);
AstCoverDecl* const declp = new AstCoverDecl(fl, page, comment, linescov, offset);
declp->hier(hier);
m_modp->addStmtp(declp);
UINFO(9, "new " << declp << endl);
AstCoverInc* incp = new AstCoverInc(fl, declp);
AstCoverInc* const incp = new AstCoverInc(fl, declp);
if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) {
AstVar* varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP, trace_var_name,
incp->findUInt32DType());
AstVar* const varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP,
trace_var_name, incp->findUInt32DType());
varp->trace(true);
varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
m_modp->addStmtp(varp);
UINFO(5, "New coverage trace: " << varp << endl);
AstAssign* assp = new AstAssign(
AstAssign* const assp = new AstAssign(
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
@@ -209,7 +209,7 @@ private:
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep) override {
AstNodeModule* origModp = m_modp;
const AstNodeModule* const origModp = m_modp;
VL_RESTORER(m_modp);
VL_RESTORER(m_state);
{
@@ -240,14 +240,14 @@ private:
iterateChildren(nodep);
if (m_state.lineCoverageOn(nodep)) {
lineTrack(nodep);
AstNode* newp
AstNode* const newp
= newCoverInc(nodep->fileline(), "", "v_line", "block",
linesCov(m_state, nodep), 0, traceNameForLine(nodep, "block"));
if (AstNodeProcedure* itemp = VN_CAST(nodep, NodeProcedure)) {
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
itemp->addStmtp(newp);
} else if (AstNodeFTask* itemp = VN_CAST(nodep, NodeFTask)) {
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
itemp->addStmtsp(newp);
} else if (AstWhile* itemp = VN_CAST(nodep, While)) {
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
itemp->addBodysp(newp);
} else {
nodep->v3fatalSrc("Bad node type");
@@ -261,7 +261,7 @@ private:
iterateChildren(nodep);
if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn()
&& v3Global.opt.coverageToggle()) {
const char* disablep = varIgnoreToggle(nodep);
const char* const disablep = varIgnoreToggle(nodep);
if (disablep) {
UINFO(4, " Disable Toggle: " << disablep << " " << nodep << endl);
} else {
@@ -279,7 +279,7 @@ private:
// Add signal to hold the old value
const string newvarname = string("__Vtogcov__") + nodep->shortName();
AstVar* chgVarp
AstVar* const chgVarp
= new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
m_modp->addStmtp(chgVarp);
@@ -298,7 +298,7 @@ private:
}
void toggleVarBottom(const ToggleEnt& above, const AstVar* varp) {
AstCoverToggle* newp = new AstCoverToggle(
AstCoverToggle* const newp = new AstCoverToggle(
varp->fileline(),
newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, "", 0,
""),
@@ -308,7 +308,7 @@ private:
void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration
const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant
if (const AstBasicDType* bdtypep = VN_CAST(dtypep, BasicDType)) {
if (const AstBasicDType* const bdtypep = VN_CAST(dtypep, BasicDType)) {
if (bdtypep->isRanged()) {
for (int index_docs = bdtypep->lo(); index_docs < bdtypep->hi() + 1;
++index_docs) {
@@ -324,7 +324,7 @@ private:
} else {
toggleVarBottom(above, varp);
}
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]",
@@ -336,9 +336,9 @@ private:
chgVarp);
newent.cleanup();
}
} else if (AstPackArrayDType* adtypep = VN_CAST(dtypep, PackArrayDType)) {
} else if (const AstPackArrayDType* const adtypep = VN_CAST(dtypep, PackArrayDType)) {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
AstNodeDType* subtypep = adtypep->subDTypep()->skipRefp();
const AstNodeDType* const subtypep = adtypep->subDTypep()->skipRefp();
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]",
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
@@ -349,11 +349,11 @@ private:
chgVarp);
newent.cleanup();
}
} else if (AstStructDType* adtypep = VN_CAST(dtypep, StructDType)) {
} else if (const AstStructDType* const adtypep = VN_CAST(dtypep, StructDType)) {
// For now it's packed, so similar to array
for (AstMemberDType* itemp = adtypep->membersp(); itemp;
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
const int index_code = itemp->lsb();
ToggleEnt newent(above.m_comment + string(".") + itemp->name(),
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
@@ -363,10 +363,10 @@ private:
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
newent.cleanup();
}
} else if (AstUnionDType* adtypep = VN_CAST(dtypep, UnionDType)) {
} else if (const AstUnionDType* const adtypep = VN_CAST(dtypep, UnionDType)) {
// Arbitrarily handle only the first member of the union
if (AstMemberDType* itemp = adtypep->membersp()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
if (const AstMemberDType* const itemp = adtypep->membersp()) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
ToggleEnt newent(above.m_comment + string(".") + itemp->name(),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true));
@@ -387,7 +387,7 @@ private:
// An else-if. When we iterate the if, use "elsif" marking
const bool elsif
= nodep->ifsp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp();
if (elsif) VN_CAST(nodep->elsesp(), If)->user1(true);
if (elsif) VN_AS(nodep->elsesp(), If)->user1(true);
const bool first_elsif = !nodep->user1() && elsif;
const bool cont_elsif = nodep->user1() && elsif;
const bool final_elsif = nodep->user1() && !elsif && nodep->elsesp();
@@ -543,6 +543,6 @@ public:
void V3Coverage::coverage(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageVisitor visitor{rootp}; } // Destruct before checking
{ CoverageVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coverage", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+4 -4
View File
@@ -60,18 +60,18 @@ private:
const auto dupit = dupFinder.findDuplicate(nodep->origp());
if (dupit == dupFinder.end()) break;
//
AstNode* duporigp = dupit->second;
const AstNode* const duporigp = dupit->second;
// Note hashed will point to the original variable (what's
// duplicated), not the covertoggle, but we need to get back to the
// covertoggle which is immediately above, so:
AstCoverToggle* removep = VN_CAST(duporigp->backp(), CoverToggle);
AstCoverToggle* const removep = VN_AS(duporigp->backp(), CoverToggle);
UASSERT_OBJ(removep, nodep, "CoverageJoin duplicate of wrong type");
UINFO(8, " Orig " << nodep << " -->> " << nodep->incp()->declp() << endl);
UINFO(8, " dup " << removep << " -->> " << removep->incp()->declp() << endl);
// The CoverDecl the duplicate pointed to now needs to point to the
// original's data. I.e. the duplicate will get the coverage number
// from the non-duplicate
AstCoverDecl* datadeclp = nodep->incp()->declp()->dataDeclThisp();
AstCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
removep->incp()->declp()->dataDeclp(datadeclp);
UINFO(8, " new " << removep->incp()->declp() << endl);
// Mark the found node as a duplicate of the first node
@@ -114,6 +114,6 @@ public:
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageJoinVisitor visitor{rootp}; } // Destruct before checking
{ CoverageJoinVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coveragejoin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+21 -21
View File
@@ -76,7 +76,7 @@ private:
// AstVar::user1() -> int. Count of number of references
// AstVarScope::user1() -> int. Count of number of references
// AstNodeDType::user1() -> int. Count of number of references
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// TYPES
using AssignMap = std::multimap<AstVarScope*, AstNodeAssign*>;
@@ -102,9 +102,9 @@ private:
void checkAll(AstNode* nodep) {
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->dtypep()) subnodep->user1Inc();
}
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
}
void checkVarRef(AstNodeVarRef* nodep) {
if (nodep->classOrPackagep() && m_elimCells) nodep->classOrPackagep(nullptr);
@@ -116,8 +116,8 @@ private:
) {
m_dtypesp.push_back(nodep);
}
if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
if (AstNode* subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
}
// VISITORS
@@ -129,7 +129,7 @@ private:
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
if (AstClass* classp = VN_CAST(nodep, Class)) {
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);
@@ -282,7 +282,7 @@ private:
iterateAndNextNull(nodep->rhsp());
checkAll(nodep);
// Has to be direct assignment without any EXTRACTing.
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef);
if (varrefp && !m_sideEffect
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
m_assignMap.emplace(varrefp->varScopep(), nodep);
@@ -310,7 +310,7 @@ private:
retry = false;
AstNodeModule* nextmodp;
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) {
nextmodp = VN_CAST(modp->nextp(), NodeModule);
nextmodp = VN_AS(modp->nextp(), NodeModule);
if (modp->dead()
|| (modp->level() > 2 && modp->user1() == 0 && !modp->internal())) {
// > 2 because L1 is the wrapper, L2 is the top user module
@@ -318,7 +318,7 @@ private:
// And its children may now be killable too; correct counts
// Recurse, as cells may not be directly under the module but in a generate
if (!modp->dead()) { // If was dead didn't increment user1's
DeadModVisitor visitor{modp};
DeadModVisitor{modp};
}
VL_DO_DANGLING(modp->unlinkFrBack()->deleteTree(), modp);
retry = true;
@@ -338,7 +338,7 @@ private:
retry = false;
for (std::vector<AstScope*>::iterator it = m_scopesp.begin(); it != m_scopesp.end();
++it) {
AstScope* scp = *it;
AstScope* const scp = *it;
if (!scp) continue;
if (scp->user1() == 0) {
UINFO(4, " Dead AstScope " << scp << endl);
@@ -364,7 +364,7 @@ private:
for (bool retry = true; retry;) {
retry = false;
for (auto& itr : m_classesp) {
if (AstClass* nodep = itr) { // nullptr if deleted earlier
if (AstClass* const nodep = itr) { // nullptr if deleted earlier
if (nodep->user1() == 0) {
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(-1);
@@ -382,10 +382,10 @@ private:
for (AstVarScope* vscp : m_vscsp) {
if (vscp->user1() == 0) {
UINFO(4, " Dead " << vscp << endl);
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
const std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
= m_assignMap.equal_range(vscp);
for (AssignMap::iterator itr = eqrange.first; itr != eqrange.second; ++itr) {
AstNodeAssign* assp = itr->second;
AstNodeAssign* const assp = itr->second;
UINFO(4, " Dead assign " << assp << endl);
assp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
@@ -398,7 +398,7 @@ private:
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) {
AstVar* varp = *it;
AstVar* const varp = *it;
if (!varp) continue;
if (varp->user1() == 0) {
UINFO(4, " Dead " << varp << endl);
@@ -411,14 +411,14 @@ private:
}
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) {
if ((*it)->user1() == 0) {
AstNodeUOrStructDType* classp;
const AstNodeUOrStructDType* classp;
// It's possible that there if a reference to each individual member, but
// not to the dtype itself. Check and don't remove the parent dtype if
// members are still alive.
if ((classp = VN_CAST((*it), NodeUOrStructDType))) {
bool cont = true;
for (AstMemberDType* memberp = classp->membersp(); memberp;
memberp = VN_CAST(memberp->nextp(), MemberDType)) {
memberp = VN_AS(memberp->nextp(), MemberDType)) {
if (memberp->user1() != 0) {
cont = false;
break;
@@ -463,31 +463,31 @@ public:
void V3Dead::deadifyModules(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, false, false, false, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, false, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, false, true, false, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, true, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, false, true, true, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0,
v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, true, true, false, true}; } // Destruct before checking
{ DeadVisitor{nodep, true, true, false, true}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, true, true, true, true}; } // Destruct before checking
{ DeadVisitor{nodep, true, true, true, true}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+54 -52
View File
@@ -81,15 +81,15 @@ private:
// Cleared each scope/active:
// AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign
// AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
const AstUser4InUse m_inuser4;
const AstUser5InUse m_inuser5;
// STATE
AstActive* m_activep = nullptr; // Current activate
AstCFunc* m_cfuncp = nullptr; // Current public C Function
const AstCFunc* m_cfuncp = nullptr; // Current public C Function
AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
@@ -104,16 +104,16 @@ private:
void markVarUsage(AstNodeVarRef* nodep, bool blocking) {
if (blocking) nodep->user5(true);
AstVarScope* vscp = nodep->varScopep();
AstVarScope* const vscp = nodep->varScopep();
// UINFO(4, " MVU " << blocking << " " << nodep << endl);
AstNode* lastrefp = vscp->user5p();
const AstNode* const lastrefp = vscp->user5p();
if (!lastrefp) {
vscp->user5p(nodep);
} else {
const bool last_was_blocking = lastrefp->user5();
if (last_was_blocking != blocking) {
AstNode* nonblockingp = blocking ? nodep : lastrefp;
AstNode* blockingp = blocking ? lastrefp : nodep;
const AstNode* const nonblockingp = blocking ? nodep : lastrefp;
const AstNode* const blockingp = blocking ? lastrefp : nodep;
vscp->v3warn(
BLKANDNBLK,
"Unsupported: Blocked and non-blocking assignments to same variable: "
@@ -131,7 +131,7 @@ private:
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
UASSERT_OBJ(oldvarscp->scopep(), oldvarscp, "Var unscoped");
AstVar* varp;
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
AstNodeModule* const addmodp = oldvarscp->scopep()->modp();
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
const auto it = m_modVarMap.find(std::make_pair(addmodp, name));
if (it != m_modVarMap.end()) {
@@ -152,13 +152,14 @@ private:
m_modVarMap.emplace(std::make_pair(addmodp, name), varp);
}
AstVarScope* varscp = new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
AstVarScope* const varscp
= new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
oldvarscp->scopep()->addVarp(varscp);
return varscp;
}
AstActive* createActivePost(AstVarRef* varrefp) {
AstActive* newactp
AstActive* const newactp
= new AstActive(varrefp->fileline(), "sequentdly", m_activep->sensesp());
// Was addNext(), but addNextHere() avoids a linear search.
m_activep->addNextHere(newactp);
@@ -184,11 +185,11 @@ private:
UINFO(4, " Act: " << m_activep << endl);
UINFO(4, " Act: " << oldactivep << endl);
// Make a new sensitivity list, which is the combination of both blocks
AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena);
AstSenItem* const sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* const senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenTree* const treep = new AstSenTree(m_activep->fileline(), sena);
if (senb) treep->addSensesp(senb);
if (AstSenTree* storep = oldactivep->sensesStorep()) {
if (AstSenTree* const storep = oldactivep->sensesStorep()) {
storep->unlinkFrBack();
pushDeletep(storep);
}
@@ -203,13 +204,13 @@ private:
// Return the new LHS for the assignment, Null = unlink
// Find selects
AstNode* newlhsp = nullptr; // nullptr = unlink old assign
AstSel* bitselp = nullptr;
const AstSel* bitselp = nullptr;
AstArraySel* arrayselp = nullptr;
if (VN_IS(lhsp, Sel)) {
bitselp = VN_CAST(lhsp, Sel);
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
bitselp = VN_AS(lhsp, Sel);
arrayselp = VN_AS(bitselp->fromp(), ArraySel);
} else {
arrayselp = VN_CAST(lhsp, ArraySel);
arrayselp = VN_AS(lhsp, ArraySel);
}
UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?");
UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep,
@@ -219,28 +220,28 @@ private:
//=== Dimensions: __Vdlyvdim__
std::deque<AstNode*> dimvalp; // Assignment value for each dimension of assignment
AstNode* dimselp = arrayselp;
for (; VN_IS(dimselp, ArraySel); dimselp = VN_CAST(dimselp, ArraySel)->fromp()) {
AstNode* valp = VN_CAST(dimselp, ArraySel)->bitp()->unlinkFrBack();
for (; VN_IS(dimselp, ArraySel); dimselp = VN_AS(dimselp, ArraySel)->fromp()) {
AstNode* const valp = VN_AS(dimselp, ArraySel)->bitp()->unlinkFrBack();
dimvalp.push_front(valp);
}
AstVarRef* varrefp = VN_CAST(dimselp, VarRef);
AstVarRef* const varrefp = VN_AS(dimselp, VarRef);
UASSERT_OBJ(varrefp, nodep, "No var underneath arraysels");
UASSERT_OBJ(varrefp->varScopep(), varrefp, "Var didn't get varscoped in V3Scope.cpp");
varrefp->unlinkFrBack();
AstVar* oldvarp = varrefp->varp();
const AstVar* const oldvarp = varrefp->varp();
const int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
//
std::deque<AstNode*> dimreadps; // Read value for each dimension of assignment
for (unsigned dimension = 0; dimension < dimvalp.size(); dimension++) {
AstNode* dimp = dimvalp[dimension];
AstNode* const dimp = dimvalp[dimension];
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));
AstVarScope* bitvscp
AstVarScope* const bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
AstAssign* const bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
dimp);
nodep->addNextHere(bitassignp);
@@ -251,16 +252,16 @@ private:
//=== Bitselect: __Vdlyvlsb__
AstNode* bitreadp = nullptr; // Code to read Vdlyvlsb
if (bitselp) {
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
AstNode* const lsbvaluep = bitselp->lsbp()->unlinkFrBack();
if (VN_IS(bitselp->fromp(), Const)) {
// vlsb = constant, can just push constant into where we use it
bitreadp = lsbvaluep;
} else {
const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
+ cvtToStr(modVecNum));
AstVarScope* bitvscp
AstVarScope* const bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
AstAssign* const bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
lsbvaluep);
nodep->addNextHere(bitassignp);
@@ -274,9 +275,9 @@ private:
// vval = constant, can just push constant into where we use it
valreadp = nodep->rhsp()->unlinkFrBack();
} else {
string valvarname
const string valvarname
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* valvscp
AstVarScope* const valvscp
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
@@ -291,16 +292,16 @@ private:
// then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
// This is good for code like:
// for (i=0; i<5; i++) vector[i] <= something;
setvscp = VN_CAST(nodep->user3p(), VarScope);
setvscp = VN_AS(nodep->user3p(), VarScope);
++m_statSharedSet;
} else { // Create new one
string setvarname
const string setvarname
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
setinitp = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), 0));
AstAssign* setassignp = new AstAssign(
AstAssign* const setassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::BitTrue()));
nodep->addNextHere(setassignp);
@@ -325,15 +326,15 @@ private:
// Build "IF (changeit) ...
UINFO(9, " For " << setvscp << endl);
UINFO(9, " & " << varrefp << endl);
AstAlwaysPost* finalp = VN_CAST(varrefp->varScopep()->user4p(), AlwaysPost);
AstAlwaysPost* finalp = VN_AS(varrefp->varScopep()->user4p(), AlwaysPost);
if (finalp) {
AstActive* oldactivep = VN_CAST(finalp->user2p(), Active);
AstActive* const oldactivep = VN_AS(finalp->user2p(), Active);
checkActivePost(varrefp, oldactivep);
if (setinitp) oldactivep->addStmtsp(setinitp);
} else { // first time we've dealt with this memory
finalp = new AstAlwaysPost(nodep->fileline(), nullptr /*sens*/, nullptr /*body*/);
UINFO(9, " Created " << finalp << endl);
AstActive* newactp = createActivePost(varrefp);
AstActive* const newactp = createActivePost(varrefp);
newactp->addStmtsp(finalp);
varrefp->varScopep()->user4p(finalp);
finalp->user2p(newactp);
@@ -343,7 +344,7 @@ private:
if (finalp->user3p() == setvscp) {
// Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
// we can share the IF statement too
postLogicp = VN_CAST(finalp->user4p(), If);
postLogicp = VN_AS(finalp->user4p(), If);
UASSERT_OBJ(postLogicp, nodep,
"Delayed assignment misoptimized; prev var found w/o associated IF");
} else {
@@ -397,14 +398,14 @@ private:
}
if (VN_IS(nodep->lhsp(), ArraySel)
|| (VN_IS(nodep->lhsp(), Sel)
&& VN_IS(VN_CAST(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newlhsp = createDlyArray(nodep, lhsp);
&& VN_IS(VN_AS(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* const newlhsp = createDlyArray(nodep, lhsp);
if (m_inLoop) {
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
"loops (non-delayed is ok - see docs)");
}
AstBasicDType* basicp = lhsp->dtypep()->basicp();
const AstBasicDType* const basicp = lhsp->dtypep()->basicp();
if (basicp && basicp->isEventValue()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays");
}
@@ -432,18 +433,18 @@ private:
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
"have converted in V3Active");
}
AstVarScope* oldvscp = nodep->varScopep();
AstVarScope* const oldvscp = nodep->varScopep();
UASSERT_OBJ(oldvscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
AstVarScope* dlyvscp = VN_CAST(oldvscp->user1p(), VarScope);
AstVarScope* dlyvscp = VN_AS(oldvscp->user1p(), VarScope);
if (dlyvscp) { // Multiple use of delayed variable
AstActive* oldactivep = VN_CAST(dlyvscp->user2p(), Active);
AstActive* const oldactivep = VN_AS(dlyvscp->user2p(), Active);
checkActivePost(nodep, oldactivep);
}
if (!dlyvscp) { // First use of this delayed variable
const string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
AstNodeAssign* prep;
AstBasicDType* basicp = oldvscp->dtypep()->basicp();
const AstBasicDType* const basicp = oldvscp->dtypep()->basicp();
if (basicp && basicp->isEventValue()) {
// Events go to zero on next timestep unless reactivated
prep = new AstAssignPre(
@@ -456,19 +457,20 @@ private:
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
}
AstNodeAssign* postp = new AstAssignPost(
AstNodeAssign* const postp = new AstAssignPost(
nodep->fileline(),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
postp->lhsp()->user2(true); // Don't detect this assignment
oldvscp->user1p(dlyvscp); // So we can find it later
// Make new ACTIVE with identical sensitivity tree
AstActive* newactp = createActivePost(nodep);
AstActive* const newactp = createActivePost(nodep);
dlyvscp->user2p(newactp);
newactp->addStmtsp(prep); // Add to FRONT of statements
newactp->addStmtsp(postp);
}
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
AstVarRef* const newrefp
= new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@@ -510,6 +512,6 @@ public:
void V3Delayed::delayedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DelayedVisitor visitor{nodep}; } // Destruct before checking
{ DelayedVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+1 -1
View File
@@ -152,6 +152,6 @@ public:
void V3Depth::depthAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthVisitor visitor{nodep}; } // Destruct before checking
{ DepthVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("depth", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
+5 -5
View File
@@ -37,8 +37,8 @@ private:
// NODE STATE
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_cfuncp = nullptr; // Current function
const AstNodeModule* m_modp = nullptr; // Current module
const AstCFunc* m_cfuncp = nullptr; // Current function
int m_depth = 0; // How deep in an expression
int m_deepNum = 0; // How many functions made
@@ -94,9 +94,9 @@ private:
if (m_depth > v3Global.opt.compLimitBlocks()
&& !VN_IS(nodep, NodeCCall)) { // Already done
UINFO(4, "DeepBlocks " << m_depth << " " << nodep << endl);
AstNode* backp = nodep->backp(); // Only for debug
const AstNode* const backp = nodep->backp(); // Only for debug
if (debug() >= 9) backp->dumpTree(cout, "- pre : ");
AstCFunc* funcp = createDeepFunc(nodep);
AstCFunc* const funcp = createDeepFunc(nodep);
iterate(funcp);
if (debug() >= 9) backp->dumpTree(cout, "- post: ");
if (debug() >= 9) funcp->dumpTree(cout, "- func: ");
@@ -129,6 +129,6 @@ public:
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthBlockVisitor visitor{nodep}; } // Destruct before checking
{ DepthBlockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deepblock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+12 -12
View File
@@ -39,7 +39,7 @@ private:
// NODE STATE
// Cleared entire netlist
// AstCFunc::user() // bool. Indicates processing completed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// TYPES
using FuncMmap = std::multimap<std::string, AstCFunc*>;
@@ -107,14 +107,14 @@ private:
// If multiple functions exist, we need to select the appropriate scope.
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
const string name = it->first;
AstCFunc* topFuncp = it->second;
AstCFunc* const topFuncp = it->second;
auto nextIt1 = it;
++nextIt1;
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
const bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
if (moreOfSame1) {
// Multiple functions under this name, need a wrapper function
UINFO(6, " Wrapping " << name << " multifuncs\n");
AstCFunc* newfuncp = topFuncp->cloneTree(false);
AstCFunc* const newfuncp = topFuncp->cloneTree(false);
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
@@ -125,7 +125,7 @@ private:
for (FuncMmap::iterator eachIt = it;
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
it = eachIt;
AstCFunc* funcp = eachIt->second;
AstCFunc* const funcp = eachIt->second;
auto nextIt2 = eachIt;
++nextIt2;
const bool moreOfSame
@@ -138,21 +138,21 @@ private:
funcp->declPrivate(true);
AstNode* argsp = nullptr;
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* newp = new AstVarRef(portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE
: VAccess::READ);
AstNode* const newp = new AstVarRef(
portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE : VAccess::READ);
argsp = argsp ? argsp->addNextNull(newp) : newp;
}
}
}
AstNode* returnp = new AstCReturn(
AstNode* const returnp = new AstCReturn(
funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp));
if (moreOfSame) {
AstIf* ifp = new AstIf(
AstIf* const ifp = new AstIf(
funcp->fileline(),
new AstEq(
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64),
@@ -289,6 +289,6 @@ public:
void V3Descope::descopeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DescopeVisitor visitor{nodep}; } // Destruct before checking
{ DescopeVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+7 -8
View File
@@ -30,7 +30,7 @@ EmitCParentModule::EmitCParentModule() {
}
};
for (AstNode* modp = v3Global.rootp()->modulesp(); modp; modp = modp->nextp()) {
setAll(VN_CAST(modp, NodeModule));
setAll(VN_AS(modp, NodeModule));
}
setAll(v3Global.rootp()->constPoolp()->modp());
}
@@ -57,7 +57,7 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
}
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) {
AstCFile* cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
cfilep->slow(slow);
cfilep->source(source);
v3Global.rootp()->addFilesp(cfilep);
@@ -78,7 +78,7 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
}
// Might be a user function with argument list.
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) {
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args += ", ";
if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) {
@@ -134,9 +134,8 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
const auto emitDeclArrayBrackets = [this](const AstVar* nodep) -> void {
// This isn't very robust and may need cleanup for other data types
for (const AstUnpackArrayDType* arrayp
= VN_CAST_CONST(nodep->dtypeSkipRefp(), UnpackArrayDType);
arrayp; arrayp = VN_CAST_CONST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
for (const AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypeSkipRefp(), UnpackArrayDType);
arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
puts("[" + cvtToStr(arrayp->elementsConst()) + "]");
}
};
@@ -221,7 +220,7 @@ 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* usep = VN_CAST(itemp, CUse)) {
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
if (usep->useType() == useType) {
if (usep->useType().isInclude()) {
puts("#include \"" + prefixNameProtect(usep) + ".h\"\n");
@@ -239,7 +238,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType)
void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, AstType type) {
int last_line = -999;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstNodeText* textp = VN_CAST(nodep, NodeText)) {
if (const AstNodeText* const textp = VN_CAST(nodep, NodeText)) {
if (nodep->type() == type) {
if (last_line != nodep->fileline()->lineno()) {
if (last_line < 0) {
+2 -2
View File
@@ -34,14 +34,14 @@ class EmitCParentModule final {
// NODE STATE
// AstFunc::user4p() AstNodeModule* Parent module pointer
// AstVar::user4p() AstNodeModule* Parent module pointer
AstUser4InUse user4InUse;
const AstUser4InUse user4InUse;
public:
EmitCParentModule();
VL_UNCOPYABLE(EmitCParentModule);
static const AstNodeModule* get(const AstNode* nodep) {
return VN_CAST_CONST(nodep->user4p(), NodeModule);
return VN_AS(nodep->user4p(), NodeModule);
}
};
+2 -2
View File
@@ -38,7 +38,7 @@ protected:
// VISITORS
virtual void visit(AstInitArray* nodep) override {
const AstUnpackArrayDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
= VN_AS(nodep->dtypep()->skipRefp(), UnpackArrayDType);
UASSERT_OBJ(dtypep, nodep, "Array initializer has non-array dtype");
const uint32_t size = dtypep->elementsConst();
const uint32_t elemBytes = dtypep->subDTypep()->widthTotalBytes();
@@ -72,7 +72,7 @@ protected:
virtual void visit(AstConst* nodep) override {
const V3Number& num = nodep->num();
UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool");
AstNodeDType* const dtypep = nodep->dtypep();
const AstNodeDType* const dtypep = nodep->dtypep();
if (num.isString()) {
// Note: putsQuoted does not track indentation, so we use this instead
puts("\"");
+1 -1
View File
@@ -68,7 +68,7 @@ class EmitCConstPool final : public EmitCConstInit {
void emitVars(const AstConstPool* poolp) {
std::vector<const AstVar*> varps;
for (AstNode* nodep = poolp->modp()->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) { varps.push_back(varp); }
if (const AstVar* const varp = VN_CAST(nodep, Var)) { varps.push_back(varp); }
}
if (varps.empty()) return; // Constant pool is empty, so we are done
+31 -35
View File
@@ -197,12 +197,12 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
} else {
// Format
bool isStmt = false;
if (const AstFScanF* dispp = VN_CAST(nodep, FScanF)) {
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
isStmt = false;
puts("VL_FSCANF_IX(");
iterate(dispp->filep());
puts(",");
} else if (const AstSScanF* dispp = VN_CAST(nodep, SScanF)) {
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
isStmt = false;
checkMaxWords(dispp->fromp());
puts("VL_SSCANF_I");
@@ -212,7 +212,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
puts(",");
iterate(dispp->fromp());
puts(",");
} else if (const AstDisplay* dispp = VN_CAST(nodep, Display)) {
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
isStmt = true;
if (dispp->filep()) {
puts("VL_FWRITEF(");
@@ -221,7 +221,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
} else {
puts("VL_WRITEF(");
}
} else if (const AstSFormat* dispp = VN_CAST(nodep, SFormat)) {
} else if (const AstSFormat* const dispp = VN_CAST(nodep, SFormat)) {
isStmt = true;
puts("VL_SFORMAT_X(");
puts(cvtToStr(dispp->lhsp()->widthMin()));
@@ -238,7 +238,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
// Arguments
for (unsigned i = 0; i < emitDispState.m_argsp.size(); i++) {
const char fmt = emitDispState.m_argsChar[i];
AstNode* argp = emitDispState.m_argsp[i];
AstNode* const argp = emitDispState.m_argsp[i];
const string func = emitDispState.m_argsFunc[i];
if (func != "" || argp) {
puts(",");
@@ -315,13 +315,14 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
}
emitDispState.pushArg(fmtLetter, argp, "");
if (fmtLetter == 't' || fmtLetter == '^') {
AstSFormatF* fmtp = nullptr;
if (AstDisplay* nodep = VN_CAST(dispp, Display))
const AstSFormatF* fmtp = nullptr;
if (const AstDisplay* const nodep = VN_CAST(dispp, Display)) {
fmtp = nodep->fmtp();
else if (AstSFormat* nodep = VN_CAST(dispp, SFormat))
} else if (const AstSFormat* const nodep = VN_CAST(dispp, SFormat)) {
fmtp = nodep->fmtp();
else
} else {
fmtp = VN_CAST(dispp, SFormatF);
}
UASSERT_OBJ(fmtp, dispp,
"Use of %t must be under AstDisplay, AstSFormat, or AstSFormatF");
UASSERT_OBJ(!fmtp->timeunit().isNone(), fmtp, "timenunit must be set");
@@ -472,7 +473,7 @@ void EmitCFunc::emitDereference(const string& pointer) {
}
void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
if (const AstConst* constp = VN_CAST(nodep, Const)) {
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
putbs("std::string(");
putsQuoted(constp->num().toString());
puts(")");
@@ -533,13 +534,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(",");
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
} else {
if (!assigntop->selfPointer().empty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
@@ -558,13 +557,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(",");
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
} else {
if (!assigntop->selfPointer().empty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
@@ -584,14 +581,14 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
ofp()->printf("%.17e", nodep->num().toDouble());
}
} else if (nodep->isQuad()) {
vluint64_t num = nodep->toUQuad();
const vluint64_t num = nodep->toUQuad();
if (num < 10) {
ofp()->printf("%" VL_PRI64 "uULL", num);
} else {
ofp()->printf("0x%" VL_PRI64 "xULL", num);
}
} else {
uint32_t num = nodep->toUInt();
const uint32_t num = nodep->toUInt();
// Only 32 bits - llx + long long here just to appease CPP format warning
if (num < 10) {
puts(cvtToStr(num));
@@ -624,20 +621,19 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
// If a simple CONST value we initialize it using an enum
// If an ARRAYINIT we initialize it using an initial block similar to a signal
// puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n");
} else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
} else if (const AstInitArray* const initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (initarp->defaultp()) {
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n");
emitSetVarConstant(varNameProtected + "[__Vi]",
VN_CAST(initarp->defaultp(), Const));
emitSetVarConstant(varNameProtected + "[__Vi]", VN_AS(initarp->defaultp(), Const));
puts("}\n");
}
const AstInitArray::KeyItemMap& mapr = initarp->map();
for (const auto& itr : mapr) {
AstNode* valuep = itr.second->valuep();
AstNode* const valuep = itr.second->valuep();
emitSetVarConstant(varNameProtected + "[" + cvtToStr(itr.first) + "]",
VN_CAST(valuep, Const));
VN_AS(valuep, Const));
}
} else {
varp->v3fatalSrc("InitArray under non-arrayed var");
@@ -650,26 +646,26 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameProtected,
AstNodeDType* dtypep, int depth, const string& suffix) {
dtypep = dtypep->skipRefp();
AstBasicDType* basicp = dtypep->basicp();
AstBasicDType* const basicp = dtypep->basicp();
// Returns string to do resetting, empty to do nothing (which caller should handle)
if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) {
if (AstAssocArrayDType* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
// Access std::array as C array
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray);
} else if (VN_IS(dtypep, ClassRefDType)) {
return ""; // Constructor does it
} else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
} else if (const AstDynArrayDType* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
// Access std::array as C array
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray);
} else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
} else if (const AstQueueDType* const adtypep = VN_CAST(dtypep, QueueDType)) {
// Access std::array as C array
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray);
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp,
"Should have swapped msb & lsb earlier.");
const string ivar = string("__Vi") + cvtToStr(depth);
@@ -683,8 +679,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
// String's constructor deals with it
return "";
} else if (basicp) {
bool zeroit
= (varp->attrFileDescr() // Zero so we don't core dump if never $fopen
const bool zeroit
= (varp->attrFileDescr() // Zero so we don't do file IO if never $fopen
|| (basicp && basicp->isZeroInit())
|| (v3Global.opt.underlineZero() && !varp->name().empty() && varp->name()[0] == '_')
|| (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0"));
@@ -692,7 +688,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide
string out;
if (varp->valuep()) {
AstConst* const constp = VN_CAST(varp->valuep(), Const);
const AstConst* const constp = VN_AS(varp->valuep(), Const);
if (!constp) varp->v3fatalSrc("non-const initializer for variable");
for (int w = 0; w < varp->widthWords(); ++w) {
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
@@ -737,8 +733,8 @@ void EmitCFunc::doubleOrDetect(AstChangeDet* changep, bool& gotOne) {
}
iterateAndNextNull(changep->lhsp());
} else {
AstNode* lhsp = changep->lhsp();
AstNode* rhsp = changep->rhsp();
AstNode* const lhsp = changep->lhsp();
AstNode* const rhsp = changep->rhsp();
UASSERT_OBJ(VN_IS(lhsp, VarRef) || VN_IS(lhsp, ArraySel), changep, "Not ref?");
UASSERT_OBJ(VN_IS(rhsp, VarRef) || VN_IS(rhsp, ArraySel), changep, "Not ref?");
for (int word = 0; word < (changep->lhsp()->isWide() ? changep->lhsp()->widthWords() : 1);
@@ -792,7 +788,7 @@ void EmitCFunc::emitChangeDet() {
doubleOrDetect(nodep, gotOneIgnore);
string varname;
if (VN_IS(nodep->lhsp(), VarRef)) {
varname = ": " + VN_CAST(nodep->lhsp(), VarRef)->varp()->prettyName();
varname = ": " + VN_AS(nodep->lhsp(), VarRef)->varp()->prettyName();
}
puts(")) VL_DBG_MSGF(\" CHANGE: ");
puts(protect(nodep->fileline()->filename()));

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