Compare commits

..
134 Commits
Author SHA1 Message Date
Wilson Snyder 02cb3d17a2 Version bump 2020-11-14 09:50:30 -05:00
Wilson Snyder c3cfaf55ed Commentary 2020-11-14 09:26:38 -05:00
Wilson Snyder 3e7013af31 Internal scope cleanup. No functional change. 2020-11-13 21:12:18 -05:00
Wilson Snyder f7a5883205 Internals: assert not double adding. No functional change intended. 2020-11-13 21:12:03 -05:00
Wilson Snyder 5d3482734a Fix precision in verilator_gantt. 2020-11-13 18:51:45 -05:00
Yutetsu TAKATSUKASA e8c03650ae Fix internal error if always block without begin-end has concat (#2640) (#2641) 2020-11-13 09:50:09 -05:00
Wilson Snyder 7eac788306 Add error on using :: with module 2020-11-12 19:45:26 -05:00
Wilson Snyder 6a58e67699 Commentary 2020-11-12 19:31:53 -05:00
Wilson Snyder b49be06a5a Tests: Standard wording. 2020-11-12 18:50:05 -05:00
Wilson Snyder 87b2adb6a1 With --debug, turn off address space layout randomization. 2020-11-12 18:49:49 -05:00
Wilson Snyder 5634a18f78 Tests: Smaller t_vpi_var test 2020-11-11 20:57:24 -05:00
Wilson Snyder b84c9bb4c0 Internals: Show scope debug information. 2020-11-11 19:00:10 -05:00
Wilson Snyder 6dfce882a1 Support $exit as alias of $finish 2020-11-10 22:49:48 -05:00
Wilson Snyder 79d33bf1ee Use C++11 for loops, from clang-migrate. No functional change intended 2020-11-10 22:10:38 -05:00
Wilson Snyder 44eb362a18 clang-tidy cleanups. No functional change intended. 2020-11-10 21:40:14 -05:00
Wilson Snyder 8664aac225 Fix missing newlines in emit. 2020-11-09 18:29:09 -05:00
Wilson Snyder 6965e138aa Add clearer unsupported message for inside on array (#2566) 2020-11-08 23:26:58 -05:00
Wilson Snyder fc52fb9093 Fix arrays of modport interfaces (#2614). 2020-11-08 22:43:32 -05:00
Wilson Snyder cef7708f38 Internals: Fix missed access change. No functional change intended. 2020-11-08 22:02:35 -05:00
Dan Petrisko 438fb01665 Fix exited typo (#2634) 2020-11-08 21:55:33 -05:00
Wilson Snyder 67d5b1a11a Internals: Preserve arrays of modports. Part of #2614. 2020-11-08 19:15:53 -05:00
Wilson Snyder d78941885b Fix cast width propagation (#2597). 2020-11-08 19:07:33 -05:00
Wilson Snyder 6e7b07c794 Internals: Prep for #2597. No functional change intended 2020-11-08 18:58:31 -05:00
Wilson Snyder 9655e287ab Tests: Travis regression fix 2020-11-08 17:06:03 -05:00
Wilson Snyder 917ca2bad7 Tests: Add t_const_opt_red (#2632) (#2633) 2020-11-08 16:39:28 -05:00
Wilson Snyder c3f5dd7414 Tests: Try to stabilize cron test. 2020-11-08 11:17:42 -05:00
Wilson Snyder 04c7fd1696 Tests: Add wire-or mux test for future optimization. 2020-11-07 21:57:31 -05:00
Wilson Snyder 152689776d Report error on typedef referencing self (#2539). 2020-11-07 15:41:37 -05:00
Wilson Snyder 778f133118 Fix dynamic new with init argument (#2325). 2020-11-07 14:28:05 -05:00
Wilson Snyder ff5465308b Internals: Tree dump DEFAULT pattern. No functional change. 2020-11-07 11:56:24 -05:00
Wilson Snyder 602750b1ee Commentary 2020-11-07 10:49:54 -05:00
Wilson Snyder 2a24bb4759 Fix queue poping wrong value when otherwise unused (#2512). 2020-11-07 10:37:55 -05:00
Krzysztof Bieganski 7c4259bc0a Support static methods and typedefs in classes (#2615) 2020-11-06 19:51:21 -05:00
Kaleb Barrett 1c2384cb3d Fix iteration over mutating list bug in VPI impl (#2588)
Previously, in any given VPI callback, if the callback body registered
the same callback, that registering would be processed in the currently
executing call to the call*Cbs function. In the worse case, this could
lead to an infinite loop.
2020-11-06 17:56:15 -05:00
Yutetsu TAKATSUKASAandWilson Snyder 75881754a9 Fix dangling reference (Issue #2622) (#2623)
* collect multiple string literals of "__Vcvt". No functional change is intended.

* temporary variable for DPI-C should be static if its type is string

* Update src/V3EmitC.cpp

Co-authored-by: Wilson Snyder <[email protected]>

Co-authored-by: Wilson Snyder <[email protected]>
2020-11-04 06:08:03 +09:00
Wilson Snyder 0505816d31 Fix C++14 deprecated random_shuffle. 2020-11-03 08:52:47 -05:00
Wilson Snyder 48bcf66ac7 Fix C++14 deprecated random_shuffle. 2020-11-02 20:07:58 -05:00
Wilson Snyder 0145d9d514 Fix C++14 deprecated random_shuffle. 2020-11-02 19:55:01 -05:00
Wilson Snyder 2ce86eddfa Internal debug. No functional change. 2020-11-01 22:27:27 -05:00
Wilson Snyder b663d1a230 Rename internal interface references, part of #2614. 2020-11-01 20:52:21 -05:00
Wilson Snyder 5821048df7 Fix clang warning. 2020-11-01 17:18:06 -05:00
Wilson Snyder 80284c437e Internals: Refactor some VAssign printing. No functional change. 2020-11-01 16:59:23 -05:00
Wilson Snyder 2aedc91151 Support queue and associative array 'with' statements. (#2616) 2020-11-01 10:56:07 -05:00
Wilson Snyder c1e8337fc1 Support pattern assignment to dynamic arrays. 2020-11-01 10:18:32 -05:00
Wilson Snyder 1858cc8ff1 Fix test stability due to #2618. 2020-11-01 09:26:55 -05:00
Wilson Snyder 5e6aca59ab Fix test stability due to #2618. 2020-11-01 09:14:45 -05:00
Wilson Snyder 726e78fdda Add 'with' syntax checks. 2020-10-31 10:33:36 -04:00
Wilson Snyder 085e8454b8 Support 'with' into elaboration (only). 2020-10-31 10:00:55 -04:00
Wilson Snyder 85b05366bc Internals: Misc prep work for 'with' support. 2020-10-31 09:24:16 -04:00
Wilson Snyder e6b0479b80 Internals: CFunc VL_RESTORER. No functional change intended. 2020-10-31 09:14:47 -04:00
Wilson Snyder 3a53b32a32 Move queue code before assoc, as assoc will eventually use queues. No functional change. 2020-10-30 22:49:55 -04:00
Wilson Snyder cf7b5c091a Internals: Track some VAccess that can be ReadOnly. No functional change. 2020-10-30 22:28:51 -04:00
Wilson Snyder 51b0963e61 Internals: Favor const for map keys. No functional change intended. 2020-10-30 18:00:40 -04:00
Wilson Snyder 0c949ceba2 Internals: classOrPackage is a module, from #2615. 2020-10-30 08:43:20 -04:00
Wilson Snyder 5c070558ae Internals: Misc cleanups in prep for interface bugfix. No functional change intended. 2020-10-29 21:27:19 -04:00
Wilson Snyder 0c328b6eaf clang-format of test_regress. No functional change. 2020-10-28 18:42:36 -04:00
Wilson Snyder f670eccf8c Tests: $countbits 2020-10-28 07:39:13 -04:00
Wilson Snyder 23140aeff0 Internals: V3Begin code cleanup. No functional change. 2020-10-27 22:39:45 -04:00
Wilson Snyder d44426b3f3 clang-format. No functional change. 2020-10-27 20:33:45 -04:00
Yutetsu TAKATSUKASA 05ff96bea3 Fix SEGV when $fgets, $sscanf, or $fscanf is used with string (#2604)
* Add a test to use string for $fgets

* Use dedicated function for $fgets to std::string

* share the implementation of $fgets

* Pass -1 for bitwidth of std::string to distinguish from POD

* add checks for scanf with string

* apply clang-format
2020-10-28 08:37:12 +09:00
Jean Berniolles 77ac9bfcc6 Fix WIFEXITED missing from MinGW/MSYS2 (#2609)
* WIFEXITED missing from MinGW/MSYS2, added defines

* Found source of the WIFEXITED macro in the binutils-gdb repo. Now with less pointer manipulation.
2020-10-27 13:33:25 -04:00
Marlon James 34b8ed4cf0 Return bool from callValueCbs() (#2589) (#2605)
* Return bool from callValueCbs()

Returns true if any registered callback was called, else false.

* Add test for callCbs() and callValueCbs()
2020-10-26 21:55:27 -04:00
Wilson Snyder 95d1272269 Support associative array pattern assignments and defaults. 2020-10-25 21:05:22 -04:00
Wilson Snyder 046c0a7aa1 Fix queue assignment with different limits, negative indicies 2020-10-24 22:08:11 -04:00
Wilson Snyder 835905bdae Convert cast tasks to assertions 2020-10-24 20:30:52 -04:00
Wilson Snyder 51d1235cda Shorter stringify of empty queues, and better queue tests 2020-10-24 18:00:40 -04:00
Wilson Snyder 2f21b3385a Tests: Casting. 2020-10-24 17:46:09 -04:00
Wilson Snyder 9d0a7d5e70 Commentary (#2606). 2020-10-23 18:30:10 -04:00
Wilson Snyder 4cec3ff2a0 Fix WIDTH warnings on comparisons with nullptr (#2602). 2020-10-22 17:27:23 -04:00
Wilson Snyder 25593c0ee2 Fix capitalization 2020-10-22 17:13:42 -04:00
Wilson Snyder 5d3dd52f13 Support queue slicing (#2326). 2020-10-18 13:23:39 -04:00
Wilson Snyder ec36d0d772 Internals: When resolving assignments pass dtype to children. 2020-10-18 12:30:33 -04:00
Wilson Snyder 3d2503f9aa Tests: Run execute on non-Verilator when unsupported test. 2020-10-17 21:31:58 -04:00
Wilson Snyder 4576644591 Prep for future queue slicing. 2020-10-17 21:09:10 -04:00
Wilson Snyder d8df216a8d Fix emit indent of VL_TO_STRING 2020-10-17 20:05:21 -04:00
Wilson Snyder 964dcd5b7c Tests: Add additional array method tests and error 2020-10-17 19:23:27 -04:00
Wilson Snyder f62c070d06 Internals: Concat strings only when final; prep for queues. 2020-10-17 18:56:38 -04:00
Wilson Snyder a56e0a6e89 Internals: Prep for type method. No functional change intended. 2020-10-17 16:48:11 -04:00
Wilson Snyder 451e961e03 Internals: Prep for type method. No functional change intended. 2020-10-17 16:04:29 -04:00
Wilson Snyder cb550e5357 Remove old MSVC 6 workarounds 2020-10-17 14:21:27 -04:00
Wilson Snyder 829db3eefa Fix tick style on %p formats. 2020-10-16 19:26:04 -04:00
Wilson Snyder 44f938e507 Use static const for emitted parameter declarations. 2020-10-16 19:05:28 -04:00
Wilson Snyder 4849c0530b Fix class extends with typedef. 2020-10-16 18:25:32 -04:00
Wilson Snyder f4ed367850 Internals: Remove verilator_difftree old cleanups. 2020-10-15 21:36:35 -04:00
Wilson Snyder d4df94d866 Internals: Move static resolution to LinkParse. 2020-10-15 21:08:24 -04:00
Wilson Snyder 5d8019f941 Internals: Only need to applyFTask once. No functional change intended. 2020-10-15 21:02:24 -04:00
Wilson Snyder 48597bebaf Tests: Better static tests 2020-10-15 20:44:51 -04:00
Wilson Snyder 470859f929 devel release 2020-10-15 08:26:36 -04:00
Wilson Snyder 77553d23fc Version bump 2020-10-15 08:21:57 -04:00
Wilson Snyder 3b9c8b64f7 Tests: Add unsupported queue method/slice testing. 2020-10-14 21:57:53 -04:00
Wilson Snyder 7e5f562500 Tests: Use internal sed as external croaks on binary. 2020-10-14 09:30:15 -04:00
Wilson Snyder d4d3ae4dfc Fix compile error. 2020-10-14 07:31:22 -04:00
Wilson Snyder 79b1b07fcd Commentary 2020-10-14 07:30:15 -04:00
Wilson Snyder e3cf5c07e4 Internal coverage improvements. No functional change. 2020-10-13 21:13:52 -04:00
Wilson Snyder 8750352495 Internal coverage: Cleanup some savable errors and coverage. 2020-10-13 19:26:16 -04:00
Wilson Snyder 3d8dc2774b Fix clang 11 warning. No functional change intended. 2020-10-13 19:22:49 -04:00
Markus Krause 0a9ae154be introduce define for FST tracing (#2592)
This is to allow C++ verilator toplevel to support
multiple modes of waveform tracing
VM_TRACE_FST can be used inside a #if VM_TRACE
section to switch between classic .vcd tracing and the
more compact .fst format supported by GTKWAVE
2020-10-10 21:17:39 -04:00
Wilson Snyder e25a6334cf Support repeated forward typedefs. 2020-10-10 11:29:10 -04:00
Wilson Snyder 070bead9f9 Internals: Refector typedef call. No functional change intended. 2020-10-10 11:25:44 -04:00
Wilson Snyder 549921be2e Disable Free BSD under travis. (#2591) 2020-10-10 09:49:50 -04:00
Wilson Snyder 7c05033b79 Add verilator_gantt warning when too few cpus (#2590) 2020-10-09 21:28:00 -04:00
Wilson Snyder 215d3614c0 Fix preprocessor stringify of undefined macro. 2020-10-09 18:53:09 -04:00
Wilson Snyder 1ebf937a6c Internals: Favor std method. No functional change intended. 2020-10-09 17:55:58 -04:00
Rafal Kapuscik 7be343fd7c Support 'this' (#2585). 2020-10-08 07:54:01 -04:00
Wilson Snyder fb2d78520f Internals: Remove redundant initial clears. No functional change intended. 2020-10-07 19:43:08 -04:00
Yutetsu TAKATSUKASA c5da072ff6 Fix performance degradation when --threads is used with --hierarchical (Issue #2562) #2581 2020-10-05 08:20:49 +09:00
Wilson Snyder efbcb094ca Fix flushCall for backward compatibility (#2580). 2020-10-04 07:47:25 -04:00
Wilson Snyder 5033c906fd Commentary (#2577) 2020-09-30 16:55:26 -04:00
Wilson Snyder f8ab30d127 Commentary (#2575) 2020-09-28 08:45:50 -04:00
Victor Besyakov 222ca4b009 Tests: Add t_stream_integer_type (#2547) (#2548) (#2573) 2020-09-27 19:25:53 -04:00
James Pallister e3a1954e20 Fix hierarchical references used inside a function (#2267) (#2572) 2020-09-27 10:10:44 -04:00
Wilson Snyder 4ba2637360 Fix class wide member display (#2567). 2020-09-25 07:37:38 -04:00
Wilson Snyder 6430743b6f Fix method calls to package class functions (#2565). [Peter Monsson] 2020-09-22 09:09:10 -04:00
Wilson Snyder 0c49cca527 Fix $urandom_range passed variable (#2563). 2020-09-22 08:44:51 -04:00
Wilson Snyder 7a9e79ea79 Fix -G dropping public indication (#2561). 2020-09-21 08:29:57 -04:00
Yutetsu TAKATSUKASA 157948c552 Fix cmake build with --hierarchical option (#2560)
* hier_block with cmake test doesn't assume prefix now.

* Add space between files

* don't set -Mdir on cmake build as it will be set by DIRECTORY option

* Use top target name instead of prefix
2020-09-20 07:48:05 +09:00
Wilson Snyder 1a127a479c Internal coverage improvements 2020-09-19 10:30:31 -04:00
Wilson Snyder 87e4a86fbb Internal coverage improvements 2020-09-18 21:27:36 -04:00
Yutetsu TAKATSUKASA 1c1b95161b Load source file of the hier_block explicitly (#2559)
* Add a test to make sure that lib modules (loaded via -y option) can be a hier_block.

* Add HDL file of the hier_block to the source list if the module is loaded via -y option.

(Each hier_block is treated as a top module when processing the hier_block.)

* Use "\n" for delimiter as the other files
2020-09-19 08:13:49 +09:00
Wilson Snyder 66d1754d19 Fix constant x propagation of xor. 2020-09-18 17:47:22 -04:00
Piotr Binkowski 57a53c014d Internals: Add proper delegation to dump methods (#2555) 2020-09-16 21:52:24 -04:00
Yutetsu TAKATSUKASA e48a859b86 Add timescale directive for hier_block if the original design has it (#2554)
* add timescale directive to a test to reproduce #2544

* add timescale directive to hierarchy blocks
2020-09-17 06:09:29 +09:00
Wilson Snyder 430238a6b4 Support # as a comment in -f files (#2497). 2020-09-15 20:12:08 -04:00
Wilson Snyder 9a4c5509fc Internals: Allow make clang-format in src 2020-09-15 07:39:50 -04:00
Wilson Snyder 0765443353 Internals: Remove unneeded constructor. 2020-09-15 07:35:53 -04:00
Yuri Victorovich d07a6f81e4 Fix cmake-based verilated rebuilds (#2543) 2020-09-11 13:07:00 -04:00
Wilson Snyder fac04521db Internals: Fix VL_LEAK_CHECK (#2542). 2020-09-11 11:52:30 -04:00
Peter Monsson d0819f156f Add support for |=> inside properties (#1292). 2020-09-10 06:49:04 -04:00
Wilson Snyder b77eab3f83 Fix crash when mismatching queue types. 2020-09-07 21:13:38 -04:00
Wilson Snyder 30f3774134 Support const object new() assignments. 2020-09-07 17:26:53 -04:00
Wilson Snyder 1899a875a4 Internals: Create VAccess class. No functional change intended. 2020-09-07 17:09:25 -04:00
Wilson Snyder cc134b38ee Internal coverage: Misc cleanups 2020-09-07 13:11:44 -04:00
Wilson Snyder 993115d30a Cleanup and test EmitV for internal coverage 2020-09-07 12:58:30 -04:00
Wilson Snyder c1d35c8622 devel release 2020-09-07 09:42:13 -04:00
389 changed files with 8997 additions and 2737 deletions
+5 -5
View File
@@ -85,7 +85,7 @@ jobs:
# OS X build
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
# FreeBSD build
- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
#- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
############################################################################
# Jobs in the 'test' stage
############################################################################
@@ -136,10 +136,10 @@ jobs:
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
# FreeBSD tests
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
notifications:
email:
+65
View File
@@ -2,6 +2,69 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.104 2020-11-14
*** Support queue and associative array 'with' statements. (#2616)
*** Support queue slicing (#2326).
*** Support associative array pattern assignments and defaults.
*** Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski]
**** Report error on typedef referencing self (#2539). [Cody Piersall]
**** With --debug, turn off address space layout randomization.
**** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett]
**** Fix cast width propagation (#2597). [flex-liu]
**** Fix return from callValueCbs (#2589) (#2605). [Marlon James]
**** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick]
**** Fix fault when $fgets, $sscanf, etc used with string (#2604). [Yutetsu TAKATSUKASA]
**** Fix WIFEXITED missing from MinGW/MSYS2 (#2609). [Jean Berniolles]
**** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1]
**** Fix arrays of modport interfaces (#2614). [Thierry Tambe]
**** Fix split_var internal error (#2640) (#2641). [Yutetsu TAKATSUKASA]
* Verilator 4.102 2020-10-15
**** Support const object new() assignments.
**** Support # as a comment in -f files (#2497). [phantom-killua]
**** Support 'this' (#2585). [Rafal Kapuscik]
**** Support defines for FST tracing (#2592). [Markus Krause]
**** Support |=> inside properties (#1292). [Peter Monsson]
**** Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA]
**** Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA]
**** Fix -G dropping public indication (#2561). [Andrew Goessling]
**** Fix $urandom_range passed variable (#2563). [nanduraj1]
**** Fix method calls to package class functions (#2565). [Peter Monsson]
**** Fix class wide member display (#2567). [Nandu Raj P]
**** Fix hierarchical references inside function (#2267) (#2572). [James Pallister]
**** Fix flushCall for backward compatibility (#2580). [chenguokai]
**** Fix preprocessor stringify of undefined macro. [Martin Whitaker]
* Verilator 4.100 2020-09-07
@@ -27,6 +90,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Add support for assume property. [Peter Monsson]
**** Add support for |=> inside properties (#1292). [Peter Monsson]
* Verilator 4.040 2020-08-15
+1
View File
@@ -66,4 +66,5 @@ ci/
/csrc/
obj_dir.*
TAGS
gmon.out
.*~
+6 -3
View File
@@ -170,6 +170,8 @@ DISTFILES_INC = $(INFOS) .gitignore \
test_regress/t/t*/*.v* \
test_regress/t/t*/*/*.sv* \
test_regress/t/t*/*/*.v* \
test_regress/t/t*/*.cpp \
test_regress/t/t*/CMakeLists.txt \
test_regress/t/*.cpp \
test_regress/t/*.h \
test_regress/t/*.dat \
@@ -440,11 +442,11 @@ cppcheck: $(CPPCHECK_DEP)
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
CLANGTIDY = clang-tidy
CLANGTIDY_FLAGS = -config=''
CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables'
CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \
$(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP))
clangtidy: $(CLANGTIDY_DEP)
clang-tidy: $(CLANGTIDY_DEP)
%.cpp.tidy: %.cpp
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@
%.h.tidy: %.h
@@ -460,11 +462,12 @@ analyzer-include:
CLANGFORMAT = clang-format
CLANGFORMAT_FLAGS = -i
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c*
clang-format:
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
ftp: info
+22 -5
View File
@@ -76,7 +76,8 @@ if ($opt_gdbbt && !gdb_works()) {
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
if ($opt_gdb) {
# Generic GDB interactive
run (($ENV{VERILATOR_GDB}||"gdb")
run (aslr_off()
.($ENV{VERILATOR_GDB}||"gdb")
." ".verilator_bin()
# Note, uncomment to set breakpoints before running:
# ." -ex 'break main'"
@@ -91,16 +92,22 @@ if ($opt_gdb) {
." -ex 'bt'");
} elsif ($opt_rr) {
# Record with rr
run ("rr record ".verilator_bin()
run (aslr_off()
."rr record ".verilator_bin()
." ".join(' ', @quoted_sw));
} elsif ($opt_gdbbt && $Debug) {
# Run under GDB to get gdbbt
run ("gdb"
run (aslr_off()
."gdb"
." ".verilator_bin()
." --batch --quiet --return-child-result"
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt' -ex 'quit'");
} elsif ($Debug) {
# Debug
run(aslr_off()
.verilator_bin()." ".join(' ',@quoted_sw));
} else {
# Normal, non gdb
run(verilator_bin()." ".join(' ',@quoted_sw));
@@ -165,6 +172,15 @@ sub gdb_works {
return $status==0;
}
sub aslr_off {
my $ok = `setarch --addr-no-randomize echo ok 2>/dev/null` || "";
if ($ok =~ /ok/) {
return "setarch --addr-no-randomize ";
} else {
return "";
}
}
sub run {
# Run command, check errors
my $command = shift;
@@ -4075,9 +4091,10 @@ is ignored, only a single trace file may be active at once.
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
$dumplimit/$dumpportlimit are currently ignored.
=item $finish, $stop
=item $exit, $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored.
The rarely used optional parameter to $finish and $stop is ignored. $exit
is aliased to $finish.
=item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets,
$fscanf, $fwrite, $fscanf, $sscanf
-25
View File
@@ -9,22 +9,6 @@ use Pod::Usage;
use strict;
use vars qw($Debug);
#======================================================================
# Old version 1 dump nodes with no dtypep's
our %Ver1_Non_Dtyped = map {$_ => 1} qw(
ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM
CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE
COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT
DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF
IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST
NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE
PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR
SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS
SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT
TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE
UDPTABLELINE UNTILSTABLE VASSERT WHILE );
#======================================================================
# main
@@ -133,8 +117,6 @@ sub filter {
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
if ($verCvt) {
next if $line =~ /^ NETLIST/;
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
# # Below Ver1_Non_Dtyped may replace above further
if ($line =~ /: ([A-Z]+) /) {
my $type = $1;
next if $type =~ 'DTYPE';
@@ -147,14 +129,7 @@ sub filter {
}
next;
}
if ($Ver1_Non_Dtyped{$type}) {
$line =~ s! w[0-9]+!!g;
}
}
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
}
print $f2 $line;
}
+17 -6
View File
@@ -156,7 +156,8 @@ sub report {
print "\nAnalysis:\n";
printf " Total threads = %d\n", $nthreads;
printf " Total mtasks = %d\n", scalar(keys %Mtasks);
printf " Total cpus used = %d\n", scalar(keys %{$Global{cpus}});
my $ncpus = scalar(keys %{$Global{cpus}});
printf " Total cpus used = %d\n", $ncpus;
printf " Total yields = %d\n", $Global{stats}{yields};
printf " Total eval time = %d rdtsc ticks\n", $Global{last_end};
printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time;
@@ -197,15 +198,25 @@ sub report {
}
print "\nStatistics:\n";
print " min log(p2e) = $min_p2e from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict}, elapsed $Mtasks{$min_mtask}{elapsed})\n";
print " max log(p2e) = $max_p2e from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict}, elapsed $Mtasks{$max_mtask}{elapsed})\n";
printf " min log(p2e) = %0.3f", $min_p2e;
print " from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict},";
print " elapsed $Mtasks{$min_mtask}{elapsed})\n";
printf " max log(p2e) = %0.3f", $max_p2e;
print " from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict},";
print " elapsed $Mtasks{$max_mtask}{elapsed})\n";
my $stddev = stddev(\@p2e_ratios);
my $mean = mean(\@p2e_ratios);
print " mean = " . ($mean) . "\n";
print " stddev = " . ($stddev) . "\n";
print " e ^ stddev = " . exp($stddev). "\n";
printf " mean = %0.3f\n", $mean;
printf " stddev = %0.3f\n", $stddev;
printf " e ^ stddev = %0.3f\n", exp($stddev);
print "\n";
if ($nthreads > $ncpus) {
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
print " : See docs on use of numactl.\n";
print "\n";
}
}
sub report_graph {
+1 -1
View File
@@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.100 2020-09-07],
AC_INIT([Verilator],[4.104 2020-11-14],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
+8
View File
@@ -25,20 +25,26 @@ Iztok Jeras
James Hanlon
James Hutchinson
Jamey Hicks
James Pallister
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
John Coiner
John Demme
Josh Redford
Julien Margetts
Kaleb Barrett
Kanad Kanhere
Kevin Kiningham
Krzysztof Bieganski
Kuba Ober
Ludwig Rogiers
Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Markus Krause
Marlon James
Marshal Qiao
Matthew Ballance
Michael Killough
@@ -52,6 +58,7 @@ Philipp Wagner
Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Rafal Kapuscik
Richard Myers
Rupert Swarbrick
Sean Cross
@@ -65,6 +72,7 @@ Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Tymoteusz Blazejczyk
Victor Besyakov
Vassilis Papaefstathiou
Veripool API Bot
Wilson Snyder
+11 -2
View File
@@ -586,7 +586,7 @@ dealing with. For example a visitor might not implement separate `visit`
methods for `AstIf` and `AstGenIf`, but just a single method for the base
class:
void visit (AstNodeIf* nodep)
void visit(AstNodeIf* nodep)
However that method might want to specify additional code if it is called
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
@@ -672,7 +672,7 @@ Set to 1 to indicate that the compilation or execution is intended to fail.
For example the following would specify that compilation requires two
defines and is expected to fail.
compile (
compile(
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
fails => 1,
);
@@ -758,6 +758,15 @@ may be required to setup the system for fuzzing.
== Debugging
=== Debug Levels
The "UINFO" calls in the source indicate a debug level. Messages level 3
and below are globally enabled with `--debug`. Higher levels may be
controlled with `--debugi <level>`. An individual source file levels may
be controlled with `-debugi-<srcfile> <level>`. For example `--debug
--debugi 5 --debugi-V3Width 9` will use the debug binary at default debug
level 5, with the V3Width.cpp file at level 9.
=== --debug
When you run with `--debug` there are two primary output file types placed
+55 -29
View File
@@ -556,7 +556,7 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W
return owp;
}
}
return 0;
return owp;
}
return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp);
}
@@ -913,10 +913,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
output += "0123456789abcdef"[charval];
}
break;
default:
default: { // LCOV_EXCL_START
std::string msg = std::string("Unknown _vl_vsformat code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // LCOV_EXCL_STOP
} // switch
}
} // switch
@@ -1078,7 +1079,17 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
WData qowp[VL_WQ_WORDS_E];
VL_SET_WQ(qowp, 0ULL);
WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
if (obits == -1) { // string
owp = nullptr;
if (VL_UNCOVERABLE(fmt != 's')) {
VL_FATAL_MT(
__FILE__, __LINE__, "",
"Internal: format other than %s is passed to string"); // LCOV_EXCL_LINE
}
} else if (obits > VL_QUADSIZE) {
owp = va_arg(ap, WDataOutP);
}
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
switch (fmt) {
case 'c': {
@@ -1092,11 +1103,13 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, nullptr);
if (!tmp[0]) goto done;
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
for (int i = 0; i < obits && lpos >= 0; --lpos) {
_vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]);
lsb += 8;
if (owp) {
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
for (int i = 0; i < obits && lpos >= 0; --lpos) {
_vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]);
lsb += 8;
}
}
break;
}
@@ -1182,15 +1195,20 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
break;
}
default:
default: { // LCOV_EXCL_START
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // LCOV_EXCL_STOP
} // switch
if (!inIgnore) ++got;
// Reload data if non-wide (if wide, we put it in the right place directly)
if (obits == 0) { // Due to inIgnore
} else if (obits == -1) { // string
std::string* p = va_arg(ap, std::string*);
*p = tmp;
} else if (obits <= VL_BYTESIZE) {
CData* p = va_arg(ap, CData*);
*p = owp[0];
@@ -1249,36 +1267,44 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
for (; i < bytes; ++i) { *op++ = 0; }
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
static IData getLine(std::string& str, IData fpi, size_t maxLen) VL_MT_SAFE {
str.clear();
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0;
// The string needs to be padded with 0's in unused spaces in front of
// any read data. This means we can't know in what location the first
// character will finally live, so we need to copy. Yuk.
IData bytes = VL_BYTES_I(obits);
char buffer[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// We don't use fgets, as we must read \0s.
while (str.size() < maxLen) {
const int c = getc(fp); // getc() is threadsafe
if (c == EOF) break;
str.push_back(c);
if (c == '\n') break;
}
return str.size();
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
std::string str;
const IData bytes = VL_BYTES_I(obits);
IData got = getLine(str, fpi, bytes);
if (VL_UNLIKELY(str.empty())) return 0;
// V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe
if (VL_UNCOVERABLE(bytes > VL_TO_STRING_MAX_WORDS * VL_EDATASIZE)) {
if (VL_UNCOVERABLE(bytes < str.size())) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun"); // LCOV_EXCL_LINE
}
// We don't use fgets, as we must read \0s.
IData got = 0;
char* cp = buffer;
while (got < bytes) {
int c = getc(fp); // getc() is threadsafe
if (c == EOF) break;
*cp++ = c;
got++;
if (c == '\n') break;
}
_VL_STRING_TO_VINT(obits, destp, got, buffer);
_VL_STRING_TO_VINT(obits, destp, got, str.data());
return got;
}
// declared in verilated_heavy.h
IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE {
return getLine(dest, fpi, std::numeric_limits<size_t>::max());
}
IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
// We ignore lhs/fpi - IEEE says "most recent error" so probably good enough
IData ret = errno;
@@ -2596,7 +2622,7 @@ vluint32_t VerilatedVarProps::entSize() const {
case VLVT_UINT32: size = sizeof(IData); break;
case VLVT_UINT64: size = sizeof(QData); break;
case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break;
default: size = 0; break;
default: size = 0; break; // LCOV_EXCL_LINE
}
return size;
}
+1
View File
@@ -499,6 +499,7 @@ public:
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void runFlushCallbacks() VL_MT_SAFE;
static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated
/// Callbacks to run prior to termination
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
+1
View File
@@ -54,6 +54,7 @@ VK_CPPFLAGS_ALWAYS += \
-DVM_COVERAGE=$(VM_COVERAGE) \
-DVM_SC=$(VM_SC) \
-DVM_TRACE=$(VM_TRACE) \
-DVM_TRACE_FST=$(VM_TRACE_FST) \
$(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
+2 -2
View File
@@ -90,7 +90,7 @@ public:
class VerilatedCovImp : VerilatedCovImpBase {
private:
// TYPES
typedef std::map<std::string, int> ValueIndexMap;
typedef std::map<const std::string, int> ValueIndexMap;
typedef std::map<int, std::string> IndexValueMap;
typedef std::deque<VerilatedCovImpItem*> ItemList;
@@ -350,7 +350,7 @@ public:
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string, std::pair<std::string, vluint64_t>> EventMap;
typedef std::map<const std::string, std::pair<std::string, vluint64_t>> EventMap;
EventMap eventCounts;
for (const auto& itemp : m_items) {
std::string name;
+508 -131
View File
@@ -26,9 +26,11 @@
#include "verilated.h"
#include <algorithm>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
//===================================================================
@@ -41,6 +43,17 @@ extern std::string VL_TO_STRING(QData lhs);
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
extern std::string VL_TO_STRING_W(int words, WDataInP obj);
//===================================================================
// Shuffle RNG
class VlURNG {
public:
typedef size_t result_type;
static constexpr size_t min() { return 0; }
static constexpr size_t max() { return 1ULL << 31; }
size_t operator()() { return VL_MASK_I(31) & VL_RANDOM_I(32); }
};
//===================================================================
// Readmem/Writemem operation classes
@@ -73,6 +86,333 @@ public:
void print(QData addr, bool addrstamp, const void* valuep);
};
//===================================================================
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
private:
// TYPES
typedef std::deque<T_Value> Deque;
public:
typedef typename Deque::const_iterator const_iterator;
private:
// MEMBERS
Deque m_deque; // State of the assoc array
T_Value m_defaultValue; // Default value
public:
// CONSTRUCTORS
VlQueue() {
// m_defaultValue isn't defaulted. Caller's constructor must do it.
}
~VlQueue() {}
// Standard copy constructor works. Verilog: assoca = assocb
// Also must allow conversion from a different T_MaxSize queue
template <size_t U_MaxSize = 0> VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
m_deque = rhs.privateDeque();
if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1);
return *this;
}
static VlQueue cons(const T_Value& lhs) {
VlQueue out;
out.push_back(lhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
VlQueue out;
out.push_back(rhs);
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
VlQueue out = lhs;
out.push_front(rhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
for (const auto& i : lhs.m_deque) out.push_back(i);
return out;
}
// METHODS
T_Value& atDefault() { return m_defaultValue; }
const Deque& privateDeque() const { return m_deque; }
// Size. Verilog: function int size(), or int num()
int size() const { return m_deque.size(); }
// Clear array. Verilog: function void delete([input index])
void clear() { m_deque.clear(); }
void erase(vlsint32_t index) {
if (VL_LIKELY(index >= 0 && index < m_deque.size()))
m_deque.erase(m_deque.begin() + index);
}
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
}
// function void q.push_back(value)
void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
}
// function value_t q.pop_front();
T_Value pop_front() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.front();
m_deque.pop_front();
return v;
}
// function value_t q.pop_back();
T_Value pop_back() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.back();
m_deque.pop_back();
return v;
}
// Setting. Verilog: assoc[index] = v
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(vlsint32_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(vlsint32_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault();
} else {
return m_deque[index];
}
}
// function void q.insert(index, value);
void insert(vlsint32_t index, const T_Value& value) {
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
m_deque.insert(m_deque.begin() + index, value);
}
// Return slice q[lsb:msb]
VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const {
VlQueue out;
if (VL_UNLIKELY(lsb < 0)) lsb = 0;
if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1;
if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1;
for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
return out;
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
const_iterator end() const { return m_deque.end(); }
// Methods
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
template <typename Func> void sort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.begin(), m_deque.end(),
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); });
}
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
template <typename Func> void rsort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.rbegin(), m_deque.rend(),
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); });
}
void reverse() { std::reverse(m_deque.begin(), m_deque.end()); }
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); }
VlQueue unique() const {
VlQueue out;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(i);
}
}
return out;
}
VlQueue<IData> unique_index() const {
VlQueue<IData> out;
IData index = 0;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func> VlQueue find(Func with_func) const {
VlQueue out;
for (const auto& i : m_deque)
if (with_func(i)) out.push_back(i);
return out;
}
template <typename Func> VlQueue<IData> find_index(Func with_func) const {
VlQueue<IData> out;
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(i)) out.push_back(index);
++index;
}
return out;
}
template <typename Func> VlQueue find_first(Func with_func) const {
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func);
if (it == m_deque.end()) return VlQueue{};
return VlQueue::cons(*it);
}
template <typename Func> VlQueue<IData> find_first_index(Func with_func) const {
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func);
if (it == m_deque.end()) return VlQueue<IData>{};
return VlQueue<IData>::cons(std::distance(m_deque.begin(), it));
}
template <typename Func> VlQueue find_last(Func with_func) const {
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func);
if (it == m_deque.rend()) return VlQueue{};
return VlQueue::cons(*it);
}
template <typename Func> VlQueue<IData> find_last_index(Func with_func) const {
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func);
if (it == m_deque.rend()) return VlQueue<IData>{};
// Return index must be relative to beginning
return VlQueue<IData>::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it));
}
// Reduction operators
VlQueue min() const {
if (m_deque.empty()) return VlQueue();
const auto it = std::min_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
VlQueue max() const {
if (m_deque.empty()) return VlQueue();
const auto it = std::max_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out += i;
return out;
}
template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out += with_func(i);
return out;
}
T_Value r_product() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{*it};
++it;
for (; it != m_deque.end(); ++it) out *= *it;
return out;
}
template <typename Func> T_Value r_product(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{with_func(*it)};
++it;
for (; it != m_deque.end(); ++it) out *= with_func(*it);
return out;
}
T_Value r_and() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{*it};
++it;
for (; it != m_deque.end(); ++it) out &= *it;
return out;
}
template <typename Func> T_Value r_and(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{with_func(*it)};
++it;
for (; it != m_deque.end(); ++it) out &= with_func(*it);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out |= i;
return out;
}
template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out |= with_func(i);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out ^= i;
return out;
}
template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out ^= with_func(i);
return out;
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
if (m_deque.empty()) return "'{}"; // No trailing space
std::string out = "'{";
std::string comma;
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
}
};
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog array container
// Similar to std::array<WData, N>, but lighter weight, only methods needed
@@ -196,12 +536,176 @@ public:
return it->second;
}
}
// Setting as a chained operation
VlAssocArray& set(const T_Key& index, const T_Value& value) {
at(index) = value;
return *this;
}
VlAssocArray& setDefault(const T_Value& value) {
atDefault() = value;
return *this;
}
// For save/restore
const_iterator begin() const { return m_map.begin(); }
const_iterator end() const { return m_map.end(); }
// Methods
VlQueue<T_Value> unique() const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_map) {
auto it = saw.find(i.second);
if (it == saw.end()) {
saw.insert(it, i.second);
out.push_back(i.second);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
std::set<T_Key> saw;
for (const auto& i : m_map) {
auto it = saw.find(i.second);
if (it == saw.end()) {
saw.insert(it, i.second);
out.push_back(i.first);
}
}
return out;
}
template <typename Func> VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
for (const auto& i : m_map)
if (with_func(i.second)) out.push_back(i.second);
return out;
}
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> out;
for (const auto& i : m_map)
if (with_func(i.second)) out.push_back(i.first);
return out;
}
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
}
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
}
// Reduction operators
VlQueue<T_Value> min() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element(
m_map.begin(), m_map.end(),
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
m_map.begin(), m_map.end(),
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out += i.second;
return out;
}
template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out += with_func(i.second);
return out;
}
T_Value r_product() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{it->second};
++it;
for (; it != m_map.end(); ++it) out *= it->second;
return out;
}
template <typename Func> T_Value r_product(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{with_func(it->second)};
++it;
for (; it != m_map.end(); ++it) out *= with_func(it->second);
return out;
}
T_Value r_and() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{it->second};
++it;
for (; it != m_map.end(); ++it) out &= it->second;
return out;
}
template <typename Func> T_Value r_and(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{with_func(it->second)};
++it;
for (; it != m_map.end(); ++it) out &= with_func(it->second);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out |= i.second;
return out;
}
template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out |= with_func(i.second);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out ^= i.second;
return out;
}
template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out ^= with_func(i.second);
return out;
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
if (m_map.empty()) return "'{}"; // No trailing space
std::string out = "'{";
std::string comma;
for (const auto& i : m_map) {
@@ -245,133 +749,6 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
}
}
//===================================================================
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
private:
// TYPES
typedef std::deque<T_Value> Deque;
public:
typedef typename Deque::const_iterator const_iterator;
private:
// MEMBERS
Deque m_deque; // State of the assoc array
T_Value m_defaultValue; // Default value
public:
// CONSTRUCTORS
VlQueue() {
// m_defaultValue isn't defaulted. Caller's constructor must do it.
}
~VlQueue() {}
// Standard copy constructor works. Verilog: assoca = assocb
// METHODS
T_Value& atDefault() { return m_defaultValue; }
// Size. Verilog: function int size(), or int num()
int size() const { return m_deque.size(); }
// Clear array. Verilog: function void delete([input index])
void clear() { m_deque.clear(); }
void erase(size_t index) {
if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index);
}
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
}
// function void q.push_back(value)
void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
}
// function value_t q.pop_front();
T_Value pop_front() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.front();
m_deque.pop_front();
return v;
}
// function value_t q.pop_back();
T_Value pop_back() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.back();
m_deque.pop_back();
return v;
}
// Setting. Verilog: assoc[index] = v
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(size_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(size_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
return atDefault();
} else {
return m_deque[index];
}
}
// function void q.insert(index, value);
void insert(size_t index, const T_Value& value) {
if (VL_UNLIKELY(index >= m_deque.size())) return;
m_deque[index] = value;
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
const_iterator end() const { return m_deque.end(); }
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
std::string out = "'{";
std::string comma;
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
}
};
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog class reference container
// There are no multithreaded locks on this; the base variable must
@@ -477,17 +854,17 @@ extern std::string VL_SUBSTR_N(const std::string& lhs, IData rhs, IData ths) VL_
inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool ignoreCase) VL_PURE {
// SystemVerilog does not allow a string variable to contain '\0'.
// So C functions such as strcmp() can correctly compare strings.
int result;
if (ignoreCase) {
result = VL_STRCASECMP(lhs.c_str(), rhs.c_str());
return VL_STRCASECMP(lhs.c_str(), rhs.c_str());
} else {
result = std::strcmp(lhs.c_str(), rhs.c_str());
return std::strcmp(lhs.c_str(), rhs.c_str());
}
return result;
}
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
extern IData VL_FGETS_NI(std::string& dest, IData fpi);
//======================================================================
// Dumping
+12 -9
View File
@@ -42,9 +42,10 @@
// clang-format on
// CONSTANTS
static const char* const VLTSAVE_HEADER_STR
= "verilatorsave01\n"; ///< Value of first bytes of each file
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
/// Value of first bytes of each file (must be multiple of 8 bytes)
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n";
/// Value of last bytes of each file (must be multiple of 8 bytes)
static const char* const VLTSAVE_TRAILER_STR = "vltsaved";
//=============================================================================
//=============================================================================
@@ -64,10 +65,10 @@ VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict da
size_t size) VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(readDiffers(datap, size))) {
std::string fn = filename();
std::string msg
= "Can't deserialize save-restore file as was made from different model:" + filename();
std::string msg = "Can't deserialize save-restore file as was made from different model: "
+ filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
// Die before we close() as close would infinite loop
}
return *this; // For function chaining
}
@@ -88,9 +89,11 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
std::string fn = filename();
std::string msg
= std::string("Can't deserialize; file has wrong header signature: ") + filename();
= std::string(
"Can't deserialize; file has wrong header signature, or file not found: ")
+ filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
// Die before we close() as close would infinite loop
}
os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size());
os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size());
@@ -109,7 +112,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
+ filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
// Die before we close() as close would infinite loop
}
}
+3 -5
View File
@@ -98,10 +98,8 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling)
}
VlThreadPool::~VlThreadPool() {
for (int i = 0; i < m_workers.size(); ++i) {
// Each ~WorkerThread will wait for its thread to exit.
delete m_workers[i];
}
// Each ~WorkerThread will wait for its thread to exit.
for (auto& i : m_workers) delete i;
if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread();
}
@@ -139,7 +137,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
if (VL_UNLIKELY(!fp)) {
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
return;
return; // LCOV_EXCL_LINE
}
// TODO Perhaps merge with verilated_coverage output format, so can
+9
View File
@@ -22,6 +22,15 @@
#include "verilatedos.h"
#include "verilated.h" // for VerilatedMutex and clang annotations
#ifndef VL_THREADED
// Hitting this likely means verilated_threads.cpp is being compiled when
// 'verilator --threads' was not used. 'verilator --threads' sets
// VL_THREADED.
// Alternatively it is always safe but may harm performance to always
// define VL_THREADED for all compiles.
#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)"
#endif
#include <condition_variable>
#include <set>
#include <vector>
+3
View File
@@ -19,6 +19,7 @@
// clang-format off
#ifndef VL_CPPCHECK
#ifndef VL_DERIVED_T
# error "This file should be included in trace format implementations"
#endif
@@ -641,3 +642,5 @@ inline static void cvtQDataToStr(char* dstp, QData value) {
}
#define cvtEDataToStr cvtIDataToStr
#endif // VL_CPPCHECK
+1 -1
View File
@@ -76,7 +76,7 @@ private:
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
const char* m_suffixesp; ///< Pointer to first element of above
typedef std::map<std::string, std::string> NameMap;
typedef std::map<const std::string, const std::string> NameMap;
NameMap* m_namemapp = nullptr; ///< List of names for the header
void bufferResize(vluint64_t minsize);
+52 -47
View File
@@ -96,7 +96,7 @@ public:
virtual vluint32_t type() const { return 0; }
virtual vluint32_t size() const { return 0; }
virtual const VerilatedRange* rangep() const { return nullptr; }
virtual vpiHandle dovpi_scan() { return 0; }
virtual vpiHandle dovpi_scan() { return nullptr; }
};
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*);
@@ -187,7 +187,7 @@ public:
nextp->iterationInc();
return ((nextp)->castVpiHandle());
}
return 0; // End of list - only one deep
return nullptr; // End of list - only one deep
}
};
@@ -312,14 +312,14 @@ public:
m_it = varsp->begin();
m_started = true;
} else if (VL_UNLIKELY(m_it == varsp->end())) {
return 0;
return nullptr;
} else {
++m_it;
}
if (m_it == varsp->end()) return 0;
if (m_it == varsp->end()) return nullptr;
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle());
}
return 0; // End of list - only one deep
return nullptr; // End of list - only one deep
}
};
@@ -346,7 +346,7 @@ public:
}
virtual vpiHandle dovpi_scan() override {
vpiHandle result;
if (m_done) return 0;
if (m_done) return nullptr;
result = vpi_handle_by_index(m_handle, m_iteration);
iterationInc();
return result;
@@ -387,7 +387,7 @@ public:
}
virtual vluint32_t type() const override { return vpiIterator; }
virtual vpiHandle dovpi_scan() override {
if (m_it == m_vec->end()) return 0;
if (m_it == m_vec->end()) return nullptr;
const VerilatedScope* modp = *m_it++;
return (new VerilatedVpioModule(modp))->castVpiHandle();
}
@@ -477,7 +477,8 @@ public:
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
bool called = false;
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
const auto end = cbObjList.end(); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); it != end;) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
continue;
@@ -489,12 +490,14 @@ public:
}
return called;
}
static void callValueCbs() VL_MT_UNSAFE_ONE {
static bool callValueCbs() VL_MT_UNSAFE_ONE {
assertOneCheck();
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
bool called = false;
typedef std::set<VerilatedVpioVar*> VpioVarSet;
VpioVarSet update; // set of objects to update after callbacks
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
const auto end = cbObjList.end(); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); it != end;) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
continue;
@@ -512,10 +515,12 @@ public:
update.insert(varop);
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
(vop->cb_rtnp())(vop->cb_datap());
called = true;
}
}
}
for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); }
return called;
}
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
@@ -599,7 +604,7 @@ VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = nullptr;
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); }
void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callValueCbs(); }
bool VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callValueCbs(); }
bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
return VerilatedVpiImp::callCbs(reason);
@@ -1048,10 +1053,10 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
}
}
PLI_INT32 vpi_remove_cb(vpiHandle object) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", object););
PLI_INT32 vpi_remove_cb(vpiHandle cb_obj) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", cb_obj););
VerilatedVpiImp::assertOneCheck();
VerilatedVpioCb* vop = VerilatedVpioCb::castp(object);
VerilatedVpioCb* vop = VerilatedVpioCb::castp(cb_obj);
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!vop)) return 0;
if (vop->cb_datap()->reason == cbAfterDelay) {
@@ -1065,7 +1070,7 @@ PLI_INT32 vpi_remove_cb(vpiHandle object) {
void vpi_get_cb_info(vpiHandle /*object*/, p_cb_data /*cb_data_p*/) { _VL_VPI_UNIMP(); }
vpiHandle vpi_register_systf(p_vpi_systf_data /*systf_data_p*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/) {
_VL_VPI_UNIMP();
@@ -1131,24 +1136,24 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
_VL_VPI_ERROR_RESET();
if (VL_LIKELY(varop)) {
if (varop->varp()->dims() < 2) return 0;
if (varop->varp()->dims() < 2) return nullptr;
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|| indx < varop->varp()->unpacked().right()))
return 0;
return nullptr;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->unpacked().right()))
->castVpiHandle();
}
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|| indx > varop->varp()->unpacked().right()))
return 0;
return nullptr;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->unpacked().left()))
->castVpiHandle();
}
_VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC);
return 0;
return nullptr;
}
// for traversing relationships
@@ -1160,56 +1165,56 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
switch (type) {
case vpiLeftRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
case vpiRightRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
case vpiIndex: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
}
case vpiScope: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
}
case vpiParent: {
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
}
vpiHandle vpi_handle_multi(PLI_INT32 /*type*/, vpiHandle /*refHandle1*/, vpiHandle /*refHandle2*/,
...) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
@@ -1219,8 +1224,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
switch (type) {
case vpiMemoryWord: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
if (vop->varp()->dims() < 2) return nullptr;
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC,
@@ -1231,8 +1236,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
}
case vpiRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
if (vop->varp()->dims() < 2) return nullptr;
// Unsupported is multidim list
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__,
@@ -1244,7 +1249,7 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
}
case vpiReg: {
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle());
}
case vpiModule: {
@@ -1252,13 +1257,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
const VerilatedScope* mod = vop ? vop->scopep() : nullptr;
const auto it = vlstd::as_const(map)->find(const_cast<VerilatedScope*>(mod));
if (it == map->end()) return 0;
if (it == map->end()) return nullptr;
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
return 0;
return nullptr;
}
}
vpiHandle vpi_scan(vpiHandle object) {
@@ -1342,7 +1347,7 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
return 0;
return nullptr;
}
}
@@ -1639,7 +1644,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!valuep)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
return 0;
return nullptr;
}
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
VL_DEBUG_IF_PLI(
@@ -1652,9 +1657,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
"Ignoring vpi_put_value to signal marked read-only,"
" use public_flat_rw instead: %s",
vop->fullname());
return 0;
return nullptr;
}
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return 0;
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr;
if (valuep->format == vpiVectorVal) {
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
if (vop->varp()->vltype() == VLVT_UINT8) {
@@ -1755,7 +1760,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
VL_FUNC, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
return 0;
return nullptr;
}
if (success > 1) {
_VL_VPI_WARNING(__FILE__, __LINE__,
@@ -1844,11 +1849,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s",
VL_FUNC, vop->fullname());
return 0;
return nullptr;
} else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s",
VL_FUNC, vop->fullname());
return 0;
return nullptr;
}
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
return nullptr;
@@ -1910,7 +1915,7 @@ PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) {
@@ -2020,7 +2025,7 @@ PLI_INT32 vpi_put_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*num
}
void* vpi_get_userdata(vpiHandle /*obj*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
PLI_INT32 vpi_put_userdata(vpiHandle /*obj*/, void* /*userdata*/) {
_VL_VPI_UNIMP();
@@ -2051,5 +2056,5 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
PLI_INT32* /*index_array*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
+1 -1
View File
@@ -40,7 +40,7 @@ public:
static void callTimedCbs() VL_MT_UNSAFE_ONE;
/// Call value based callbacks
/// Users should call this from their main loops
static void callValueCbs() VL_MT_UNSAFE_ONE;
static bool callValueCbs() VL_MT_UNSAFE_ONE;
/// Call callbacks of arbitrary types
/// Users can call this from their application code
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE;
+3
View File
@@ -46,14 +46,17 @@ remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
exclude_line_regexp(qr/(\bv3fatalSrc\b
|\bfatalSrc\b
|\bVL_UNCOVERABLE\b
|\bVL_UNREACHABLE\b
|\bVL_FATAL
|\bUASSERT
|\bNUM_ASSERT
|\bERROR_RSVD_WORD
|\bV3ERROR_NA
|\bUINFO\b)/x);
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\)
|\bassert\(
|\bSELF_CHECK)/x);
1;
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add axiom-athdl`;
exec('atsim',@ARGV);
exec('atsim', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_atsim - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_atsim {ncv arguments}
invoke_atsim {arguments}
=head1 DESCRIPTION
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add cds-ius`;
exec('iccr',@ARGV);
exec('iccr', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_iccr - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_iccr {ncv arguments}
invoke_iccr {arguments}
=head1 DESCRIPTION
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add cds-ius/latest`;
exec('ncverilog',@ARGV);
exec('ncverilog', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_ncverilog - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_ncverilog {ncv arguments}
invoke_ncverilog {arguments}
=head1 DESCRIPTION
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add synopsys-sim/latest`;
exec('vcs',@ARGV);
exec('vcs', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_vcs - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_vcs {ncv arguments}
invoke_vcs {arguments}
=head1 DESCRIPTION
+4
View File
@@ -81,6 +81,10 @@ prefiles:: config_rev.h
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
# Human convenience
clang-format:
$(MAKE) -C .. $@
maintainer-copy::
clean mostlyclean distclean maintainer-clean::
-rm -rf obj_* *.log *.dmp *.vpd core
+3 -3
View File
@@ -317,12 +317,12 @@ private:
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
inp->dtypep());
m_modp->addStmtp(outvarp);
AstNode* assp = new AstAssignDly(nodep->fileline(),
new AstVarRef(nodep->fileline(), outvarp, true), inp);
AstNode* assp = new AstAssignDly(
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
alwaysp->addStmtp(assp);
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
invarp = outvarp;
inp = new AstVarRef(nodep->fileline(), invarp, false);
inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ);
}
nodep->replaceWith(inp);
}
+26 -3
View File
@@ -39,6 +39,8 @@ private:
AstSenItem* m_senip = nullptr; // Last sensitivity
// Reset each always:
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
// Reset each assertion:
AstNode* m_disablep = nullptr; // Last disable
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -58,7 +60,10 @@ private:
}
return newp;
}
void clearAssertInfo() { m_senip = nullptr; }
void clearAssertInfo() {
m_senip = nullptr;
m_disablep = nullptr;
}
// VISITORS
//========== Statements
@@ -129,8 +134,25 @@ private:
AstNode* exprp = nodep->exprp()->unlinkFrBack();
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstEq(fl, past,
exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true)
exprp = new AstEq(fl, past, exprp->cloneTree(false));
exprp->dtypeSetLogicBool();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstImplication* nodep) override {
if (nodep->sentreep()) return; // Already processed
FileLine* fl = nodep->fileline();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); }
AstNode* past = new AstPast(fl, lhsp, nullptr);
past->dtypeFrom(lhsp);
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
exprp->dtypeSetLogicBool();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@@ -145,6 +167,7 @@ private:
// Block is the new expression to evaluate
AstNode* blockp = nodep->propp()->unlinkFrBack();
if (nodep->disablep()) {
m_disablep = nodep->disablep()->cloneTree(false);
if (VN_IS(nodep->backp(), Cover)) {
blockp = new AstAnd(
nodep->disablep()->fileline(),
+12 -4
View File
@@ -58,9 +58,10 @@ std::ostream& operator<<(std::ostream& os, AstType rhs);
//######################################################################
// Creators
void AstNode::init() {
AstNode::AstNode(AstType t, FileLine* fl)
: m_type{t}
, m_fileline{fl} {
editCountInc();
m_fileline = nullptr;
m_nextp = nullptr;
m_backp = nullptr;
m_headtailp = this; // When made, we're a list of only a single element
@@ -393,6 +394,7 @@ void AstNode::setOp4p(AstNode* newp) {
void AstNode::addOp1p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp1p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op1p) {
op1p(newp);
} else {
@@ -402,6 +404,7 @@ void AstNode::addOp1p(AstNode* newp) {
void AstNode::addOp2p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp2p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op2p) {
op2p(newp);
} else {
@@ -411,6 +414,7 @@ void AstNode::addOp2p(AstNode* newp) {
void AstNode::addOp3p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp3p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op3p) {
op3p(newp);
} else {
@@ -420,6 +424,7 @@ void AstNode::addOp3p(AstNode* newp) {
void AstNode::addOp4p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp4p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op4p) {
op4p(newp);
} else {
@@ -1112,7 +1117,7 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
}
}
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, bool doCheck) {
// Not const function as calls checkTree
if (doDump) {
{ // Write log & close
@@ -1130,7 +1135,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
}
}
}
if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) {
if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
@@ -1260,6 +1265,9 @@ AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
AstNodeDType* AstNode::findQueueIndexDType() const {
return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline());
}
//######################################################################
// AstNVisitor
+76 -22
View File
@@ -123,6 +123,49 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
//######################################################################
class VAccess {
public:
enum en : uint8_t {
READ, // Read/Consumed, variable not changed
WRITE, // Written/Updated, variable might be updated, but not consumed
// // so variable might be removable if not consumed elsewhere
READWRITE, // Read/Consumed and written/updated, variable both set and
// // also consumed, cannot remove usage of variable.
// // For non-simple data types only e.g. no tristates/delayed vars.
NOCHANGE // No change to previous state, used only in V3LinkLValue
};
enum en m_e;
const char* ascii() const {
static const char* const names[] = {"RD", "WR", "RW", "--"};
return names[m_e];
}
const char* arrow() const {
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
return names[m_e];
}
inline VAccess()
: m_e{READ} {}
// cppcheck-suppress noExplicitConstructor
inline VAccess(en _e)
: m_e{_e} {}
explicit inline VAccess(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
VAccess invert() const {
return (m_e == READWRITE) ? VAccess(m_e) : (m_e == WRITE ? VAccess(READ) : VAccess(WRITE));
}
bool isReadOnly() const { return m_e == READ; } // False with READWRITE
bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; }
bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; }
bool isRW() const { return m_e == READWRITE; } // False with READWRITE
};
inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); }
//######################################################################
class VSigning {
public:
enum en : uint8_t {
@@ -1227,7 +1270,10 @@ public:
/// 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
void pushDeletep(AstNode* nodep) { m_deleteps.push_back(nodep); }
void pushDeletep(AstNode* nodep) {
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
m_deleteps.push_back(nodep);
}
/// Call deleteTree on all previously pushDeletep()'ed nodes
void doDeletes();
@@ -1422,7 +1468,6 @@ class AstNode {
if (nodep) nodep->m_backp = this;
}
void init(); // initialize value of AstNode
private:
AstNode* cloneTreeIter();
AstNode* cloneTreeIterList();
@@ -1442,15 +1487,7 @@ public:
protected:
// CONSTRUCTORS
AstNode(AstType t)
: m_type{t} {
init();
}
AstNode(AstType t, FileLine* fl)
: m_type{t} {
init();
m_fileline = fl;
}
AstNode(AstType t, FileLine* fl);
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
virtual void cloneRelink() {}
void cloneRelinkTree();
@@ -1713,6 +1750,7 @@ public:
AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); }
AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); }
AstNodeDType* findVoidDType() const;
AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
@@ -1783,7 +1821,8 @@ public:
void dumpTreeGdb(); // For GDB only
void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ",
int maxDepth = 0) const;
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true);
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
bool doCheck = true);
static void dumpTreeFileGdb(const char* filenamep = nullptr);
// METHODS - queries
@@ -1889,6 +1928,7 @@ public:
: AstNode{t, fl} {}
ASTNODE_BASE_FUNCS(NodeMath)
// METHODS
virtual void dump(std::ostream& str) const override;
virtual bool hasDType() const override { return true; }
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
// For documentation on emitC format see EmitCStmts::emitOpName
@@ -1911,6 +1951,7 @@ public:
// See checkTreeIter also that asserts no children
// cppcheck-suppress functionConst
void iterateChildren(AstNVisitor& v) {}
virtual void dump(std::ostream& str) const override;
};
class AstNodeUniop : public AstNodeMath {
@@ -1925,6 +1966,7 @@ public:
AstNode* lhsp() const { return op1p(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
// METHODS
virtual void dump(std::ostream& str) const override;
// Set out to evaluation of a AstConst'ed lhs
virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0;
virtual bool cleanLhs() const = 0;
@@ -1987,6 +2029,7 @@ public:
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
// METHODS
virtual void dump(std::ostream& str) const override;
// Set out to evaluation of a AstConst'ed
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths)
@@ -2142,6 +2185,7 @@ public:
}
ASTNODE_BASE_FUNCS(NodeProcedure)
// METHODS
virtual void dump(std::ostream& str) const override;
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
@@ -2158,8 +2202,11 @@ public:
// METHODS
bool isStatement() const { return m_statement; } // Really a statement
void statement(bool flag) { m_statement = flag; }
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
virtual void addBeforeStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
virtual void dump(std::ostream& str = std::cout) const override;
};
class AstNodeAssign : public AstNodeStmt {
@@ -2255,7 +2302,7 @@ public:
class AstNodeVarRef : public AstNodeMath {
// An AstVarRef or AstVarXRef
private:
bool m_lvalue; // Left hand side assignment
VAccess m_access; // Left hand side assignment
AstVar* m_varp; // [AfterLink] Pointer to variable itself
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
AstNodeModule* m_packagep = nullptr; // Package hierarchy
@@ -2264,28 +2311,29 @@ private:
bool m_hierThis = false; // Hiername points to "this" function
public:
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access)
: AstNodeMath{t, fl}
, m_lvalue{lvalue}
, m_access{access}
, m_name{name} {
this->varp(nullptr);
}
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
: AstNodeMath{t, fl}
, m_lvalue{lvalue}
, m_access{access}
, m_name{name} {
// May have varp==nullptr
this->varp(varp);
}
ASTNODE_BASE_FUNCS(NodeVarRef)
virtual void dump(std::ostream& str) const override;
virtual bool hasDType() const override { return true; }
virtual const char* broken() const override;
virtual int instrCount() const override { return widthInstrs(); }
virtual void cloneRelink() override;
virtual string name() const override { return m_name; } // * = Var name
virtual void name(const string& name) override { m_name = name; }
bool lvalue() const { return m_lvalue; }
void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp);
AstVarScope* varScopep() const { return m_varScopep; }
@@ -2412,13 +2460,18 @@ public:
const char* charIQWN() const {
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
}
string cType(const string& name, bool forFunc, bool isRef) const;
private:
class CTypeRecursed;
CTypeRecursed cTypeRecurse(bool compound) const;
};
class AstNodeUOrStructDType : public AstNodeDType {
// A struct or union; common handling
private:
// TYPES
typedef std::map<string, AstMemberDType*> MemberNameMap;
typedef std::map<const string, AstMemberDType*> MemberNameMap;
// MEMBERS
string m_name; // Name from upper typedef, if any
bool m_packed;
@@ -2862,6 +2915,7 @@ public:
AstNodeRange(AstType t, FileLine* fl)
: AstNode{t, fl} {}
ASTNODE_BASE_FUNCS(NodeRange)
virtual void dump(std::ostream& str) const override;
};
//######################################################################
+159 -134
View File
@@ -87,8 +87,10 @@ const char* AstNodeUOrStructDType::broken() const {
return nullptr;
}
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeCCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (funcp()) {
str << " " << funcp()->name() << " => ";
funcp()->dump(str);
@@ -310,107 +312,22 @@ string AstVar::verilogKwd() const {
}
}
class AstVar::VlArgTypeRecursed {
public:
bool m_isRef; // Is it a reference?
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name) const {
string out;
out += m_type;
out += " ";
out += m_isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const {
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
bool isRef = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
string oname;
if (named) {
if (!namespc.empty()) oname += namespc + "::";
oname += VIdProtect::protectIf(name(), protect());
}
return ostatic + info.render(oname);
}
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool compound) const {
VlArgTypeRecursed info;
info.m_isRef
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
dtypep = dtypep->skipRefp();
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
return info;
return ostatic + dtypep()->cType(oname, forFunc, isRef);
}
string AstVar::vlEnumType() const {
@@ -636,6 +553,92 @@ string AstVar::mtasksString() const {
return os.str();
}
class AstNodeDType::CTypeRecursed {
public:
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name, bool isRef) const {
string out;
out += m_type;
if (name != "") out += " ";
out += isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const {
CTypeRecursed info = cTypeRecurse(false);
return info.render(name, isRef);
}
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
CTypeRecursed info;
const AstNodeDType* dtypep = this->skipRefp();
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
return info;
}
AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
// dimension passed from AstArraySel::dimension
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
@@ -843,9 +846,7 @@ bool AstSenTree::hasCombo() const {
void AstTypeTable::clearCache() {
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
// Just clear out the maps; the search functions will be used to rebuild the map
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
m_basicps[i] = nullptr;
}
for (auto& itr : m_basicps) itr = nullptr;
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
@@ -872,6 +873,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
return m_voidp;
}
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
addTypesp(newp);
m_queueIndexp = newp;
}
return m_queueIndexp;
}
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
//
@@ -1035,8 +1045,10 @@ void AstNode::dump(std::ostream& str) const {
}
}
void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstAlways::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeProcedure::dump(str);
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
}
@@ -1057,8 +1069,12 @@ string AstBasicDType::prettyDTypeName() const {
}
return os.str();
}
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstCCast::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeUniop::dump(str);
str << " sz" << size();
}
void AstCell::dump(std::ostream& str) const {
@@ -1074,6 +1090,7 @@ void AstCell::dump(std::ostream& str) const {
void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << origModName();
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
}
const char* AstClassPackage::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
@@ -1119,15 +1136,15 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
str << "class:" << name();
}
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (immediate()) str << " [IMMEDIATE]";
}
void AstDisplay::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
// str<<" "<<displayType().ascii();
}
void AstEnumItemRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeMath::dump(str);
str << " -> ";
if (itemp()) {
itemp()->dump(str);
@@ -1158,16 +1175,16 @@ void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str);
int n = 0;
const AstInitArray::KeyItemMap& mapr = map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
for (const auto& itr : mapr) {
if (n++ > 5) {
str << " ...";
break;
}
str << " [" << it->first << "]=" << (void*)it->second;
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
}
}
void AstJumpGo::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (labelp()) {
labelp()->dump(str);
@@ -1176,7 +1193,7 @@ void AstJumpGo::dump(std::ostream& str) const {
}
}
void AstJumpLabel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (blockp()) {
blockp()->dump(str);
@@ -1185,7 +1202,7 @@ void AstJumpLabel::dump(std::ostream& str) const {
}
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeMath::dump(str);
str << " -> ";
if (varp()) {
varp()->dump(str);
@@ -1194,7 +1211,7 @@ void AstMemberSel::dump(std::ostream& str) const {
}
}
void AstMethodCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (isStatement()) str << " [STMT]";
str << " -> ";
if (taskp()) {
@@ -1235,27 +1252,30 @@ void AstPin::dump(std::ostream& str) const {
if (svImplicit()) str << " [.SV]";
}
void AstPrintTimeScale::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " " << timeunit();
}
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstTime::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTermop::dump(str);
str << " " << timeunit();
}
void AstTimeD::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTermop::dump(str);
str << " " << timeunit();
}
void AstTimeImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeUniop::dump(str);
str << " " << timeunit();
}
void AstTypedef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (attrPublic()) str << " [PUBLIC]";
}
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstRange::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeRange::dump(str);
if (littleEndian()) str << " [LITTLE]";
}
void AstRefDType::dump(std::ostream& str) const {
@@ -1352,15 +1372,20 @@ void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstSel::dump(std::ostream& str) const {
void AstPatMember::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isDefault()) str << " [DEFAULT]";
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str);
if (declRange().ranged()) {
str << " decl" << declRange() << "]";
if (declElWidth() != 1) str << "/" << declElWidth();
}
}
void AstSliceSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTriop::dump(str);
if (declRange().ranged()) str << " decl" << declRange();
}
void AstMTaskBody::dump(std::ostream& str) const {
@@ -1380,8 +1405,8 @@ void AstTypeTable::dump(std::ostream& str) const {
}
{
const DetailedMap& mapr = m_detailedMap;
for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
AstBasicDType* dtypep = it->second;
for (const auto& itr : mapr) {
AstBasicDType* dtypep = itr.second;
str << endl; // Newline from caller, so newline first
str << "\t\tdetailed -> ";
dtypep->dump(str);
@@ -1391,7 +1416,7 @@ void AstTypeTable::dump(std::ostream& str) const {
}
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "[assoc-" << (void*)keyDTypep() << "]";
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
}
string AstAssocArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
@@ -1428,14 +1453,11 @@ void AstVarScope::dump(std::ostream& str) const {
str << " ->UNLINKED";
}
}
void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstVarXRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
}
this->AstNodeVarRef::dump(str);
if (packagep()) str << " pkg=" << nodeAddr(packagep());
str << " " << access().arrow() << " ";
str << ".=" << dotted() << " ";
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
if (varScopep()) {
@@ -1447,13 +1469,9 @@ void AstVarXRef::dump(std::ostream& str) const {
}
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
}
this->AstNodeVarRef::dump(str);
if (packagep()) str << " pkg=" << nodeAddr(packagep());
str << " " << access().arrow() << " ";
if (varScopep()) {
varScopep()->dump(str);
} else if (varp()) {
@@ -1486,6 +1504,12 @@ void AstVar::dump(std::ostream& str) const {
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
}
void AstScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
void AstSenTree::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isMulti()) str << " [MULTI]";
@@ -1522,7 +1546,7 @@ void AstActive::dump(std::ostream& str) const {
}
}
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> ";
if (dotted() != "") { str << ".=" << dotted() << " "; }
@@ -1554,7 +1578,7 @@ void AstBegin::dump(std::ostream& str) const {
if (implied()) str << " [IMPLIED]";
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (!page().empty()) str << " page=" << page();
if (!linescov().empty()) str << " lc=" << linescov();
if (this->dataDeclNullp()) {
@@ -1565,7 +1589,7 @@ void AstCoverDecl::dump(std::ostream& str) const {
}
}
void AstCoverInc::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (declp()) {
declp()->dump(str);
@@ -1578,7 +1602,7 @@ void AstFork::dump(std::ostream& str) const {
if (!joinType().join()) str << " [" << joinType() << "]";
}
void AstTraceInc::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (declp()) {
declp()->dump(str);
@@ -1597,10 +1621,11 @@ void AstNodeText::dump(std::ostream& str) const {
str << " \"" << out << "\"";
}
void AstVFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
void AstCFile::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeFile::dump(str);
if (source()) str << " [SRC]";
if (slow()) str << " [SLOW]";
}
+218 -27
View File
@@ -300,7 +300,7 @@ public:
class AstClass : public AstNodeModule {
// TYPES
typedef std::map<string, AstNode*> MemberNameMap;
typedef std::map<const string, AstNode*> MemberNameMap;
// MEMBERS
MemberNameMap m_members; // Members or method children
AstClassPackage* m_packagep = nullptr; // Class package this is under
@@ -539,10 +539,13 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
if (!asamep->keyDTypep()) return false;
return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep());
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual string prettyDTypeName() const override;
@@ -635,10 +638,12 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return subDTypep() == asamep->subDTypep();
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual string prettyDTypeName() const override;
@@ -741,10 +746,12 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual void dumpSmall(std::ostream& str) const override;
@@ -1093,6 +1100,12 @@ public:
refDTypep(nullptr);
dtypep(nullptr); // V3Width will resolve
}
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp)
: ASTGEN_SUPER(fl) {
setNOp2p(boundp);
refDTypep(dtp);
dtypep(dtp);
}
ASTNODE_NODE_FUNCS(QueueDType)
virtual const char* broken() const override {
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
@@ -1104,10 +1117,12 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual void dumpSmall(std::ostream& str) const override;
@@ -1669,7 +1684,7 @@ class AstSel : public AstNodeTriop {
// Multiple bit range extraction
// Parents: math|stmt
// Children: varref|arraysel, math, constant math
// Tempting to have an lvalue() style method here as LHS selects are quite
// Tempting to have an access() style method here as LHS selects are quite
// different, but that doesn't play well with V3Inst and bidirects which don't know direction
private:
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
@@ -2173,11 +2188,6 @@ public:
void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); }
const MTaskIdSet& mtaskIds() const { return m_mtaskIds; }
string mtasksString() const;
private:
class VlArgTypeRecursed;
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool compound = false) const;
};
class AstDefParam : public AstNode {
@@ -2238,6 +2248,7 @@ public:
virtual bool maybePointedTo() const override { return true; }
virtual string name() const override { return m_name; } // * = Scope name
virtual void name(const string& name) override { m_name = name; }
virtual void dump(std::ostream& str) const override;
string nameDotless() const;
string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); }
AstNodeModule* modp() const { return m_modp; }
@@ -2319,15 +2330,15 @@ public:
class AstVarRef : public AstNodeVarRef {
// A reference to a variable (lvalue or rvalue)
public:
AstVarRef(FileLine* fl, const string& name, bool lvalue)
: ASTGEN_SUPER(fl, name, nullptr, lvalue) {}
AstVarRef(FileLine* fl, const string& name, const VAccess& access)
: ASTGEN_SUPER(fl, name, nullptr, access) {}
// This form only allowed post-link because output/wire compression may
// lead to deletion of AstVar's
AstVarRef(FileLine* fl, AstVar* varp, bool lvalue)
: ASTGEN_SUPER(fl, varp->name(), varp, lvalue) {}
AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
: ASTGEN_SUPER(fl, varp->name(), varp, access) {}
// This form only allowed post-link (see above)
AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue)
: ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), lvalue) {
AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
: ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), access) {
varScopep(varscp);
}
ASTNODE_NODE_FUNCS(VarRef)
@@ -2340,21 +2351,23 @@ public:
}
inline bool same(const AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep() && lvalue() == samep->lvalue());
return (varScopep() == samep->varScopep() && access() == samep->access());
} else {
return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name()
&& lvalue() == samep->lvalue());
&& access() == samep->access());
}
}
inline bool sameNoLvalue(AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep());
} else {
return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name());
return (hiername() == samep->hiername()
&& (hiername() != "" || samep->hiername() != "")
&& varp()->name() == samep->varp()->name());
}
}
virtual int instrCount() const override {
return widthInstrs() * (lvalue() ? 1 : instrCountLd());
return widthInstrs() * (access().isReadOrRW() ? instrCountLd() : 1);
}
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -2368,11 +2381,11 @@ private:
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
public:
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
: ASTGEN_SUPER(fl, name, nullptr, lvalue)
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
: ASTGEN_SUPER(fl, name, nullptr, access)
, m_dotted{dotted} {}
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue)
: ASTGEN_SUPER(fl, varp->name(), varp, lvalue)
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
: ASTGEN_SUPER(fl, varp->name(), varp, access)
, m_dotted{dotted} {
dtypeFrom(varp);
}
@@ -2959,7 +2972,7 @@ public:
virtual V3Hash sameHash() const override { return V3Hash(m_classOrPackagep); }
virtual void dump(std::ostream& str = std::cout) const override;
virtual string name() const override { return m_name; } // * = Var name
AstNode* classOrPackagep() const { return m_classOrPackagep; }
AstNodeModule* classOrPackagep() const { return VN_CAST(m_classOrPackagep, NodeModule); }
AstPackage* packagep() const { return VN_CAST(classOrPackagep(), Package); }
void classOrPackagep(AstNode* nodep) { m_classOrPackagep = nodep; }
AstPin* paramsp() const { return VN_CAST(op4p(), Pin); }
@@ -3065,19 +3078,72 @@ public:
void cname(const string& cname) { m_cname = cname; }
};
class AstWith : public AstNodeStmt {
class AstWithParse : public AstNodeStmt {
// In early parse, FUNC(index) WITH equation-using-index
// Replaced with AstWith
// Parents: math|stmt
// Children: funcref, math
public:
AstWith(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* argsp)
AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp)
: ASTGEN_SUPER(fl) {
statement(stmt);
setOp1p(funcrefp);
addNOp2p(argsp);
addNOp2p(exprp);
}
ASTNODE_NODE_FUNCS(With)
ASTNODE_NODE_FUNCS(WithParse)
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
//
AstNode* funcrefp() const { return op1p(); }
AstNode* exprp() const { return op2p(); }
};
class AstLambdaArgRef : public AstNodeMath {
// Lambda argument usage
// These are not AstVarRefs because we need to be able to delete/clone lambdas during
// optimizations and AstVar's are painful to remove.
private:
string m_name; // Name of variable
public:
AstLambdaArgRef(FileLine* fl, const string& name)
: ASTGEN_SUPER(fl)
, m_name{name} {}
ASTNODE_NODE_FUNCS(LambdaArgRef)
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
virtual string emitVerilog() override { return name(); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual bool hasDType() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
virtual string name() const override { return m_name; } // * = Var name
virtual void name(const string& name) override { m_name = name; }
};
class AstWith : public AstNodeStmt {
// Used as argument to method, then to AstCMethodHard
// dtypep() contains the with lambda's return dtype
// Parents: funcref (similar to AstArg)
// Children: VAR that declares the index variable
// Children: math (equation establishing the with)
public:
AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp)
: ASTGEN_SUPER(fl) {
addOp1p(argrefp);
addNOp2p(exprp);
}
ASTNODE_NODE_FUNCS(With)
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
virtual bool hasDType() const override { return true; }
virtual const char* broken() const override {
BROKEN_RTN(!argrefp()); // varp needed to know lambda's arg dtype
return nullptr;
}
//
AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); }
AstNode* exprp() const { return op2p(); }
};
//######################################################################
@@ -4593,6 +4659,93 @@ public:
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstConsAssoc : public AstNodeMath {
// Construct an assoc array and return object, '{}
// Parents: math
// Children: expression (elements or other queues)
public:
AstConsAssoc(FileLine* fl, AstNode* defaultp)
: ASTGEN_SUPER(fl) {
setNOp1p(defaultp);
}
ASTNODE_NODE_FUNCS(ConsAssoc)
virtual string emitVerilog() override { return "'{}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* defaultp() const { return op1p(); }
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstSetAssoc : public AstNodeMath {
// Set an assoc array element and return object, '{}
// Parents: math
// Children: expression (elements or other queues)
public:
AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep)
: ASTGEN_SUPER(fl) {
setOp1p(lhsp);
setNOp2p(keyp);
setOp3p(valuep);
}
ASTNODE_NODE_FUNCS(SetAssoc)
virtual string emitVerilog() override { return "'{}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); }
AstNode* keyp() const { return op2p(); }
AstNode* valuep() const { return op3p(); }
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstConsDynArray : public AstNodeMath {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// Parents: math
// Children: expression (elements or other queues)
public:
AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
: ASTGEN_SUPER(fl) {
setNOp1p(lhsp);
setNOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(ConsDynArray)
virtual string emitVerilog() override { return "'{%l, %r}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); } // op1 = expression
AstNode* rhsp() const { return op2p(); } // op2 = expression
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstConsQueue : public AstNodeMath {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// Parents: math
// Children: expression (elements or other queues)
public:
AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
: ASTGEN_SUPER(fl) {
setNOp1p(lhsp);
setNOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(ConsQueue)
virtual string emitVerilog() override { return "'{%l, %r}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); } // op1 = expression
AstNode* rhsp() const { return op2p(); } // op2 = expression
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstBegin : public AstNodeBlock {
// A Begin/end named block, only exists shortly after parsing until linking
// Parents: statement
@@ -5801,12 +5954,17 @@ public:
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
AstNode* lhsp() const { return op1p(); }
void lhsp(AstNode* nodep) { setOp1p(nodep); }
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastDynamic : public AstNodeBiop {
// Verilog $cast used as a function
// Task usage of $cast is converted during parse to assert($cast(...))
// Parents: MATH
// Children: MATH
public:
AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER(fl, lhsp, rhsp) {}
@@ -7884,7 +8042,10 @@ public:
V3ERROR_NA;
}
virtual string emitVerilog() override { return "%f$fgets(%l,%r)"; }
virtual string emitC() override { return "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; }
virtual string emitC() override {
return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)"
: "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)";
}
virtual bool cleanOut() const override { return false; }
virtual bool cleanLhs() const override { return true; }
virtual bool cleanRhs() const override { return true; }
@@ -8227,6 +8388,7 @@ public:
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
virtual int instrCount() const override { return widthInstrs() * 2; }
virtual void dump(std::ostream& str = std::cout) const override;
// op1 = expression to assign or another AstPattern (list if replicated)
AstNode* lhssp() const { return op1p(); }
AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text)
@@ -8235,6 +8397,32 @@ public:
void isDefault(bool flag) { m_default = flag; }
};
class AstImplication : public AstNodeMath {
// Verilog |-> |=>
// Parents: math
// Children: expression
public:
AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs)
: ASTGEN_SUPER(fl) {
setOp1p(lhs);
setOp2p(rhs);
}
ASTNODE_NODE_FUNCS(Implication)
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain
void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
//======================================================================
// Assertions
@@ -8461,6 +8649,7 @@ public:
m_name = name;
}
ASTNODE_BASE_FUNCS(NodeFile)
virtual void dump(std::ostream& str) const override;
virtual string name() const override { return m_name; }
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
@@ -8875,6 +9064,7 @@ class AstTypeTable : public AstNode {
// Container for hash of standard data types
// Children: NODEDTYPEs
AstVoidDType* m_voidp = nullptr;
AstQueueDType* m_queueIndexp = nullptr;
AstBasicDType* m_basicps[AstBasicDTypeKwd::_ENUM_MAX];
//
typedef std::map<VBasicTypeKey, AstBasicDType*> DetailedMap;
@@ -8889,6 +9079,7 @@ public:
AstNodeDType* typesp() const { return VN_CAST(op1p(), NodeDType); } // op1 = List of dtypes
void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); }
AstVoidDType* findVoidDType(FileLine* fl);
AstQueueDType* findQueueIndexDType(FileLine* fl);
AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd);
AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, int widthMin,
VSigning numeric);
+29 -36
View File
@@ -69,6 +69,11 @@ private:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
string dot(const string& a, const string& b) {
if (a == "") return b;
return a + "__DOT__" + b;
}
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
@@ -81,7 +86,7 @@ private:
UINFO(8, " " << nodep << endl);
// Rename it
if (m_unnamedScope != "") {
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
UINFO(8, " rename to " << nodep->name() << endl);
m_statep->userMarkChanged(nodep);
}
@@ -103,8 +108,8 @@ private:
virtual void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep << endl);
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
UINFO(8, "nname " << m_namedScope << endl);
if (nodep->name() != "") { // Else unneeded unnamed block
@@ -114,18 +119,8 @@ private:
while ((pos = dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") {
if (m_namedScope == "") {
m_namedScope = ident;
} else {
m_namedScope = m_namedScope + "__DOT__" + ident;
}
}
if (m_unnamedScope == "") {
m_unnamedScope = ident;
} else {
m_unnamedScope = m_unnamedScope + "__DOT__" + ident;
}
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(
@@ -138,31 +133,29 @@ private:
// Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp());
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
}
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstVar* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
@@ -176,7 +169,7 @@ private:
virtual void visit(AstTypedef* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
@@ -193,7 +186,7 @@ private:
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
// Rename it
nodep->name(m_namedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_namedScope, nodep->name()));
UINFO(8, " rename to " << nodep->name() << endl);
// Move to module
nodep->unlinkFrBack();
@@ -203,7 +196,7 @@ private:
}
virtual void visit(AstVarXRef* nodep) override {
UINFO(9, " VARXREF " << nodep << endl);
if (m_namedScope != "" && nodep->inlinedDots() == "") {
if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) {
nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to " << nodep << endl);
}
+1 -1
View File
@@ -275,7 +275,7 @@ private:
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstNode* nodep) override {
+4 -3
View File
@@ -111,7 +111,7 @@ void V3CCtors::evalAsserts() {
int lastWordWidth = varp->width() % storedWidth;
if (lastWordWidth != 0) {
// if (signal & CONST(upper_non_clean_mask)) { fail; }
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
AstNode* newp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
if (varp->isWide()) {
newp = new AstWordSel(
varp->fileline(), newp,
@@ -151,8 +151,9 @@ void V3CCtors::cctorsAll() {
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) {
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
var_reset.add(new AstCReset(varp->fileline(),
new AstVarRef(varp->fileline(), varp, true)));
var_reset.add(
new AstCReset(varp->fileline(),
new AstVarRef(varp->fileline(), varp, VAccess::WRITE)));
}
}
}
+21 -12
View File
@@ -41,7 +41,7 @@ private:
// MEMBERS
AstNodeModule* m_modInsertp; // Current module to insert AstCUse under
typedef std::pair<VUseType, string> UseString;
std::map<UseString, AstCUse*> m_didUse; // What we already used
std::map<const UseString, AstCUse*> m_didUse; // What we already used
// NODE STATE
// Entire netlist:
@@ -148,7 +148,7 @@ class CUseVisitor : public AstNVisitor {
funcp->isStatic(false);
funcp->protect(false);
AstNode* exprp = new AstCMath(nodep->fileline(),
"std::string(\"`{\") + to_string_middle() + \"}\"", 0);
R"(std::string("'{") + to_string_middle() + "}")", 0);
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp));
nodep->addStmtp(funcp);
@@ -162,16 +162,25 @@ class CUseVisitor : public AstNVisitor {
funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n"));
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var)) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + VL_TO_STRING(";
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
if (auto* varp = VN_CAST(itemp, Var)) {
if (!varp->isParam()) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + ";
if (itemp->isWide()) {
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
} else {
stmt += "VL_TO_STRING(";
}
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
}
}
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {
+1 -1
View File
@@ -486,7 +486,7 @@ private:
public:
// CONSTRUCTORS
explicit CaseVisitor(AstNetlist* nodep) {
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr;
for (auto& itr : m_valueItem) itr = nullptr;
iterate(nodep);
}
virtual ~CaseVisitor() override {
+4 -4
View File
@@ -73,7 +73,7 @@ private:
ensureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
}
int castSize(AstNode* nodep) {
static int castSize(AstNode* nodep) {
if (nodep->isQuad()) {
return VL_QUADSIZE;
} else if (nodep->width() <= 8) {
@@ -154,9 +154,9 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
&& castSize(nodep) != castSize(nodep->varp())) {
if (nodep->access().isReadOnly() && !VN_IS(nodep->backp(), CCast)
&& VN_IS(nodep->backp(), NodeMath) && !VN_IS(nodep->backp(), ArraySel)
&& nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
insertCast(nodep, castSize(nodep));
+6 -7
View File
@@ -311,13 +311,12 @@ private:
}
}
string spaces(int level) {
static string spaces(int level) {
string out;
while (level--) out += " ";
return out;
} // LCOV_EXCL_LINE
string pad(unsigned column, const string& in) {
static string pad(unsigned column, const string& in) {
string out = in;
while (out.length() < column) out += ' ';
return out;
@@ -588,15 +587,15 @@ private:
// Convert list of senses into one sense node
AstSenTree* senoutp = nullptr;
bool senedited = false;
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
for (const auto& itr : senouts) {
if (!senoutp) {
senoutp = *it;
senoutp = itr;
} else {
if (!senedited) {
senedited = true;
senoutp = senoutp->cloneTree(true);
}
senoutp->addSensesp((*it)->sensesp()->cloneTree(true));
senoutp->addSensesp(itr->sensesp()->cloneTree(true));
}
}
// If multiple domains need to do complicated optimizations
@@ -661,7 +660,7 @@ private:
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
// When simplify we'll take the MAX weight
if (nodep->lvalue()) {
if (nodep->access().isWriteOrRW()) {
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
if (m_inDly) {
varvertexp->fromFlop(true);
+3 -3
View File
@@ -199,9 +199,9 @@ public:
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
m_statep->m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, VAccess::READ);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::WRITE);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::READ);
}
iterate(vscp->dtypep()->skipRefp());
m_varEqnp->deleteTree();
+33 -7
View File
@@ -35,6 +35,8 @@ private:
AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep = nullptr; // Package moving scopes into
AstScope* m_packageScopep = nullptr; // Class package scope
AstNodeFTask* m_ftaskp = nullptr; // Current task
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
MoveVector m_moves;
@@ -76,12 +78,14 @@ private:
packagep->addStmtp(scopep);
// Iterate
VL_RESTORER(m_prefix);
VL_RESTORER(m_classScopep);
VL_RESTORER(m_packageScopep);
{
m_classScopep = classScopep;
m_packageScopep = scopep;
m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep);
}
m_classScopep = nullptr;
}
virtual void visit(AstPackage* nodep) override {
VL_RESTORER(m_prefix);
@@ -94,11 +98,28 @@ private:
virtual void visit(AstVar* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move class statics only
// if (m_classScopep) {
// m_moves.push_back(make_pair(nodep, m_classScopep));
//}
// TODO move class statics too
if (m_ftaskp && m_ftaskp->lifetime().isStatic()) {
m_moves.push_back(make_pair(nodep, m_packageScopep));
}
}
virtual void visit(AstVarScope* nodep) override {
iterateChildren(nodep);
nodep->varp()->user1p(nodep);
}
virtual void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_ftaskp);
{
m_ftaskp = nodep;
iterateChildren(nodep);
if (nodep->lifetime().isStatic()) {
m_moves.push_back(make_pair(nodep, m_packageScopep));
}
}
}
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
@@ -116,8 +137,13 @@ public:
// CONSTRUCTORS
explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ClassVisitor() override {
for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) {
it->second->addVarp(it->first->unlinkFrBack());
for (auto moved : m_moves) {
if (VN_IS(moved.first, NodeFTask)) {
moved.second->addActivep(moved.first->unlinkFrBack());
} else if (VN_IS(moved.first, Var)) {
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
moved.second->addVarp(scopep->unlinkFrBack());
}
}
}
};
+5
View File
@@ -285,6 +285,11 @@ private:
ensureCleanAndNext(nodep->pinsp());
setClean(nodep, true);
}
virtual void visit(AstWith* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->exprp());
setClean(nodep, true);
}
virtual void visit(AstIntfRef* nodep) override {
iterateChildren(nodep);
setClean(nodep, true); // generates a string, so not relevant
+16 -13
View File
@@ -79,15 +79,15 @@ private:
vscp->user1p(newvscp);
m_scopep->addVarp(newvscp);
// Add init
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
AstNode* newinitp = new AstAssign(
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp);
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
addToInitial(newinitp);
// At bottom, assign them
AstAssign* finalp
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
AstAssign* finalp = new AstAssign(vscp->fileline(),
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_evalFuncp->addFinalsp(finalp);
//
UINFO(4, "New Last: " << newvscp << endl);
@@ -112,25 +112,28 @@ private:
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false)));
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)),
new AstVarRef(nodep->fileline(), lastVscp, false));
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(),
VAccess::READ)),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstXor(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
new AstVarRef(nodep->fileline(), lastVscp, false));
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
newp = new AstVarRef(nodep->fileline(), clkvscp, false);
newp = new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ);
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false));
newp = new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ));
} else {
nodep->v3fatalSrc("Bad edge type");
}
+8 -8
View File
@@ -177,7 +177,7 @@ private:
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state = STATE_IDLE; // Major state
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs = 0; // Number of functions made
#ifdef VL_COMBINE_STATEMENTS
@@ -203,8 +203,8 @@ private:
}
#endif
void walkEmptyFuncs() {
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* node1p = it->second;
for (const auto& itr : m_hashed) {
AstNode* node1p = itr.second;
AstCFunc* oldfuncp = VN_CAST(node1p, CFunc);
if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) {
UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " "
@@ -330,7 +330,7 @@ private:
AstNode* last2p) { // Final node in linked list, maybe null if all statements
// to be grabbed
// Make new function
string oldname = m_funcp->name();
string oldname = m_cfuncp->name();
string::size_type pos;
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
@@ -423,7 +423,8 @@ private:
m_modp = nullptr;
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
VL_RESTORER(m_cfuncp);
m_cfuncp = nodep;
if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) {
hashStatement(nodep); // Hash the entire function - it might be identical
@@ -434,18 +435,17 @@ private:
}
#endif
}
m_funcp = nullptr;
}
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
if (m_state == STATE_HASH && m_funcp) {
if (m_state == STATE_HASH && m_cfuncp) {
hashStatement(nodep);
}
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP && m_funcp) {
else if (m_state == STATE_DUP && m_cfuncp) {
walkDupCodeStart(nodep);
}
#endif
+6 -12
View File
@@ -33,7 +33,7 @@
// cache of resolved entities. Entities stored in this container need an update
// function that takes a reference of this type to join multiple entities into one.
template <typename T> class V3ConfigWildcardResolver {
typedef std::map<string, T> Map;
typedef std::map<const string, T> Map;
Map m_mapWildcard; // Wildcard strings to entities
Map m_mapResolved; // Resolved strings to converged entities
@@ -282,15 +282,9 @@ public:
}
void update(const V3ConfigFile& file) {
// Copy in all Attributes
for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin();
it != file.m_lineAttrs.end(); ++it) {
m_lineAttrs[it->first] |= it->second;
}
for (const auto& itr : file.m_lineAttrs) { m_lineAttrs[itr.first] |= itr.second; }
// Copy in all ignores
for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end();
++it) {
m_ignLines.insert(*it);
}
for (const auto& ignLine : file.m_ignLines) m_ignLines.insert(ignLine);
// Update the iterator after the list has changed
m_lastIgnore.it = m_ignLines.begin();
m_waivers.reserve(m_waivers.size() + file.m_waivers.size());
@@ -338,9 +332,9 @@ public:
}
}
bool waive(V3ErrorCode code, const string& match) {
for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) {
if (((it->first == code) || (it->first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, it->second)) {
for (const auto& itr : m_waivers) {
if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, itr.second)) {
return true;
}
}
+32 -23
View File
@@ -314,7 +314,7 @@ private:
// It was an expression, then got constified. In reality, the WordSel
// must be wrapped in a Cond, that will be false.
return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef)
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->lvalue()
&& VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isReadOnly()
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
}
@@ -1132,18 +1132,22 @@ private:
VFlagLogicPacked(), msb2 - lsb2 + 1);
m_modp->addStmtp(temp1p);
m_modp->addStmtp(temp2p);
AstNodeAssign* asn1ap = VN_CAST(
nodep->cloneType(new AstVarRef(sel1p->fileline(), temp1p, true), sel1p),
NodeAssign);
AstNodeAssign* asn2ap = VN_CAST(
nodep->cloneType(new AstVarRef(sel2p->fileline(), temp2p, true), sel2p),
NodeAssign);
AstNodeAssign* asn1bp = VN_CAST(
nodep->cloneType(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)),
NodeAssign);
AstNodeAssign* asn2bp = VN_CAST(
nodep->cloneType(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)),
NodeAssign);
AstNodeAssign* asn1ap
= VN_CAST(nodep->cloneType(
new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p),
NodeAssign);
AstNodeAssign* asn2ap
= VN_CAST(nodep->cloneType(
new AstVarRef(sel2p->fileline(), temp2p, VAccess::WRITE), sel2p),
NodeAssign);
AstNodeAssign* asn1bp
= VN_CAST(nodep->cloneType(
lc1p, new AstVarRef(sel1p->fileline(), temp1p, VAccess::READ)),
NodeAssign);
AstNodeAssign* asn2bp
= VN_CAST(nodep->cloneType(
lc2p, new AstVarRef(sel2p->fileline(), temp2p, VAccess::READ)),
NodeAssign);
asn1ap->dtypeFrom(temp1p);
asn1bp->dtypeFrom(temp1p);
asn2ap->dtypeFrom(temp2p);
@@ -1293,17 +1297,21 @@ private:
virtual void visit(AstCFunc* nodep) override {
// No ASSIGNW removals under funcs, we've long eliminated INITIALs
// (We should perhaps rename the assignw's to just assigns)
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
VL_RESTORER(m_wremove);
{
m_wremove = false;
iterateChildren(nodep);
}
}
virtual void visit(AstScope* nodep) override {
// No ASSIGNW removals under scope, we've long eliminated INITIALs
m_scopep = nodep;
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
m_scopep = nullptr;
VL_RESTORER(m_wremove);
VL_RESTORER(m_scopep);
{
m_wremove = false;
m_scopep = nodep;
iterateChildren(nodep);
}
}
void swapSides(AstNodeBiCom* nodep) {
@@ -1601,7 +1609,7 @@ private:
// if (debug()) valuep->dumpTree(cout, " visitvaref: ");
iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep()
AstNode* valuep = nodep->varp()->valuep();
if (!nodep->lvalue()
if (nodep->access().isReadOnly()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
@@ -1933,7 +1941,8 @@ private:
ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep));
nodep->replaceWith(ifp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
} else if (false // Disabled, as vpm assertions are faster
// without due to short-circuiting
&& operandIfIf(nodep)) {
UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl);
AstNodeIf* lowerIfp = VN_CAST(nodep->ifsp(), NodeIf);
+9 -8
View File
@@ -130,8 +130,8 @@ private:
m_modp->addStmtp(varp);
UINFO(5, "New coverage trace: " << varp << endl);
AstAssign* assp = new AstAssign(
incp->fileline(), new AstVarRef(incp->fileline(), varp, true),
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, false),
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
incp->addNext(assp);
}
@@ -188,15 +188,15 @@ private:
const LinenoSet& lines = m_handleLines[state.m_handle];
int first = 0;
int last = 0;
for (LinenoSet::iterator it = lines.begin(); it != lines.end(); ++it) {
for (int linen : lines) {
if (!first) {
first = last = *it;
} else if (*it == last + 1) {
first = last = linen;
} else if (linen == last + 1) {
++last;
} else {
if (!out.empty()) out += ",";
out += linesFirstLast(first, last);
first = last = *it;
first = last = linen;
}
}
if (first) {
@@ -288,8 +288,9 @@ private:
// This is necessarily an O(n^2) expansion, which is why
// we limit coverage to signals with < 256 bits.
ToggleEnt newvec(string(""), new AstVarRef(nodep->fileline(), nodep, false),
new AstVarRef(nodep->fileline(), chgVarp, true));
ToggleEnt newvec(string(""),
new AstVarRef(nodep->fileline(), nodep, VAccess::READ),
new AstVarRef(nodep->fileline(), chgVarp, VAccess::WRITE));
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp);
newvec.cleanup();
}
+3 -4
View File
@@ -367,14 +367,13 @@ private:
void deadCheckClasses() {
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
++it) {
if (AstClass* nodep = *it) { // nullptr if deleted earlier
for (auto& itr : m_classesp) {
if (AstClass* nodep = itr) { // nullptr if deleted earlier
if (nodep->user1() == 0) {
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
if (nodep->packagep()) nodep->packagep()->user1Inc(-1);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
*it = nullptr;
itr = nullptr;
retry = true;
}
}
+35 -27
View File
@@ -95,10 +95,10 @@ private:
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
bool m_inInitial = false; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
typedef std::map<const std::pair<AstNodeModule*, string>, AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<AstVarScope*, int> ScopeVecMap;
typedef std::map<const AstVarScope*, int> ScopeVecMap;
ScopeVecMap m_scopeVecMap; // Next var number for each scope
// METHODS
@@ -228,9 +228,10 @@ private:
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp);
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
dimp);
nodep->addNextHere(bitassignp);
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ));
}
}
//
@@ -247,9 +248,10 @@ private:
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep);
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
lsbvaluep);
nodep->addNextHere(bitassignp);
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ);
}
}
//
@@ -263,8 +265,8 @@ private:
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* valvscp
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
}
//
//=== Setting/not setting boolean: __Vdlyvset__
@@ -283,11 +285,11 @@ private:
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
setinitp = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, true),
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), 0));
AstAssign* setassignp
= new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true),
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
AstAssign* setassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
nodep->addNextHere(setassignp);
}
if (m_nextDlyp) { // Tell next assigndly it can share the variable
@@ -332,9 +334,9 @@ private:
UASSERT_OBJ(postLogicp, nodep,
"Delayed assignment misoptimized; prev var found w/o associated IF");
} else {
postLogicp
= new AstIf(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, false),
nullptr, nullptr);
postLogicp = new AstIf(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, VAccess::READ),
nullptr, nullptr);
UINFO(9, " Created " << postLogicp << endl);
finalp->addBodysp(postLogicp);
finalp->user3p(setvscp); // Remember IF's vset variable
@@ -356,9 +358,11 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) override {
m_cfuncp = nodep;
iterateChildren(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
@@ -406,10 +410,11 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->lvalue()) {
if (m_inDly && nodep->access().isWriteOrRW()) {
UINFO(4, "AssignDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_DLY);
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
UASSERT_OBJ(!nodep->access().isRW(), nodep, "<= on read+write method");
if (!m_activep->hasClocked()) {
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
"have converted in V3Active");
@@ -429,16 +434,19 @@ private:
if (basicp && basicp->isEventValue()) {
// Events go to zero on next timestep unless reactivated
prep = new AstAssignPre(
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
} else {
prep = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, true),
new AstVarRef(nodep->fileline(), oldvscp, false));
prep = new AstAssignPre(
nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
}
AstNodeAssign* postp = new AstAssignPost(
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
new AstVarRef(nodep->fileline(), dlyvscp, false));
nodep->fileline(),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
postp->lhsp()->user2(true); // Don't detect this assignment
oldvscp->user1p(dlyvscp); // So we can find it later
// Make new ACTIVE with identical sensitivity tree
@@ -447,11 +455,11 @@ private:
newactp->addStmtsp(prep); // Add to FRONT of statements
newactp->addStmtsp(postp);
}
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!m_inDly && nodep->lvalue()) {
} else if (!m_inDly && nodep->access().isWriteOrRW()) {
// UINFO(9, "NBA " << nodep << endl);
if (!m_inInitial) {
UINFO(4, "AssignNDlyVar: " << nodep << endl);
+24 -20
View File
@@ -40,7 +40,7 @@ private:
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current block
AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement
int m_depth = 0; // How deep in an expression
int m_maxdepth = 0; // Maximum depth in an expression
@@ -61,14 +61,14 @@ private:
// bitmask instead of widths....)
// See t_func_crc for an example test that requires this
VFlagLogicPacked(), nodep->width());
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
m_funcp->addInitsp(varp);
UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function");
m_cfuncp->addInitsp(varp);
// Replace node tree with reference to var
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, false);
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
nodep->replaceWith(newp);
// Put assignment before the referencing statement
AstAssign* assp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true), nodep);
AstAssign* assp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep);
AstNRelinker linker2;
m_stmtp->unlinkFrBack(&linker2);
assp->addNext(m_stmtp);
@@ -81,23 +81,27 @@ private:
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_funcp = nullptr;
m_cfuncp = nullptr;
iterateChildren(nodep);
}
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
}
}
void visitStmt(AstNodeStmt* nodep) {
m_depth = 0;
m_maxdepth = 0;
m_stmtp = nodep;
iterateChildren(nodep);
m_stmtp = nullptr;
VL_RESTORER(m_stmtp);
{
m_stmtp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
}
}
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
@@ -128,10 +132,10 @@ private:
// Marking of non-static functions (because they might need "this")
// (Here instead of new visitor after V3Descope just to avoid another visitor)
void needNonStaticFunc(AstNode* nodep) {
UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function");
if (m_funcp->isStatic().trueUnknown()) {
UASSERT_OBJ(m_cfuncp, nodep, "Non-static accessor not under a function");
if (m_cfuncp->isStatic().trueUnknown()) {
UINFO(5, "Mark non-public due to " << nodep << endl);
m_funcp->isStatic(false);
m_cfuncp->isStatic(false);
}
}
virtual void visit(AstUCFunc* nodep) override {
+5 -5
View File
@@ -38,7 +38,7 @@ private:
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
int m_depth = 0; // How deep in an expression
int m_deepNum = 0; // How many functions made
@@ -49,11 +49,11 @@ private:
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
// Create function
string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum);
string name = m_cfuncp->name() + "__deep" + cvtToStr(++m_deepNum);
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr);
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->symProlog(true);
funcp->slow(m_funcp->slow());
funcp->slow(m_cfuncp->slow());
funcp->addStmtsp(nodep);
m_modp->addStmtp(funcp);
// Call it at the point where the body was removed from
@@ -78,10 +78,10 @@ private:
virtual void visit(AstCFunc* nodep) override {
// We recurse into this.
VL_RESTORER(m_depth);
VL_RESTORER(m_funcp);
VL_RESTORER(m_cfuncp);
{
m_depth = 0;
m_funcp = nodep;
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
+5 -2
View File
@@ -184,8 +184,9 @@ private:
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* newp
= new AstVarRef(portp->fileline(), portp, portp->isWritable());
AstNode* newp = new AstVarRef(portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE
: VAccess::READ);
argsp = argsp ? argsp->addNextNull(newp) : newp;
}
}
@@ -267,6 +268,8 @@ private:
// nodep->funcp()->scopep(nullptr);
}
virtual void visit(AstCFunc* nodep) override {
VL_RESTORER(m_needThis);
VL_RESTORER(m_allowThis);
if (!nodep->user1()) {
m_needThis = false;
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
+127 -50
View File
@@ -23,6 +23,7 @@
#include "V3EmitCBase.h"
#include "V3Number.h"
#include "V3PartitionGraph.h"
#include "V3Task.h"
#include "V3TSP.h"
#include <algorithm>
@@ -156,6 +157,7 @@ public:
}
void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) {
bool anyi = false;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
@@ -172,12 +174,15 @@ public:
}
} else if (varp->isString()) {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
puts("const std::string ");
puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name())
+ "(");
iterateAndNextNull(varp->valuep());
puts(")");
puts(");\n");
anyi = true;
} else {
puts("const std::string " + protect("var_" + varp->name()) + ";\n");
puts("static const std::string " + protect("var_" + varp->name())
+ ";\n");
}
} else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output
// putsDecoration("// enum ..... "+varp->nameProtect()
@@ -187,10 +192,12 @@ public:
->isOpaque()) { // Can't put out e.g. doubles
} else {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name())
+ "(");
iterateAndNextNull(varp->valuep());
puts(")");
puts(");\n");
anyi = true;
} else {
// enum
puts(varp->isQuad() ? "enum _QData" : "enum _IData");
@@ -198,13 +205,14 @@ public:
iterateAndNextNull(varp->valuep());
puts("};\n");
// var
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(varp->isQuad() ? "static const QData " : "static const IData ");
puts(protect("var_" + varp->name()) + ";\n");
}
}
}
}
}
if (anyi) puts("\n");
}
struct CmpName {
@@ -418,6 +426,18 @@ public:
UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep,
"Statement of non-void data type");
}
virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
virtual void visit(AstWith* nodep) override {
// With uses a C++11 lambda
putbs("[=](");
if (auto* argrefp = nodep->argrefp()) {
putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false));
}
// Probably fragile, V3Task may need to convert to a AstCReturn
puts(") { return ");
iterateAndNextNull(nodep->exprp());
puts("; }\n");
}
virtual void visit(AstIntfRef* nodep) override {
putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect()));
}
@@ -1225,7 +1245,6 @@ public:
nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName());
}
public:
EmitCStmts() {
m_suppressSemi = false;
m_wideTempRefp = nullptr;
@@ -1275,8 +1294,8 @@ public:
// Returns the number of elements in set_a that don't appear in set_b
static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) {
int diffs = 0;
for (MTaskIdSet::iterator it = set_a.begin(); it != set_a.end(); ++it) {
if (set_b.find(*it) == set_b.end()) ++diffs;
for (int i : set_a) {
if (set_b.find(i) == set_b.end()) ++diffs;
}
return diffs;
}
@@ -1568,6 +1587,55 @@ class EmitCImp : EmitCStmts {
}
}
virtual void visit(AstConsAssoc* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
iterateAndNextNull(nodep->defaultp());
puts(")");
}
}
virtual void visit(AstSetAssoc* nodep) override {
iterateAndNextNull(nodep->lhsp());
putbs(".set(");
iterateAndNextNull(nodep->keyp());
puts(", ");
putbs("");
iterateAndNextNull(nodep->valuep());
puts(")");
}
virtual void visit(AstConsDynArray* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
puts(")");
}
}
virtual void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
puts(")");
}
}
virtual void visit(AstChangeDet* nodep) override { //
m_blkChangeDetVec.push_back(nodep);
}
@@ -1656,19 +1724,16 @@ class EmitCImp : EmitCStmts {
} else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (initarp->defaultp()) {
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi=0;");
puts(" for (; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n");
emitSetVarConstant(varp->nameProtect() + "[__Vi]",
VN_CAST(initarp->defaultp(), Const));
puts("}}\n");
puts("}\n");
}
const AstInitArray::KeyItemMap& mapr = initarp->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end();
++it) {
AstNode* valuep = it->second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(it->first) + "]",
for (const auto& itr : mapr) {
AstNode* valuep = itr.second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]",
VN_CAST(valuep, Const));
}
} else {
@@ -1704,12 +1769,11 @@ class EmitCImp : EmitCStmts {
UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(depth);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
string pre = ("{ int " + ivar + "=" + cvtToStr(0) + ";" + " for (; " + ivar + "<"
string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<"
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1,
suffix + "[" + ivar + "]");
string post = "}}\n";
string post = "}\n";
return below.empty() ? "" : pre + below + post;
} else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) {
// String's constructor deals with it
@@ -1839,6 +1903,16 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
puts(");\n");
} else {
// strings and other fundamental c types
if (nodep->isFuncLocal() && nodep->isString()) {
const string name = nodep->name();
const string suffix = V3Task::dpiTemporaryVarSuffix();
// string temporary variable for DPI-C needs to be static because c_str() will be
// passed to C code and the lifetime of the variable must be long enough. See also
// Issue 2622.
const bool beStatic = name.size() >= suffix.size()
&& name.substr(name.size() - suffix.size()) == suffix;
if (beStatic) puts("static VL_THREAD_LOCAL ");
}
puts(nodep->vlArgType(true, false, false, prefixIfImp));
puts(";\n");
}
@@ -2161,7 +2235,12 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
}
emitDispState.pushFormat(pfmt);
if (!ignore) {
emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin()));
if (argp->dtypep()->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
// string in SystemVerilog is std::string in C++ which is not POD
emitDispState.pushArg(' ', nullptr, "-1");
} else {
emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin()));
}
emitDispState.pushArg(fmtLetter, argp, "");
} else {
emitDispState.pushArg(fmtLetter, nullptr, "");
@@ -2272,7 +2351,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, const str
//######################################################################
// Internal EmitC
void EmitCImp::emitCoverageDecl(AstNodeModule* modp) {
void EmitCImp::emitCoverageDecl(AstNodeModule*) {
if (v3Global.opt.coverage()) {
ofp()->putsPrivate(true);
putsDecoration("// Coverage\n");
@@ -2319,6 +2398,9 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) {
void EmitCImp::emitCtorImp(AstNodeModule* modp) {
puts("\n");
bool first = true;
string section;
emitParams(modp, true, &first, section /*ref*/);
if (VN_IS(modp, Class)) {
modp->v3fatalSrc("constructors should be AstCFuncs instead");
} else if (optSystemC() && modp->isTop()) {
@@ -2329,8 +2411,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
}
emitVarCtors(&first);
if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first);
string section("");
emitParams(modp, true, &first, section /*ref*/);
puts(" {\n");
emitCellCtors(modp);
emitSensitives();
@@ -2397,7 +2478,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
splitSizeInc(10);
}
void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
void EmitCImp::emitCoverageImp(AstNodeModule*) {
if (v3Global.opt.coverage()) {
puts("\n// Coverage\n");
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
@@ -2499,10 +2580,8 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)',
// so declare in sep block
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";");
puts(" for (; " + ivar + "<" + cvtToStr(arrayp->elementsConst()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0));
puts("; " + ivar + "<" + cvtToStr(arrayp->elementsConst()));
puts("; ++" + ivar + ") {\n");
elementp = arrayp->subDTypep()->skipRefp();
}
@@ -2513,14 +2592,14 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
&& !(basicp && basicp->keyword() == AstBasicDTypeKwd::STRING)) {
int vecnum = vects++;
string ivar = string("__Vi") + cvtToStr(vecnum);
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";");
puts(" for (; " + ivar + "<" + cvtToStr(elementp->widthWords()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0));
puts("; " + ivar + "<" + cvtToStr(elementp->widthWords()));
puts("; ++" + ivar + ") {\n");
}
puts("os" + op + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}}\n");
for (int v = 0; v < vects; ++v) puts("}\n");
}
}
}
@@ -2588,16 +2667,14 @@ void EmitCImp::emitSensitives() {
UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb())
+ ";");
puts(" for (; " + ivar + "<=" + cvtToStr(arrayp->msb()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb()));
puts("; " + ivar + "<=" + cvtToStr(arrayp->msb()));
puts("; ++" + ivar + ") {\n");
}
puts("sensitive << " + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}}\n");
for (int v = 0; v < vects; ++v) puts("}\n");
}
}
}
@@ -2824,8 +2901,8 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
if (!v3Global.opt.mtasks()) {
// Plain old serial mode. Sort by size, from small to large,
// to optimize for both packing and small offsets in code.
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
for (VarVec::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) {
for (const auto& itr : vmap) {
for (VarVec::const_iterator jt = itr.second.begin(); jt != itr.second.end(); ++jt) {
sortedp->push_back(*jt);
}
}
@@ -2833,7 +2910,7 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
}
// MacroTask mode. Sort by MTask-affinity group first, size second.
typedef std::map<MTaskIdSet, VarSortMap> MTaskVarSortMap;
typedef std::map<const MTaskIdSet, VarSortMap> MTaskVarSortMap;
MTaskVarSortMap m2v;
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
int size_class = it->first;
@@ -2954,7 +3031,7 @@ void EmitCImp::emitMTaskState() {
puts("bool __Vm_even_cycle;\n");
}
void EmitCImp::emitIntTop(AstNodeModule* modp) {
void EmitCImp::emitIntTop(AstNodeModule*) {
// Always have this first; gcc has short circuiting if #ifdef is first in a file
ofp()->putsGuard();
puts("\n");
@@ -3150,13 +3227,13 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n// INTERNAL METHODS\n");
if (modp->isTop()) {
ofp()->putsPrivate(true); // private:
ofp()->putsPrivate(false); // public: as accessed by another VL_MODULE
puts("static void " + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar()
+ ");\n");
if (v3Global.needTraceDumper()) {
if (!optSystemC()) puts("void _traceDump();");
puts("void _traceDumpOpen();");
puts("void _traceDumpClose();");
if (!optSystemC()) puts("void _traceDump();\n");
puts("void _traceDumpOpen();\n");
puts("void _traceDumpClose();\n");
}
}
@@ -3331,7 +3408,7 @@ class EmitCTrace : EmitCStmts {
AstUser1InUse m_inuser1;
// MEMBERS
AstCFunc* m_funcp = nullptr; // Function we're in now
AstCFunc* m_cfuncp = nullptr; // Function we're in now
bool m_slow; // Making slow file
int m_enumNum = 0; // Enumeration number (whole netlist)
int m_baseCode = -1; // Code of first AstTraceInc in this function
@@ -3663,8 +3740,9 @@ class EmitCTrace : EmitCStmts {
virtual void visit(AstNodeModule* nodep) override { iterateChildren(nodep); }
virtual void visit(AstCFunc* nodep) override {
if (nodep->slow() != m_slow) return;
VL_RESTORER(m_cfuncp);
if (nodep->funcType().isTrace()) { // TRACE_*
m_funcp = nodep;
m_cfuncp = nodep;
if (splitNeeded()) {
// Splitting file, so using parallel build.
@@ -3734,7 +3812,6 @@ class EmitCTrace : EmitCStmts {
}
puts("}\n");
}
m_funcp = nullptr;
}
virtual void visit(AstTraceDecl* nodep) override {
int enumNum = emitTraceDeclDType(nodep->dtypep());
+27 -24
View File
@@ -71,8 +71,8 @@ class CMakeEmitter {
// Swap all backslashes for forward slashes, because of Windows
static string deslash(const string& s) {
std::string res = s;
for (string::iterator it = res.begin(); it != res.end(); ++it) {
if (*it == '\\') *it = '/';
for (char& c : res) {
if (c == '\\') c = '/';
}
return res;
}
@@ -150,37 +150,37 @@ class CMakeEmitter {
}
}
global.push_back("${VERILATOR_ROOT}/include/verilated.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated.cpp");
if (v3Global.dpi()) { //
global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
}
if (v3Global.opt.vpi()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp");
}
if (v3Global.opt.savable()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_save.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_save.cpp");
}
if (v3Global.opt.coverage()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
}
if (v3Global.opt.trace()) {
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
+ "_c.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
+ "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3warn(E_UNSUPPORTED,
"Unsupported: This trace format is not supported in SystemC, "
"use VCD format.");
}
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
+ ".cpp");
global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
+ ".cpp");
}
}
if (v3Global.opt.mtasks()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
}
if (!v3Global.opt.protectLib().empty()) {
global.push_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
}
*of << "# Global classes, need linked once per executable\n";
@@ -204,15 +204,14 @@ class CMakeEmitter {
*of << "# Verilate hierarchical blocks\n";
// Sorted hierarchical blocks in order of leaf-first.
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
const string topTarget = v3Global.opt.protectLib().empty() ? v3Global.opt.prefix()
: v3Global.opt.protectLib();
*of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n";
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
it != hierBlocks.end(); ++it) {
const V3HierBlock* hblockp = *it;
const V3HierBlock::HierBlockSet& children = hblockp->children();
const string prefix = hblockp->hierPrefix();
*of << "add_library(" << prefix << " STATIC)\n";
*of << "target_link_libraries(" << topTarget << " PRIVATE " << prefix << ")\n";
*of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
if (!children.empty()) {
*of << "target_link_libraries(" << prefix << " INTERFACE";
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
@@ -223,14 +222,17 @@ class CMakeEmitter {
}
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
<< hblockp->modp()->name() << " DIRECTORY "
<< deslash("${CMAKE_CURRENT_BINARY_DIR}/" + prefix) << " SOURCES ";
<< deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES ";
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
child != children.end(); ++child) {
*of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + (*child)->hierWrapper(true));
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + (*child)->hierWrapper(true));
}
*of << " ";
const string vFile = hblockp->vFileIfNecessary();
if (!vFile.empty()) *of << vFile << " ";
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i);
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
*of << " VERILATOR_ARGS ";
*of << "-f " << deslash(hblockp->commandArgsFileName(true))
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
@@ -238,11 +240,12 @@ class CMakeEmitter {
<< ")\n";
}
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
*of << "verilate(" << topTarget << " PREFIX " << v3Global.opt.prefix()
<< " TOP_MODULE " << v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash("${CMAKE_CURRENT_BINARY_DIR}/" + topTarget + ".dir") << " SOURCES ";
for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) {
*of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + it->second->hierWrapper(true));
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
for (const auto& itr : *planp) {
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true));
}
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
*of << " VERILATOR_ARGS ";
+38 -38
View File
@@ -50,11 +50,11 @@ class EmitCSyms : EmitCBaseVisitor {
};
struct ScopeFuncData {
AstScopeName* m_scopep;
AstCFunc* m_funcp;
AstCFunc* m_cfuncp;
AstNodeModule* m_modp;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
: m_scopep{scopep}
, m_funcp{funcp}
, m_cfuncp{funcp}
, m_modp{modp} {}
};
struct ScopeVarData {
@@ -71,13 +71,13 @@ class EmitCSyms : EmitCBaseVisitor {
, m_modp{modp}
, m_scopep{scopep} {}
};
typedef std::map<string, ScopeFuncData> ScopeFuncs;
typedef std::map<string, ScopeVarData> ScopeVars;
typedef std::map<string, ScopeData> ScopeNames;
typedef std::map<const string, ScopeFuncData> ScopeFuncs;
typedef std::map<const string, ScopeVarData> ScopeVars;
typedef std::map<const string, ScopeData> ScopeNames;
typedef std::pair<AstScope*, AstNodeModule*> ScopeModPair;
typedef std::pair<AstNodeModule*, AstVar*> ModVarPair;
typedef std::vector<string> ScopeNameList;
typedef std::map<string, ScopeNameList> ScopeNameHierarchy;
typedef std::map<const string, ScopeNameList> ScopeNameHierarchy;
struct CmpName {
inline bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
return lhsp.first->name() < rhsp.first->name();
@@ -94,7 +94,7 @@ class EmitCSyms : EmitCBaseVisitor {
};
// STATE
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
AstNodeModule* m_modp = nullptr; // Current module
std::vector<ScopeModPair> m_scopes; // Every scope by module
std::vector<AstCFunc*> m_dpis; // DPI functions
@@ -296,7 +296,7 @@ class EmitCSyms : EmitCBaseVisitor {
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
nameCheck(nodep);
m_scopes.push_back(make_pair(nodep, m_modp));
m_scopes.emplace_back(make_pair(nodep, m_modp));
if (v3Global.opt.vpi() && !nodep->isTop()) {
string name_dedot = AstNode::dedotName(nodep->shortName());
@@ -316,9 +316,9 @@ class EmitCSyms : EmitCBaseVisitor {
name, ScopeData(name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER")));
}
if (nodep->dpiExport()) {
UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function");
UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function");
m_scopeFuncs.insert(
make_pair(name + " " + m_funcp->name(), ScopeFuncData(nodep, m_funcp, m_modp)));
make_pair(name + " " + m_cfuncp->name(), ScopeFuncData(nodep, m_cfuncp, m_modp)));
} else {
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
m_scopeNames.insert(
@@ -331,7 +331,7 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstVar* nodep) override {
nameCheck(nodep);
iterateChildren(nodep);
if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); }
if (nodep->isSigUserRdPublic()) { m_modVars.emplace_back(make_pair(m_modp, nodep)); }
}
virtual void visit(AstCoverDecl* nodep) override {
// Assign numbers to all bins, so we know how big of an array to use
@@ -342,9 +342,11 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstCFunc* nodep) override {
nameCheck(nodep);
if (nodep->dpiImport() || nodep->dpiExportWrapper()) m_dpis.push_back(nodep);
m_funcp = nodep;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
//---------------------------------------
@@ -395,17 +397,15 @@ void EmitCSyms::emitSymHdr() {
if (v3Global.dpi()) {
puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n");
std::map<string, int> types; // Remove duplicates and sort
for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstCFunc* funcp = it->second.m_funcp;
std::map<const string, int> types; // Remove duplicates and sort
for (const auto& itr : m_scopeFuncs) {
AstCFunc* funcp = itr.second.m_cfuncp;
if (funcp->dpiExport()) {
string cbtype = protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t");
types["typedef void (*" + cbtype + ") (" + cFuncArgs(funcp) + ");\n"] = 1;
}
}
for (std::map<string, int>::iterator it = types.begin(); it != types.end(); ++it) {
puts(it->first);
}
for (const auto& i : types) puts(i.first);
}
puts("\n// SYMS CLASS\n");
@@ -432,9 +432,9 @@ void EmitCSyms::emitSymHdr() {
puts("bool __Vm_didInit;\n");
puts("\n// SUBCELL STATE\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (VN_IS(modp, Class)) continue;
if (modp->isTop()) {
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str());
@@ -455,8 +455,8 @@ void EmitCSyms::emitSymHdr() {
if (!m_scopeNames.empty()) { // Scope names
puts("\n// SCOPE NAMES\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
puts("VerilatedScope " + protect("__Vscope_" + it->second.m_symName) + ";\n");
for (const auto& itr : m_scopeNames) {
puts("VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n");
}
}
@@ -469,9 +469,9 @@ void EmitCSyms::emitSymHdr() {
puts(symClassName() + "(" + topClassName() + "* topp, const char* namep);\n");
puts(string("~") + symClassName() + "() {}\n");
for (std::map<int, bool>::iterator it = m_usesVfinal.begin(); it != m_usesVfinal.end(); ++it) {
puts("void " + symClassName() + "_" + cvtToStr(it->first) + "(");
if (it->second) {
for (const auto& i : m_usesVfinal) {
puts("void " + symClassName() + "_" + cvtToStr(i.first) + "(");
if (i.second) {
puts("int __Vfinal");
} else {
puts(topClassName() + "* topp");
@@ -619,9 +619,9 @@ void EmitCSyms::emitSymImp() {
puts(" , __Vm_didInit(false)\n");
puts(" // Setup submodule names\n");
char comma = ',';
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (modp->isTop()) {
} else {
puts(string(" ") + comma + " " + protect(scopep->nameDotless()));
@@ -638,9 +638,9 @@ void EmitCSyms::emitSymImp() {
puts("// Pointer to top level\n");
puts("TOPp = topp;\n");
puts("// Setup each module's pointers to their submodules\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (!modp->isTop()) {
checkSplit(false);
string arrow = scopep->name();
@@ -656,9 +656,9 @@ void EmitCSyms::emitSymImp() {
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
puts("TOPp->" + protect("__Vconfigure") + "(this, true);\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (!modp->isTop()) {
checkSplit(false);
// first is used by AstCoverDecl's call to __vlCoverInsert
@@ -723,7 +723,7 @@ void EmitCSyms::emitSymImp() {
m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstScopeName* scopep = it->second.m_scopep;
AstCFunc* funcp = it->second.m_funcp;
AstCFunc* funcp = it->second.m_cfuncp;
AstNodeModule* modp = it->second.m_modp;
if (funcp->dpiExport()) {
checkSplit(true);
+5 -5
View File
@@ -65,6 +65,10 @@ public:
of.puts("VM_TRACE = ");
of.puts(v3Global.opt.trace() ? "1" : "0");
of.puts("\n");
of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n");
of.puts("VM_TRACE_FST = ");
of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0");
of.puts("\n");
of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n");
of.puts("VM_TRACE_THREADS = ");
of.puts(cvtToStr(v3Global.opt.trueTraceThreads()));
@@ -277,7 +281,6 @@ public:
of.putsHeader();
}
public:
explicit EmitMk() {
emitClassMake();
emitOverallMake();
@@ -359,10 +362,7 @@ class EmitMkHierVerilation {
of.puts(v3Global.opt.prefix()
+ ".mk: $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
of.puts(V3Os::filenameNonDir(argsFile) + " ");
for (V3HierBlockPlan::const_iterator it = m_planp->begin(); it != m_planp->end();
++it) {
of.puts(it->second->hierWrapper(true) + " ");
}
for (const auto& itr : *m_planp) of.puts(itr.second->hierWrapper(true) + " ");
of.puts("\n");
emitLaunchVerilator(of, argsFile);
}
+43 -29
View File
@@ -31,6 +31,7 @@
class EmitVBaseVisitor : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi = false;
bool m_suppressUnknown = false;
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
// METHODS
@@ -51,12 +52,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); }
virtual void visit(AstNodeModule* nodep) override {
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
iterateChildren(nodep);
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
}
virtual void visit(AstPort* nodep) override {}
virtual void visit(AstNodeFTask* nodep) override {
putfs(nodep, nodep->isFunction() ? "function" : "task");
puts(" ");
@@ -212,14 +214,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
AstNode* exprsp) {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (fileOrStrgp) {
iterateAndNextNull(fileOrStrgp);
putbs(",");
putbs(", ");
}
putsQuoted(text);
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
puts(",");
puts(", ");
iterateAndNextNull(expp);
}
puts(");\n");
@@ -247,7 +249,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, nodep->verilogKwd());
putbs("(");
iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->modep());
puts(");\n");
}
@@ -259,13 +261,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstFClose* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstFFlush* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
@@ -282,16 +284,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstNodeReadWriteMem* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
if (nodep->memp()) iterateAndNextNull(nodep->memp());
if (nodep->lsbp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->lsbp());
}
if (nodep->msbp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->msbp());
}
puts(");\n");
@@ -302,7 +304,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstSysIgnore* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
iterateAndNextNull(nodep->exprsp());
puts(");\n");
}
@@ -358,7 +360,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$past(");
iterateAndNextNull(nodep->exprp());
if (nodep->ticksp()) {
puts(",");
puts(", ");
iterateAndNextNull(nodep->ticksp());
}
puts(")");
@@ -482,20 +484,20 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$_ATTROF(");
iterateAndNextNull(nodep->fromp());
if (nodep->dimp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->dimp());
}
puts(")");
}
virtual void visit(AstInitArray* nodep) override {
putfs(nodep, "`{");
putfs(nodep, "'{");
int comma = 0;
const AstInitArray::KeyItemMap& mapr = nodep->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
for (const auto& itr : mapr) {
if (comma++) putbs(", ");
puts(cvtToStr(it->first));
puts(cvtToStr(itr.first));
puts(":");
AstNode* valuep = it->second->valuep();
AstNode* valuep = itr.second->valuep();
iterate(valuep);
}
puts("}");
@@ -654,13 +656,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
iterateChildren(nodep);
// Not v3fatalSrc so we keep processing
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
if (!m_suppressUnknown) {
nodep->v3error(
"Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
}
}
public:
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(AstSenTree* domainp = nullptr)
: m_sensesp{domainp} {}
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
: m_suppressUnknown{suppressUnknown}
, m_sensesp{domainp} {}
virtual ~EmitVBaseVisitor() override {}
};
@@ -679,8 +685,9 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
bool suppressVarSemi = false) {
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressVarSemi,
bool suppressUnknown)
: EmitVBaseVisitor{suppressUnknown, nullptr} {
m_ofp = ofp;
m_trackText = trackText;
m_suppressVarSemi = suppressVarSemi;
@@ -704,7 +711,8 @@ class EmitVStreamVisitor : public EmitVBaseVisitor {
public:
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
: m_os(os) { // Need () or GCC 4.8 false warning
: EmitVBaseVisitor{false, nullptr}
, m_os(os) { // Need () or GCC 4.8 false warning
iterate(nodep);
}
virtual ~EmitVStreamVisitor() override {}
@@ -747,9 +755,8 @@ public:
, m_prefix{prefix}
, m_flWidth{flWidth} {
m_column = 0;
m_prefixFl
= v3Global.rootp()
->fileline(); // NETLIST's fileline instead of nullptr to avoid nullptr checks
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
// avoid nullptr checks
}
virtual ~EmitVPrefixedFormatter() override {
if (m_column) puts("\n");
@@ -780,7 +787,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor{domainp}
: EmitVBaseVisitor{false, domainp}
, m_formatter{os, prefix, flWidth} {
if (user3mark) { AstUser3InUse::check(); }
iterate(nodep);
@@ -807,7 +814,14 @@ void V3EmitV::emitvFiles() {
V3OutVFile of(vfilep->name());
of.puts("// DESCR"
"IPTION: Verilator generated Verilog\n");
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true, false);
}
}
}
void V3EmitV::debugEmitV(const string& stage) {
UINFO(2, __FUNCTION__ << ": " << endl);
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
V3OutVFile of(filename);
EmitVFileVisitor visitor(v3Global.rootp(), &of, true, false, true);
}
+1
View File
@@ -31,6 +31,7 @@ public:
static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
int flWidth, AstSenTree* domainp, bool user3mark);
static void emitvFiles();
static void debugEmitV(const string& stage);
};
#endif // Guard
+1 -1
View File
@@ -94,7 +94,7 @@ private:
void fixCloneLvalue(AstNode* nodep) {
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
// but are now being used on the RHS of the assignment
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->lvalue(false);
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ);
// Iterate
if (nodep->op1p()) fixCloneLvalue(nodep->op1p());
if (nodep->op2p()) fixCloneLvalue(nodep->op2p());
+10 -11
View File
@@ -172,9 +172,8 @@ inline void V3FileDependImp::writeDepend(const string& filename) {
inline std::vector<string> V3FileDependImp::getAllDeps() const {
std::vector<string> r;
for (std::set<DependFile>::const_iterator iter = m_filenameList.begin();
iter != m_filenameList.end(); ++iter) {
if (!iter->target() && iter->exists()) { r.push_back(iter->filename()); }
for (const auto& itr : m_filenameList) {
if (!itr.target() && itr.exists()) r.push_back(itr.filename());
}
return r;
}
@@ -331,7 +330,7 @@ void V3File::createMakeDir() {
// VInFilterImp
class VInFilterImp {
typedef std::map<string, string> FileContentsMap;
typedef std::map<const string, string> FileContentsMap;
typedef VInFilter::StrList StrList;
FileContentsMap m_contentsMap; // Cache of file contents
@@ -587,12 +586,12 @@ protected:
}
return true;
}
size_t listSize(StrList& sl) {
static size_t listSize(StrList& sl) {
size_t out = 0;
for (const string& i : sl) out += i.length();
return out;
}
string listString(StrList& sl) {
static string listString(StrList& sl) {
string out;
for (const string& i : sl) out += i;
return out;
@@ -942,8 +941,8 @@ void V3OutCFile::putsGuard() {
UASSERT(!m_guard, "Already called putsGuard in emit file");
m_guard = true;
string var = VString::upcase(string("_") + V3Os::filenameNonDir(filename()) + "_");
for (string::iterator pos = var.begin(); pos != var.end(); ++pos) {
if (!isalnum(*pos)) *pos = '_';
for (char& c : var) {
if (!isalnum(c)) c = '_';
}
puts("\n#ifndef " + var + "\n");
puts("#define " + var + " // guard\n");
@@ -954,7 +953,7 @@ void V3OutCFile::putsGuard() {
class VIdProtectImp {
// MEMBERS
typedef std::map<string, string> IdMap;
typedef std::map<const string, string> IdMap;
IdMap m_nameMap; // Map of old name into new name
typedef std::unordered_set<std::string> IdSet;
IdSet m_newIdSet; // Which new names exist
@@ -1046,8 +1045,8 @@ public:
"IPTION: Verilator output: XML representation of netlist -->\n");
of.puts("<verilator_id_map>\n");
{
for (IdMap::const_iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it) {
of.puts("<map from=\"" + it->second + "\" to=\"" + it->first + "\"/>\n");
for (const auto& itr : m_nameMap) {
of.puts("<map from=\"" + itr.second + "\" to=\"" + itr.first + "\"/>\n");
}
}
of.puts("</verilator_id_map>\n");
+3 -3
View File
@@ -90,8 +90,8 @@ int VFileContent::debug() {
void VFileContent::pushText(const string& text) {
if (m_lines.size() == 0) {
m_lines.push_back(""); // no such thing as line [0]
m_lines.push_back(""); // start with no leftover
m_lines.emplace_back(""); // no such thing as line [0]
m_lines.emplace_back(""); // start with no leftover
}
// Any leftover text is stored on largest line (might be "")
@@ -112,7 +112,7 @@ void VFileContent::pushText(const string& text) {
}
}
// Keep leftover for next time
m_lines.push_back(string(leftover, line_start)); // Might be ""
m_lines.emplace_back(string(leftover, line_start)); // Might be ""
}
string VFileContent::getLine(int lineno) const {
+1 -1
View File
@@ -39,7 +39,7 @@ class FileLine;
//! source file (each with its own unique filename number).
class FileLineSingleton {
// TYPES
typedef std::map<string, int> FileNameNumMap;
typedef std::map<const string, int> FileNameNumMap;
// MEMBERS
FileNameNumMap m_namemap; // filenameno for each filename
std::deque<string> m_names; // filename text for each filenameno
+19 -18
View File
@@ -220,7 +220,9 @@ private:
if (nodep->varScopep()->varp()->isSc()) {
clearSimple("SystemC sig"); // Don't want to eliminate the VL_ASSIGN_SI's
}
if (nodep->lvalue()) {
if (nodep->access().isRW()) {
clearSimple("R/W");
} else if (nodep->access().isWriteOrRW()) {
if (m_lhsVarRef) clearSimple(">1 lhs varRefs");
m_lhsVarRef = nodep;
} else {
@@ -448,7 +450,7 @@ private:
vvertexp->setIsClock();
// For SYNCASYNCNET
varscp->user2(true);
} else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) {
} else if (m_activep && m_activep->hasClocked() && nodep->access().isReadOnly()) {
if (varscp->user2()) {
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
} else {
@@ -457,9 +459,10 @@ private:
}
// We use weight of one; if we ref the var more than once, when we simplify,
// the weight will increase
if (nodep->lvalue()) {
if (nodep->access().isWriteOrRW()) {
new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1);
} else {
}
if (nodep->access().isReadOrRW()) {
new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1);
}
}
@@ -525,10 +528,7 @@ private:
public:
// CONSTRUCTORS
explicit GateVisitor(AstNode* nodep) {
AstNode::user1ClearTree();
iterate(nodep);
}
explicit GateVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~GateVisitor() override {
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
@@ -603,7 +603,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
<< " ob" << vvertexp->outBeginp() << " on"
<< (vvertexp->outBeginp()
? vvertexp->outBeginp()->outNextp()
: 0)
: nullptr)
<< " " << vvertexp->name() << endl);
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
@@ -845,7 +845,7 @@ private:
// It's possible we substitute into something that will be reduced more later,
// however, as we never delete the top Always/initial statement, all should be well.
m_didReplace = true;
UASSERT_OBJ(!nodep->lvalue(), nodep,
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
"Can't replace lvalue assignments with const var");
AstNode* substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(
@@ -859,7 +859,8 @@ private:
// to throw warnings that point to a PIN rather than where the pin us used.
if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline());
// Make the substp an rvalue like nodep. This facilitates the hashing in dedupe.
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false);
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef))
varrefp->access(VAccess::READ);
hashReplace(nodep, substp);
nodep->replaceWith(substp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@@ -939,7 +940,7 @@ private:
public:
GateDedupeHash() {}
~GateDedupeHash() {
virtual ~GateDedupeHash() override {
if (v3Global.opt.debugCheck()) check();
}
@@ -965,7 +966,7 @@ public:
}
// Callback from V3Hashed::findDuplicate
bool isSame(AstNode* node1p, AstNode* node2p) {
virtual bool isSame(AstNode* node1p, AstNode* node2p) override {
// Assignment may have been hashReplaced, if so consider non-match (effectively removed)
if (isReplaced(node1p) || isReplaced(node2p)) {
// UINFO(9, "isSame hit on replaced "<<(void*)node1p<<" "<<(void*)node2p<<endl);
@@ -1001,8 +1002,8 @@ public:
void check() {
m_hashed.check();
for (V3Hashed::HashMmap::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* nodep = it->second;
for (const auto& itr : m_hashed) {
AstNode* nodep = itr.second;
AstNode* activep = nodep->user3p();
AstNode* condVarp = nodep->user5p();
if (!isReplaced(nodep)) {
@@ -1086,7 +1087,7 @@ private:
public:
// CONSTRUCTORS
GateDedupeVarVisitor() {}
~GateDedupeVarVisitor() {}
virtual ~GateDedupeVarVisitor() override {}
// PUBLIC METHODS
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
m_assignp = nullptr;
@@ -1348,7 +1349,7 @@ private:
}
return VNUser(0);
}
virtual VNUser visit(GateLogicVertex*, VNUser vu) override { //
virtual VNUser visit(GateLogicVertex*, VNUser) override { //
return VNUser(0);
}
@@ -1514,7 +1515,7 @@ private:
UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl);
UINFO(9, " to - " << m_clk_vsp << endl);
AstNode* rhsp = assignp->rhsp();
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ));
while (V3GraphEdge* edgep = lvertexp->inBeginp()) {
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
+5 -6
View File
@@ -67,9 +67,9 @@ private:
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
m_scopetopp->addVarp(newvscp);
AstAssign* asninitp
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
AstAssign* asninitp = new AstAssign(
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_scopetopp->addFinalClkp(asninitp);
//
vscp->user2p(newvscp);
@@ -98,7 +98,7 @@ private:
UINFO(8, " VarActReplace " << nodep << endl);
// Replace with the new variable
AstVarScope* newvscp = genInpClk(vscp);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
@@ -111,7 +111,6 @@ private:
m_activep = nullptr;
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); }
//-----
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
@@ -186,7 +185,7 @@ private:
UINFO(8, " VarAct " << nodep << endl);
vscp->user1(true);
}
if (m_assignp && nodep->lvalue() && vscp->user1()) {
if (m_assignp && nodep->access().isWriteOrRW() && vscp->user1()) {
// Variable was previously used as a clock, and is now being set
// Thus a unordered generated clock...
UINFO(8, " VarSetAct " << nodep << endl);
+6
View File
@@ -35,6 +35,12 @@ AstNetlist* V3Global::makeNetlist() {
return newp;
}
void V3Global::clear() {
#ifdef VL_LEAK_CHECK
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
#endif
}
void V3Global::shutdown() {
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
}
+1
View File
@@ -119,6 +119,7 @@ public:
UASSERT(!m_rootp, "call once");
m_rootp = makeNetlist();
}
void clear();
void shutdown(); // Release allocated resorces
// ACCESSORS (general)
AstNetlist* rootp() const { return m_rootp; }
+1 -1
View File
@@ -335,7 +335,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
// We use a map here, as we don't want to corrupt anything (userp) in the graph,
// and we don't care if this is slow.
std::map<V3GraphVertex*, int> numMap;
std::map<const V3GraphVertex*, int> numMap;
// Print vertices
int n = 0;
+2 -5
View File
@@ -143,9 +143,7 @@ private:
}
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(toEdgep->userp());
if (OrigEdgeList* addListp = static_cast<OrigEdgeList*>(addEdgep->userp())) {
for (OrigEdgeList::iterator it = addListp->begin(); it != addListp->end(); ++it) {
oEListp->push_back(*it);
}
for (const auto& itr : *addListp) oEListp->push_back(itr);
addListp->clear(); // Done with it
} else {
oEListp->push_back(addEdgep);
@@ -160,8 +158,7 @@ private:
v3fatalSrc("No original edge associated with cutting edge " << breakEdgep << endl);
}
// The breakGraph edge may represent multiple real edges; cut them all
for (OrigEdgeList::iterator it = oEListp->begin(); it != oEListp->end(); ++it) {
V3GraphEdge* origEdgep = *it;
for (const auto& origEdgep : *oEListp) {
origEdgep->cut();
UINFO(8,
" " << why << " " << origEdgep->fromp() << " ->" << origEdgep->top() << endl);
+4 -5
View File
@@ -73,8 +73,8 @@ private:
// METHODS
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; }
// bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; }
static bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; }
// static bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; }
void nextStep() { m_step++; }
@@ -317,9 +317,8 @@ private:
}
// Foreach input state (NFA inputs of this DFA state)
for (std::set<int>::const_iterator inIt = inputs.begin(); inIt != inputs.end();
++inIt) {
DfaInput input = *inIt;
for (int inIt : inputs) {
DfaInput input = inIt;
UINFO(9, " ===" << ++i << "=======================\n");
UINFO(9, " On input " << cvtToHex(input.toNodep()) << endl);
+1 -1
View File
@@ -42,7 +42,7 @@ struct GraphPCNode {
// CONSTRUCTORS
GraphPCNode() {
for (int w = 0; w < GraphWay::NUM_WAYS; w++) m_cp[w] = 0;
for (unsigned int& w : m_cp) w = 0;
}
~GraphPCNode() {}
};
+10 -11
View File
@@ -139,8 +139,8 @@ void V3Hashed::erase(iterator it) {
}
void V3Hashed::check() {
for (HashMmap::iterator it = begin(); it != end(); ++it) {
AstNode* nodep = it->second;
for (const auto& itr : *this) {
AstNode* nodep = itr.second;
UASSERT_OBJ(nodep->user4p(), nodep, "V3Hashed check failed, non-hashed node");
}
}
@@ -174,21 +174,20 @@ void V3Hashed::dumpFile(const string& filename, bool tree) {
}
*logp << "\n*** STATS:\n" << endl;
*logp << " #InBucket Occurrences\n";
for (std::map<int, int>::iterator it = dist.begin(); it != dist.end(); ++it) {
*logp << " " << std::setw(9) << it->first << " " << std::setw(12) << it->second
<< endl;
for (const auto& i : dist) {
*logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << endl;
}
*logp << "\n*** Dump:\n" << endl;
for (HashMmap::iterator it = begin(); it != end(); ++it) {
if (lasthash != it->first) {
lasthash = it->first;
*logp << " " << it->first << endl;
for (const auto& itr : *this) {
if (lasthash != itr.first) {
lasthash = itr.first;
*logp << " " << itr.first << endl;
}
*logp << "\t" << it->second << endl;
*logp << "\t" << itr.second << endl;
// Dumping the entire tree may make nearly N^2 sized dumps,
// because the nodes under this one may also be in the hash table!
if (tree) it->second->dumpTree(*logp, " ");
if (tree) itr.second->dumpTree(*logp, " ");
}
}
+3 -2
View File
@@ -75,8 +75,9 @@ public:
void check(); // Check assertions on structure
// Hash the node, and insert into map. Return iterator to inserted
iterator hashAndInsert(AstNode* nodep);
void hash(AstNode* nodep); // Only hash the node
bool sameNodes(AstNode* node1p, AstNode* node2p); // After hashing, and tell if identical
static void hash(AstNode* nodep); // Only hash the node
// After hashing, and tell if identical
static bool sameNodes(AstNode* node1p, AstNode* node2p);
void erase(iterator it); // Remove node from structures
// Return duplicate in hash, if any, with optional user check for sameness
iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = nullptr);
+35 -20
View File
@@ -80,6 +80,7 @@
#include "V3Error.h"
#include "V3File.h"
#include "V3HierBlock.h"
#include "V3Os.h"
#include "V3String.h"
#include "V3Stats.h"
@@ -88,22 +89,26 @@ static string V3HierCommandArgsFileName(const string& prefix, bool forCMake) {
+ (forCMake ? "_hierCMakeArgs.f" : "_hierMkArgs.f");
}
static void V3HierWriteCommonInputs(std::ostream* of, bool forCMake) {
static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of, bool forCMake) {
string topModuleFile;
if (hblockp) topModuleFile = hblockp->vFileIfNecessary();
if (!forCMake) {
if (!topModuleFile.empty()) *of << topModuleFile << "\n";
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles) *of << i << "\n";
}
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
for (const string& i : libraryFiles) *of << "-v " << i << "\n";
for (const string& i : libraryFiles) {
if (V3Os::filenameRealPath(i) != topModuleFile) *of << "-v " << i << "\n";
}
}
//######################################################################
V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, bool forGOption) {
StrGParams strParams;
for (V3HierBlock::GParams::const_iterator gparamIt = gparams.begin();
gparamIt != gparams.end(); ++gparamIt) {
if (const AstConst* constp = VN_CAST((*gparamIt)->valuep(), Const)) {
for (const auto& gparam : gparams) {
if (const AstConst* constp = VN_CAST(gparam->valuep(), Const)) {
string s;
// Only constant parameter needs to be set to -G because already checked in
// V3Param.cpp. See also ParamVisitor::checkSupportedParam() in the file.
@@ -125,7 +130,7 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, boo
s = constp->num().ascii(true, true);
s = VString::quoteAny(s, '\'', '\\');
}
strParams.push_back(std::make_pair((*gparamIt)->name(), s));
strParams.push_back(std::make_pair(gparam->name(), s));
}
}
return strParams;
@@ -133,9 +138,8 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, boo
V3HierBlock::~V3HierBlock() {
UASSERT(m_children.empty(), "at least one module must be a leaf");
for (HierBlockSet::const_iterator child = m_children.begin(); child != m_children.end();
++child) {
const bool deleted = (*child)->m_children.erase(this);
for (const auto& hierblockp : m_children) {
const bool deleted = hierblockp->m_children.erase(this);
UASSERT_OBJ(deleted, m_modp, " is not registered");
}
}
@@ -194,25 +198,33 @@ string V3HierBlock::hierGenerated(bool withDir) const {
return hierWrapper(withDir) + ' ' + hierMk(withDir);
}
string V3HierBlock::vFileIfNecessary() const {
const string filename = V3Os::filenameRealPath(m_modp->fileline()->filename());
for (const string& v : v3Global.opt.vFiles()) {
// Already listed in vFiles, so no need to add the file.
if (filename == V3Os::filenameRealPath(v)) return "";
}
return filename;
}
void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
std::unique_ptr<std::ofstream> of(V3File::new_ofstream(commandArgsFileName(forCMake)));
*of << "--cc\n";
if (!forCMake) {
for (V3HierBlock::HierBlockSet::const_iterator child = m_children.begin();
child != m_children.end(); ++child) {
*of << v3Global.opt.makeDir() << "/" << (*child)->hierWrapper(true) << "\n";
for (const auto& hierblockp : m_children) {
*of << v3Global.opt.makeDir() << "/" << hierblockp->hierWrapper(true) << "\n";
}
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
}
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
V3HierWriteCommonInputs(of.get(), forCMake);
V3HierWriteCommonInputs(this, of.get(), forCMake);
const V3StringList& commandOpts = commandArgs(false);
for (const string& opt : commandOpts) *of << opt << "\n";
*of << hierBlockArgs().front() << "\n";
for (HierBlockSet::const_iterator child = m_children.begin(); child != m_children.end();
++child) {
*of << (*child)->hierBlockArgs().front() << "\n";
}
for (const auto& hierblockp : m_children) *of << hierblockp->hierBlockArgs().front() << "\n";
// Hierarchical blocks should not use multi-threading,
// but needs to be thread safe when top is multi-threaded.
if (v3Global.opt.threads() > 0) { *of << "--threads 1\n"; }
*of << v3Global.opt.allArgsStringForHierBlock(false) << "\n";
}
@@ -394,7 +406,7 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
*of << it->second->hierWrapper(true) << "\n";
}
}
V3HierWriteCommonInputs(of.get(), forCMake);
V3HierWriteCommonInputs(nullptr, of.get(), forCMake);
if (!forCMake) {
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
for (const string& i : cppFiles) *of << i << "\n";
@@ -411,10 +423,13 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
*of << "--protect-lib " << v3Global.opt.protectLib() << "\n";
*of << "--protect-key " << v3Global.opt.protectKeyDefaulted() << "\n";
}
if (v3Global.opt.threads() > 0) {
*of << "--threads " << cvtToStr(v3Global.opt.threads()) << "\n";
}
*of << (v3Global.opt.systemC() ? "--sc" : "--cc") << "\n";
*of << v3Global.opt.allArgsStringForHierBlock(true) << "\n";
}
string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) const {
string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) {
return V3HierCommandArgsFileName(v3Global.opt.prefix(), forCMake);
}
+3 -1
View File
@@ -85,6 +85,8 @@ public:
string hierMk(bool withDir) const;
string hierLib(bool withDir) const;
string hierGenerated(bool withDir) const;
// Returns the original HDL file if it is not included in v3Global.opt.vFiles().
string vFileIfNecessary() const;
// Write command line argumuents to .f file for this hierarchical block
void writeCommandArgsFile(bool forCMake) const;
string commandArgsFileName(bool forCMake) const;
@@ -120,7 +122,7 @@ public:
// Write command line arguments to .f files for child Verilation run
void writeCommandArgsFiles(bool forCMake) const;
string topCommandArgsFileName(bool forCMake) const;
static string topCommandArgsFileName(bool forCMake);
static void createPlan(AstNetlist* nodep);
};
+14 -12
View File
@@ -313,9 +313,9 @@ private:
UASSERT_OBJ(exprconstp || exprvarrefp, nodep,
"Unknown interconnect type; pinReconnectSimple should have cleared up");
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
exprconstp->cloneTree(true)));
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
exprconstp->cloneTree(true)));
} else if (nodep->user3()) {
// Public variable at the lower module end - we need to make sure we propagate
// the logic changes up and down; if we aliased, we might
@@ -323,20 +323,22 @@ private:
UINFO(9, "public pin assign: " << exprvarrefp << endl);
UASSERT_OBJ(!nodep->isNonOutput(), nodep, "Outputs only - inputs use AssignAlias");
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE),
new AstVarRef(nodep->fileline(), nodep, VAccess::READ)));
} else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) {
// Public variable at this end and it is an unpacked array. We need to assign
// instead of aliased, because otherwise it will pass V3Slice and invalid
// code will be emitted.
UINFO(9, "assign to public and unpacked: " << nodep << endl);
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE),
new AstVarRef(nodep->fileline(), nodep, VAccess::READ)));
} else if (nodep->isIfaceRef()) {
m_modp->addStmtp(new AstAssignVarScope(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ)));
AstNode* nodebp = exprvarrefp->varp();
nodep->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep->fileline());
@@ -344,8 +346,8 @@ private:
// Do to inlining child's variable now within the same
// module, so a AstVarRef not AstVarXRef below
m_modp->addStmtp(new AstAssignAlias(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ)));
AstNode* nodebp = exprvarrefp->varp();
nodep->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep->fileline());
@@ -415,7 +417,7 @@ private:
// Track what scope it was originally under so V3LinkDot can resolve it
string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots());
nodep->inlinedDots(newdots);
for (string tryname = nodep->dotted(); 1;) {
for (string tryname = nodep->dotted(); true;) {
if (m_renamedInterfaces.count(tryname)) {
nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted());
break;
+27 -24
View File
@@ -76,17 +76,17 @@ private:
if (nodep->modVarp()->isInoutish()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isWritable()) {
AstNode* rhsp
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstNode* rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
m_cellp->name(), VAccess::READ);
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
m_cellp->addNextHere(assp);
} else if (nodep->modVarp()->isNonOutput()) {
// Don't bother moving constants now,
// we'll be pushing the const down to the cell soon enough.
AstNode* assp = new AstAssignW(
exprp->fileline(),
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
exprp);
AstNode* assp = new AstAssignW(exprp->fileline(),
new AstVarXRef(exprp->fileline(), nodep->modVarp(),
m_cellp->name(), VAccess::WRITE),
exprp);
m_cellp->addNextHere(assp);
if (debug() >= 9) assp->dumpTree(cout, " _new: ");
} else if (nodep->modVarp()->isIfaceRef()
@@ -96,8 +96,8 @@ private:
IfaceRefDType))) {
// Create an AstAssignVarScope for Vars to Cells so we can
// link with their scope later
AstNode* lhsp
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstNode* lhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
m_cellp->name(), VAccess::READ);
const AstVarRef* refp = VN_CAST(exprp, VarRef);
const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef);
UASSERT_OBJ(refp || xrefp, exprp,
@@ -141,7 +141,7 @@ class InstDeModVarVisitor : public AstNVisitor {
// Expand all module variables, and save names for later reference
private:
// STATE
typedef std::map<string, AstVar*> VarNameMap;
typedef std::map<const string, AstVar*> VarNameMap;
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
VL_DEBUG_FUNC; // Declare debug()
@@ -172,13 +172,11 @@ public:
}
}
void dump() {
for (VarNameMap::iterator it = m_modVarNameMap.begin(); it != m_modVarNameMap.end();
++it) {
cout << "-namemap: " << it->first << " -> " << it->second << endl;
for (const auto& itr : m_modVarNameMap) {
cout << "-namemap: " << itr.first << " -> " << itr.second << endl;
}
}
public:
// CONSTRUCTORS
explicit InstDeModVarVisitor() {}
void main(AstNodeModule* nodep) {
@@ -195,8 +193,8 @@ class InstDeVisitor : public AstNVisitor {
// Find all cells with arrays, and convert to non-arrayed
private:
// STATE
AstRange* m_cellRangep
= nullptr; // Range for arrayed instantiations, nullptr for normal instantiations
// Range for arrayed instantiations, nullptr for normal instantiations
AstRange* m_cellRangep = nullptr;
int m_instSelNum = 0; // Current instantiation count 0..N-1
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
@@ -278,8 +276,7 @@ private:
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
origIfaceRefp->cellp(nullptr);
AstVar* varNewp = ifaceVarp->cloneTree(false);
AstIfaceRefDType* ifaceRefp
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
AstIfaceRefDType* ifaceRefp = origIfaceRefp->cloneTree(false);
arrdtype->addNextHere(ifaceRefp);
ifaceRefp->cellp(newp);
ifaceRefp->cellName(newp->name());
@@ -378,9 +375,13 @@ private:
return;
}
string index = AstNode::encodeNumber(constp->toSInt());
if (VN_IS(arrselp->lhsp(), SliceSel))
arrselp->lhsp()->v3error("Unsupported: interface slices");
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
AstVarXRef* newp = new AstVarXRef(
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true);
UASSERT_OBJ(varrefp, arrselp, "No interface varref under array");
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
varrefp->name() + "__BRA__" + index + "__KET__",
"", VAccess::WRITE);
newp->dtypep(nodep->modVarp()->dtypep());
newp->packagep(varrefp->packagep());
arrselp->addNextHere(newp);
@@ -438,7 +439,8 @@ private:
}
if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); }
string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__";
AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true);
AstVarXRef* newVarXRefp
= new AstVarXRef(nodep->fileline(), newname, "", VAccess::WRITE);
newVarXRefp->varp(newp->modVarp());
newp->exprp()->unlinkFrBack()->deleteTree();
newp->exprp(newVarXRefp);
@@ -553,18 +555,19 @@ public:
" direct one-to-one connection (without any expression)");
} else if (pinVarp->isWritable()) {
// See also V3Inst
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, VAccess::READ);
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
<< pinexprp->width() << endl);
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, VAccess::WRITE));
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
} else {
// V3 width should have range/extended to make the widths correct
assignp = new AstAssignW(pinp->fileline(),
new AstVarRef(pinp->fileline(), newvarp, true), pinexprp);
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false));
new AstVarRef(pinp->fileline(), newvarp, VAccess::WRITE),
pinexprp);
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, VAccess::READ));
}
if (assignp) cellp->addNextHere(assignp);
// if (debug()) { pinp->dumpTree(cout, "- out:"); }
+2 -3
View File
@@ -241,13 +241,12 @@ private:
UASSERT_OBJ(m_tracingCall || nodep == m_startNodep, nodep,
"AstCFunc not under AstCCall, or not start node");
m_tracingCall = false;
bool saved_inCFunc = m_inCFunc;
m_inCFunc = true;
VL_RESTORER(m_inCFunc);
{
m_inCFunc = true;
VisitBase vb(this, nodep);
iterateChildren(nodep);
}
m_inCFunc = saved_inCFunc;
}
virtual void visit(AstNode* nodep) override {
VisitBase vb(this, nodep);
+2 -2
View File
@@ -27,7 +27,7 @@
class V3LanguageWords {
// List of common reserved keywords
private:
typedef std::map<string, string> KeywordMap;
typedef std::map<const string, string> KeywordMap;
struct Singleton {
KeywordMap s_kwdMap; // List of keywords, and what language applies
Singleton() { init(); }
@@ -48,7 +48,7 @@ public:
private:
static Singleton& s() {
static Singleton s_s;
static Singleton s_s; // LCOV_EXCL_BR_LINE
return s_s;
}
};
+11 -18
View File
@@ -49,7 +49,6 @@ public:
VDouble0 m_statAssnCon; // Statistic tracking
std::vector<AstNode*> m_unlinkps;
public:
// CONSTRUCTORS
LifeState() {}
~LifeState() {
@@ -68,35 +67,29 @@ public:
// Structure for each variable encountered
class LifeVarEntry {
AstNodeAssign* m_assignp; // Last assignment to this varscope, nullptr if no longer relevant
AstConst* m_constp; // Known constant value
// Last assignment to this varscope, nullptr if no longer relevant
AstNodeAssign* m_assignp = nullptr;
AstConst* m_constp = nullptr; // Known constant value
// First access was a set (and thus block above may have a set that can be deleted
bool m_setBeforeUse;
// Was ever assigned (and thus above block may not preserve constant propagation)
bool m_everSet;
inline void init(bool setBeforeUse) {
m_assignp = nullptr;
m_constp = nullptr;
m_setBeforeUse = setBeforeUse;
m_everSet = false;
}
bool m_everSet = false;
public:
class SIMPLEASSIGN {};
class COMPLEXASSIGN {};
class CONSUMED {};
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) {
init(true);
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp)
: m_setBeforeUse{true} {
simpleAssign(assp);
}
explicit LifeVarEntry(COMPLEXASSIGN) {
init(false);
explicit LifeVarEntry(COMPLEXASSIGN)
: m_setBeforeUse{false} {
complexAssign();
}
explicit LifeVarEntry(CONSUMED) {
init(false);
explicit LifeVarEntry(CONSUMED)
: m_setBeforeUse{false} {
consumed();
}
~LifeVarEntry() {}
@@ -300,7 +293,7 @@ private:
//
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (nodep->lvalue()) {
if (nodep->access().isWriteOrRW()) {
m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues
m_lifep->complexAssign(vscp);
} else {
+12 -19
View File
@@ -58,7 +58,7 @@ private:
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (AstVarScope* newvscp = reinterpret_cast<AstVarScope*>(vscp->user4p())) {
UINFO(9, " Replace " << nodep << " to " << newvscp << endl);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@@ -99,13 +99,11 @@ public:
// and a sequence number within the mtask:
struct LifeLocation {
const ExecMTask* mtaskp;
uint32_t sequence;
const ExecMTask* mtaskp = nullptr;
uint32_t sequence = 0;
public:
LifeLocation()
: mtaskp{nullptr}
, sequence{0} {}
LifeLocation() {}
LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_)
: mtaskp{mtaskp_}
, sequence{sequence_} {}
@@ -120,9 +118,8 @@ public:
struct LifePostLocation {
LifeLocation loc;
AstAssignPost* nodep;
LifePostLocation()
: nodep{nullptr} {}
AstAssignPost* nodep = nullptr;
LifePostLocation() {}
LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_)
: loc{loc_}
, nodep{nodep_} {}
@@ -183,15 +180,14 @@ private:
return true;
}
if (before(assignPostLoc, loc)) return true;
for (std::set<LifeLocation>::iterator it = dlyVarAssigns.begin();
it != dlyVarAssigns.end(); ++it) {
if (!before(loc, *it)) return false;
for (const auto& i : dlyVarAssigns) {
if (!before(loc, i)) return false;
}
return true;
}
void squashAssignposts() {
for (PostLocMap::iterator it = m_assignposts.begin(); it != m_assignposts.end(); ++it) {
LifePostLocation* app = &it->second;
for (auto& itr : m_assignposts) {
LifePostLocation* app = &itr.second;
AstVarRef* lhsp = VN_CAST(app->nodep->lhsp(), VarRef); // original var
AstVarRef* rhsp = VN_CAST(app->nodep->rhsp(), VarRef); // dly var
AstVarScope* dlyVarp = rhsp->varScopep();
@@ -284,11 +280,8 @@ private:
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
LifeLocation loc(m_execMTaskp, ++m_sequence);
if (nodep->lvalue()) {
m_writes[vscp].insert(loc);
} else {
m_reads[vscp].insert(loc);
}
if (nodep->access().isWriteOrRW()) m_writes[vscp].insert(loc);
if (nodep->access().isReadOrRW()) m_reads[vscp].insert(loc);
}
virtual void visit(AstAssignPre* nodep) override {
// Do not record varrefs within assign pre.
+204 -125
View File
@@ -46,6 +46,8 @@
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
// LinkResolve:
// #10: Unlink modports, not needed later except for XML/Lint
//*************************************************************************
// TOP
// {name-of-top-modulename}
@@ -90,7 +92,9 @@ public:
};
class LinkNodeMatcherVar : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Var); }
virtual bool nodeMatch(const AstNode* nodep) const override {
return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef);
}
};
class LinkNodeMatcherVarIO : public VNodeMatcher {
public:
@@ -108,12 +112,6 @@ public:
return varp->isParam();
}
};
class LinkNodeMatcherVarOrScope : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const override {
return VN_IS(nodep, Var) || VN_IS(nodep, Scope);
}
};
//######################################################################
// LinkDot state, as a visitor of each AstNode
@@ -450,6 +448,8 @@ public:
if (!ifacerefp->ifaceViaCellp()) {
if (!ifacerefp->cellp()) { // Probably a NotFoundModule, or a normal module if
// made mistake
UINFO(1, "Associated cell " << AstNode::prettyNameQ(ifacerefp->cellName())
<< endl);
ifacerefp->v3error("Cannot find file containing interface: "
<< AstNode::prettyNameQ(ifacerefp->ifaceName()));
continue;
@@ -719,6 +719,7 @@ class LinkDotFindVisitor : public AstNVisitor {
int m_blockNum = 0; // Begin block number, 0=none seen
bool m_explicitNew = false; // Hit a "new" function
int m_modBlockNum = 0; // Begin block number in module, 0=none seen
int m_modWithNum = 0; // With block number, 0=none seen
// METHODS
static int debug() { return LinkDotState::debug(); }
@@ -781,6 +782,7 @@ class LinkDotFindVisitor : public AstNVisitor {
VL_RESTORER(m_paramNum);
VL_RESTORER(m_blockNum);
VL_RESTORER(m_modBlockNum);
VL_RESTORER(m_modWithNum);
if (doit && nodep->user2()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Identically recursive module (module instantiates "
@@ -807,6 +809,7 @@ class LinkDotFindVisitor : public AstNVisitor {
m_paramNum = 0;
m_blockNum = 0;
m_modBlockNum = 0;
m_modWithNum = 0;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
nodep->user2(true);
@@ -842,6 +845,7 @@ class LinkDotFindVisitor : public AstNVisitor {
VL_RESTORER(m_paramNum);
VL_RESTORER(m_blockNum);
VL_RESTORER(m_modBlockNum);
VL_RESTORER(m_modWithNum);
{
UINFO(4, " Link Class: " << nodep << endl);
VSymEnt* upperSymp = m_curSymp;
@@ -854,6 +858,7 @@ class LinkDotFindVisitor : public AstNVisitor {
m_paramNum = 0;
m_blockNum = 0;
m_modBlockNum = 0;
m_modWithNum = 0;
m_explicitNew = false;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
@@ -1001,7 +1006,12 @@ class LinkDotFindVisitor : public AstNVisitor {
}
// Create symbol table for the task's vars
string name = string{nodep->isExternProto() ? "extern " : ""} + nodep->name();
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_packagep);
auto pkgp = m_packagep;
// Set the class as package for static class methods
if (nodep->lifetime().isStatic() && VN_IS(m_curSymp->nodep(), Class)) {
pkgp = VN_CAST(m_curSymp->nodep(), Class);
}
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, pkgp);
m_curSymp->fallbackp(oldCurSymp);
// Convert the func's range to the output variable
// This should probably be done in the Parser instead, as then we could
@@ -1128,6 +1138,7 @@ class LinkDotFindVisitor : public AstNVisitor {
AstVar* newp
= new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM),
nodep->name(), nodep);
newp->combineType(nodep);
string svalue = v3Global.opt.parameter(nodep->name());
if (AstNode* valuep
= AstConst::parseParamLiteral(nodep->fileline(), svalue)) {
@@ -1252,6 +1263,46 @@ class LinkDotFindVisitor : public AstNVisitor {
m_curSymp->exportStarStar(m_statep->symsp());
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
virtual void visit(AstWithParse* nodep) override {
// Change WITHPARSE(FUNCREF, equation) to FUNCREF(WITH(equation))
auto funcrefp = VN_CAST(nodep->funcrefp(), NodeFTaskRef);
UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task");
string name = "item";
FileLine* argFl = nodep->fileline();
if (auto argp = VN_CAST(funcrefp->pinsp(), Arg)) {
if (auto parserefp = VN_CAST(argp->exprp(), ParseRef)) {
name = parserefp->name();
argFl = parserefp->fileline();
} else {
argp->v3error("'with' function expects simple variable name");
}
if (argp->nextp())
argp->nextp()->v3error("'with' function expects only up to one argument");
VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp);
}
// Type depends on the method used, let V3Width figure it out later
auto* argrefp = new AstLambdaArgRef(argFl, name);
auto* newp
= new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext());
funcrefp->addPinsp(newp);
nodep->replaceWith(funcrefp->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstWith* nodep) override {
// Symbol table needs nodep->name() as the index variable's name
// Iteration will pickup the AstVar we made under AstWith
VL_RESTORER(m_curSymp);
VSymEnt* const oldCurSymp = m_curSymp;
{
++m_modWithNum;
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
m_packagep);
m_curSymp->fallbackp(oldCurSymp);
UASSERT_OBJ(nodep->argrefp(), nodep, "Missing lambda argref");
// Insert argref's name into symbol table
m_statep->insertSym(m_curSymp, nodep->argrefp()->name(), nodep->argrefp(), nullptr);
}
}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
@@ -1501,6 +1552,11 @@ class LinkDotScopeVisitor : public AstNVisitor {
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
}
virtual void visit(AstWith* nodep) override {
VSymEnt* symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
}
virtual void visit(AstAssignAlias* nodep) override {
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
@@ -1670,9 +1726,9 @@ public:
};
void LinkDotState::computeIfaceModSyms() {
for (IfaceModSyms::iterator it = m_ifaceModSyms.begin(); it != m_ifaceModSyms.end(); ++it) {
AstIface* nodep = it->first;
VSymEnt* symp = it->second;
for (const auto& itr : m_ifaceModSyms) {
AstIface* nodep = itr.first;
VSymEnt* symp = itr.second;
LinkDotIfaceVisitor(nodep, symp, this);
}
m_ifaceModSyms.clear();
@@ -1717,7 +1773,7 @@ private:
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
AstDot* m_dotp; // Current dot
bool m_unresolved; // Unresolved, needs help from V3Param
AstNode* m_unlinkedScope; // Unresolved scope, needs corresponding VarXRef
AstNode* m_unlinkedScopep; // Unresolved scope, needs corresponding VarXRef
bool m_dotErr; // Error found in dotted resolution, ignore upwards
string m_dotText; // String of dotted names found in below parseref
DotStates() { init(nullptr); }
@@ -1729,7 +1785,7 @@ private:
m_dotErr = false;
m_dotText = "";
m_unresolved = false;
m_unlinkedScope = nullptr;
m_unlinkedScopep = nullptr;
}
string ascii() const {
static const char* const names[] = {"NONE", "PACKAGE", "SCOPE", "FINAL", "MEMBER"};
@@ -1780,7 +1836,7 @@ private:
m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*packagep*/);
}
}
AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, bool lvalue) {
AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, VAccess access) {
// Return a variable if possible, auto converting a modport to variable
if (!symp) {
return nullptr;
@@ -1789,7 +1845,7 @@ private:
} else if (VN_IS(symp->nodep(), ModportVarRef)) {
AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef);
AstVar* varp = snodep->varp();
if (lvalue && snodep->direction().isReadOnly()) {
if (access.isWriteOrRW() && snodep->direction().isReadOnly()) {
nodep->v3error("Attempt to drive input-only modport: " << nodep->prettyNameQ());
} // else other simulators don't warn about reading, and IEEE doesn't say illegal
return varp;
@@ -1811,18 +1867,12 @@ private:
m_ds.m_dotErr = true;
}
}
AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep,
AstModport* modportp) {
// Create iface variable, using duplicate var when under same module scope
string varName = ifacep->name() + "__Vmp__" + modportp->name() + "__Viftop"
+ cvtToStr(++m_modportNum);
AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(),
ifacep->name(), modportp->name());
idtypep->cellp(cellp);
AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
m_modp->addStmtp(varp);
return varp;
AstVar* findIfaceTopVarp(AstNode* nodep, VSymEnt* parentEntp, const string& name) {
string findName = name + "__Viftop";
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
AstVar* ifaceTopVarp = ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr;
UASSERT_OBJ(ifaceTopVarp, nodep, "Can't find interface var ref: " << findName);
return ifaceTopVarp;
}
void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) {
if (refp->user5p() && refp->user5p() != nodep) {
@@ -1960,19 +2010,29 @@ private:
m_ds.m_dotp = nodep; // Always, not just at start
m_ds.m_dotPos = DP_SCOPE;
// m_ds.m_dotText communicates the cell prefix between stages
if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") {
VSymEnt* classSymp = m_ds.m_dotSymp;
do {
classSymp = classSymp->fallbackp();
} while (classSymp && !VN_IS(classSymp->nodep(), Class));
m_ds.m_dotSymp = classSymp;
if (!classSymp) {
nodep->v3error("'this' used outside class");
m_ds.m_dotErr = true;
}
} else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
// m_ds.m_dotText communicates the cell prefix between stages
// if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in
// dotted reference"); m_ds.m_dotErr=true; }
m_ds.m_dotPos = DP_PACKAGE;
} else {
m_ds.m_dotPos = DP_SCOPE;
iterateAndNextNull(nodep->lhsp());
// if (debug()>=9) nodep->dumpTree("-dot-lho: ");
// if (debug() >= 9) nodep->dumpTree("-dot-lho: ");
}
if (m_ds.m_unresolved
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
m_ds.m_unlinkedScope = nodep->lhsp();
m_ds.m_unlinkedScopep = nodep->lhsp();
}
if (!m_ds.m_dotErr) { // Once something wrong, give up
// Top 'final' dot RHS is final RHS, else it's a
@@ -2018,21 +2078,14 @@ private:
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep,
"ParseRefs should no longer exist");
if (nodep->name() == "this") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
} else if (nodep->name() == "super") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
}
if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); }
DotStates lastStates = m_ds;
bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
if (start) {
m_ds.init(m_curSymp);
// Note m_ds.m_dot remains nullptr; this is a reference not under a dot
}
if (nodep->name() == "this") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
m_ds.m_dotErr = true;
} else if (nodep->name() == "super") {
if (nodep->name() == "super") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
m_ds.m_dotErr = true;
}
@@ -2062,12 +2115,7 @@ private:
"Bad package link");
AstClassOrPackageRef* cpackagerefp
= VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
packagep = cpackagerefp->packagep();
if (!packagep && cpackagerefp->classOrPackagep()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Class '::' references: "
<< AstNode::prettyNameQ(cpackagerefp->name()));
}
packagep = cpackagerefp->classOrPackagep();
UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link");
m_ds.m_dotSymp = m_statep->getNodeSym(packagep);
m_ds.m_dotPos = DP_SCOPE;
@@ -2119,12 +2167,7 @@ private:
VSymEnt* parentEntp
= cellEntp->parentp(); // Container of the var; probably a module or
// generate begin
string findName = nodep->name() + "__Viftop";
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
AstVar* ifaceRefVarp
= ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr;
UASSERT_OBJ(ifaceRefVarp, nodep,
"Can't find interface var ref: " << findName);
AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, nodep->name());
//
ok = true;
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
@@ -2132,7 +2175,7 @@ private:
m_ds.m_dotPos = DP_SCOPE;
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
AstNode* newp
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(cellp->modp(), NotFoundModule)) {
@@ -2140,7 +2183,7 @@ private:
<< cellp->modp()->prettyNameQ());
}
}
} else if (AstVar* varp = foundToVarp(foundp, nodep, false)) {
} else if (AstVar* varp = foundToVarp(foundp, nodep, VAccess::READ)) {
AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(varp->subDTypep());
if (ifacerefp) {
UASSERT_OBJ(ifacerefp->ifaceViaCellp(), ifacerefp, "Unlinked interface");
@@ -2150,7 +2193,7 @@ private:
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
AstNode* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (allowVar) {
@@ -2158,7 +2201,7 @@ private:
if (m_ds.m_dotText != "") {
AstVarXRef* refp
= new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText,
false); // lvalue'ness computed later
VAccess::READ); // lvalue'ness computed later
refp->varp(varp);
if (varp->attrSplitVar()) {
refp->v3warn(
@@ -2169,27 +2212,28 @@ private:
varp->attrSplitVar(false);
}
m_ds.m_dotText = "";
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
string dotted = refp->dotted();
size_t pos = dotted.find("__BRA__??__KET__");
// Arrays of interfaces all have the same parameters
if (pos != string::npos && varp->isParam()
&& VN_IS(m_ds.m_unlinkedScope, CellArrayRef)) {
&& VN_IS(m_ds.m_unlinkedScopep, CellArrayRef)) {
refp->dotted(dotted.substr(0, pos));
newp = refp;
} else {
newp = new AstUnlinkedRef(nodep->fileline(),
VN_CAST(refp, VarXRef), refp->name(),
m_ds.m_unlinkedScope->unlinkFrBack());
m_ds.m_unlinkedScope = nullptr;
m_ds.m_unlinkedScopep->unlinkFrBack());
m_ds.m_unlinkedScopep = nullptr;
m_ds.m_unresolved = false;
}
} else {
newp = refp;
}
} else {
AstVarRef* refp = new AstVarRef(nodep->fileline(), varp,
false); // lvalue'ness computed later
AstVarRef* refp
= new AstVarRef(nodep->fileline(), varp,
VAccess::READ); // lvalue'ness computed later
refp->packagep(foundp->packagep());
newp = refp;
}
@@ -2203,6 +2247,7 @@ private:
// A scope reference into an interface's modport (not
// necessarily at a pin connection)
UINFO(9, "cell-ref-to-modport " << m_ds.m_dotText << " " << nodep << endl);
UINFO(9, "unlinked " << m_ds.m_unlinkedScopep << endl);
UINFO(9, "dotSymp " << m_ds.m_dotSymp << " " << m_ds.m_dotSymp->nodep() << endl);
// Iface was the previously dotted component
if (!m_ds.m_dotSymp || !VN_IS(m_ds.m_dotSymp->nodep(), Cell)
@@ -2217,15 +2262,32 @@ private:
} else {
AstCell* cellp = VN_CAST(m_ds.m_dotSymp->nodep(), Cell);
UASSERT_OBJ(cellp, nodep, "Modport not referenced from a cell");
AstIface* ifacep = VN_CAST(cellp->modp(), Iface);
// string cellName = m_ds.m_dotText; // Use cellp->name
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
m_ds.m_dotPos = DP_SCOPE;
VSymEnt* cellEntp = m_statep->getNodeSym(cellp);
UASSERT_OBJ(cellEntp, nodep, "No interface sym entry");
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a
// module or generate begin
// We drop __BRA__??__KET__ as cells don't have that naming yet
AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, cellp->name());
//
ok = true;
AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
nodep->replaceWith(refp);
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
m_ds.m_dotSymp = foundp;
m_ds.m_dotPos = DP_SCOPE;
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
AstNode* newp
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ);
auto* cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef);
if (cellarrayrefp) {
// iface[vec].modport became CellArrayRef(iface, lsb)
// Convert back to SelBit(iface, lsb)
UINFO(9, " Array modport to SelBit " << cellarrayrefp << endl);
newp = new AstSelBit(cellarrayrefp->fileline(), newp,
cellarrayrefp->selp()->unlinkFrBack());
newp->user3(true); // Don't process again
VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp);
m_ds.m_unlinkedScopep = nullptr;
}
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) {
@@ -2237,6 +2299,14 @@ private:
ok = true;
m_ds.m_dotText = "";
}
} else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) {
if (allowVar) {
AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name());
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
ok = true;
m_ds.m_dotText = "";
}
}
//
if (!ok) {
@@ -2274,7 +2344,8 @@ private:
if (checkImplicit) {
// Create if implicit, and also if error (so only complain once)
// Else if a scope is allowed, making a signal won't help error cascade
AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false);
AstVarRef* newp
= new AstVarRef(nodep->fileline(), nodep->name(), VAccess::READ);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err);
@@ -2293,7 +2364,7 @@ private:
UINFO(9, " linkVarRef se" << cvtToHex(m_curSymp) << " n=" << nodep << endl);
UASSERT_OBJ(m_curSymp, nodep, "nullptr lookup symbol table");
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr) {
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) {
nodep->varp(varp);
// Generally set by parse, but might be an import
nodep->packagep(foundp->packagep());
@@ -2333,7 +2404,7 @@ private:
okSymp); // Maybe nullptr
if (!m_statep->forScopeCreation()) {
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr;
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr;
nodep->varp(varp);
UINFO(7, " Resolved " << nodep << endl); // Also prints varp
if (!nodep->varp()) {
@@ -2349,7 +2420,7 @@ private:
if (!m_statep->forPrearray() && !m_statep->forScopeCreation()) {
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
AstVarRef* newrefp
= new AstVarRef(nodep->fileline(), nodep->varp(), nodep->lvalue());
= new AstVarRef(nodep->fileline(), nodep->varp(), nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@@ -2373,7 +2444,7 @@ private:
nodep->varp(vscp->varp());
nodep->varScopep(vscp);
UINFO(7, " Resolved " << nodep << endl); // Also prints taskp
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->access());
nodep->replaceWith(newvscp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
UINFO(9, " new " << newvscp << endl); // Also prints taskp
@@ -2400,11 +2471,6 @@ private:
iterateChildren(nodep);
}
}
virtual void visit(AstWith* nodep) override {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements");
nodep->replaceWith(nodep->funcrefp()->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstVar* nodep) override {
checkNoDot(nodep);
iterateChildren(nodep);
@@ -2427,18 +2493,17 @@ private:
if (cpackagerefp->paramsp()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages");
}
UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(),
m_ds.m_dotp->lhsp(), "Bad package link");
nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep());
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
nodep->packagep(cpackagerefp->classOrPackagep());
m_ds.m_dotPos = DP_SCOPE;
m_ds.m_dotp = nullptr;
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
AstNodeFTaskRef* newftaskp = nodep->cloneTree(false);
newftaskp->dotted(m_ds.m_dotText);
AstNode* newp = new AstUnlinkedRef(nodep->fileline(), newftaskp, nodep->name(),
m_ds.m_unlinkedScope->unlinkFrBack());
m_ds.m_unlinkedScope = nullptr;
m_ds.m_unlinkedScopep->unlinkFrBack());
m_ds.m_unlinkedScopep = nullptr;
m_ds.m_unresolved = false;
nodep->replaceWith(newp);
return;
@@ -2636,9 +2701,6 @@ private:
virtual void visit(AstNodeFTask* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
if (nodep->classMethod() && nodep->lifetime().isStatic()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method");
}
if (nodep->isExternDef()) {
if (!m_curSymp->findIdFallback("extern " + nodep->name())) {
nodep->v3error("extern not found that declares " + nodep->prettyNameQ());
@@ -2658,6 +2720,16 @@ private:
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
m_ftaskp = nullptr;
}
virtual void visit(AstWith* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
VSymEnt* oldCurSymp = m_curSymp;
{
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
iterateChildren(nodep);
}
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
}
virtual void visit(AstClass* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
@@ -2668,42 +2740,46 @@ private:
// Until overridden by a SCOPE
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep);
m_modp = nodep;
iterateChildren(nodep);
}
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
if (AstClassExtends* cextp = VN_CAST(itemp, ClassExtends)) {
// Replace abstract reference with hard pointer
// Will need later resolution when deal with parameters
if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted
AstClassOrPackageRef* cpackagerefp
= VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef);
if (!cpackagerefp) {
cextp->v3error("Attempting to extend using a non-class ");
} else {
VSymEnt* foundp = m_curSymp->findIdFallback(cpackagerefp->name());
bool ok = false;
if (foundp) {
if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) {
AstClassRefDType* newp
= new AstClassRefDType{nodep->fileline(), classp};
cextp->childDTypep(newp);
classp->isExtended(true);
nodep->isExtended(true);
VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(),
cpackagerefp);
ok = true;
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
if (AstClassExtends* cextp = VN_CAST(itemp, ClassExtends)) {
// Replace abstract reference with hard pointer
// Will need later resolution when deal with parameters
if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted
AstClassOrPackageRef* cpackagerefp
= VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef);
if (!cpackagerefp) {
cextp->v3error("Attempting to extend using a non-class ");
} else {
VSymEnt* foundp = m_curSymp->findIdFallback(cpackagerefp->name());
bool ok = false;
if (foundp) {
if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) {
UINFO(8, "Import to " << nodep << " from export class " << classp
<< endl);
AstClassRefDType* newp
= new AstClassRefDType{nodep->fileline(), classp};
cextp->childDTypep(newp);
classp->isExtended(true);
nodep->isExtended(true);
VSymEnt* srcp = m_statep->getNodeSym(classp);
m_curSymp->importFromClass(m_statep->symsp(), srcp);
VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(),
cpackagerefp);
ok = true;
}
}
if (!ok) {
string suggest = m_statep->suggestSymFallback(
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
cpackagerefp->v3error(
"Class to extend not found: "
<< cpackagerefp->prettyNameQ() << endl
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
}
}
if (!ok) {
string suggest = m_statep->suggestSymFallback(
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
cpackagerefp->v3error(
"Class to extend not found: "
<< cpackagerefp->prettyNameQ() << endl
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
}
}
}
iterateChildren(nodep);
}
// V3Width when determines types needs to find enum values and such
// so add members pointing to appropriate enum values
@@ -2730,10 +2806,13 @@ private:
if (cpackagerefp->packagep()) {
nodep->packagep(cpackagerefp->packagep());
} else {
cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference");
// if (cpackagerefp->paramsp()) {
// nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages");
// }
nodep->packagep(cpackagerefp->classOrPackagep());
if (!VN_IS(nodep->packagep(), Class) && !VN_IS(nodep->packagep(), Package)) {
cpackagerefp->v3error(
"'::' expected to reference a class/package but referenced "
<< nodep->packagep()->prettyTypeName() << endl
<< cpackagerefp->warnMore() + "... Suggest '.' instead of '::'");
}
}
} else {
cpackagep->v3warn(E_UNSUPPORTED,
+12 -9
View File
@@ -199,30 +199,33 @@ private:
// Define what operation will we be doing
AstNode* operp;
if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) {
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp);
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
} else {
operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp);
operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
}
if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) {
// PreAdd/PreSub operations
// Immediately after declaration - increment it by one
m_insStmtp->addHereThisAsNext(new AstAssign(fl, new AstVarRef(fl, varp, true), operp));
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), operp));
// Immediately after incrementing - assign it to the original variable
m_insStmtp->addHereThisAsNext(new AstAssign(
fl, new AstVarRef(fl, varrefp->varp(), true), new AstVarRef(fl, varp, false)));
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE),
new AstVarRef(fl, varp, VAccess::READ)));
} else {
// PostAdd/PostSub operations
// assign the original variable to the temporary one
m_insStmtp->addHereThisAsNext(new AstAssign(
fl, new AstVarRef(fl, varp, true), new AstVarRef(fl, varrefp->varp(), false)));
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE),
new AstVarRef(fl, varrefp->varp(), VAccess::READ)));
// Increment the original variable by one
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), true), operp));
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE), operp));
}
// Replace the node with the temporary
nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, true));
nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, VAccess::WRITE));
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstPreAdd* nodep) override { prepost_visit(nodep); }
+7 -7
View File
@@ -153,15 +153,15 @@ private:
nodep->findSigned32DType());
varp->usedLoopIdx(true);
m_modp->addStmtp(varp);
AstNode* initsp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true), countp);
AstNode* initsp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), countp);
AstNode* decp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE),
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ),
new AstConst(nodep->fileline(), 1)));
AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
AstNode* condp
= new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp);
AstNode* condp = new AstGtS(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, VAccess::READ), zerosp);
AstNode* bodysp = nodep->bodysp();
if (bodysp) bodysp->unlinkFrBackWithNext();
AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp);
@@ -213,7 +213,7 @@ private:
// Set output variable to return value
nodep->addPrev(new AstAssign(
nodep->fileline(),
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true),
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), VAccess::WRITE),
nodep->lhsp()->unlinkFrBackWithNext()));
}
// Jump to the end of the function call
+46 -37
View File
@@ -35,7 +35,7 @@ private:
// NODE STATE
// STATE
bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
// METHODS
@@ -45,9 +45,9 @@ private:
// Result handing
virtual void visit(AstNodeVarRef* nodep) override {
// VarRef: LValue its reference
if (m_setRefLvalue) nodep->lvalue(true);
if (m_setRefLvalue != VAccess::NOCHANGE) nodep->access(m_setRefLvalue);
if (nodep->varp()) {
if (nodep->lvalue() && !m_ftaskp && nodep->varp()->isReadOnly()) {
if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) {
nodep->v3warn(ASSIGNIN,
"Assigning to input/const variable: " << nodep->prettyNameQ());
}
@@ -60,9 +60,9 @@ private:
if (nodep->modVarp() && nodep->modVarp()->isWritable()) {
// When the varref's were created, we didn't know the I/O state
// Now that we do, and it's from a output, we know it's a lvalue
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateChildren(nodep);
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
} else {
iterateChildren(nodep);
}
@@ -70,18 +70,27 @@ private:
virtual void visit(AstNodeAssign* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
}
}
virtual void visit(AstCastDynamic* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
}
}
virtual void visit(AstFOpen* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->filenamep());
iterateAndNextNull(nodep->modep());
}
@@ -89,23 +98,23 @@ private:
virtual void visit(AstFOpenMcd* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->filenamep());
}
}
virtual void visit(AstFClose* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstFError* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->strp());
}
@@ -113,21 +122,21 @@ private:
virtual void visit(AstFFlush* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstFGetC* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstFGetS* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->strgp());
}
@@ -135,7 +144,7 @@ private:
virtual void visit(AstFRead* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->memp());
iterateAndNextNull(nodep->filep());
}
@@ -143,7 +152,7 @@ private:
virtual void visit(AstFScanF* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->exprsp());
}
@@ -151,14 +160,14 @@ private:
virtual void visit(AstFUngetC* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstSScanF* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->exprsp());
}
}
@@ -170,9 +179,9 @@ private:
virtual void visit(AstReadMem* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->memp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->filenamep());
iterateAndNextNull(nodep->lsbp());
iterateAndNextNull(nodep->msbp());
@@ -181,28 +190,28 @@ private:
virtual void visit(AstValuePlusArgs* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->searchp());
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->outp());
}
}
virtual void visit(AstSFormat* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->fmtp());
}
}
void prepost_visit(AstNodeTriop* nodep) {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->lhsp());
iterateAndNextNull(nodep->rhsp());
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->thsp());
}
}
@@ -217,7 +226,7 @@ private:
{
iterateAndNextNull(nodep->lhsp());
// Only set lvalues on the from
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
iterateAndNextNull(nodep->thsp());
}
@@ -226,14 +235,14 @@ private:
VL_RESTORER(m_setRefLvalue);
{ // Only set lvalues on the from
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
}
}
virtual void visit(AstCellArrayRef* nodep) override {
VL_RESTORER(m_setRefLvalue);
{ // selp is not an lvalue
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->selp());
}
}
@@ -241,7 +250,7 @@ private:
VL_RESTORER(m_setRefLvalue);
{ // Only set lvalues on the from
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
iterateAndNextNull(nodep->thsp());
}
@@ -260,9 +269,9 @@ private:
if (const AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO()) {
if (portp->isWritable()) {
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterate(pinp);
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
} else {
iterate(pinp);
}
@@ -277,7 +286,7 @@ private:
public:
// CONSTRUCTORS
LinkLValueVisitor(AstNode* nodep, bool start)
LinkLValueVisitor(AstNode* nodep, VAccess start)
: m_setRefLvalue{start} {
iterate(nodep);
}
@@ -289,12 +298,12 @@ public:
void V3LinkLValue::linkLValue(AstNetlist* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
{ LinkLValueVisitor visitor(nodep, false); } // Destruct before checking
{ LinkLValueVisitor visitor(nodep, VAccess::NOCHANGE); } // Destruct before checking
V3Global::dumpCheckGlobalTree("linklvalue", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3LinkLValue::linkLValueSet(AstNode* nodep) {
// Called by later link functions when it is known a node needs
// to be converted to a lvalue.
UINFO(9, __FUNCTION__ << ": " << endl);
LinkLValueVisitor visitor(nodep, true);
LinkLValueVisitor visitor(nodep, VAccess::WRITE);
}
+7 -6
View File
@@ -89,9 +89,9 @@ void V3LinkLevel::timescaling(const ModVec& mods) {
AstNodeModule* modTimedp = nullptr;
VTimescale unit(VTimescale::NONE);
// Use highest level module as default unit - already sorted in proper order
for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) {
if (!modTimedp && !(*it)->timeunit().isNone()) {
modTimedp = *it;
for (const auto& modp : mods) {
if (!modTimedp && !modp->timeunit().isNone()) {
modTimedp = modp;
unit = modTimedp->timeunit();
break;
}
@@ -233,9 +233,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
varp->trace(false);
}
AstPin* pinp
= new AstPin(oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(), varp, oldvarp->isWritable()));
AstPin* pinp = new AstPin(
oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(), varp,
oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ));
// Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);
+44 -24
View File
@@ -44,7 +44,7 @@ private:
AstUser2InUse m_inuser2;
// TYPES
typedef std::map<std::pair<void*, string>, AstTypedef*> ImplTypedefMap;
typedef std::map<const std::pair<void*, string>, AstTypedef*> ImplTypedefMap;
typedef std::set<FileLine*> FileLineSet;
// STATE
@@ -57,6 +57,7 @@ private:
AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current task
AstNodeDType* m_dtypep = nullptr; // Current data type
VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -104,13 +105,20 @@ private:
// VISITs
virtual void visit(AstNodeFTask* nodep) override {
V3Config::applyFTask(m_modp, nodep);
if (!nodep->user1SetOnce()) { // Process only once.
V3Config::applyFTask(m_modp, nodep);
cleanFileline(nodep);
m_ftaskp = nodep;
iterateChildren(nodep);
m_ftaskp = nullptr;
VL_RESTORER(m_ftaskp);
VL_RESTORER(m_lifetime);
{
m_ftaskp = nodep;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) {
// Automatic always until we support static
m_lifetime = VLifetime::AUTOMATIC;
}
iterateChildren(nodep);
}
}
}
virtual void visit(AstNodeFTaskRef* nodep) override {
@@ -172,6 +180,13 @@ private:
virtual void visit(AstVar* nodep) override {
cleanFileline(nodep);
if (nodep->lifetime().isNone()) {
if (m_ftaskp) {
nodep->lifetime(VLifetime::AUTOMATIC);
} else {
nodep->lifetime(m_lifetime);
}
}
if (nodep->isParam() && !nodep->valuep()
&& nodep->fileline()->language() < V3LangCode::L1800_2009) {
nodep->v3error("Parameter requires default value, or use IEEE 1800-2009 or later.");
@@ -223,27 +238,24 @@ private:
FileLine* fl = nodep->valuep()->fileline();
if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) {
// 1. Parameters and function inputs: It's a default to use if not overridden
} else if (VN_IS(m_modp, Class)) {
// 2. Class member init become initials (as might call functions)
// later move into class constructor
nodep->addNextHere(
new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
} else if (!m_ftaskp && nodep->isNonOutput()) {
} else if (!m_ftaskp && !VN_IS(m_modp, Class) && nodep->isNonOutput()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: "
<< nodep->prettyNameQ());
nodep->valuep()->unlinkFrBack()->deleteTree();
} // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial
} // 2. Under modules/class, it's an initial value to be loaded at time 0 via an
// AstInitial
else if (m_valueModp) {
// Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it
FileLine* newfl = new FileLine(fl);
newfl->warnOff(V3ErrorCode::PROCASSWIRE, true);
nodep->addNextHere(new AstInitial(
newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
auto* assp
= new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack());
nodep->addNextHere(new AstInitial(newfl, assp));
} // 4. Under blocks, it's an initial value to be under an assign
else {
nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->addNextHere(new AstAssign(fl,
new AstVarRef(fl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack()));
}
}
@@ -333,7 +345,8 @@ private:
// lvalue is true, because we know we have a verilator public_flat_rw
// but someday we may be more general
bool lvalue = m_varp->isSigUserRWPublic();
nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue));
nodep->addStmtp(
new AstVarRef(nodep->fileline(), m_varp, lvalue ? VAccess::WRITE : VAccess::READ));
}
}
@@ -445,7 +458,8 @@ private:
new AstConst(fl, dimension));
AstNode* stmtsp = varp;
// Assign left-dimension into the loop var:
stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp));
stmtsp->addNext(
new AstAssign(fl, new AstVarRef(fl, varp->name(), VAccess::WRITE), leftp));
// This will turn into a constant bool for static arrays
AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0));
// This will turn into a bool constant, indicating whether
@@ -454,14 +468,15 @@ private:
AstNode* comparep = new AstCond(
fl, countupp->cloneTree(true),
// Left increments up to right
new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)),
new AstLte(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
rightp->cloneTree(true)),
// Left decrements down to right
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
new AstGte(fl, new AstVarRef(fl, varp->name(), VAccess::READ), rightp));
// This will reduce to comparep for static arrays
AstNode* condp = new AstAnd(fl, notemptyp, comparep);
AstNode* incp = new AstAssign(
fl, new AstVarRef(fl, varp->name(), true),
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
fl, new AstVarRef(fl, varp->name(), VAccess::WRITE),
new AstAdd(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1))));
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);
@@ -477,12 +492,17 @@ private:
V3Config::applyModule(nodep);
VL_RESTORER(m_modp);
VL_RESTORER(m_lifetime);
{
// Module: Create sim table for entire module and iterate
cleanFileline(nodep);
//
m_modp = nodep;
m_valueModp = nodep;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) {
m_lifetime = VN_IS(nodep, Class) ? VLifetime::AUTOMATIC : VLifetime::STATIC;
}
iterateChildren(nodep);
}
m_valueModp = nodep;
+22 -28
View File
@@ -51,7 +51,6 @@ private:
AstClass* m_classp = nullptr; // Class we're inside
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime
int m_senitemCvtNum = 0; // Temporary signal counter
// METHODS
@@ -66,23 +65,17 @@ private:
UINFO(8, "MODULE " << nodep << endl);
if (nodep->dead()) return;
VL_RESTORER(m_modp);
VL_RESTORER(m_lifetime);
VL_RESTORER(m_senitemCvtNum);
{
m_modp = nodep;
m_senitemCvtNum = 0;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::STATIC;
iterateChildren(nodep);
}
}
virtual void visit(AstClass* nodep) override {
VL_RESTORER(m_classp);
VL_RESTORER(m_lifetime);
{
m_classp = nodep;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC;
iterateChildren(nodep);
}
}
@@ -106,13 +99,6 @@ private:
if (m_classp && nodep->isParam())
nodep->v3warn(E_UNSUPPORTED, "Unsupported: class parameter");
if (m_ftaskp) nodep->funcLocal(true);
if (nodep->lifetime().isNone()) {
if (nodep->isFuncLocal() && nodep->isIO()) {
nodep->lifetime(VLifetime::AUTOMATIC);
} else {
nodep->lifetime(m_lifetime);
}
}
if (nodep->isSigModPublic()) {
nodep->sigModPublic(false); // We're done with this attribute
m_modp->modPublic(true); // Avoid flattening if signals are exposed
@@ -136,15 +122,11 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
VLifetime origLifetime = m_lifetime;
{
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC;
m_ftaskp = nodep;
iterateChildren(nodep);
}
m_ftaskp = nullptr;
m_lifetime = origLifetime;
if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); }
}
virtual void visit(AstNodeFTaskRef* nodep) override {
@@ -183,33 +165,34 @@ private:
}
addwherep->addNext(newvarp);
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false));
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, VAccess::READ));
AstAssignW* assignp = new AstAssignW(
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp);
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, VAccess::WRITE),
sensp);
addwherep->addNext(assignp);
}
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
bool did = 1;
bool did = true;
while (did) {
did = 0;
did = false;
if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) {
AstNode* fromp = selp->fromp()->unlinkFrBack();
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
did = true;
}
// NodeSel doesn't include AstSel....
if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) {
AstNode* fromp = selp->fromp()->unlinkFrBack();
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
did = true;
}
if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) {
AstNode* fromp = selp->lhsp()->unlinkFrBack();
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
did = true;
}
}
}
@@ -376,7 +359,7 @@ private:
if (!inpercent && c == '%') {
inpercent = true;
} else if (inpercent) {
inpercent = 0;
inpercent = false;
switch (c) {
case '0': // FALLTHRU
case '1': // FALLTHRU
@@ -409,7 +392,7 @@ private:
return newFormat;
}
void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
static void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
if (!filep) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
@@ -490,7 +473,8 @@ private:
varoutp = varp;
// Tie off
m_modp->addStmtp(new AstAssignW(
varp->fileline(), new AstVarRef(varp->fileline(), varp, true),
varp->fileline(),
new AstVarRef(varp->fileline(), varp, VAccess::WRITE),
new AstConst(varp->fileline(), AstConst::LogicFalse())));
} else {
varp->v3error("Only inputs and outputs are allowed in udp modules");
@@ -518,6 +502,16 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstIfaceRefDType* nodep) override {
// LinkDot checked modports, now remove references to them
// Keeping them later caused problems with InstDeArray,
// as it needed to make new modport arrays and such
nodep->modportp(nullptr);
iterateChildren(nodep);
}
// virtual void visit(AstModport* nodep) override { ... }
// We keep Modport's themselves around for XML dump purposes
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
+11 -8
View File
@@ -150,13 +150,15 @@ private:
}
virtual void visit(AstCFunc* nodep) override {
UINFO(4, " CFUNC " << nodep << endl);
m_cfuncp = nodep;
searchFuncStmts(nodep->argsp());
searchFuncStmts(nodep->initsp());
searchFuncStmts(nodep->stmtsp());
searchFuncStmts(nodep->finalsp());
iterateChildren(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
searchFuncStmts(nodep->argsp());
searchFuncStmts(nodep->initsp());
searchFuncStmts(nodep->stmtsp());
searchFuncStmts(nodep->finalsp());
iterateChildren(nodep);
}
}
void searchFuncStmts(AstNode* nodep) {
// Search for basic assignments to allow moving non-blocktemps
@@ -166,7 +168,8 @@ private:
for (; nodep; nodep = nodep->nextp()) {
if (VN_IS(nodep, NodeAssign)) {
if (AstVarRef* varrefp = VN_CAST(VN_CAST(nodep, NodeAssign)->lhsp(), VarRef)) {
UASSERT_OBJ(varrefp->lvalue(), varrefp, "LHS assignment not lvalue");
UASSERT_OBJ(varrefp->access().isWriteOrRW(), varrefp,
"LHS assignment not lvalue");
if (!varrefp->varp()->user4p()) {
UINFO(4, " FuncAsn " << varrefp << endl);
varrefp->varp()->user4p(varrefp);
+1 -1
View File
@@ -80,7 +80,7 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (!m_mergeable) return;
// Clear if it's an LValue referencing a marked variable
if (nodep->lvalue() && nodep->varp()->user1()) {
if (nodep->access().isWriteOrRW() && nodep->varp()->user1()) {
clearMergeable(nodep, "might modify condition");
}
}
+1 -1
View File
@@ -1267,7 +1267,7 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) {
setBit(bit, 1);
} else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) {
setBit(bit, 1);
} else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) {
} else if (lhs.bitIsXZ(bit) || rhs.bitIsXZ(bit)) {
setBit(bit, 'x');
}
// else zero
+15 -21
View File
@@ -53,7 +53,7 @@
class V3OptionsImp {
public:
// TYPES
typedef std::map<string, std::set<string>> DirMap; // Directory listing
typedef std::map<const string, std::set<string>> DirMap; // Directory listing
// STATE
std::list<string> m_allArgs; // List of every argument encountered
@@ -61,7 +61,7 @@ public:
std::set<string> m_incDirUserSet; // Include directories (for removing duplicates)
std::list<string> m_incDirFallbacks; // Include directories (ordered)
std::set<string> m_incDirFallbackSet; // Include directories (for removing duplicates)
std::map<string, V3LangCode> m_langExts; // Language extension map
std::map<const string, V3LangCode> m_langExts; // Language extension map
std::list<string> m_libExtVs; // Library extensions (ordered)
std::set<string> m_libExtVSet; // Library extensions (for removing duplicates)
DirMap m_dirMap; // Directory listing
@@ -346,10 +346,7 @@ void V3Options::checkParameters() {
if (!m_parameters.empty()) {
std::stringstream msg;
msg << "Parameters from the command line were not found in the design:";
for (std::map<string, string>::iterator it = m_parameters.begin();
it != m_parameters.end(); ++it) {
msg << " " << it->first;
}
for (const auto& i : m_parameters) msg << " " << i.first;
v3error(msg.str());
}
}
@@ -395,8 +392,7 @@ string V3Options::allArgsString() const {
// Delete some options for Verilation of the hierarchical blocks.
string V3Options::allArgsStringForHierBlock(bool forTop) const {
std::set<string> vFiles;
for (V3StringList::const_iterator it = m_vFiles.begin(); it != m_vFiles.end(); ++it)
vFiles.insert(*it);
for (const auto& vFile : m_vFiles) vFiles.insert(vFile);
string out;
for (std::list<string>::const_iterator it = m_impp->m_allArgs.begin();
it != m_impp->m_allArgs.end(); ++it) {
@@ -431,15 +427,6 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const {
//######################################################################
// File searching
bool V3Options::fileStatDir(const string& filename) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct stat sstat; // Stat information
int err = stat(filename.c_str(), &sstat);
if (err != 0) return false;
if (!S_ISDIR(sstat.st_mode)) return false;
return true;
}
bool V3Options::fileStatNormal(const string& filename) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct stat sstat; // Stat information
@@ -510,10 +497,10 @@ string V3Options::filePathCheckOneDir(const string& modname, const string& dirna
// 0: Keep the option including its argument
// 1: Delete the option which has no argument
// 2: Delete the option and its argument
int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) const {
int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) {
if (opt == "Mdir" || opt == "clk" || opt == "f" || opt == "j" || opt == "l2-name"
|| opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib" || opt == "protect-key"
|| opt == "top-module" || opt == "v") {
|| opt == "threads" || opt == "top-module" || opt == "v") {
return 2;
}
if (opt == "build" || (!forTop && (opt == "cc" || opt == "exe" || opt == "sc"))
@@ -651,9 +638,9 @@ string V3Options::getenvSYSTEMC_ARCH() {
struct utsname uts;
uname(&uts);
string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
if (VString::wildmatch(sysname.c_str(), "*solaris*")) {
if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*solaris*"))) {
var = "gccsparcOS5";
} else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) {
} else if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*cygwin*"))) {
var = "cygwin";
} else {
var = "linux";
@@ -1013,6 +1000,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
m_debugCheck = flag;
} else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented
m_debugCollision = flag;
} else if (onoff(sw, "-debug-emitv", flag /*ref*/)) { // Undocumented
m_debugEmitV = flag;
} else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented
m_debugExitParse = flag;
} else if (onoff(sw, "-debug-exit-uvm", flag /*ref*/)) { // Undocumented
@@ -1594,6 +1583,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
string oline;
// cppcheck-suppress StlMissingComparison
char lastch = ' ';
bool space_begin = true; // At beginning or leading spaces only
for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) {
if (inCmt) {
if (*pos == '*' && *(pos + 1) == '/') {
@@ -1603,11 +1593,15 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
} else if (*pos == '/' && *(pos + 1) == '/'
&& (pos == line.begin() || isspace(lastch))) { // But allow /file//path
break; // Ignore to EOL
} else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line
break; // Ignore to EOL
} else if (*pos == '/' && *(pos + 1) == '*') {
inCmt = true;
space_begin = false;
// cppcheck-suppress StlMissingComparison
++pos;
} else {
if (!isspace(*pos)) space_begin = false;
oline += *pos;
}
}
+12 -11
View File
@@ -201,7 +201,7 @@ typedef std::set<string> V3StringSet;
class V3HierarchicalBlockOption {
public:
// key:parameter name, value:value (as string)
typedef std::map<string, string> ParamStrMap;
typedef std::map<const string, string> ParamStrMap;
private:
string m_origName; // module name
@@ -218,7 +218,7 @@ public:
const ParamStrMap params() const { return m_parameters; }
};
typedef std::map<string, V3HierarchicalBlockOption> V3HierBlockOptSet;
typedef std::map<const string, V3HierarchicalBlockOption> V3HierBlockOptSet;
//######################################################################
// V3Options - Command line options
@@ -227,7 +227,7 @@ class V3Options {
public:
private:
// TYPES
typedef std::map<string, int> DebugSrcMap;
typedef std::map<const string, int> DebugSrcMap;
// MEMBERS (general options)
V3OptionsImp* m_impp; // Slow hidden options
@@ -245,8 +245,8 @@ private:
V3StringList m_forceIncs; // argument: -FI
DebugSrcMap m_debugSrcs; // argument: --debugi-<srcfile>=<level>
DebugSrcMap m_dumpTrees; // argument: --dump-treei-<srcfile>=<level>
std::map<string,string> m_parameters; // Parameters
std::map<string, V3HierarchicalBlockOption> m_hierBlocks; // main switch: --hierarchical-block
std::map<const string, string> m_parameters; // Parameters
std::map<const string, V3HierarchicalBlockOption> m_hierBlocks; // main switch: --hierarchical-block
bool m_preprocOnly = false; // main switch: -E
bool m_makePhony = false; // main switch: -MP
@@ -265,6 +265,7 @@ private:
bool m_coverageUser = false; // main switch: --coverage-func
bool m_debugCheck = false; // main switch: --debug-check
bool m_debugCollision = false; // main switch: --debug-collision
bool m_debugEmitV = false; // main switch: --debug-emitv
bool m_debugExitParse = false; // main switch: --debug-exit-parse
bool m_debugExitUvm = false; // main switch: --debug-exit-uvm
bool m_debugLeak = true; // main switch: --debug-leak
@@ -409,13 +410,13 @@ private:
void optimize(int level);
void showVersion(bool verbose);
void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; }
bool onoff(const char* sw, const char* arg, bool& flag);
bool onoffb(const char* sw, const char* arg, VOptionBool& flagr);
bool suffixed(const string& sw, const char* arg);
string parseFileArg(const string& optdir, const string& relfilename);
static bool onoff(const char* sw, const char* arg, bool& flag);
static bool onoffb(const char* sw, const char* arg, VOptionBool& flagr);
static bool suffixed(const string& sw, const char* arg);
static string parseFileArg(const string& optdir, const string& relfilename);
bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc);
string filePathCheckOneDir(const string& modname, const string& dirname);
int stripOptionsForChildRun(const string& opt, bool forTop) const;
static int stripOptionsForChildRun(const string& opt, bool forTop);
// CONSTRUCTORS
VL_UNCOPYABLE(V3Options);
@@ -469,6 +470,7 @@ public:
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool debugCollision() const { return m_debugCollision; }
bool debugEmitV() const { return m_debugEmitV; }
bool debugExitParse() const { return m_debugExitParse; }
bool debugExitUvm() const { return m_debugExitUvm; }
bool debugLeak() const { return m_debugLeak; }
@@ -669,7 +671,6 @@ public:
const string& errmsg);
void filePathLookedMsg(FileLine* fl, const string& modname);
V3LangCode fileLanguage(const string& filename);
static bool fileStatDir(const string& filename);
static bool fileStatNormal(const string& filename);
static void fileNfsFlush(const string& filename);
+21 -15
View File
@@ -36,6 +36,9 @@
// assignments to avoid saving state, thus we prefer
// a <= b ... As the opposite order would
// b <= c ... require the old value of b.
// Add edge consumed_var_POST->logic_vertex
// This prevents a consumer of the "early" value to be
// scheduled after we've changed to the next-cycle value
// For Logic
// Add vertex for this logic
// Add edge logic_sensitive_vertex->logic_vertex
@@ -49,6 +52,7 @@
// Add edge logic_sensitive_vertex->logic_vertex
// Add edge logic_consumed_var->logic_vertex (same as if comb)
// Add edge logic_vertex->logic_generated_var (same as if comb)
// Add edge consumed_var_POST->logic_vertex (same as if comb)
//
// For comb logic
// For comb logic
@@ -149,9 +153,7 @@ public:
OrderMoveVertex* vertexp); // Mark one vertex as finished, remove from ready list if done
// STATIC MEMBERS (for lookup)
static void clear() {
for (DomScopeMap::iterator it = s_dsMap.begin(); it != s_dsMap.end(); ++it) {
delete it->second;
}
for (const auto& itr : s_dsMap) delete itr.second;
s_dsMap.clear();
}
V3List<OrderMoveVertex*>& readyVertices() { return m_readyVertices; }
@@ -213,10 +215,9 @@ public:
return vertexp;
}
public:
// CONSTRUCTORS
OrderUser() {
for (int i = 0; i < WV_MAX; i++) m_vertexp[i] = nullptr;
for (auto& vertexp : m_vertexp) vertexp = nullptr;
}
~OrderUser() {}
};
@@ -561,14 +562,15 @@ public:
: m_pomGraphp{pomGraphp}
, m_pomWaitingp{pomWaitingp} {}
// METHODS
OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*,
const AstScope* scopep, const AstSenTree* domainp) {
virtual OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*,
const AstScope* scopep,
const AstSenTree* domainp) override {
OrderMoveVertex* resultp = new OrderMoveVertex(m_pomGraphp, lvertexp);
resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep));
resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp);
return resultp;
}
void freeVertexp(OrderMoveVertex* freeMep) {
virtual void freeVertexp(OrderMoveVertex* freeMep) override {
freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep);
freeMep->unlinkDelete(m_pomGraphp);
}
@@ -583,14 +585,18 @@ class OrderMTaskMoveVertexMaker : public ProcessMoveBuildGraph<MTaskMoveVertex>:
public:
explicit OrderMTaskMoveVertexMaker(V3Graph* pomGraphp)
: m_pomGraphp{pomGraphp} {}
MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex* varVertexp,
const AstScope* scopep, const AstSenTree* domainp) {
virtual MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp,
const OrderEitherVertex* varVertexp,
const AstScope* scopep,
const AstSenTree* domainp) override {
// Exclude initial/settle logic from the mtasks graph.
// We'll output time-zero logic separately.
if (domainp->hasInitial() || domainp->hasSettle()) return nullptr;
return new MTaskMoveVertex(m_pomGraphp, lvertexp, varVertexp, scopep, domainp);
}
void freeVertexp(MTaskMoveVertex* freeMep) { freeMep->unlinkDelete(m_pomGraphp); }
virtual void freeVertexp(MTaskMoveVertex* freeMep) override {
freeMep->unlinkDelete(m_pomGraphp);
}
private:
VL_UNCOPYABLE(OrderMTaskMoveVertexMaker);
@@ -1026,7 +1032,8 @@ private:
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
if (m_inSenTree) {
// Add CLOCK dependency... This is a root of the tree we'll trace
UASSERT_OBJ(!nodep->lvalue(), nodep, "How can a sensitivity be setting a var?");
UASSERT_OBJ(!nodep->access().isWriteOrRW(), nodep,
"How can a sensitivity be setting a var?");
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
varVxp->isClock(true);
new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM);
@@ -1036,9 +1043,8 @@ private:
// We don't want to add extra edges if the logic block has many usages of same var
bool gen = false;
bool con = false;
if (nodep->lvalue()) {
gen = !(varscp->user4() & VU_GEN);
} else {
if (nodep->access().isWriteOrRW()) gen = !(varscp->user4() & VU_GEN);
if (nodep->access().isReadOrRW()) {
con = !(varscp->user4() & VU_CON);
if ((varscp->user4() & VU_GEN) && !m_inClocked) {
// Dangerous assumption:
+8
View File
@@ -49,6 +49,14 @@
# include <direct.h> // mkdir
# include <psapi.h> // GetProcessMemoryInfo
# include <thread>
// These macros taken from gdbsupport/gdb_wait.h in binutils-gdb
# ifndef WIFEXITED
# ifdef __MINGW32__
# define WIFEXITED(w) (((w) & 0xC0000000) == 0)
# else
# define WIFEXITED(w) (((w) & 0377) == 0)
# endif
# endif
#else
# include <sys/time.h>
# include <sys/wait.h> // Needed on FreeBSD for WIFEXITED
+21 -27
View File
@@ -68,8 +68,8 @@
class ParameterizedHierBlocks {
typedef std::multimap<string, const V3HierarchicalBlockOption*> HierBlockOptsByOrigName;
typedef HierBlockOptsByOrigName::const_iterator HierMapIt;
typedef std::map<string, AstNodeModule*> HierBlockModMap;
typedef std::map<string, AstConst*> ParamConstMap;
typedef std::map<const string, AstNodeModule*> HierBlockModMap;
typedef std::map<const string, AstConst*> ParamConstMap;
typedef std::map<const V3HierarchicalBlockOption*, ParamConstMap> ParamsMap;
// MEMBERS
@@ -119,10 +119,11 @@ class ParameterizedHierBlocks {
public:
ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep) {
for (V3HierBlockOptSet::const_iterator it = hierOpts.begin(); it != hierOpts.end(); ++it) {
m_hierBlockOptsByOrigName.insert(std::make_pair(it->second.origName(), &it->second));
const V3HierarchicalBlockOption::ParamStrMap& params = it->second.params();
ParamConstMap& consts = m_params[&it->second];
for (const auto& hierOpt : hierOpts) {
m_hierBlockOptsByOrigName.insert(
std::make_pair(hierOpt.second.origName(), &hierOpt.second));
const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params();
ParamConstMap& consts = m_params[&hierOpt.second];
for (V3HierarchicalBlockOption::ParamStrMap::const_iterator pIt = params.begin();
pIt != params.end(); ++pIt) {
AstConst* constp = AstConst::parseParamLiteral(
@@ -141,10 +142,7 @@ public:
}
~ParameterizedHierBlocks() {
for (ParamsMap::const_iterator it = m_params.begin(); it != m_params.end(); ++it) {
for (ParamConstMap::const_iterator pIt = it->second.begin(); pIt != it->second.end();
++pIt) {
delete pIt->second;
}
for (const auto& pItr : it->second) { delete pItr.second; }
}
}
AstNodeModule* findByParams(const string& origName, AstPin* firstPinp,
@@ -218,17 +216,17 @@ private:
typedef std::deque<std::pair<AstIfaceRefDType*, AstIfaceRefDType*>> IfaceRefRefs;
// STATE
typedef std::map<AstNode*, AstNode*> CloneMap;
typedef std::map<const AstNode*, AstNode*> CloneMap;
struct ModInfo {
AstNodeModule* m_modp; // Module with specified name
CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
explicit ModInfo(AstNodeModule* modp)
: m_modp{modp} {}
};
typedef std::map<string, ModInfo> ModNameMap;
typedef std::map<const string, ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string, string> LongMap;
typedef std::map<const string, string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId = 0;
@@ -237,7 +235,7 @@ private:
V3StringSet m_allModuleNames;
typedef std::pair<int, string> ValueMapValue;
typedef std::map<V3Hash, ValueMapValue> ValueMap;
typedef std::map<const V3Hash, ValueMapValue> ValueMap;
ValueMap m_valueMap; // Hash of node hash to (param value, name)
int m_nextValue = 1; // Next value to use in m_valueMap
@@ -370,7 +368,7 @@ private:
}
}
void relinkPinsByName(AstPin* startpinp, AstNodeModule* modp) {
std::map<string, AstVar*> nameToPin;
std::map<const string, AstVar*> nameToPin;
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = VN_CAST(stmtp, Var)) {
if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
@@ -535,7 +533,7 @@ private:
nodep->addNext(new AstInitial(
nodep->fileline(),
new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
nodep->valuep()->cloneTree(true))));
if (m_ftaskp) {
// We put the initial in wrong place under a function. We
@@ -892,10 +890,13 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
AstIfaceRefDType* pinIrefp = nullptr;
AstNode* exprp = pinp->exprp();
if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& VN_IS(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType);
AstVar* varp
= (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() : nullptr;
if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType);
} else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep())
&& VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) {
pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType);
} else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef)
&& VN_CAST(exprp->op1p(), VarRef)->varp()
&& VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()
@@ -906,13 +907,6 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
pinIrefp = VN_CAST(
arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()),
IfaceRefDType);
} else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep())
&& VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()),
IfaceRefDType)) {
pinIrefp = VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()),
IfaceRefDType);
}
UINFO(9, " portIfaceRef " << portIrefp << endl);
+1 -1
View File
@@ -83,7 +83,7 @@ AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) {
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
return new AstAssignW(
fileline, new AstVarRef(fileline, name, true),
fileline, new AstVarRef(fileline, name, VAccess::WRITE),
new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0")));
}
+5 -10
View File
@@ -49,13 +49,9 @@ int V3ParseSym::s_anonNum = 0;
// Parser constructor
V3ParseImp::~V3ParseImp() {
for (std::deque<string*>::iterator it = m_stringps.begin(); it != m_stringps.end(); ++it) {
VL_DO_DANGLING(delete *it, *it);
}
for (auto& itr : m_stringps) VL_DO_DANGLING(delete itr, itr);
m_stringps.clear();
for (std::deque<V3Number*>::iterator it = m_numberps.begin(); it != m_numberps.end(); ++it) {
VL_DO_DANGLING(delete *it, *it);
}
for (auto& itr : m_numberps) VL_DO_DANGLING(delete itr, itr);
m_numberps.clear();
lexDestroy();
parserClear();
@@ -252,11 +248,10 @@ void V3ParseImp::preprocDumps(std::ostream& os) {
V3PreShell::dumpDefines(os);
} else {
bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine();
for (std::deque<string>::iterator it = m_ppBuffers.begin(); it != m_ppBuffers.end();
++it) {
for (auto& buf : m_ppBuffers) {
if (noblanks) {
bool blank = true;
for (string::iterator its = it->begin(); its != it->end(); ++its) {
for (string::iterator its = buf.begin(); its != buf.end(); ++its) {
if (!isspace(*its) && *its != '\n') {
blank = false;
break;
@@ -264,7 +259,7 @@ void V3ParseImp::preprocDumps(std::ostream& os) {
}
if (blank) continue;
}
os << *it;
os << buf;
}
}
}
+1 -1
View File
@@ -37,7 +37,7 @@ public:
// CONSTRUCTORS
V3Lexer()
: V3LexerBase{nullptr} {}
~V3Lexer() {}
~V3Lexer() override {}
// METHODS
void unputString(const char* textp, size_t length) {
// Add characters to input stream in back-to-front order

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