Compare commits

..
266 Commits
Author SHA1 Message Date
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
Wilson Snyder 16fba59480 Version bump 2020-09-07 09:26:03 -04:00
Wilson Snyder 4266c789ce Commentary 2020-09-07 09:20:17 -04:00
Peter Monsson 627d83e807 Add support for assume property (#2531) 2020-09-03 12:38:48 -04:00
Peter Monsson 80f5738544 Tests: Move t_rose t_fell and t_stable to a single test (#2530) 2020-09-03 08:09:47 -04:00
Wilson Snyder 600641b4a1 Tests: Add process test #2527 2020-08-31 19:02:58 -04:00
Yutetsu TAKATSUKASA 70eb99b050 Fix double-free on shared protect-lib (#2526)
* Add a test to use shared object of protect-lib
* Add a guard to call ctor/dtor just once even when a protec-lib is shared object.
* Pass .a to linker in leaf-last order for older ld.
* Add -flat_namespace for mac
2020-08-31 08:22:31 -04:00
Wilson Snyder dc1ad16b03 Travis: Try install twice 2020-08-30 17:34:25 -04:00
Wilson Snyder ba5779c69e Fix queues as class members (#2525). 2020-08-29 12:56:43 -04:00
Wilson Snyder 069eb97eca SystemC 2.3.0 or newer (SYSTEMC_VERSION >= 20111121) is now required. 2020-08-29 10:45:47 -04:00
Wilson Snyder 96a959154a Commentary #2518. 2020-08-29 10:22:50 -04:00
Yutetsu TAKATSUKASA 4f88ec3518 Fix hier test failure on mac (#2524)
* No need to link the intermediate .so in hierarchical verilation

* apply clang-format

* run all tests in ci instead of cron. DONT_MERGE

* Add -undefined dynamic_lookup for mac environment when linking a shared protect-lib.

* Let's just check on mac for now. DONT_MERGE

* Revert "Let's just check on mac for now. DONT_MERGE"

This reverts commit 533fac6f9f.

* Revert "run all tests in ci instead of cron. DONT_MERGE"

This reverts commit fb4ac1fb42.
2020-08-29 07:56:06 -04:00
Patrick Stewart ef4f91ae5a CMake: Unconditionally require C++11 or greater (#2522) 2020-08-28 00:01:47 -04:00
Wilson Snyder 45eccaecaf Fix Travis/GCC warnings. 2020-08-27 18:48:26 -04:00
Wilson Snyder 0397e19726 Tests: CMAKE flags fix, #2514. 2020-08-27 18:48:10 -04:00
Wilson Snyder 687edba969 Make: less verbose archive 2020-08-27 18:47:12 -04:00
Wilson Snyder 02e83da2fa Fix Travis/GCC warnings. 2020-08-27 08:47:34 -04:00
Yutetsu TAKATSUKASA ef04ada12b Fix test failure on FreeBSD (#2521)
* Don't use thin-archive to merge multiple archives because it is gnu-ar specific.

* remove -time option that may caues -Wunused-command-line-argument warning
2020-08-27 07:52:48 +09:00
Wilson Snyder bed3101dfc Internals: Use VL_RESTORER class to save/restore vars. No functional change intended. 2020-08-24 21:13:28 -04:00
Wilson Snyder 4265f9499d Support dotted references in foreach in early parsing (for UVM) 2020-08-24 19:33:26 -04:00
Yutetsu TAKATSUKASA 6acd5847e7 Fix range check in V3SplitVar to be consistent with #2507 (#2511)
* test:Add more tests for checking split_var for unpacked array.

* Fix range calculation of SliceSel and change to UASSERT_OBJ because the range check is done in V3Width beforehand.
2020-08-24 19:11:20 -04:00
Wilson Snyder 16547077a1 Remove temporary file. 2020-08-24 18:56:52 -04:00
Wilson Snyder 3ad3944f2c Fix Travis/GCC warnings. For VPI/DPI still avoid C++11. 2020-08-24 18:49:36 -04:00
Wilson Snyder be8f1a25c6 Commentary (#2510) 2020-08-24 08:58:33 -04:00
Wilson Snyder f7f3d3fd43 Fix splitting eval functions with --output-split-cfuncs (#2368). 2020-08-23 22:21:40 -04:00
Wilson Snyder 4003e01283 Commentary 2020-08-23 20:58:23 -04:00
Wilson Snyder 917d3b0fb3 Support virtual class 2020-08-23 20:27:25 -04:00
Wilson Snyder 3d073c9534 Fix class extends to use virtual destruction 2020-08-23 20:00:39 -04:00
Wilson Snyder 20206b1e2e Support simple class extends. 2020-08-23 19:37:56 -04:00
Wilson Snyder fefe731105 Tests: Better virtual test 2020-08-23 11:50:42 -04:00
Wilson Snyder 1dce6b2500 Support $stable 2020-08-23 11:34:19 -04:00
Wilson Snyder d2fac4aa2f Internals: Add --debug-exit-uvm 2020-08-23 09:05:18 -04:00
Wilson Snyder 132cc1d068 Parser: Move timing control unsupported message 2020-08-23 08:56:35 -04:00
Wilson Snyder f4a72946eb Support $urandom, $urandom_range without stability. 2020-08-23 08:42:50 -04:00
Wilson Snyder e10156548d Fix GCC warnings 2020-08-23 07:19:20 -04:00
Wilson Snyder 4e6d2cfe38 Fix class constructor error on assignments to const. 2020-08-22 22:44:00 -04:00
Wilson Snyder 7f3a73e314 Fix naming of "id : begin" blocks. 2020-08-22 22:21:37 -04:00
Wilson Snyder 143050e034 Fix fwrite GCC warning 2020-08-22 21:34:41 -04:00
Wilson Snyder 8455ee7091 Optimize one-statement fork/join into begin 2020-08-22 20:04:02 -04:00
Wilson Snyder 9702d11657 Support class extern. 2020-08-22 19:46:21 -04:00
Wilson Snyder decbf79f39 Convert unnamed error to new PKGNODECL error. 2020-08-22 19:42:21 -04:00
Wilson Snyder 2d7d2c5992 Fix false DECLFILENAME on black-boxed modules (#2430). 2020-08-22 16:56:21 -04:00
Wilson Snyder 2abbd5c145 Convert unnamed error to new PKGNODECL error. 2020-08-22 16:37:49 -04:00
Wilson Snyder 583605b218 Parser: Move extern decl unsupported message 2020-08-22 16:24:29 -04:00
Wilson Snyder 67fab0b4fc Internals: Add missing package null test. No functional change intended. 2020-08-22 10:22:56 -04:00
Wilson Snyder 43213fcdc2 Fix GCC warnings 2020-08-22 07:44:22 -04:00
Yutetsu TAKATSUKASA f632ea500c Fix slice of unpacked array calculation (Issue #2506) (#2507)
Fixes Issue #2506 by shifting index as ArraySel does
2020-08-22 15:23:26 +09:00
Wilson Snyder dbb69412e5 Travis: Use make -k 2020-08-21 08:31:27 -04:00
Wilson Snyder d7bc0ff5e5 Fix GCC warnings 2020-08-21 08:30:12 -04:00
Wilson Snyder 14604a24d6 Fix GCC warnings 2020-08-20 08:12:06 -04:00
Wilson Snyder 816c5e0dc9 Fix GCC warnings 2020-08-19 08:20:06 -04:00
Rupert Swarbrick aa39d020d8 Fix build with Bison 3.7 and newer (#2505) 2020-08-18 12:12:52 -04:00
Wilson Snyder b67f1f0e94 Fix GCC warnings 2020-08-18 08:10:44 -04:00
Wilson Snyder f5546febe8 Fix OSX GCC register warning. 2020-08-18 08:02:50 -04:00
Wilson Snyder 27181d534e Commentary 2020-08-17 07:57:38 -04:00
Wilson Snyder 698e0fbbd1 configure: Try compiler flags to get to C++11 (#2502) 2020-08-17 07:40:07 -04:00
Wilson Snyder ea9b65fe6d Hardcode VM_C11 as always need C++11 now 2020-08-16 15:10:43 -04:00
Wilson Snyder 3c1ed075e5 tests: Disable wide line test as breaks user commits. 2020-08-16 14:57:16 -04:00
Wilson Snyder 6013b54f7b clang-tidy cleanups. No functional change intended. 2020-08-16 14:55:46 -04:00
Wilson Snyder d75a8624c1 C++11: constexpr replacing defines. No functional change intended. 2020-08-16 14:19:12 -04:00
Wilson Snyder ac04e85a1c C++11: More range for. No functional change intended. 2020-08-16 12:54:32 -04:00
Wilson Snyder 78aee6f4e7 C++11: Use sized enums (+4% performance). 2020-08-16 12:05:35 -04:00
Wilson Snyder ee9d6dd63f C++11: Favor auto, range for. No functional change intended. 2020-08-16 11:44:06 -04:00
Wilson Snyder 034737d2a8 C++11: Use member declaration initalizations (in nodes). No functional change intended. 2020-08-16 11:44:06 -04:00
Wilson Snyder 72d2cff0a1 C++11: Use member declaration initalizations. No functional change intended. 2020-08-16 11:44:06 -04:00
Wilson Snyder 033e7ac020 C++11: Use member declaration initalizations. No functional change intended. 2020-08-16 11:44:06 -04:00
Wilson Snyder 042d3eed23 C++11: Use override where possible. No functional change. 2020-08-16 11:44:05 -04:00
Wilson Snyder ea4031cbd3 C++11: Use delegating constructors. No functional change. 2020-08-16 11:44:05 -04:00
Wilson Snyder c0127599df C++11: Use nullptr. No functional change. 2020-08-16 11:44:05 -04:00
Wilson Snyder 7c54a451a9 C++11: Remove pre-c11 VL_OVERRIDE etc. No functional change. 2020-08-16 11:44:05 -04:00
Wilson Snyder 2118038cb9 Commentary 2020-08-15 14:22:50 -04:00
Wilson Snyder 9927e8b3ee clang-format uses C++11 style. No functional change. 2020-08-15 09:48:08 -04:00
Yutetsu TAKATSUKASA 953a442827 Support hierarchical verilation using protect lib (#2206) 2020-08-15 09:43:53 -04:00
Wilson Snyder f3b28c5c74 Remove configure --enable-prec11-final 2020-08-15 09:39:59 -04:00
Wilson Snyder 7a33fe2bf2 devel release 2020-08-15 09:20:50 -04:00
Wilson Snyder bdecf6c4e1 Version bump 2020-08-15 09:14:36 -04:00
Wilson Snyder 6fcf05e2b6 Commentary 2020-08-15 09:12:36 -04:00
Peter Monsson 4a5e4b04f3 Support $rose and $fell. (#2148) (#2501) 2020-08-14 07:37:10 -04:00
Edgar E. Iglesias 5d98035170 Fix sc names (#2500)
cint.mainInt(nodep) walks the tree and populates m_ctorVarsVec.
Reuse EmitCImp cint for the slow mainImp() emition steps to make sure
we emit constructor calls to setup SystemC sc_module names.
2020-08-13 08:23:02 -04:00
Wilson Snyder 20c906261b Fix casting non-self-determined subexpressions (#2493). 2020-08-09 20:59:06 -04:00
Wilson Snyder 74754d94c3 Codacy fix 2020-08-06 22:03:00 -04:00
Wilson Snyder 98cd925fda Fix non-32 bit conversion to float (#2495). 2020-08-06 21:56:43 -04:00
Wilson Snyder e029ba845e Travis: Trusty must use default CPAN 2020-08-06 17:50:49 -04:00
Julien Margetts e53a522662 Fix protect lib VCS warning (#2479) 2020-08-04 17:07:40 -04:00
Wilson Snyder 2bc813da4a Refactor and test VL_MULS_MAX_WORDS 2020-08-03 22:12:24 -04:00
James HanlonandJames Hanlon 555408b5d3 Fix V3Unknown from running with flat XML output (#2494)
* Prevent V3Unknown pass from being run

Co-authored-by: James Hanlon <[email protected]>
2020-08-03 11:44:47 -04:00
Wilson Snyder a07f2b3611 Travis: Force CPAN mirror to avoid false failures. 2020-08-02 08:47:27 -04:00
Yutetsu TAKATSUKASA c85589371a Fix protect-lib without sequential logic (#2492)
* add a test for protect-lib without sequential logic that cause the follwoing error.

%Error: obj_vlt/t_prot_lib_comb/secret/secret.sv:78:14: syntax error, unexpected ')'
   78 |     always @() begin
      |              ^

* protect-lib wrapper must contain sequential signal related statements
only if the protected design is a sequential logic.

Diff looks big, but actually just add "if (m_hasClk)" condition.

Signed-off-by: Yutetsu TAKATSUKASA <[email protected]>
2020-08-01 07:16:15 -04:00
Peter Monsson 1280070abb Support $stable (#2488) 2020-07-28 18:26:24 -04:00
Wilson Snyder a52f975bd7 Fix combining different-width parameters (#2484). 2020-07-26 17:54:23 -04:00
Wilson Snyder 0c70f0c786 clang-format 2020-07-26 17:50:31 -04:00
Wilson Snyder edf6a40f19 Fix VL_CONSTHI truncation (#2473) 2020-07-18 17:35:20 -04:00
Piotr Binkowski 58739a0a99 Internals: add isProgram to AstModule (#2470)
This allows to check which AstModules were created from `program` keyword
2020-07-16 07:31:16 -04:00
Wilson Snyder 1488f9130d Enable simple function localparams (#2461) 2020-07-15 19:31:19 -04:00
Josh Redford a18d8cbe86 Test for arrayed interfaces (#2469). 2020-07-15 17:58:59 -04:00
Wilson Snyder bfea4b7f99 Fix arrayed interfaces, broke in 4.038 (#2468). 2020-07-15 17:58:26 -04:00
Wilson Snyder 84b8307938 Ignore .nfs files 2020-07-15 07:50:32 -04:00
Wilson Snyder ce340658d6 Internals: revert (#2467) 2020-07-15 07:50:17 -04:00
Piotr Binkowski a02c420064 Internals: separate AST class for program (#2467) 2020-07-15 07:39:58 -04:00
Marshal Qiao d55c233427 Fix bad delete in verilated_save.h (#2462) 2020-07-14 06:39:00 -04:00
Marshal Qiao 25bbbbd37b Update Contributors (#2465) 2020-07-14 06:36:01 -04:00
Wilson Snyder fdb4d3a145 Fix coredump with UVM parse, caused by recent commit. 2020-07-11 20:32:27 -04:00
Wilson Snyder ced1af8cb8 Parser: Move extends param class unsupported message 2020-07-11 19:53:41 -04:00
Wilson Snyder f0a6e4c2b2 Parser: Move scoped id unsupported messages down out of parser 2020-07-11 19:11:58 -04:00
Wilson Snyder 9e5cd463e5 Parser: Move class parameter unsupported messages down out of parser 2020-07-11 18:39:01 -04:00
Wilson Snyder bb8899f307 Internals: Rename AstPackageRef as may point to class. 2020-07-11 10:29:15 -04:00
Wilson Snyder 1194dbf19c devel release 2020-07-11 09:18:40 -04:00
Wilson Snyder 0cd4a57ad9 Version bump 2020-07-11 09:05:24 -04:00
Wilson Snyder 1bd1e21a69 Change --enable-prec11 to --enable-prec11-final and give stronger warning 2020-07-11 08:56:40 -04:00
Wilson Snyder 7e7447812c Fix modulus exception (#2460) 2020-07-11 08:17:16 -04:00
Wilson Snyder af3ab13012 Tests: Fix 64-bit code coverage, part of last commit 2020-07-10 22:38:08 -04:00
Wilson Snyder b35b5aacfa Fix division exception (#2460) 2020-07-10 22:28:02 -04:00
Wilson Snyder 9c01665078 Tests: Fix bison stability. 2020-07-10 22:05:51 -04:00
Wilson Snyder a500140f1d Fix Bison 3.6 error messages 2020-07-10 21:54:58 -04:00
Wilson Snyder dced49a804 Internals: Cleanup branch coverage. No functional change. 2020-07-10 19:17:21 -04:00
Wilson Snyder f8a67b2fe8 Configure: Show bison/flex version. 2020-07-10 18:37:31 -04:00
Wilson Snyder 8cdecd5668 Commentary: Changes update 2020-07-10 18:18:02 -04:00
Wilson Snyder 75d255a3bf Internals: clang-format 2020-07-10 18:08:04 -04:00
Wilson Snyder 0674267333 Parser: Test and handle semaphore, mailbox and process. 2020-07-09 20:04:22 -04:00
Geza Lore 1632160fb1 Internals: Remove redunand SenItem nodes (#2457) 2020-07-05 13:13:03 -04:00
Geza Lore e609328ebb Ensure VarRef inherits dtype when varp is set.
Inlining used to set some VarRefs to point to new Var nodes, without
updating the dtype of the VarRef to the dtype of the new Var.
AstNode::sameTree does identity comparison on the dtype, so some trees
that were semantically the same did not compare as such with sameTree
because of the dtype. This in turn results in some missed opportunities
for combining equivalent SenTree sensitivities when the clock came from
outside.
2020-07-05 16:09:22 +01:00
Yutetsu TAKATSUKASA 8291ef6537 Internals: Pass FileLine to findDotted() for error location (#2455)
* Pass FileLine so that findDotted() will be able to tell the error location though it is not used yet.

* reorder the parameter order. No functional change is intended.
2020-07-04 09:35:04 -04:00
Yutetsu TAKATSUKASA 30600bf1a3 Internals: Add const 2020-07-03 14:16:43 -04:00
Wilson Snyder b968f57711 Suppress unsupported constraint, as implied by unsupported randomize. 2020-07-02 21:10:05 -04:00
Wilson Snyder ee7b399bf5 Parser: Move 'static' unsupported messages down out of parser. 2020-07-02 21:02:49 -04:00
Wilson Snyder 50c28fa9d3 Parser: Move 'pure virtual' and 'extern' unsupported messages down out of parser. 2020-07-02 08:24:50 -04:00
Geza Lore a17f51eac0 Improve V3MergeCond
- Do try to merge after assignment to condition when possible.
- Do not try to merge reduced form if not the expected statement.
  This used to cause a crash.
2020-07-02 13:13:51 +01:00
Yutetsu TAKATSUKASA cc50126ad3 Internals: Generalize V3Config to be able to set any module pragma. No functional change intended. (#2451) 2020-07-02 07:54:37 -04:00
Wilson Snyder 9d1a39a5e4 Parser: Move 'with' block unsupported messages down out of parser 2020-07-02 07:36:15 -04:00
Yutetsu TAKATSUKASA 82cc1a319f Internals: Simplify condition in V3Dead.cpp. No functional change intended. (#2454) 2020-07-02 07:35:55 -04:00
Yutetsu TAKATSUKASA 2fd23458ce Internals: Factor out making a make cmd string in Verilator.cpp. No functional change intended. (#2453) 2020-07-02 07:30:40 -04:00
Yutetsu TAKATSUKASA 271fa5fe3c Internals: move parseParamLiteral() to AstConst . No functional change intended. (#2452) 2020-07-02 07:29:52 -04:00
Fan Shupei 04c96694e6 Add $writememb support (#2450) 2020-07-01 17:32:15 -04:00
Wilson Snyder e7bd44561c Parse dotted new 2020-07-01 07:39:37 -04:00
Wilson Snyder 4d5e448664 Parser: Move member qualifier unsupporteds out of parser. 2020-07-01 07:31:53 -04:00
Wilson Snyder 236c2141e3 Parser: Move 'with' block unsupported messages down out of parser 2020-06-30 21:37:11 -04:00
Wilson Snyder 788fe3dc27 Tests: Ignore gtkwave spaces. 2020-06-30 21:36:39 -04:00
Wilson Snyder a2abd361db gtkwave: Update to match spacing of upstream. No functional change. 2020-06-30 19:16:10 -04:00
Geza Lore 09806d7576 Update fstapi.c to latest (fix undefined thread behaviour) 2020-06-30 19:50:41 +01:00
Geza Lore a2aa678278 Travis: only use SystemC when not M32 2020-06-30 19:16:28 +01:00
Wilson Snyder 0b09636c58 Support for-loop increments with commas. 2020-06-29 21:18:41 -04:00
Wilson Snyder af197f2ceb Parser: Move 'virtual class' block unsupported messages down out of parser 2020-06-29 21:03:14 -04:00
Wilson Snyder 748c818ccb Parser: Move 'wait' block unsupported messages down out of parser 2020-06-29 20:39:39 -04:00
Wilson Snyder ad55564905 Parser: Move disable fork and wait fork down into elaborate stage 2020-06-29 20:22:39 -04:00
Wilson Snyder ad2cb45a14 Parser: Move unsupported error detection of 'this'/'super' down into link stage 2020-06-29 20:02:15 -04:00
Wilson Snyder 277fd9197f Tests: Add number case for #2432. 2020-06-29 18:03:16 -04:00
Wilson Snyder 61ff7039b4 Commentary (#2439) 2020-06-28 18:37:42 -04:00
Geza Lore 7342cf278a Travis: Add 32-bit build on focal 2020-06-28 20:11:22 +01:00
Harald Heckmann 958654909f Added perl-doc to optional apt packages (#2445) 2020-06-28 11:00:57 -04:00
Geza Lore d9be86d69a Remove Travis FreeBSD debug acces workaround (ENV_HACK) 2020-06-28 15:37:24 +01:00
Geza Lore 378d947702 Travis: Add FreeBSD build + portability fixes 2020-06-28 15:37:24 +01:00
Stephen Henry 98b5417e04 Disable argument template type deduction. (#2426)
Fixes #2421, #2435 relating to 32-bit build failures.
2020-06-28 10:54:15 +01:00
Wilson Snyder 0af971292e Commentary (#2437) 2020-06-27 22:35:31 -04:00
Wilson Snyder 43a2fa080a For maintainers, set fill-column. 2020-06-27 21:44:32 -04:00
Geza Lore 0cdc2e038c Workaround for Travis OS X dbg exe corruption 2020-06-25 14:12:24 +01:00
Geza Lore d4a411db6c Don't use configure default compiler flags 2020-06-24 11:44:25 +01:00
Geza Lore 8d367dc8a3 Fix github links in documentation (#2443) 2020-06-24 11:09:49 +01:00
Geza Lore 5a4cc333fb Travis: Add OS X build (#2440) 2020-06-22 10:13:54 +01:00
Ludwig Rogiers f13fd4478c Init params in constructor to support pre-c++11 compilers 2020-06-22 09:01:39 +01:00
Geza Lore 23e4a0f784 Improve documentation 2020-06-20 05:17:46 +01:00
Geza Lore aa595d40de Do not fold IF with 'bx condition before V3Unknown (#2438)
Fixes #2425
2020-06-20 04:16:07 +01:00
Wilson Snyder fa828ac9ba Commentary (#2419) 2020-06-14 10:47:17 -04:00
Wilson Snyder b1495f0742 Commentary (#2423) 2020-06-14 10:44:57 -04:00
Stefan Wallentowitz 8006b5479c Missing entry in Changes for VPI parameters (#2417) 2020-06-13 05:22:12 -04:00
Yutetsu TAKATSUKASA 19c2906a64 Improve code coverage of V3SplitVar.cpp (#2418) 2020-06-13 04:45:47 -04:00
Ludwig Rogiers c367b671b6 Support VPI parameter and localparam (#2370) 2020-06-12 18:38:01 -04:00
Wilson Snyder 35226d5e1a Commentary 2020-06-12 08:12:54 -04:00
Geza Lore fac89c5d62 Close trace on vl_fatal/vl_finish (#2414)
This is required to get the last bit of FST trace and close the FST file
properly on $stop or assertion failure.
2020-06-12 07:15:42 +01:00
Conor McCullough f40f0464e2 Fix replaceMulShift optimization (#2413) 2020-06-11 07:42:25 -04:00
Wilson Snyder 262ed9c03a Tests: Avoid using std. No functional change. 2020-06-10 08:04:34 -04:00
Yutetsu TAKATSUKASA a7edf13d62 Fix V3SplitVar test stability (#2408) 2020-06-09 22:39:10 -04:00
Wilson Snyder 6e57076726 Support --bbox-unsup parsing of nested foreach. 2020-06-09 22:05:06 -04:00
Wilson Snyder cef56c6fca Support --bbox-unsup parsing of class extend typedefs 2020-06-09 20:59:45 -04:00
Wilson Snyder 91f30af01f Fix --bbox-unsup crash from earlier commit. 2020-06-09 19:49:11 -04:00
Wilson Snyder 3c8953fec2 Fix $sformat with non-constant string first argument 2020-06-09 19:40:49 -04:00
Wilson Snyder 6de78d58fa Add new UNSUPPORTED error code to replace most previous Unsupported: messages. 2020-06-09 19:20:16 -04:00
Wilson Snyder d42f9c095b Delay parsing of associative arrays until dtypes known. 2020-06-09 07:13:40 -04:00
Wilson Snyder 46e10173f8 Support --bbox-unsup parsing of class extern function/task. 2020-06-08 22:33:57 -04:00
Wilson Snyder d84c7df38f Internals: Reformat V3Options. No functional change. 2020-06-08 22:17:30 -04:00
Wilson Snyder 6e2d8df9e5 Tests: Add --debug-exit-parse 2020-06-08 22:10:55 -04:00
Wilson Snyder e2b40195b4 Tests: Reference issue #2410. 2020-06-08 20:58:04 -04:00
Wilson Snyder 541f983dba Merge tests from issue-2409-timing (but disabled mostly) 2020-06-08 20:36:22 -04:00
Wilson Snyder 5658cd3394 Commentary 2020-06-08 20:11:29 -04:00
Wilson Snyder 3963a50aef Internals: Refactor param array handling to use subroutine. No functional change intended. 2020-06-08 07:43:07 -04:00
Wilson Snyder 47f040a5fd Internals: Do data type elaboration always as child node, before movement to symbol table. 2020-06-08 06:47:18 -04:00
Wilson Snyder 7b7a2e99e3 Internals: Misc parser cleanups. 2020-06-07 22:15:19 -04:00
Wilson Snyder 25397e7612 Author site: Don't rebuild revision if VERILATOR_NO_OPT_BUILD 2020-06-07 20:08:19 -04:00
Wilson Snyder 4984d19ae9 Support --bbox-unsup parsing :: referencing typedef in class 2020-06-07 19:59:03 -04:00
Wilson Snyder 305448ea86 Cleanup parser errors to identify packages by :: instead of symbol table 2020-06-07 16:54:25 -04:00
Wilson Snyder 4a1d18f0e9 Internals: Refactor parser pipeline to use deque. No functional change intended. 2020-06-07 15:35:36 -04:00
Wilson Snyder 30482f3eea Internals: Add parser debug printer. 2020-06-07 14:07:15 -04:00
Wilson Snyder b469feb44b Fix some syntax error context by splitting internal parse and lex filelines 2020-06-07 13:45:50 -04:00
Wilson Snyder 466fd56d18 Move XML verilator tag handling into parser. 2020-06-07 13:09:18 -04:00
Wilson Snyder 1aaf3f3424 Internals: Rename parser functions called by lexer. No functional change intended. 2020-06-07 12:18:23 -04:00
Wilson Snyder b5e4917405 Internals: Pass unconnected drive in parser token stream. 2020-06-07 12:08:12 -04:00
Wilson Snyder 140671300c Internals: Pass parser celldefine state through FileLine. No functional change intended. 2020-06-07 11:58:53 -04:00
Wilson Snyder 820a4dbbdd Internals: Pass fileline directly. No functional change intended. 2020-06-07 10:53:21 -04:00
Wilson Snyder 53d8ccd149 Internals: Move yyerror to parser. No functional change intended. 2020-06-07 10:31:42 -04:00
Wilson Snyder 418b36ea71 Internals: Pass fileline directly and avoid yyerror 2020-06-07 10:17:50 -04:00
Wilson Snyder 05e51d0d18 Tests: Excempt some wide files 2020-06-07 09:59:09 -04:00
Wilson Snyder 575c565e77 Internals: Refactor to decouple LinkDot from ParseImp. No functional change intended. 2020-06-07 08:23:01 -04:00
Wilson Snyder 01255082a6 Internals: Refactor to decouple LinkDot from ParseImp. No functional change intended. 2020-06-07 08:21:22 -04:00
Wilson Snyder 0098e67e59 Tests: Use lint in many negative tests to avoid running under both vlt and vltmt 2020-06-07 07:15:07 -04:00
Wilson Snyder 3798a472b5 Commentary: Indicate mid-rule parser actions. 2020-06-06 17:42:10 -04:00
Wilson Snyder 0e322e2e85 Fix segfault after pin unsupported error. 2020-06-06 16:17:41 -04:00
Wilson Snyder 5cd5c05c05 Support --bbox-unsup parsing of event control expressions 2020-06-06 15:54:44 -04:00
Wilson Snyder 933e796cc2 Support $swrite with arbitrary arguments 2020-06-06 14:47:54 -04:00
Wilson Snyder ae701e014d Support --bbox-unsup parsing of for with multiple increments 2020-06-06 13:55:15 -04:00
Wilson Snyder 3a0b8c8870 Fix parsing parameter type with assignment and no type keyword. 2020-06-06 13:44:45 -04:00
Geza Lore dea0e6793f Simplify V3SenTree.h. No functional change intended.
- Remove unused headers
- Simplify container functors
- SenTreeFinder need not be a Visitor
- Update comments

Line coverage should now be 100%
2020-06-06 17:30:32 +01:00
Wilson Snyder 4862916f39 Support --bbox-unsup parsing of 'constraint', 'dist', 'solve' 2020-06-06 12:08:36 -04:00
Wilson Snyder 870ec27b73 Support --bbox-unsup parsing of 'randomize' 2020-06-06 11:22:48 -04:00
Wilson Snyder a21947d887 Support --bbox-unsup parsing of 'with' 2020-06-06 11:11:23 -04:00
Wilson Snyder 893dee3434 Support --bbox-unsup parsing of forward defed class calls 2020-06-06 10:21:16 -04:00
Wilson Snyder f083805ab5 Support --bbox-unsup parsing of parameterized classes 2020-06-06 10:06:32 -04:00
Wilson Snyder 7067afde5d Support --bbox-unsup parsing of foreach(this.foo) 2020-06-06 09:43:13 -04:00
Wilson Snyder 1eaec2aa8a Support --bbox-unsup of $cast 2020-06-06 09:30:11 -04:00
Wilson Snyder da01810d98 Internals: Add UNSUP tokens from VParseBison and sort lists. No functional change. 2020-06-06 09:09:26 -04:00
Wilson Snyder 4c7d5a1dc0 Fix --bbox-unsup to bypass more parser unsupported errors. 2020-06-06 08:50:47 -04:00
Wilson Snyder d15e3d93c4 Internals: Reindent and move parser code. No functional change. 2020-06-06 08:44:44 -04:00
Wilson Snyder aae2bf872c devel release 2020-06-06 07:51:54 -04:00
599 changed files with 26826 additions and 17208 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
Standard: Cpp11
TabWidth: 8
UseTab: Never
...
+1
View File
@@ -1,5 +1,6 @@
\#*
.#*
.nfs*
*~
*.tidy
*.old
+33 -2
View File
@@ -35,18 +35,28 @@ before_install:
- clang++ -E -dM -c -x c++ /dev/null | sort
# Install all dependencies
# We run twice to attempt on failure to recover from temp network problems
install:
- ./ci/travis-install.bash
- ./ci/travis-install.bash || ./ci/travis-install.bash
before_script:
# ccache maintenance
- ./ci/travis-ccache-maint.bash
# Don't produce core dumps (esp. on FreeBSD)
- ulimit -c 0
# On Focal, set the SystemC installation location
- |
if [ "$TRAVIS_DIST" = "focal" ]; then
if [ "$TRAVIS_DIST" = "focal" ] && [ "$M32" != "1" ]; then
export SYSTEMC_INCLUDE=/usr/include
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
fi
# Override compiler for M32
- |
if [ "$M32" = "1" ]; then
export CC="$CC -m32"
export CXX="$CXX -m32"
unset M32 # verilated.mk actually references $(M32) so unset
fi
before_cache:
- ccache -s -z
@@ -70,6 +80,12 @@ jobs:
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
# Coverage build
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
# 32-bit build
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc-m32, paths: .}}, env: M32=1}
# 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: .}}}
############################################################################
# Jobs in the 'test' stage
############################################################################
@@ -109,6 +125,21 @@ jobs:
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
# 32-bit tests
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-0]}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-1]}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-0]}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-1]}
# OS X tests
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {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}
notifications:
email:
+120
View File
@@ -3,6 +3,126 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.102 2020-10-15
**** Support const object new() assignments.
**** Support # as a comment in -f files (#2497). [phantom-killua]
**** Support 'this' (#2585). [Rafal Kapuscik]
**** Support defines for FST tracing (#2592). [Markus Krause]
**** Support |=> inside properties (#1292). [Peter Monsson]
**** Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA]
**** Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA]
**** Fix -G dropping public indication (#2561). [Andrew Goessling]
**** Fix $urandom_range passed variable (#2563). [nanduraj1]
**** Fix method calls to package class functions (#2565). [Peter Monsson]
**** Fix class wide member display (#2567). [Nandu Raj P]
**** Fix hierarchical references inside function (#2267) (#2572). [James Pallister]
**** Fix flushCall for backward compatibility (#2580). [chenguokai]
**** Fix preprocessor stringify of undefined macro. [Martin Whitaker]
* Verilator 4.100 2020-09-07
** C++11 or newer compilers are now required.
** SystemC 2.3.0 or newer (SYSTEMC_VERSION >= 20111121) is now required.
** Support hierarchical Verilation (#2206). [Yutetsu TAKATSUKASA]
**** Support (with limitations) class extern, class extends, virtual class.
**** Support $urandom, $urandom_range without stability.
**** Fix false DECLFILENAME on black-boxed modules (#2430). [Philipp Wagner]
**** Fix naming of "id : begin" blocks.
**** Fix class constructor error on assignments to const.
**** Fix splitting eval functions with --output-split-cfuncs (#2368). [Geza Lore]
**** Fix queues as class members (#2525). [nanduraj1]
**** Add support for assume property. [Peter Monsson]
**** Add support for |=> inside properties (#1292). [Peter Monsson]
* Verilator 4.040 2020-08-15
** Version 4.040 is planned to be the final version that will
support pre-C++11 compilers. Please move to C++11 or newer compilers.
*** Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford]
**** Support $stable, $rose and $fell. (#2148) (#2501) [Peter Monsson]
**** Support simple function localparams (#2461). [James Hanlon]
**** Miscellaneous parsing error changes towards UVM support.
**** Fix arrayed interfaces (#2469). [Josh Redford]
**** Fix protect lib VCS warning. (#2479) [Julien Margetts]
**** Fix combining different-width parameters (#2484). [abirkmanis]
**** Fix protect-lib without sequential logic (#2492). [Yutetsu TAKATSUKASA]
**** Fix V3Unknown from running with flat XML output (#2494). [James Hanlon]
**** Fix non-32 bit conversion to float (#2495). [dsvf]
**** Fix casting non-self-determined subexpressions (#2493). [phantom-killua]
**** Fix SystemC net names (#2500). [Edgar E. Iglesias]
**** Fix build with Bison 3.7 and newer (#2505). [Rupert Swarbrick]
**** Fix slice of unpacked array (#2506) (#2507). [Yutetsu TAKATSUKASA]
* Verilator 4.038 2020-07-11
** Versions 4.038 and 4.040 are planned to be the final versions that will
support pre-C++11 compilers. Please move to C++11 or newer compilers.
*** Support VPI access to parameters and localparam. [Ludwig Rogiers]
*** Support parsing (not elaboration, yet) of UVM.
**** Add new UNSUPPORTED error code to replace most previous Unsupported: messages.
**** With --bbox-unsup continue parsing on many (not all) UVM constructs.
**** Support for-loop increments with commas.
**** Support $swrite with arbitrary arguments.
**** Support $writememb (#2450). [Fan Shupei]
**** Fix OS X, Free BSD, and -m32 portability issues. [Geza Lore]
**** Fix to flush FST trace on termination due to $stop or assertion failure.
**** Fix part select error when multipling by power-of-two (#2413). [Conor McCullough]
**** Fix division exception (#2460) [Kuoping Hsu]
* Verilator 4.036 2020-06-06
** OPT_FAST is now -Os by default. See the BENCHMARKING & OPTIMIZATION part
+7 -6
View File
@@ -89,7 +89,6 @@ datarootdir = @datarootdir@
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
CFG_WITH_THREADED = @CFG_WITH_THREADED@
PACKAGE_VERSION = @PACKAGE_VERSION@
#### End of system configuration section. ####
@@ -171,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 \
@@ -425,6 +426,9 @@ CPPCHECK_CPP = $(wildcard \
CPPCHECK_H = $(wildcard \
$(srcdir)/include/*.h \
$(srcdir)/src/*.h )
CPPCHECK_YL = $(wildcard \
$(srcdir)/src/*.y \
$(srcdir)/src/*.l )
CPPCHECK = src/cppcheck_filtered
CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
@@ -435,7 +439,7 @@ CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
cppcheck: $(CPPCHECK_DEP)
%.cppcheck: %.cpp
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $<
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
CLANGTIDY = clang-tidy
CLANGTIDY_FLAGS = -config=''
@@ -462,7 +466,7 @@ CLANGFORMAT_FLAGS = -i
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)
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
ftp: info
@@ -543,9 +547,6 @@ dist-file-list:
@echo $(wildcard $(DISTFILES))
@echo "end-dist-file-list:"; # Scripts look for this
print-cfg-with-threaded:
@echo $(CFG_WITH_THREADED)
######################################################################
# Distributions
+534 -414
View File
File diff suppressed because it is too large Load Diff
+8 -1
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;
@@ -206,6 +207,12 @@ sub report {
print " stddev = " . ($stddev) . "\n";
print " e ^ stddev = " . exp($stddev). "\n";
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 {
+37 -5
View File
@@ -25,11 +25,21 @@ fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
MAKE=make
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
MAKE=make
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
MAKE=gmake
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
install-vcddiff() {
TMP_DIR="$(mktemp -d)"
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${TMP_DIR}"
"$MAKE" -C "${TMP_DIR}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
}
@@ -39,12 +49,20 @@ if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
# build Verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
time sudo apt-get update
sudo apt-get update
sudo apt-get install libfl-dev
sudo apt-get install libgoogle-perftools-dev
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
fi
if [ "$M32" = 1 ]; then
sudo apt-get install gcc-multilib g++-multilib
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update
brew install ccache perl gperftools
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
sudo pkg install -y autoconf bison ccache gmake perl5
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
@@ -59,12 +77,26 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
if [ "$TRAVIS_DIST" = "focal" ]; then
sudo apt-get install libsystemc-dev
fi
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
# Not listing Bit::Vector as slow to install, and only skips one test
install-vcddiff
if [ "$M32" = 1 ]; then
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
brew install ccache perl
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
# fst2vcd fails with "Could not open '<input file>', exiting."
sudo pkg install -y ccache gmake perl5 python3
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
# Common installs
if [ "$TRAVIS_DIST" != "trusty" ]; then
TRAVIS_CPAN_REPO=https://cpan.org
fi
# Not listing Bit::Vector as slow to install, and only skips one test
yes yes | sudo cpan -M $TRAVIS_CPAN_REPO -fi Unix::Processors Parallel::Forker
install-vcddiff
else
##############################################################################
# Unknown build stage
+93 -60
View File
@@ -22,77 +22,110 @@ fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export MAKE=make
NPROC=$(nproc)
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
export MAKE=make
NPROC=$(sysctl -n hw.logicalcpu)
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
export MAKE=gmake
NPROC=$(sysctl -n hw.ncpu)
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Build verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn
make -j $(nproc)
else
nodist/code_coverage --stages 1-2
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn
"$MAKE" -j "$NPROC" -k
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
file bin/verilator_bin
file bin/verilator_bin_dbg
md5 bin/verilator_bin
md5 bin/verilator_bin_dbg
stat bin/verilator_bin
stat bin/verilator_bin_dbg
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
nodist/code_coverage --stages 1-2
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Run tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# Run the specified test
case $TESTS in
dist-vlt-0)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
;;
dist-vlt-1)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
;;
vltmt-0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt-1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
coverage-dist)
nodist/code_coverage --stages 3- --scenarios=--dist
;;
coverage-vlt-0)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
;;
coverage-vlt-1)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
;;
coverage-vlt-2)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
;;
coverage-vlt-3)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
;;
coverage-vltmt-0)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
;;
coverage-vltmt-1)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
;;
coverage-vltmt-2)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
;;
coverage-vltmt-3)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
;;
*)
fatal "Unknown test: $TESTS"
;;
esac
# Upload coverage data to codecov.io
if [[ $TESTS == coverage-* ]]; then
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg
# export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd
file bin/verilator_bin
file bin/verilator_bin_dbg
md5 bin/verilator_bin
md5 bin/verilator_bin_dbg
stat bin/verilator_bin
stat bin/verilator_bin_dbg
# For some reason, the dbg exe is corrupted by this point ('file' reports
# it as data rather than a Mach-O). Unclear if this is an OS X issue or
# one for Travis. Remove the file and re-link...
rm bin/verilator_bin_dbg
"$MAKE" -j "$NPROC" -k
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run
export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable
fi
# Run the specified test
case $TESTS in
dist-vlt-0)
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
;;
dist-vlt-1)
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
;;
vltmt-0)
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt-1)
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
coverage-dist)
nodist/code_coverage --stages 3- --scenarios=--dist
;;
coverage-vlt-0)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
;;
coverage-vlt-1)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
;;
coverage-vlt-2)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
;;
coverage-vlt-3)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
;;
coverage-vltmt-0)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
;;
coverage-vltmt-1)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
;;
coverage-vltmt-2)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
;;
coverage-vltmt-3)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
;;
*)
fatal "Unknown test: $TESTS"
;;
esac
# Upload coverage data to codecov.io
if [[ $TESTS == coverage-* ]]; then
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
fi
else
##############################################################################
+47 -48
View File
@@ -7,11 +7,12 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.036 2020-06-06],
AC_INIT([Verilator],[4.102 2020-10-15],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
# and commit using "devel release" or "Version bump" message
# Then 'make maintainer-dist'
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
@@ -112,27 +113,11 @@ AC_ARG_ENABLE([longtests],
AC_SUBST(CFG_WITH_LONGTESTS)
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
# CFG_WITH_PREC11
AC_MSG_CHECKING(whether allow pre-C++11)
AC_ARG_ENABLE([prec11],
[AS_HELP_STRING([--enable-prec11],
[enable pre-C++11 compilers for Verilator binary
and Verilated makefiles])],
[case "${enableval}" in
yes) CFG_WITH_PREC11=yes ;;
no) CFG_WITH_PREC11=no ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11]) ;;
esac],
[CFG_WITH_PREC11=no;]
)
AC_SUBST(CFG_WITH_PREC11)
AC_MSG_RESULT($CFG_WITH_PREC11)
# Compiler flags
CFLAGS+=" -I${includedir}"
CPPFLAGS+=" -I${includedir}"
CXXFLAGS+=" -I${includedir}"
LDFLAGS+=" -L${libdir}"
# Compiler flags (ensure they are not empty to avoid configure defaults)
CFLAGS+=" "
CPPFLAGS+=" "
CXXFLAGS+=" "
LDFLAGS+=" "
# Checks for programs.
AC_PROG_CC
@@ -153,14 +138,20 @@ AC_PATH_PROG(PERL,perl)
if test "x$PERL" = "x" ; then
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
fi
AC_PATH_PROG(LEX,flex)
if test "x$LEX" = "x" ; then
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
fi
flex_version=$($LEX --version | head -1)
AC_MSG_RESULT([$LEX --version = $flex_version])
AC_PATH_PROG(YACC,bison)
if test "x$YACC" = "x" ; then
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
fi
bison_version=$($YACC --version | head -1)
AC_MSG_RESULT([$YACC --version = $bison_version])
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
if test "x$OBJCACHE" != "x" ; then
@@ -403,12 +394,17 @@ _MY_LDLIBS_CHECK_IFELSE(
fi])
AC_SUBST(CFG_LIBS)
# Set CFG_WITH_THREADED if can support threading
AC_MSG_CHECKING(whether $CXX supports Verilated threads)
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST $CFG_CXXFLAGS_NO_UNUSED"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <thread>], [[ ]])],
# Need C++11 at least
#Alternative: AX_CXX_COMPILE_STDCXX([11])
AC_DEFUN([_MY_CXX_CHECK_CXX_VER],
[# _MY_CXX_CHECK_CXX_VER(flag) -- Check if compiler runs C++11
# Set $_my_result
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <thread>
#if (__cplusplus < 201103L)
# error "Too old"
#endif
], [[ ]])],
[_my_result=yes
if test -s conftest.err; then
if grep -e "$1" conftest.err >/dev/null; then
@@ -416,25 +412,24 @@ AC_LINK_IFELSE(
fi
fi],
[_my_result=no])
CFG_WITH_THREADED=$_my_result
AC_SUBST(CFG_WITH_THREADED)
AC_MSG_RESULT($CFG_WITH_THREADED)
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
])
# Check compiler flag
if test "$CFG_WITH_THREADED" = "no" ; then
if test "$CFG_WITH_PREC11" = "no" ; then
AC_MSG_NOTICE([[]])
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
AC_MSG_CHECKING(whether $CXX supports C++11)
_MY_CXX_CHECK_CXX_VER()
AC_MSG_RESULT($_my_result)
if test "$_my_result" = "no" ; then
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST"
CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE $CFG_CXXFLAGS_STD_NEWEST"
AC_MSG_CHECKING(whether $CXX supports C++11 with $CFG_CXXFLAGS_STD_NEWEST)
_MY_CXX_CHECK_CXX_VER()
AC_MSG_RESULT($_my_result)
fi
if test "$_my_result" = "no" ; then
AC_MSG_NOTICE([[]])
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
Verilator plans to require a C++11 or newer compiler in a future release,
unless sufficient people report problems. Therefore, if you do not have a
C++11 compiler, please post a message to
https://www.veripool.org/boards/3/topics/2580-Verilator-Requiring-C-11-compiler
indicating your OS and when you think C++11 might be ok, and then rerun
configure with the --enable-prec11 argument. Thanks.]])
Verilator requires a C++11 or newer compiler.]])
fi
fi
# Checks for library functions.
@@ -447,14 +442,18 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
AC_MSG_CHECKING([whether SystemC is found (in system path)])
AC_COMPILE_IFELSE(
ACO_SAVE_LIBS="$LIBS"
LIBS="$LIBS -lsystemc"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <systemc.h>
]],[])],
extern "C" int sc_main(int argc, char* argv[]) {}
]],[[sc_version()]])],
[_my_result=yes
AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])],
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
[_my_result=no])
AC_MSG_RESULT($_my_result)
AC_SUBST(HAVE_SYSTEMC_H)
LIBS="$ACO_SAVE_LIBS"
AC_SUBST(HAVE_SYSTEMC)
# Checks for system services
+12
View File
@@ -6,25 +6,31 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
Ahmed El-Mahmoudy
Alex Chadwick
Chris Randall
Conor McCullough
Dan Petrisko
David Horton
David Stanford
Driss Hafdi
Edgar E. Iglesias
Eric Rippey
Fan Shupei
Garrett Smith
Geza Lore
Gianfranco Costamagna
Glen Gibb
Harald Heckmann
Howard Su
Huang Rui
Iztok Jeras
James Hanlon
James Hutchinson
Jamey Hicks
James Pallister
Jan Van Winkel
Jeremy Bennett
John Coiner
John Demme
Josh Redford
Julien Margetts
Kanad Kanhere
Kevin Kiningham
@@ -34,6 +40,8 @@ Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Markus Krause
Marshal Qiao
Matthew Ballance
Michael Killough
Mike Popoloski
@@ -44,8 +52,11 @@ Peter Horvath
Peter Monsson
Philipp Wagner
Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Rafal Kapuscik
Richard Myers
Rupert Swarbrick
Sean Cross
Sebastien Van Cauwenberghe
Sergi Granell
@@ -57,6 +68,7 @@ Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Tymoteusz Blazejczyk
Victor Besyakov
Vassilis Papaefstathiou
Veripool API Bot
Wilson Snyder
+9 -9
View File
@@ -39,7 +39,7 @@ brief:
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
git clone https://git.veripool.org/git/verilator # Only first time
git clone https://github.com/verilator/verilator # Only first time
## Note the URL above is not a page you can see with a browser, it's for git only
# Every time you need to build:
@@ -69,12 +69,12 @@ Linux distribution, see instead <<Install From a Package Manager>>.
=== OS Requirements
Verilator is developed and has primary testing on Ubuntu. Versions have
also built on Redhat Linux, Apple OS-X, HPUX and Solaris. It should run
with minor porting on any GNU/Linux-ish platform. Verilator also works on
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
output (not Verilator itself) compiles under all the options above, plus
MSVC++.
Verilator is developed and has primary testing on Ubuntu, with additional
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
Linux, HPUX and Solaris. It should run with minor porting on any
GNU/Linux-ish platform. Verilator also works on Windows under Cygwin, and
Windows under MinGW (gcc -mno-cygwin). Verilated output (not Verilator
itself) compiles under all the options above, plus MSVC++.
=== Install Prerequisites
@@ -89,7 +89,7 @@ To build or run the following are optional but should be installed for
good performance:
sudo apt-get install ccache # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl
sudo apt-get install libgoogle-perftools-dev numactl perl-doc
To build Verilator you will need to install these packages; these do not
need to be present to run Verilator:
@@ -128,7 +128,7 @@ Downloads]; we presume you know how to use it, and is not described here.)
Get the sources from the repository: (You need do this only once, ever.)
git clone https://git.veripool.org/git/verilator # Only first time
git clone https://github.com/verilator/verilator # Only first time
## Note the URL above is not a page you can see with a browser, it's for git only
Enter the checkout and determine what version/branch to use:
+16 -8
View File
@@ -387,10 +387,8 @@ changed; if clear, checking those signals for changes may be skipped.
=== Compiler Version and C++11
Verilator supports GCC 4.4.7 and newer. GCC 4.4.7 does not support C++11,
therefore C++11 is generally not required. Exceptions may be made to
require C++11 for features that are only practical with C++11,
e.g. threads.
Verilator requires C++11. Verilator does not require any newer versions,
but is maintained to build successfully with C++14/C++17/C++20.
=== Indentation and Naming Style
@@ -588,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
@@ -674,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,
);
@@ -760,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
@@ -777,9 +784,10 @@ output, for example:
You can then print a.ps. You may prefer gif format, which doesn't get
scaled so can be more useful with large graphs.
For dynamic graph viewing consider
For interactive graph viewing consider
https://github.com/jrfonseca/xdot.py[xdot] or
http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of
better viewers let us know; ZGRViewer isn't great for large graphs.
better viewers (especially for large graphs) please let us know.
=== .tree Output
-8
View File
@@ -29,19 +29,11 @@ int sc_main(int argc, char* argv[]) {
Vtop* top = new Vtop("top");
// Initialize SC model
#if (SYSTEMC_VERSION >= 20070314)
sc_start(1, SC_NS);
#else
sc_start(1);
#endif
// Simulate until $finish
while (!Verilated::gotFinish()) {
#if (SYSTEMC_VERSION >= 20070314)
sc_start(1, SC_NS);
#else
sc_start(1);
#endif
}
// Final model cleanup
+1 -1
View File
@@ -68,7 +68,7 @@ run:
@echo " library (libverilated_secret.a) generated from the previous"
@echo " step"
@echo "---------------------------------------------------------------"
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '../obj_dir_secret/libverilated_secret.a' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
@echo
@echo "-- COMPILE entire design --------------------------------------"
+3 -3
View File
@@ -31,7 +31,7 @@ int main(int argc, char** argv, char** env) {
#if VM_TRACE
// When tracing, the contents of the secret module will not be seen
VerilatedVcdC* tfp = NULL;
VerilatedVcdC* tfp = nullptr;
const char* flag = Verilated::commandArgsPlusMatch("trace");
if (flag && 0 == strcmp(flag, "+trace")) {
Verilated::traceEverOn(true);
@@ -62,13 +62,13 @@ int main(int argc, char** argv, char** env) {
#if VM_TRACE
if (tfp) {
tfp->close();
tfp = NULL;
tfp = nullptr;
}
#endif
// Destroy model
delete top;
top = NULL;
top = nullptr;
// Fin
exit(0);
+1 -1
View File
@@ -99,7 +99,7 @@ int main(int argc, char** argv, char** env) {
// Destroy model
delete top;
top = NULL;
top = nullptr;
// Fin
exit(0);
+3 -23
View File
@@ -44,21 +44,9 @@ int sc_main(int argc, char* argv[]) {
// General logfile
ios::sync_with_stdio();
// Defaults time
#if (SYSTEMC_VERSION > 20011000)
#else
sc_time dut(1.0, sc_ns);
sc_set_default_time_unit(dut);
#endif
// Define clocks
#if (SYSTEMC_VERSION >= 20070314)
sc_clock clk("clk", 10, SC_NS, 0.5, 3, SC_NS, true);
sc_clock fastclk("fastclk", 2, SC_NS, 0.5, 2, SC_NS, true);
#else
sc_clock clk("clk", 10, 0.5, 3, true);
sc_clock fastclk("fastclk", 2, 0.5, 2, true);
#endif
// Define interconnect
sc_signal<bool> reset_l;
@@ -89,16 +77,12 @@ int sc_main(int argc, char* argv[]) {
// You must do one evaluation before enabling waves, in order to allow
// SystemC to interconnect everything for testing.
#if (SYSTEMC_VERSION >= 20070314)
sc_start(1, SC_NS);
#else
sc_start(1);
#endif
#if VM_TRACE
// If verilator was invoked with --trace argument,
// and if at run time passed the +trace argument, turn on tracing
VerilatedVcdSc* tfp = NULL;
VerilatedVcdSc* tfp = nullptr;
const char* flag = Verilated::commandArgsPlusMatch("trace");
if (flag && 0 == strcmp(flag, "+trace")) {
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
@@ -125,11 +109,7 @@ int sc_main(int argc, char* argv[]) {
}
// Simulate 1ns
#if (SYSTEMC_VERSION >= 20070314)
sc_start(1, SC_NS);
#else
sc_start(1);
#endif
}
// Final model cleanup
@@ -139,7 +119,7 @@ int sc_main(int argc, char* argv[]) {
#if VM_TRACE
if (tfp) {
tfp->close();
tfp = NULL;
tfp = nullptr;
}
#endif
@@ -151,7 +131,7 @@ int sc_main(int argc, char* argv[]) {
// Destroy model
delete top;
top = NULL;
top = nullptr;
// Fin
return 0;
+1 -1
View File
@@ -3,7 +3,7 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
#if !defined(__MINGW32__)
#if !defined(__MINGW32__) && !defined(__FreeBSD__)
# define HAVE_ALLOCA_H 1
#endif
+19 -2
View File
@@ -794,6 +794,7 @@ pthread_t thread;
pthread_attr_t thread_attr;
struct fstWriterContext *xc_parent;
#endif
unsigned in_pthread : 1;
size_t fst_orig_break_size;
size_t fst_orig_break_add_size;
@@ -1806,10 +1807,9 @@ static void *fstWriterFlushContextPrivate1(void *ctx)
{
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
pthread_mutex_lock(&(xc->xc_parent->mutex));
fstWriterFlushContextPrivate2(xc);
pthread_mutex_unlock(&(xc->xc_parent->mutex));
#ifdef FST_REMOVE_DUPLICATE_VC
free(xc->curval_mem);
#endif
@@ -1818,6 +1818,9 @@ free(xc->vchg_mem);
tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
free(xc);
xc->xc_parent->in_pthread = 0;
pthread_mutex_unlock(&(xc->xc_parent->mutex));
return(NULL);
}
@@ -1865,7 +1868,15 @@ if(xc->parallel_enabled)
xc->section_header_only = 0;
xc->secnum++;
while (xc->in_pthread)
{
pthread_mutex_lock(&xc->mutex);
pthread_mutex_unlock(&xc->mutex);
};
pthread_mutex_lock(&xc->mutex);
xc->in_pthread = 1;
pthread_mutex_unlock(&xc->mutex);
pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
}
@@ -1947,6 +1958,12 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
#ifdef FST_WRITER_PARALLEL
pthread_mutex_lock(&xc->mutex);
pthread_mutex_unlock(&xc->mutex);
while (xc->in_pthread)
{
pthread_mutex_lock(&xc->mutex);
pthread_mutex_unlock(&xc->mutex);
};
#endif
}
}
+247 -140
View File
@@ -31,6 +31,8 @@
#include <cerrno>
#include <sstream>
#include <sys/stat.h> // mkdir
#include <list>
#include <utility>
// clang-format off
#if defined(_WIN32) || defined(__MINGW32__)
@@ -38,7 +40,8 @@
#endif
// clang-format on
#define VL_VALUE_STRING_MAX_WIDTH 8192 ///< Max static char array for VL_VALUE_STRING
/// Max static char array for VL_VALUE_STRING
constexpr unsigned VL_VALUE_STRING_MAX_WIDTH = 8192;
//===========================================================================
// Static sanity checks (when get C++11 can use static_assert)
@@ -59,7 +62,6 @@ typedef union {
// Slow path variables
VerilatedMutex Verilated::m_mutex;
VerilatedVoidCb Verilated::s_flushCb = NULL;
// Keep below together in one cache line
Verilated::Serialized Verilated::s_s;
@@ -68,7 +70,12 @@ VL_THREAD_LOCAL Verilated::ThreadLocal Verilated::t_s;
Verilated::CommandArgValues Verilated::s_args;
VerilatedImp VerilatedImp::s_s;
VerilatedImp::VerilatedImpU VerilatedImp::s_s;
struct VerilatedImpInitializer {
VerilatedImpInitializer() { VerilatedImp::setup(); }
~VerilatedImpInitializer() { VerilatedImp::teardown(); }
} g_VerilatedImpInitializer;
//===========================================================================
// User definable functions
@@ -83,7 +90,8 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
if (Verilated::gotFinish()) {
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
"- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
Verilated::flushCall();
Verilated::runFlushCallbacks();
Verilated::runExitCallbacks();
exit(0);
}
Verilated::gotFinish(true);
@@ -93,7 +101,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
#ifndef VL_USER_STOP ///< Define this to override this function
void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
Verilated::gotFinish(true);
Verilated::flushCall();
Verilated::runFlushCallbacks();
vl_fatal(filename, linenum, hier, "Verilog $stop");
}
#endif
@@ -108,10 +116,15 @@ void vl_fatal(const char* filename, int linenum, const char* hier, const char* m
} else {
VL_PRINTF("%%Error: %s\n", msg);
}
Verilated::flushCall();
Verilated::runFlushCallbacks();
VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread
Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush
// Second flush in case VL_PRINTF does something needing a flush
Verilated::runFlushCallbacks();
// Callbacks prior to termination
Verilated::runExitCallbacks();
abort();
}
#endif
@@ -169,7 +182,7 @@ void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char
std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
va_list aq;
va_copy(aq, ap);
int len = VL_VSNPRINTF(NULL, 0, formatp, aq);
int len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
va_end(aq);
if (VL_UNLIKELY(len < 1)) return "";
@@ -248,19 +261,17 @@ Verilated::Serialized::Serialized() {
}
Verilated::NonSerialized::NonSerialized() {
s_profThreadsStart = 1;
s_profThreadsWindow = 2;
s_profThreadsFilenamep = strdup("profile_threads.dat");
}
Verilated::NonSerialized::~NonSerialized() {
if (s_profThreadsFilenamep) {
VL_DO_CLEAR(free(const_cast<char*>(s_profThreadsFilenamep)),
s_profThreadsFilenamep = NULL);
s_profThreadsFilenamep = nullptr);
}
}
size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::s_s.m_ser); }
void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.m_ser; }
size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::s_s.v.m_ser); }
void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.v.m_ser; }
//===========================================================================
// Random -- Mostly called at init time, so not inline.
@@ -309,8 +320,6 @@ vluint64_t vl_rand64() VL_MT_SAFE {
return result;
}
IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
// LCOV_EXCL_START
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
@@ -577,6 +586,30 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsig
return VL_POW_QQW(obits, rbits, rbits, lhs, rwp);
}
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE {
int ms_word = VL_WORDS_I(lbits) - 1;
for (; !lwp[ms_word] && ms_word > 0;) --ms_word;
if (ms_word == 0) return static_cast<double>(lwp[0]);
if (ms_word == 1) return static_cast<double>(VL_SET_QW(lwp));
// We need 53 bits of mantissa, which might mean looking at 3 words
// namely ms_word, ms_word-1 and ms_word-2
EData ihi = lwp[ms_word];
EData imid = lwp[ms_word - 1];
EData ilo = lwp[ms_word - 2];
double hi = static_cast<double>(ihi) * exp2(2 * VL_EDATASIZE);
double mid = static_cast<double>(imid) * exp2(VL_EDATASIZE);
double lo = static_cast<double>(ilo);
double d = (hi + mid + lo) * exp2(VL_EDATASIZE * (ms_word - 2));
return d;
}
double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE {
if (!VL_SIGN_W(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp);
vluint32_t pos[VL_MULS_MAX_WORDS + 1]; // Fixed size, as MSVC++ doesn't allow [words] here
VL_NEGATE_W(VL_WORDS_I(lbits), pos, lwp);
_VL_CLEAN_INPLACE_W(lbits, pos);
return -VL_ITOR_D_W(lbits, pos);
}
//===========================================================================
// Formatting
@@ -656,7 +689,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
// Note also assumes variables < 64 are not wide, this assumption is
// sometimes not true in low-level routines written here in verilated.cpp
static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH];
const char* pctp = NULL; // Most recent %##.##g format
const char* pctp = nullptr; // Most recent %##.##g format
bool inPct = false;
bool widthSet = false;
bool left = false;
@@ -735,8 +768,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
if (!widthSet) width = VerilatedImp::timeFormatWidth();
output += _vl_vsformat_time(tmp, d, left, width);
} else {
std::string fmt(pctp, pos - pctp + 1);
sprintf(tmp, fmt.c_str(), d);
std::string fmts(pctp, pos - pctp + 1);
sprintf(tmp, fmts.c_str(), d);
output += tmp;
}
break;
@@ -746,7 +779,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const int lbits = va_arg(ap, int);
QData ld = 0;
WData qlwp[VL_WQ_WORDS_E];
WDataInP lwp = NULL;
WDataInP lwp = nullptr;
if (lbits <= VL_QUADSIZE) {
ld = _VL_VA_ARG_Q(ap, lbits);
VL_SET_WQ(qlwp, ld);
@@ -880,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
@@ -916,7 +950,7 @@ static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp,
} else {
if (floc < 0) return EOF;
floc = floc & ~7; // Align to closest character
if (fromp == NULL) {
if (fromp == nullptr) {
return fstr[fstr.length() - 1 - (floc >> 3)];
} else {
return VL_BITRSHIFT_W(fromp, floc) & 0xff;
@@ -938,7 +972,7 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, WDataInP fromp, const
while (true) {
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF || isspace(c)) break;
if (acceptp && NULL == strchr(acceptp, c)) break; // String - allow anything
if (acceptp && nullptr == strchr(acceptp, c)) break; // String - allow anything
if (acceptp) c = tolower(c); // Non-strings we'll simplify
*cp++ = c;
_vl_vsss_advance(fp, floc);
@@ -953,7 +987,7 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, WDataInP fromp, const
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
while (n-- > 0) {
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF) return NULL;
if (c == EOF) return nullptr;
if (!inhibit) *beginp++ = c;
_vl_vsss_advance(fp, floc);
}
@@ -1057,7 +1091,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 's': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, NULL);
_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;
@@ -1087,7 +1121,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
double r;
vlsint64_t ld;
} u;
u.r = strtod(tmp, NULL);
u.r = strtod(tmp, nullptr);
VL_SET_WQ(owp, u.ld);
break;
}
@@ -1149,10 +1183,12 @@ 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;
@@ -1378,7 +1414,7 @@ IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
IData got = _vl_vsscanf(fp, 0, NULL, "", formatp, ap);
IData got = _vl_vsscanf(fp, 0, nullptr, "", formatp, ap);
va_end(ap);
return got;
}
@@ -1389,7 +1425,7 @@ IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
IData got = _vl_vsscanf(NULL, lbits, fnw, "", formatp, ap);
IData got = _vl_vsscanf(nullptr, lbits, fnw, "", formatp, ap);
va_end(ap);
return got;
}
@@ -1399,21 +1435,21 @@ IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
IData got = _vl_vsscanf(NULL, lbits, fnw, "", formatp, ap);
IData got = _vl_vsscanf(nullptr, lbits, fnw, "", formatp, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
IData got = _vl_vsscanf(NULL, lbits, lwp, "", formatp, ap);
IData got = _vl_vsscanf(nullptr, lbits, lwp, "", formatp, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
IData got = _vl_vsscanf(NULL, ld.length() * 8, NULL, ld, formatp, ap);
IData got = _vl_vsscanf(nullptr, ld.length() * 8, nullptr, ld, formatp, ap);
va_end(ap);
return got;
}
@@ -1590,7 +1626,7 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_S
const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE {
const std::string& match = VerilatedImp::argPlusMatch(prefixp);
static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH];
if (match.empty()) return NULL;
if (match.empty()) return nullptr;
outstr[0] = '\0';
strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+"
VL_VALUE_STRING_MAX_WIDTH - 1);
@@ -1610,12 +1646,12 @@ std::string VL_TO_STRING_W(int words, WDataInP obj) {
std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE {
std::string out = ld;
for (std::string::iterator it = out.begin(); it != out.end(); ++it) *it = tolower(*it);
for (auto& cr : out) cr = tolower(cr);
return out;
}
std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
std::string out = ld;
for (std::string::iterator it = out.begin(); it != out.end(); ++it) *it = toupper(*it);
for (auto& cr : out) cr = toupper(cr);
return out;
}
@@ -1670,7 +1706,7 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
str_mod.erase(std::remove(str_mod.begin(), str_mod.end(), '_'), str_mod.end());
errno = 0;
long v = std::strtol(str_mod.c_str(), NULL, base);
auto v = std::strtol(str_mod.c_str(), nullptr, base);
if (errno != 0) v = 0;
return static_cast<IData>(v);
}
@@ -1700,7 +1736,7 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_
static const char* memhFormat(int nBits) {
assert((nBits >= 1) && (nBits <= 32));
static char buf[32];
static VL_THREAD_LOCAL char buf[32];
switch ((nBits - 1) / 4) {
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
@@ -1715,25 +1751,37 @@ static const char* memhFormat(int nBits) {
return buf;
}
static const char* formatBinary(int nBits, vluint32_t bits) {
assert((nBits >= 1) && (nBits <= 32));
static VL_THREAD_LOCAL char buf[64];
for (int i = 0; i < nBits; i++) {
bool isOne = bits & (1 << (nBits - 1 - i));
buf[i] = (isOne ? '1' : '0');
}
buf[nBits] = '\0';
return buf;
}
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
: m_hex(hex)
, m_bits(bits)
, m_filename(filename)
, m_end(end)
, m_addr(start)
, m_linenum(0) {
: m_hex{hex}
, m_bits{bits}
, m_filename(filename) // Need () or GCC 4.8 false warning
, m_end{end}
, m_addr{start}
, m_linenum{0} {
m_fp = fopen(filename.c_str(), "r");
if (VL_UNLIKELY(!m_fp)) {
// We don't report the Verilog source filename as it slow to have to pass it down
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
return;
}
}
VlReadMem::~VlReadMem() {
if (m_fp) {
fclose(m_fp);
m_fp = NULL;
m_fp = nullptr;
}
}
bool VlReadMem::get(QData& addrr, std::string& valuer) {
@@ -1821,8 +1869,8 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
QData shift = m_hex ? 4ULL : 1ULL;
bool innum = false;
// Shift value in
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
char c = tolower(*it);
for (const auto& i : rhs) {
char c = tolower(i);
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
if (m_bits <= 8) {
CData* datap = reinterpret_cast<CData*>(valuep);
@@ -1852,14 +1900,9 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
}
VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end)
: m_bits(bits)
, m_addr(0) {
if (VL_UNLIKELY(!hex)) {
VL_FATAL_MT(filename.c_str(), 0, "",
"Unsupported: $writemem binary format (suggest hex format)");
return;
}
: m_hex{hex}
, m_bits{bits}
, m_addr{0} {
if (VL_UNLIKELY(start > end)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range");
return;
@@ -1868,14 +1911,14 @@ VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData st
m_fp = fopen(filename.c_str(), "w");
if (VL_UNLIKELY(!m_fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
return;
}
}
VlWriteMem::~VlWriteMem() {
if (m_fp) {
fclose(m_fp);
m_fp = NULL;
m_fp = nullptr;
}
}
void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
@@ -1886,23 +1929,40 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
m_addr = addr + 1;
if (m_bits <= 8) {
const CData* datap = reinterpret_cast<const CData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else {
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
}
} else if (m_bits <= 16) {
const SData* datap = reinterpret_cast<const SData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else {
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
}
} else if (m_bits <= 32) {
const IData* datap = reinterpret_cast<const IData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else {
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
}
} else if (m_bits <= 64) {
const QData* datap = reinterpret_cast<const QData*>(valuep);
vluint64_t value = VL_MASK_Q(m_bits) & *datap;
vluint32_t lo = value & 0xffffffff;
vluint32_t hi = value >> 32;
fprintf(m_fp, memhFormat(m_bits - 32), hi);
fprintf(m_fp, "%08x\n", lo);
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits - 32), hi);
fprintf(m_fp, "%08x\n", lo);
} else {
fprintf(m_fp, "%s", formatBinary(m_bits - 32, hi));
fprintf(m_fp, "%s\n", formatBinary(32, lo));
}
} else {
WDataInP datap = reinterpret_cast<WDataInP>(valuep);
// output as a sequence of VL_EDATASIZE'd words
@@ -1915,9 +1975,17 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
if (first) {
data &= VL_MASK_E(m_bits);
int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1;
fprintf(m_fp, memhFormat(top_word_nbits), data);
if (m_hex) {
fprintf(m_fp, memhFormat(top_word_nbits), data);
} else {
fprintf(m_fp, "%s", formatBinary(top_word_nbits, data));
}
} else {
fprintf(m_fp, "%08x", data);
if (m_hex) {
fprintf(m_fp, "%08x", data);
} else {
fprintf(m_fp, "%s", formatBinary(32, data));
}
}
word_idx--;
first = false;
@@ -2111,17 +2179,7 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
//===========================================================================
// Verilated:: Methods
Verilated::ThreadLocal::ThreadLocal()
:
#ifdef VL_THREADED
t_mtaskId(0)
, t_endOfEvalReqd(0)
,
#endif
t_dpiScopep(NULL)
, t_dpiFilename(0)
, t_dpiLineno(0) {
}
Verilated::ThreadLocal::ThreadLocal() {}
Verilated::ThreadLocal::~ThreadLocal() {}
void Verilated::debug(int level) VL_MT_SAFE {
@@ -2228,7 +2286,7 @@ void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE {
// Returns new'ed data
// Used by symbol table creation to make module names
static VL_THREAD_LOCAL char* strp = NULL;
static VL_THREAD_LOCAL char* strp = nullptr;
static VL_THREAD_LOCAL size_t len = 0;
size_t newlen = strlen(n1) + strlen(n2) + strlen(delimiter) + 1;
if (!strp || newlen > len) {
@@ -2242,29 +2300,60 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
return strp;
}
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
if (s_flushCb == cb) { // Ok - don't duplicate
} else if (!s_flushCb) {
s_flushCb = cb;
} else { // LCOV_EXCL_LINE
// Someday we may allow multiple callbacks ala atexit(), but until then
VL_FATAL_MT("unknown", 0, "", // LCOV_EXCL_LINE
"Verilated::flushCb called twice with different callbacks");
}
//=========================================================================
// Flush and exit callbacks
// Keeping these out of class Verilated to avoid having to include <list>
// in verilated.h (for compilation speed)
typedef std::list<std::pair<Verilated::VoidPCb, void*>> VoidPCbList;
static VoidPCbList g_flushCbs;
static VoidPCbList g_exitCbs;
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
cbs.remove(pair); // Just in case it's a duplicate
cbs.push_back(pair);
}
static void removeCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
cbs.remove(pair);
}
static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE {
for (const auto& i : cbs) i.first(i.second);
}
// When running internal code coverage (gcc --coverage, as opposed to
// verilator --coverage), dump coverage data to properly cover failing
// tests.
void Verilated::flushCall() VL_MT_SAFE {
void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
if (s_flushCb) (*s_flushCb)();
addCb(cb, datap, g_flushCbs);
}
void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
removeCb(cb, datap, g_flushCbs);
}
void Verilated::runFlushCallbacks() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
runCallbacks(g_flushCbs);
fflush(stderr);
fflush(stdout);
// When running internal code coverage (gcc --coverage, as opposed to
// verilator --coverage), dump coverage data to properly cover failing
// tests.
VL_GCOV_FLUSH();
}
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
addCb(cb, datap, g_exitCbs);
}
void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
removeCb(cb, datap, g_exitCbs);
}
void Verilated::runExitCallbacks() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
runCallbacks(g_exitCbs);
}
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
@@ -2341,31 +2430,60 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
}
#endif
//===========================================================================
// VerilatedImp:: Constructors
// verilated.o may exist both in protect-lib and main module.
// Both the main module and the protec-lib refer the same instance of
// static variables such as Verilated or VerilatedImplData.
// This is important to share the state such as Verilated::gotFinish.
// But the sharing may cause double-free error when shutting down because destructors
// are called twice.
// 1st time:From protec-lib shared object on the way of unloading after exitting main()
// 2nd time:From main executable.
//
// To avoid the trouble, all member variables are enclosed in VerilatedImpU union.
// ctor nor dtor of members are not called automatically.
// VerilatedImp::setup() and teardown() guarantees to initialize/destruct just once.
void VerilatedImp::setup() {
static bool done = false;
if (!done) {
new (&VerilatedImp::s_s) VerilatedImpData();
done = true;
}
}
void VerilatedImp::teardown() {
static bool done = false;
if (!done) {
VerilatedImp::s_s.~VerilatedImpU();
done = true;
}
}
//===========================================================================
// VerilatedImp:: Methods
std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_sergMutex);
return s_s.m_serg.m_timeFormatSuffix;
const VerilatedLockGuard lock(s_s.v.m_sergMutex);
return s_s.v.m_serg.m_timeFormatSuffix;
}
void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_sergMutex);
s_s.m_serg.m_timeFormatSuffix = value;
const VerilatedLockGuard lock(s_s.v.m_sergMutex);
s_s.v.m_serg.m_timeFormatSuffix = value;
}
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = value; }
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.v.m_ser.m_timeFormatUnits = value; }
void VerilatedImp::timeFormatPrecision(int value) VL_MT_SAFE {
s_s.m_ser.m_timeFormatPrecision = value;
s_s.v.m_ser.m_timeFormatPrecision = value;
}
void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; }
void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.v.m_ser.m_timeFormatWidth = value; }
void VerilatedImp::internalsDump() VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_argMutex);
const VerilatedLockGuard lock(s_s.v.m_argMutex);
VL_PRINTF_MT("internalsDump:\n");
versionDump();
VL_PRINTF_MT(" Argv:");
for (ArgVec::const_iterator it = s_s.m_argVec.begin(); it != s_s.m_argVec.end(); ++it) {
VL_PRINTF_MT(" %s", it->c_str());
}
for (const auto& i : s_s.v.m_argVec) VL_PRINTF_MT(" %s", i.c_str());
VL_PRINTF_MT("\n");
scopesDump();
exportsDump();
@@ -2375,22 +2493,22 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
}
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
const VerilatedLockGuard lock(s_s.m_argMutex);
s_s.m_argVec.clear(); // Always clear
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex) {
const VerilatedLockGuard lock(s_s.v.m_argMutex);
s_s.v.m_argVec.clear(); // Always clear
commandArgsAddGuts(argc, argv);
}
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
const VerilatedLockGuard lock(s_s.m_argMutex);
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex) {
const VerilatedLockGuard lock(s_s.v.m_argMutex);
commandArgsAddGuts(argc, argv);
}
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.v.m_argMutex) {
if (!s_s.v.m_argVecLoaded) s_s.v.m_argVec.clear();
for (int i = 0; i < argc; ++i) {
s_s.m_argVec.push_back(argv[i]);
s_s.v.m_argVec.push_back(argv[i]);
commandArgVl(argv[i]);
}
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
s_s.v.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
}
void VerilatedImp::commandArgVl(const std::string& arg) {
if (0 == strncmp(arg.c_str(), "+verilator+", strlen("+verilator+"))) {
@@ -2460,12 +2578,12 @@ VerilatedSyms::~VerilatedSyms() {
// VerilatedModule:: Methods
VerilatedModule::VerilatedModule(const char* namep)
: m_namep(strdup(namep)) {}
: m_namep{strdup(namep)} {}
VerilatedModule::~VerilatedModule() {
// Memory cleanup - not called during normal operation
// NOLINTNEXTLINE(google-readability-casting)
if (m_namep) VL_DO_CLEAR(free((void*)(m_namep)), m_namep = NULL);
if (m_namep) VL_DO_CLEAR(free((void*)(m_namep)), m_namep = nullptr);
}
//======================================================================
@@ -2481,7 +2599,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;
}
@@ -2493,8 +2611,8 @@ size_t VerilatedVarProps::totalSize() const {
}
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return NULL;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL;
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
int indxAdj = indx - low(dim);
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
@@ -2507,23 +2625,14 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
//======================================================================
// VerilatedScope:: Methods
VerilatedScope::VerilatedScope() {
m_callbacksp = NULL;
m_namep = NULL;
m_identifierp = NULL;
m_funcnumMax = 0;
m_symsp = NULL;
m_varsp = NULL;
m_timeunit = 0;
m_type = SCOPE_OTHER;
}
VerilatedScope::VerilatedScope() {}
VerilatedScope::~VerilatedScope() {
// Memory cleanup - not called during normal operation
VerilatedImp::scopeErase(this);
if (m_namep) VL_DO_CLEAR(delete[] m_namep, m_namep = NULL);
if (m_callbacksp) VL_DO_CLEAR(delete[] m_callbacksp, m_callbacksp = NULL);
if (m_varsp) VL_DO_CLEAR(delete m_varsp, m_varsp = NULL);
if (m_namep) VL_DO_CLEAR(delete[] m_namep, m_namep = nullptr);
if (m_callbacksp) VL_DO_CLEAR(delete[] m_callbacksp, m_callbacksp = nullptr);
if (m_varsp) VL_DO_CLEAR(delete m_varsp, m_varsp = nullptr);
m_funcnumMax = 0; // Force callback table to empty
}
@@ -2565,7 +2674,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
}
}
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE {
// Grab dimensions
// In the future we may just create a large table at emit time and
@@ -2573,7 +2682,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
if (!finalize) return;
if (!m_varsp) m_varsp = new VerilatedVarNameMap();
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims);
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims, isParam);
va_list ap;
va_start(ap, dims);
@@ -2602,10 +2711,10 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
// cppcheck-suppress unusedFunction // Used by applications
VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTINIT {
if (VL_LIKELY(m_varsp)) {
VerilatedVarNameMap::iterator it = m_varsp->find(namep);
const auto it = m_varsp->find(namep);
if (VL_LIKELY(it != m_varsp->end())) return &(it->second);
}
return NULL;
return nullptr;
}
void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
@@ -2614,7 +2723,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
+ "' but scope wasn't set, perhaps due to dpi import call without "
+ "'context', or missing svSetScope. See IEEE 1800-2017 35.5.3.");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return NULL;
return nullptr;
}
void* VerilatedScope::exportFindError(int funcnum) const {
@@ -2623,7 +2732,7 @@ void* VerilatedScope::exportFindError(int funcnum) const {
+ "' but this DPI export function exists only in other scopes, not scope '"
+ name() + "'");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return NULL;
return nullptr;
}
void VerilatedScope::scopeDump() const {
@@ -2635,9 +2744,7 @@ void VerilatedScope::scopeDump() const {
}
}
if (VerilatedVarNameMap* varsp = this->varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp->begin(); it != varsp->end(); ++it) {
VL_PRINTF_MT(" VAR %p: %s\n", &(it->second), it->first);
}
for (const auto& i : *varsp) VL_PRINTF_MT(" VAR %p: %s\n", &(i.second), i.first);
}
}
+87 -57
View File
@@ -61,7 +61,7 @@
// Version check
#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION < 20111121)
# warning "Verilator soon requires SystemC 2.3.*; see manual for deprecated other versions."
# warning "Verilator requires SystemC 2.3.* or newer."
#endif
// clang-format on
@@ -84,10 +84,6 @@ typedef EData WData; ///< Verilated pack data, >64 bits, as an array
typedef const WData* WDataInP; ///< Array input to a function
typedef WData* WDataOutP; ///< Array output from a function
typedef void (*VerilatedVoidCb)(void);
class SpTraceVcd;
class SpTraceVcdCFile;
class VerilatedEvalMsgQueue;
class VerilatedScopeNameMap;
class VerilatedVar;
@@ -98,7 +94,7 @@ class VerilatedVcdSc;
class VerilatedFst;
class VerilatedFstC;
enum VerilatedVarType {
enum VerilatedVarType : vluint8_t {
VLVT_UNKNOWN = 0,
VLVT_PTR, // Pointer to something
VLVT_UINT8, // AKA CData
@@ -167,7 +163,7 @@ private:
public:
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr)
: m_mutexr(mutexr) {
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
m_mutexr.lock();
}
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
@@ -207,7 +203,7 @@ public:
/// The constructor establishes the thread id for all later calls.
/// If necessary, a different class could be made that inits it otherwise.
VerilatedAssertOneThread()
: m_threadid(VL_THREAD_ID()) {}
: m_threadid{VL_THREAD_ID()} {}
~VerilatedAssertOneThread() { check(); }
// METHODS
/// Check that the current thread ID is the same as the construction thread ID
@@ -317,21 +313,21 @@ public: // But for internal use only
class VerilatedScope {
public:
typedef enum {
typedef enum : vluint8_t {
SCOPE_MODULE,
SCOPE_OTHER
} Type; // Type of a scope, currently module is only interesting
private:
// Fastpath:
VerilatedSyms* m_symsp; ///< Symbol table
void** m_callbacksp; ///< Callback table pointer (Fastpath)
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
VerilatedSyms* m_symsp = nullptr; ///< Symbol table
void** m_callbacksp = nullptr; ///< Callback table pointer (Fastpath)
int m_funcnumMax = 0; ///< Maxium function number stored (Fastpath)
// 4 bytes padding (on -m64), for rent.
VerilatedVarNameMap* m_varsp; ///< Variable map
const char* m_namep; ///< Scope name (Slowpath)
const char* m_identifierp; ///< Identifier of scope (with escapes removed)
vlsint8_t m_timeunit; ///< Timeunit in negative power-of-10
Type m_type; ///< Type of the scope
VerilatedVarNameMap* m_varsp = nullptr; ///< Variable map
const char* m_namep = nullptr; ///< Scope name (Slowpath)
const char* m_identifierp = nullptr; ///< Identifier of scope (with escapes removed)
vlsint8_t m_timeunit = 0; ///< Timeunit in negative power-of-10
Type m_type = SCOPE_OTHER; ///< Type of the scope
public: // But internals only - called from VerilatedModule's
VerilatedScope();
@@ -339,8 +335,8 @@ public: // But internals only - called from VerilatedModule's
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
int vlflags, int dims, ...) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
// ACCESSORS
const char* name() const { return m_namep; }
const char* identifier() const { return m_identifierp; }
@@ -376,8 +372,6 @@ class Verilated {
// Slow path variables
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
static VerilatedVoidCb s_flushCb; ///< Flush callback function
static struct Serialized { // All these members serialized/deserialized
// Fast path
int s_debug; ///< See accessors... only when VL_DEBUG set
@@ -399,8 +393,8 @@ class Verilated {
static struct NonSerialized { // Non-serialized information
// These are reloaded from on command-line settings, so do not need to persist
// Fast path
vluint64_t s_profThreadsStart; ///< +prof+threads starting time
vluint32_t s_profThreadsWindow; ///< +prof+threads window size
vluint64_t s_profThreadsStart = 1; ///< +prof+threads starting time
vluint32_t s_profThreadsWindow = 2; ///< +prof+threads window size
// Slow path
const char* s_profThreadsFilenamep; ///< +prof+threads filename
NonSerialized();
@@ -411,23 +405,22 @@ class Verilated {
// assumption is that the restore is allowed to pass different arguments
static struct CommandArgValues {
VerilatedMutex m_argMutex; ///< Mutex for s_args members, when VL_THREADED
int argc;
const char** argv;
CommandArgValues()
: argc(0)
, argv(NULL) {}
int argc = 0;
const char** argv = nullptr;
CommandArgValues() {}
~CommandArgValues() {}
} s_args;
// Not covered by mutex, as per-thread
static VL_THREAD_LOCAL struct ThreadLocal {
#ifdef VL_THREADED
vluint32_t t_mtaskId; ///< Current mtask# executing on this thread
vluint32_t t_endOfEvalReqd; ///< Messages may be pending, thread needs endOf-eval calls
vluint32_t t_mtaskId = 0; ///< Current mtask# executing on this thread
vluint32_t t_endOfEvalReqd
= 0; ///< Messages may be pending, thread needs endOf-eval calls
#endif
const VerilatedScope* t_dpiScopep; ///< DPI context scope
const char* t_dpiFilename; ///< DPI context filename
int t_dpiLineno; ///< DPI context line number
const VerilatedScope* t_dpiScopep = nullptr; ///< DPI context scope
const char* t_dpiFilename = nullptr; ///< DPI context filename
int t_dpiLineno = 0; ///< DPI context line number
ThreadLocal();
~ThreadLocal();
@@ -501,9 +494,16 @@ public:
static void profThreadsFilenamep(const char* flagp) VL_MT_SAFE;
static const char* profThreadsFilenamep() VL_MT_SAFE { return s_ns.s_profThreadsFilenamep; }
/// Flush callback for VCD waves
static void flushCb(VerilatedVoidCb cb) VL_MT_SAFE;
static void flushCall() VL_MT_SAFE;
typedef void (*VoidPCb)(void*); // Callback type for below
/// Callbacks to run on global flush
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;
static void runExitCallbacks() VL_MT_SAFE;
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs,
/// and for parsing +verilator+ run-time arguments.
@@ -561,8 +561,8 @@ public:
t_s.t_dpiFilename = filenamep;
t_s.t_dpiLineno = lineno;
}
static void dpiClearContext() VL_MT_SAFE { t_s.t_dpiScopep = NULL; }
static bool dpiInContext() VL_MT_SAFE { return t_s.t_dpiScopep != NULL; }
static void dpiClearContext() VL_MT_SAFE { t_s.t_dpiScopep = nullptr; }
static bool dpiInContext() VL_MT_SAFE { return t_s.t_dpiScopep != nullptr; }
static const char* dpiFilenamep() VL_MT_SAFE { return t_s.t_dpiFilename; }
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
static int exportFuncNum(const char* namep) VL_MT_SAFE;
@@ -644,9 +644,19 @@ extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
/// Print a debug message from internals with standard prefix, with printf style format
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
extern IData VL_RANDOM_I(int obits); ///< Randomize a signal
extern QData VL_RANDOM_Q(int obits); ///< Randomize a signal
extern vluint64_t vl_rand64() VL_MT_SAFE;
inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signal
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
vluint64_t rnd = vl_rand64();
if (VL_LIKELY(hi > lo)) {
// Modulus isn't very fast but it's common that hi-low is power-of-two
return (rnd % (hi - lo)) + lo;
} else {
return (rnd % (lo - hi)) + hi;
}
}
/// Init time only, so slow is fine
extern IData VL_RAND_RESET_I(int obits); ///< Random reset a signal
@@ -764,9 +774,27 @@ static inline QData VL_CVT_Q_D(double lhs) VL_PURE {
}
// clang-format on
/// Return double from QData (numeric)
static inline double VL_ITOR_D_I(IData lhs) VL_PURE {
return static_cast<double>(static_cast<vlsint32_t>(lhs));
/// Return double from lhs (numeric) unsigned
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE;
static inline double VL_ITOR_D_I(int, IData lhs) VL_PURE {
return static_cast<double>(static_cast<vluint32_t>(lhs));
}
static inline double VL_ITOR_D_Q(int, QData lhs) VL_PURE {
return static_cast<double>(static_cast<vluint64_t>(lhs));
}
/// Return double from lhs (numeric) signed
double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE;
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_PURE {
if (lbits == 32) return static_cast<double>(static_cast<vlsint32_t>(lhs));
WData lwp[VL_WQ_WORDS_E];
VL_SET_WI(lwp, lhs);
return VL_ISTOR_D_W(lbits, lwp);
}
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_PURE {
if (lbits == 64) return static_cast<double>(static_cast<vlsint64_t>(lhs));
WData lwp[VL_WQ_WORDS_E];
VL_SET_WQ(lwp, lhs);
return VL_ISTOR_D_W(lbits, lwp);
}
/// Return QData from double (numeric)
static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
@@ -819,13 +847,8 @@ extern int VL_TIME_STR_CONVERT(const char* strp) VL_PURE;
/// Return current simulation time
#if defined(SYSTEMC_VERSION)
# if SYSTEMC_VERSION > 20011000
// Already defined: extern sc_time sc_time_stamp();
inline vluint64_t vl_time_stamp64() { return sc_time_stamp().value(); }
# else // Before SystemC changed to integral time representation
// Already defined: extern double sc_time_stamp();
inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_stamp()); }
# endif
#else // Non-SystemC
# ifdef VL_TIME_STAMP64
extern vluint64_t vl_time_stamp64();
@@ -843,7 +866,7 @@ inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_sta
// Optimized assuming scale is always constant.
// Can't use multiply in Q flavor, as might lose precision
#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast<QData>(scale))
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() * (1.0 / (scale)))
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast<double>(scale))
/// Time imported from units to time precision
double vl_time_multiplier(int scale);
@@ -1453,6 +1476,7 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
//=========================================================================
// Math
// Output NOT clean
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE {
EData carry = 1;
for (int i = 0; i < words; ++i) {
@@ -1571,24 +1595,30 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
static inline IData VL_DIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline QData VL_DIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline IData VL_MODDIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
return lhs_signed % rhs_signed;
}
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
return lhs_signed % rhs_signed;
@@ -2532,25 +2562,25 @@ static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase,
EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0;
_END(obits,1);
_END(obits, VL_WORDS_I(lsb) + 1);
}
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase,
EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1;
_END(obits,2);
_END(obits, VL_WORDS_I(lsb) + 2);
}
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase,
EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2;
_END(obits,3);
_END(obits, VL_WORDS_I(lsb) + 3);
}
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase,
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
_END(obits,4);
_END(obits, VL_WORDS_I(lsb) + 4);
}
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
EData d4,
@@ -2558,7 +2588,7 @@ static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4;
_END(obits,5);
_END(obits, VL_WORDS_I(lsb) + 5);
}
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
EData d5, EData d4,
@@ -2566,7 +2596,7 @@ static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4; o[5] = d5;
_END(obits,6);
_END(obits, VL_WORDS_I(lsb) + 6);
}
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
EData d6, EData d5, EData d4,
@@ -2574,7 +2604,7 @@ static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4; o[5] = d5; o[6] = d6;
_END(obits,7);
_END(obits, VL_WORDS_I(lsb) + 7);
}
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
EData d7, EData d6, EData d5, EData d4,
@@ -2582,7 +2612,7 @@ static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4; o[5] = d5; o[6] = d6; o[7] = d7;
_END(obits,8);
_END(obits, VL_WORDS_I(lsb) + 8);
}
#undef _END
+24 -3
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
@@ -200,9 +201,29 @@ else
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
endif
$(VM_PREFIX)__ALL.a: $(VK_OBJS)
$(AR) -cr $@ $^
$(RANLIB) $@
# When archiving just objects (.o), single $(AR) run is enough.
# When merging objects (.o) and archives (.a), the following steps are taken.
# 1. Extract object files from .a
# 2. Create a new archive from extracted .o and given .o
%.a:
@echo "Archive $(AR) -cr $@ $^"
@if test $(words $(filter %.a,$^)) -eq 0; then \
$(AR) -cr $@ $^; \
$(RANLIB) $@; \
else \
$(RM) -rf $*__tmpdir; \
for archive in $(filter %.a,$^); do \
mkdir -p $*__tmpdir/$$(basename $${archive}); \
cd $*__tmpdir/$$(basename $${archive}); \
$(AR) -x ../../$${archive}; \
cd ../..; \
done; \
$(AR) -cr $@ $(filter %.o,$^) $*__tmpdir/*/*.o; \
$(RM) -rf $*__tmpdir; \
fi
$(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
######################################################################
### Compile rules
+38 -50
View File
@@ -70,15 +70,15 @@ private:
public:
// METHODS
// cppcheck-suppress truncLongCastReturn
virtual vluint64_t count() const VL_OVERRIDE { return *m_countp; }
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
virtual vluint64_t count() const override { return *m_countp; }
virtual void zero() const override { *m_countp = 0; }
// CONSTRUCTORS
// cppcheck-suppress noExplicitConstructor
explicit VerilatedCoverItemSpec(T* countp)
: m_countp(countp) {
: m_countp{countp} {
*m_countp = 0;
}
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
virtual ~VerilatedCoverItemSpec() override {}
};
//=============================================================================
@@ -100,16 +100,12 @@ private:
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for keys
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert
int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex) = nullptr; ///< Item about to insert
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex) = nullptr; ///< Filename about to insert
int m_insertLineno VL_GUARDED_BY(m_mutex) = 0; ///< Line number about to insert
// CONSTRUCTORS
VerilatedCovImp() {
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
}
VerilatedCovImp() {}
VL_UNCOPYABLE(VerilatedCovImp);
public:
@@ -123,7 +119,7 @@ private:
// PRIVATE METHODS
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
static int nextIndex = KEY_UNDEF + 1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
const auto iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++;
assert(nextIndex > 0); // Didn't rollover
@@ -220,26 +216,22 @@ private:
}
static void selftest() VL_MT_SAFE {
// Little selftest
#define VL_CST_CHECK(got, exp) \
#define SELF_CHECK(got, exp) \
do { \
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
} while (0)
VL_CST_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
VL_CST_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
VL_CST_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
VL_CST_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
VL_CST_CHECK(combineHier("z", "a"), "*");
VL_CST_CHECK(combineHier("q.a", "q.b"), "q.*");
VL_CST_CHECK(combineHier("q.za", "q.zb"), "q.z*");
VL_CST_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
#undef VL_CST_CHECK
SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
SELF_CHECK(combineHier("z", "a"), "*");
SELF_CHECK(combineHier("q.a", "q.b"), "q.*");
SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*");
SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
#undef SELF_CHECK
}
void clearGuts() VL_REQUIRES(m_mutex) {
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
VL_DO_DANGLING(delete itemp, itemp);
}
for (const auto& itemp : m_items) VL_DO_DANGLING(delete itemp, itemp);
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
@@ -257,8 +249,7 @@ public:
const VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
for (const auto& itemp : m_items) {
if (!itemMatchesString(itemp, matchp)) {
VL_DO_DANGLING(delete itemp, itemp);
} else {
@@ -271,9 +262,7 @@ public:
void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
const VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
(*it)->zero();
}
for (const auto& itemp : m_items) itemp->zero();
}
// We assume there's always call to i/f/p in that order
@@ -341,7 +330,7 @@ public:
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
m_insertp = nullptr;
}
void write(const char* filename) VL_EXCLUDES(m_mutex) {
@@ -361,10 +350,9 @@ 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<std::string, std::pair<std::string, vluint64_t>> EventMap;
EventMap eventCounts;
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
for (const auto& itemp : m_items) {
std::string name;
std::string hier;
bool per_instance = false;
@@ -395,7 +383,7 @@ public:
// inefficient)
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
const auto cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const std::string& oldhier = cit->second.first;
cit->second.second += itemp->count();
@@ -406,11 +394,11 @@ public:
}
// Output body
for (EventMap::const_iterator it = eventCounts.begin(); it != eventCounts.end(); ++it) {
for (const auto& i : eventCounts) {
os << "C '" << std::dec;
os << it->first;
if (!it->second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, it->second.first);
os << "' " << it->second.second;
os << i.first;
if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first);
os << "' " << i.second.second;
os << std::endl;
}
}
@@ -446,15 +434,15 @@ void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8)
A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28),
A(29)) VL_MT_SAFE {
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
= {NULL, NULL, NULL, // filename,lineno,page
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
= {nullptr, nullptr, nullptr, // filename,lineno,page
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
const char* valps[VerilatedCovImpBase::MAX_KEYS]
= {NULL, NULL, NULL, // filename,lineno,page
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
= {nullptr, nullptr, nullptr, // filename,lineno,page
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
VerilatedCovImp::imp().insertp(keyps, valps);
}
+1 -1
View File
@@ -112,7 +112,7 @@ public:
// there's not much more gain in having a version for each number of args.
#define K(n) const char* key##n
#define A(n) const char *key##n, const char *valp##n // Argument list
#define D(n) const char *key##n = NULL, const char *valp##n = NULL // Argument list
#define D(n) const char *key##n = nullptr, const char *valp##n = nullptr // Argument list
static void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9));
static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11),
D(12), D(13), D(14), D(15), D(16), D(17), D(18), D(19));
+10 -10
View File
@@ -181,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
if (VL_UNLIKELY(!h)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"%%Error: DPI svOpenArrayHandle function called with NULL handle");
"%%Error: DPI svOpenArrayHandle function called with nullptr handle");
}
const VerilatedDpiOpenVar* varp = reinterpret_cast<const VerilatedDpiOpenVar*>(h);
if (VL_UNLIKELY(!varp->magicOk())) {
@@ -202,10 +202,10 @@ int svIncrement(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h
int svSize(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->elements(d); }
int svDimensions(const svOpenArrayHandle h) { return _vl_openhandle_varp(h)->udims(); }
/// Return pointer to open array data, or NULL if not in IEEE standard C layout
/// Return pointer to open array data, or nullptr if not in IEEE standard C layout
void* svGetArrayPtr(const svOpenArrayHandle h) {
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return nullptr;
return varp->datap();
}
/// Return size of open array, or 0 if not in IEEE standard C layout
@@ -226,7 +226,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
" %d dimensional array using %d dimensional function.\n",
varp->udims(), nargs);
return NULL;
return nullptr;
}
if (nargs >= 1) {
datap = varp->datapAdjustIndex(datap, 1, indx1);
@@ -234,7 +234,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 "
"out of bounds; %d outside [%d:%d].\n",
indx1, varp->left(1), varp->right(1));
return NULL;
return nullptr;
}
}
if (nargs >= 2) {
@@ -243,7 +243,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 "
"out of bounds; %d outside [%d:%d].\n",
indx2, varp->left(2), varp->right(2));
return NULL;
return nullptr;
}
}
if (nargs >= 3) {
@@ -252,7 +252,7 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, i
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 "
"out of bounds; %d outside [%d:%d].\n",
indx1, varp->left(3), varp->right(3));
return NULL;
return nullptr;
}
}
return datap;
@@ -268,11 +268,11 @@ static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
return indx - varp->low(0);
}
/// Return pointer to simulator open array element, or NULL if outside range
/// Return pointer to simulator open array element, or nullptr if outside range
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, int nargs, int indx1, int indx2,
int indx3) VL_MT_SAFE {
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return nullptr;
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
return datap;
}
@@ -794,7 +794,7 @@ void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int
svScope svGetScope() {
if (VL_UNLIKELY(!Verilated::dpiInContext())) {
_VL_SVDPI_CONTEXT_WARN();
return NULL;
return nullptr;
}
// NOLINTNEXTLINE(google-readability-casting)
return (svScope)(Verilated::dpiScope());
+15 -20
View File
@@ -58,14 +58,12 @@
// VerilatedFst
VerilatedFst::VerilatedFst(void* fst)
: m_fst(fst)
, m_symbolp(NULL)
, m_strbuf(NULL) {}
: m_fst{fst} {}
VerilatedFst::~VerilatedFst() {
if (m_fst) fstWriterClose(m_fst);
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL);
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = NULL);
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = nullptr);
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = nullptr);
}
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
@@ -82,7 +80,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
VerilatedTrace<VerilatedFst>::traceInit();
// Clear the scope stack
std::list<std::string>::iterator it = m_curScope.begin();
auto it = m_curScope.begin();
while (it != m_curScope.end()) {
fstWriterSetUpscope(m_fst);
it = m_curScope.erase(it);
@@ -91,10 +89,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
// convert m_code2symbol into an array for fast lookup
if (!m_symbolp) {
m_symbolp = new fstHandle[nextCode()];
for (Code2SymbolType::iterator it = m_code2symbol.begin(); it != m_code2symbol.end();
++it) {
m_symbolp[it->first] = it->second;
}
for (const auto& i : m_code2symbol) m_symbolp[i.first] = i.second;
}
m_code2symbol.clear();
@@ -106,7 +101,7 @@ void VerilatedFst::close() {
m_assertOne.check();
VerilatedTrace<VerilatedFst>::close();
fstWriterClose(m_fst);
m_fst = NULL;
m_fst = nullptr;
}
void VerilatedFst::flush() {
@@ -133,8 +128,6 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
std::pair<Code2SymbolType::iterator, bool> p
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
std::istringstream nameiss(name);
std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
@@ -144,8 +137,8 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy
// Find point where current and new scope diverge
std::list<std::string>::iterator cur_it = m_curScope.begin();
std::list<std::string>::iterator new_it = tokens.begin();
auto cur_it = m_curScope.begin();
auto new_it = tokens.begin();
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
if (*cur_it != *new_it) break;
++cur_it;
@@ -160,7 +153,7 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
// Follow the hierarchy of the new variable from the common scope point
while (new_it != tokens.end()) {
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), NULL);
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), nullptr);
m_curScope.push_back(*new_it);
new_it = tokens.erase(new_it);
}
@@ -174,11 +167,13 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
fstWriterEmitEnumTableRef(m_fst, enumNum);
}
if (p.second) { // New
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
assert(p.first->second);
const auto it = vlstd::as_const(m_code2symbol).find(code);
if (it == m_code2symbol.end()) { // New
m_code2symbol[code]
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
} else { // Alias
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second);
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
}
}
+9 -9
View File
@@ -50,8 +50,8 @@ private:
Code2SymbolType m_code2symbol;
Local2FstDtype m_local2fstdtype;
std::list<std::string> m_curScope;
fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array
char* m_strbuf; ///< String buffer long enough to hold maxBits() chars
fstHandle* m_symbolp = nullptr; ///< same as m_code2symbol, but as an array
char* m_strbuf = nullptr; ///< String buffer long enough to hold maxBits() chars
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFst);
@@ -63,11 +63,11 @@ protected:
// Implementation of VerilatedTrace interface
// Implementations of protected virtual methods for VerilatedTrace
void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;
virtual void emitTimeChange(vluint64_t timeui) override;
// Hooks called from VerilatedTrace
bool preFullDump() VL_OVERRIDE { return isOpen(); }
bool preChangeDump() VL_OVERRIDE { return isOpen(); }
virtual bool preFullDump() override { return isOpen(); }
virtual bool preChangeDump() override { return isOpen(); }
// Implementations of duck-typed methods for VerilatedTrace. These are
// called from only one place (namely full*) so always inline them.
@@ -83,7 +83,7 @@ public:
//=========================================================================
// External interface to client code
explicit VerilatedFst(void* fst = NULL);
explicit VerilatedFst(void* fst = nullptr);
~VerilatedFst();
/// Open the file; call isOpen() to see if errors
@@ -93,7 +93,7 @@ public:
/// Flush any remaining data to this file
void flush() VL_MT_UNSAFE;
/// Is file open?
bool isOpen() const { return m_fst != NULL; }
bool isOpen() const { return m_fst != nullptr; }
//=========================================================================
// Internal interface to Verilator generated code
@@ -135,8 +135,8 @@ class VerilatedFstC {
VL_UNCOPYABLE(VerilatedFstC);
public:
explicit VerilatedFstC(void* filep = NULL)
: m_sptrace(filep) {}
explicit VerilatedFstC(void* filep = nullptr)
: m_sptrace{filep} {}
~VerilatedFstC() { close(); }
/// Routines can only be called from one thread; allow next call from different thread
void changeThread() { spTrace()->changeThread(); }
+19 -26
View File
@@ -55,28 +55,28 @@ class VlReadMem {
public:
VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end);
~VlReadMem();
bool isOpen() const { return m_fp != NULL; }
bool isOpen() const { return m_fp != nullptr; }
int linenum() const { return m_linenum; }
bool get(QData& addrr, std::string& valuer);
void setData(void* valuep, const std::string& rhs);
};
class VlWriteMem {
bool m_hex; // Hex format
int m_bits; // Bit width of values
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to write
public:
VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end);
~VlWriteMem();
bool isOpen() const { return m_fp != NULL; }
bool isOpen() const { return m_fp != nullptr; }
void print(QData addr, bool addrstamp, const void* valuep);
};
//===================================================================
// Verilog array container
// Similar to std::array<WData, N>, but:
// 1. Doesn't require C++11
// 2. Lighter weight, only methods needed by Verilator, to help compile time.
// Similar to std::array<WData, N>, but lighter weight, only methods needed
// by Verilator, to help compile time.
//
// This is only used when we need an upper-level container and so can't
// simply use a C style array (which is just a pointer).
@@ -145,21 +145,21 @@ public:
int exists(const T_Key& index) const { return m_map.find(index) != m_map.end(); }
// Return first element. Verilog: function int first(ref index);
int first(T_Key& indexr) const {
typename Map::const_iterator it = m_map.begin();
const auto it = m_map.cbegin();
if (it == m_map.end()) return 0;
indexr = it->first;
return 1;
}
// Return last element. Verilog: function int last(ref index)
int last(T_Key& indexr) const {
typename Map::const_reverse_iterator it = m_map.rbegin();
const auto it = m_map.crbegin();
if (it == m_map.rend()) return 0;
indexr = it->first;
return 1;
}
// Return next element. Verilog: function int next(ref index)
int next(T_Key& indexr) const {
typename Map::const_iterator it = m_map.find(indexr);
auto it = m_map.find(indexr);
if (VL_UNLIKELY(it == m_map.end())) return 0;
++it;
if (VL_UNLIKELY(it == m_map.end())) return 0;
@@ -168,7 +168,7 @@ public:
}
// Return prev element. Verilog: function int prev(ref index)
int prev(T_Key& indexr) const {
typename Map::const_iterator it = m_map.find(indexr);
auto it = m_map.find(indexr);
if (VL_UNLIKELY(it == m_map.end())) return 0;
if (VL_UNLIKELY(it == m_map.begin())) return 0;
--it;
@@ -179,7 +179,7 @@ public:
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(const T_Key& index) {
typename Map::iterator it = m_map.find(index);
const auto it = m_map.find(index);
if (it == m_map.end()) {
std::pair<typename Map::iterator, bool> pit
= m_map.insert(std::make_pair(index, m_defaultValue));
@@ -189,7 +189,7 @@ public:
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(const T_Key& index) const {
typename Map::iterator it = m_map.find(index);
const auto it = m_map.find(index);
if (it == m_map.end()) {
return m_defaultValue;
} else {
@@ -204,8 +204,8 @@ public:
std::string to_string() const {
std::string out = "'{";
std::string comma;
for (typename Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
out += comma + VL_TO_STRING(it->first) + ":" + VL_TO_STRING(it->second);
for (const auto& i : m_map) {
out += comma + VL_TO_STRING(i.first) + ":" + VL_TO_STRING(i.second);
comma = ", ";
}
// Default not printed - maybe random init data
@@ -239,10 +239,9 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
const VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
VlWriteMem wmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!wmem.isOpen())) return;
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = obj.begin(); it != obj.end();
++it) {
QData addr = it->first;
if (addr >= start && addr <= end) wmem.print(addr, true, &(it->second));
for (const auto& i : obj) {
QData addr = i.first;
if (addr >= start && addr <= end) wmem.print(addr, true, &(i.second));
}
}
@@ -361,8 +360,8 @@ public:
std::string to_string() const {
std::string out = "'{";
std::string comma;
for (typename Deque::const_iterator it = m_deque.begin(); it != m_deque.end(); ++it) {
out += comma + VL_TO_STRING(*it);
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
@@ -379,13 +378,7 @@ template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
// be protected by other means
//
// clang-format off
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || (__cplusplus >= 201103L)
# define VlClassRef std::shared_ptr
#else
# define VlClassRef VlClassRef__SystemVerilog_class_support_requires_a_C11_or_newer_compiler
#endif
// clang-format on
#define VlClassRef std::shared_ptr
template <class T> // T typically of type VlClassRef<x>
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
+140 -130
View File
@@ -62,8 +62,8 @@ private:
public:
// CONSTRUCTORS
VerilatedMsg(const std::function<void()>& cb)
: m_mtaskId(Verilated::mtaskId())
, m_cb(cb) {}
: m_mtaskId{Verilated::mtaskId()}
, m_cb{cb} {}
~VerilatedMsg() {}
// METHODS
vluint32_t mtaskId() const { return m_mtaskId; }
@@ -84,7 +84,7 @@ class VerilatedEvalMsgQueue {
public:
// CONSTRUCTORS
VerilatedEvalMsgQueue()
: m_depth(0) {
: m_depth{0} {
assert(atomic_is_lock_free(&m_depth));
}
~VerilatedEvalMsgQueue() {}
@@ -112,7 +112,7 @@ public:
// Unfortunately to release the lock we need to copy the message
// (Or have the message be a pointer, but then new/delete cost on each message)
// We assume messages are small, so copy
auto it = m_queue.begin();
const auto it = m_queue.begin();
const VerilatedMsg msg = *(it);
m_queue.erase(it);
m_mutex.unlock();
@@ -172,12 +172,11 @@ public:
// FILE* list constructed from a file-descriptor
class VerilatedFpList {
FILE* m_fp[31];
std::size_t m_sz;
std::size_t m_sz = 0;
public:
typedef FILE* const* const_iterator;
explicit VerilatedFpList()
: m_sz(0) {}
explicit VerilatedFpList() {}
const_iterator begin() const { return m_fp; }
const_iterator end() const { return m_fp + m_sz; }
std::size_t size() const { return m_sz; }
@@ -190,10 +189,11 @@ public:
//======================================================================
// VerilatedImp
class VerilatedImp {
class VerilatedImpData {
// Whole class is internal use only - Global information shared between verilated*.cpp files.
protected:
friend class Verilated;
friend class VerilatedImp;
// TYPES
typedef std::vector<std::string> ArgVec;
@@ -201,17 +201,13 @@ protected:
typedef std::map<const char*, int, VerilatedCStrCmp> ExportNameMap;
// MEMBERS
static VerilatedImp s_s; ///< Static Singleton; One and only static this
struct Serialized { // All these members serialized/deserialized
int m_timeFormatUnits; // $timeformat units
int m_timeFormatPrecision; // $timeformat number of decimal places
int m_timeFormatWidth; // $timeformat character width
int m_timeFormatUnits = UNITS_NONE; // $timeformat units
int m_timeFormatPrecision = 0; // $timeformat number of decimal places
int m_timeFormatWidth = 20; // $timeformat character width
enum { UNITS_NONE = 99 }; // Default based on precision
Serialized()
: m_timeFormatUnits(UNITS_NONE)
, m_timeFormatPrecision(0)
, m_timeFormatWidth(20) {}
Serialized() {}
~Serialized() {}
} m_ser;
@@ -252,19 +248,37 @@ protected:
// List of free descriptors in the MCT region [4, 32)
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
// CONSTRUCTORS
VerilatedImpData()
: m_argVecLoaded{false}
, m_exportNext{0} {
m_fdps.resize(31);
std::fill(m_fdps.begin(), m_fdps.end(), (FILE*)0);
m_fdFreeMct.resize(30);
for (std::size_t i = 0, id = 1; i < m_fdFreeMct.size(); ++i, ++id) { m_fdFreeMct[i] = id; }
}
};
class VerilatedImp {
// Whole class is internal use only - Global information shared between verilated*.cpp files.
protected:
friend class Verilated;
// MEMBERS
union VerilatedImpU { ///< Enclose in an union to call ctor/dtor manually
VerilatedImpData v;
VerilatedImpU() {}
~VerilatedImpU() {}
};
static VerilatedImpU s_s; ///< Static Singleton; One and only static this
public: // But only for verilated*.cpp
// CONSTRUCTORS
VerilatedImp()
: m_argVecLoaded(false)
, m_exportNext(0) {
s_s.m_fdps.resize(31);
std::fill(s_s.m_fdps.begin(), s_s.m_fdps.end(), (FILE*)0);
s_s.m_fdFreeMct.resize(30);
for (std::size_t i = 0, id = 1; i < s_s.m_fdFreeMct.size(); ++i, ++id) {
s_s.m_fdFreeMct[i] = id;
}
}
VerilatedImp() {}
~VerilatedImp() {}
static void setup();
static void teardown();
private:
VL_UNCOPYABLE(VerilatedImp);
@@ -276,28 +290,28 @@ public:
// METHODS - arguments
public:
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
const VerilatedLockGuard lock(s_s.m_argMutex);
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex);
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex);
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.v.m_argMutex) {
const VerilatedLockGuard lock(s_s.v.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
s_s.m_argVecLoaded = true; // Complain only once
if (VL_UNLIKELY(!s_s.v.m_argVecLoaded)) {
s_s.v.m_argVecLoaded = true; // Complain only once
VL_FATAL_MT("unknown", 0, "",
"%Error: Verilog called $test$plusargs or $value$plusargs without"
" testbench C first calling Verilated::commandArgs(argc,argv).");
}
for (ArgVec::const_iterator it = s_s.m_argVec.begin(); it != s_s.m_argVec.end(); ++it) {
if ((*it)[0] == '+') {
if (0 == strncmp(prefixp, it->c_str() + 1, len)) return *it;
for (const auto& i : s_s.v.m_argVec) {
if (i[0] == '+') {
if (0 == strncmp(prefixp, i.c_str() + 1, len)) return i;
}
}
return "";
}
private:
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.v.m_argMutex);
static void commandArgVl(const std::string& arg);
static bool commandArgVlValue(const std::string& arg, const std::string& prefix,
std::string& valuer);
@@ -308,18 +322,18 @@ public:
// There's often many more scopes than userdata's and thus having a ~48byte
// per map overhead * N scopes would take much more space and cache thrashing.
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (it != s_s.m_userMap.end()) {
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
const auto it = s_s.v.m_userMap.find(std::make_pair(scopep, userKey));
if (it != s_s.v.m_userMap.end()) {
it->second = userData;
} else {
s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
s_s.v.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
}
}
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL;
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
const auto& it = vlstd::as_const(s_s.v.m_userMap).find(std::make_pair(scopep, userKey));
if (VL_UNLIKELY(it == s_s.v.m_userMap.end())) return nullptr;
return it->second;
}
@@ -327,25 +341,26 @@ private:
/// Symbol table destruction cleans up the entries for each scope.
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope on destruction, so we simply iterate.
const VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) {
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
for (auto it = s_s.v.m_userMap.begin(); it != s_s.v.m_userMap.end();) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
s_s.v.m_userMap.erase(it++);
} else {
++it;
}
}
}
static void userDump() VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
const VerilatedLockGuard lock(
s_s.v.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) {
for (const auto& i : s_s.v.m_userMap) {
if (first) {
VL_PRINTF_MT(" userDump:\n");
first = false;
}
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", it->first.first,
it->first.second, it->second);
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", i.first.first, i.first.second,
i.second);
}
}
@@ -353,51 +368,50 @@ public: // But only for verilated*.cpp
// METHODS - scope name
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at construction
const VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
const auto it = s_s.v.m_nameMap.find(scopep->name());
if (it == s_s.v.m_nameMap.end()) {
s_s.v.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
}
}
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep);
if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL;
const auto& it = s_s.v.m_nameMap.find(namep);
if (VL_UNLIKELY(it == s_s.v.m_nameMap.end())) return nullptr;
return it->second;
}
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at destruction
const VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
const auto it = s_s.v.m_nameMap.find(scopep->name());
if (it != s_s.v.m_nameMap.end()) s_s.v.m_nameMap.erase(it);
}
static void scopesDump() VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
it != s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
for (const auto& i : s_s.v.m_nameMap) {
const VerilatedScope* scopep = i.second;
scopep->scopeDump();
}
VL_PRINTF_MT("\n");
}
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
// Thread save only assuming this is called only after model construction completed
return &s_s.m_nameMap;
return &s_s.v.m_nameMap;
}
public: // But only for verilated*.cpp
// METHODS - hierarchy
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
// Slow ok - called at construction for VPI accessible elements
const VerilatedLockGuard lock(s_s.m_hierMapMutex);
s_s.m_hierMap[fromp].push_back(top);
const VerilatedLockGuard lock(s_s.v.m_hierMapMutex);
s_s.v.m_hierMap[fromp].push_back(top);
}
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
// Thread save only assuming this is called only after model construction completed
return &s_s.m_hierMap;
return &s_s.v.m_hierMap;
}
public: // But only for verilated*.cpp
@@ -411,19 +425,19 @@ public: // But only for verilated*.cpp
// miss at the cost of a multiply, and all lookups move to slowpath.
static int exportInsert(const char* namep) VL_MT_SAFE {
// Slow ok - called once/function at creation
const VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it = s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
return s_s.m_exportNext++;
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
const auto it = s_s.v.m_exportMap.find(namep);
if (it == s_s.v.m_exportMap.end()) {
s_s.v.m_exportMap.insert(it, std::make_pair(namep, s_s.v.m_exportNext++));
return s_s.v.m_exportNext++;
} else {
return it->second;
}
}
static int exportFind(const char* namep) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
const auto& it = s_s.v.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.v.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ") + namep
+ " but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
@@ -431,23 +445,21 @@ public: // But only for verilated*.cpp
}
static const char* exportName(int funcnum) VL_MT_SAFE {
// Slowpath; find name for given export; errors only so no map to reverse-map it
const VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
it != s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
for (const auto& i : s_s.v.m_exportMap) {
if (i.second == funcnum) return i.first;
}
return "*UNKNOWN*";
}
static void exportsDump() VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_exportMutex);
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
it != s_s.m_exportMap.end(); ++it) {
for (const auto& i : s_s.v.m_exportMap) {
if (first) {
VL_PRINTF_MT(" exportDump:\n");
first = false;
}
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", i.second, i.first);
}
}
// We don't free up m_exportMap until the end, because we can't be sure
@@ -458,13 +470,13 @@ public: // But only for verilated*.cpp
static std::string timeFormatSuffix() VL_MT_SAFE;
static void timeFormatSuffix(const std::string& value) VL_MT_SAFE;
static int timeFormatUnits() VL_MT_SAFE {
if (s_s.m_ser.m_timeFormatUnits == Serialized::UNITS_NONE) {
if (s_s.v.m_ser.m_timeFormatUnits == VerilatedImpData::Serialized::UNITS_NONE) {
return Verilated::timeprecision();
}
return s_s.m_ser.m_timeFormatUnits;
return s_s.v.m_ser.m_timeFormatUnits;
}
static int timeFormatPrecision() VL_MT_SAFE { return s_s.m_ser.m_timeFormatPrecision; }
static int timeFormatWidth() VL_MT_SAFE { return s_s.m_ser.m_timeFormatWidth; }
static int timeFormatPrecision() VL_MT_SAFE { return s_s.v.m_ser.m_timeFormatPrecision; }
static int timeFormatWidth() VL_MT_SAFE { return s_s.v.m_ser.m_timeFormatWidth; }
static void timeFormatUnits(int value) VL_MT_SAFE;
static void timeFormatPrecision(int value) VL_MT_SAFE;
static void timeFormatWidth(int value) VL_MT_SAFE;
@@ -472,93 +484,91 @@ public: // But only for verilated*.cpp
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFreeMct.empty()) return 0;
IData idx = s_s.m_fdFreeMct.back();
s_s.m_fdFreeMct.pop_back();
s_s.m_fdps[idx] = fopen(filenamep, "w");
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return 0;
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
if (s_s.v.m_fdFreeMct.empty()) return 0;
IData idx = s_s.v.m_fdFreeMct.back();
s_s.v.m_fdFreeMct.pop_back();
s_s.v.m_fdps[idx] = fopen(filenamep, "w");
if (VL_UNLIKELY(!s_s.v.m_fdps[idx])) return 0;
return (1 << idx);
}
static IData fdNew(const char* filenamep, const char* modep) VL_MT_SAFE {
FILE* fp = fopen(filenamep, modep);
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
if (s_s.v.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
const size_t excess = 10;
s_s.m_fdps.resize(start + excess);
std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0);
s_s.m_fdFree.resize(excess);
for (std::size_t i = 0, id = start; i < s_s.m_fdFree.size(); ++i, ++id) {
s_s.m_fdFree[i] = id;
const std::size_t start = std::max<std::size_t>(31UL + 1UL + 3UL, s_s.v.m_fdps.size());
const std::size_t excess = 10;
s_s.v.m_fdps.resize(start + excess);
std::fill(s_s.v.m_fdps.begin() + start, s_s.v.m_fdps.end(), (FILE*)0);
s_s.v.m_fdFree.resize(excess);
for (std::size_t i = 0, id = start; i < s_s.v.m_fdFree.size(); ++i, ++id) {
s_s.v.m_fdFree[i] = id;
}
}
IData idx = s_s.m_fdFree.back();
s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
IData idx = s_s.v.m_fdFree.back();
s_s.v.m_fdFree.pop_back();
s_s.v.m_fdps[idx] = fp;
return (idx | (1UL << 31)); // bit 31 indicates not MCD
}
static void fdFlush(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
fflush(*it);
}
for (const auto& i : fdlist) fflush(i);
}
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(
fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
}
static IData fdTell(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(ftell(*fdlist.begin()));
}
static void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
if (VL_UNLIKELY(!*it)) continue;
fwrite(output.c_str(), 1, output.size(), *it);
for (const auto& i : fdlist) {
if (VL_UNLIKELY(!i)) continue;
(void)fwrite(output.c_str(), 1, output.size(), i);
}
}
static void fdClose(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
fclose(s_s.m_fdps[idx]);
s_s.m_fdps[idx] = (FILE*)0;
s_s.m_fdFree.push_back(idx);
if (VL_UNLIKELY(idx >= s_s.v.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.v.m_fdps[idx])) return; // Already free
fclose(s_s.v.m_fdps[idx]);
s_s.v.m_fdps[idx] = (FILE*)0;
s_s.v.m_fdFree.push_back(idx);
} else {
// MCD case
for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) {
fclose(s_s.m_fdps[i]);
s_s.m_fdps[i] = NULL;
s_s.m_fdFreeMct.push_back(i);
fclose(s_s.v.m_fdps[i]);
s_s.v.m_fdps[i] = nullptr;
s_s.v.m_fdFreeMct.push_back(i);
}
}
}
}
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return NULL;
if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr;
return *fdlist.begin();
}
private:
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.m_fdMutex) {
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.v.m_fdMutex) {
VerilatedFpList fp;
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
@@ -568,13 +578,13 @@ private:
case 1: fp.push_back(stdout); break;
case 2: fp.push_back(stderr); break;
default:
if (VL_LIKELY(idx < s_s.m_fdps.size())) fp.push_back(s_s.m_fdps[idx]);
if (VL_LIKELY(idx < s_s.v.m_fdps.size())) fp.push_back(s_s.v.m_fdps[idx]);
break;
}
} else {
// MCD Case
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.m_fdps[i]);
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.v.m_fdps[i]);
}
}
return fp;
+14 -11
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
}
}
@@ -129,7 +132,7 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep,
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
if (m_fd < 0) {
if (VL_UNLIKELY(m_fd < 0)) {
// User code can check isOpen()
m_isOpen = false;
return;
@@ -151,7 +154,7 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
if (m_fd < 0) {
if (VL_UNLIKELY(m_fd < 0)) {
// User code can check isOpen()
m_isOpen = false;
return;
+19 -25
View File
@@ -34,7 +34,7 @@ protected:
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
bool m_isOpen; ///< True indicates open file/stream
bool m_isOpen = false; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
@@ -49,13 +49,12 @@ protected:
public:
VerilatedSerialize() {
m_isOpen = false;
m_bufp = new vluint8_t[bufferSize()];
m_cp = m_bufp;
}
virtual ~VerilatedSerialize() {
close();
if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL);
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
}
// METHODS
bool isOpen() const { return m_isOpen; }
@@ -94,8 +93,8 @@ protected:
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
bool m_isOpen; ///< True indicates open file/stream
vluint8_t* m_endp = nullptr; ///< Last valid byte in m_bufp buffer
bool m_isOpen = false; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
@@ -111,14 +110,12 @@ protected:
public:
VerilatedDeserialize() {
m_isOpen = false;
m_bufp = new vluint8_t[bufferSize()];
m_cp = m_bufp;
m_endp = NULL;
}
virtual ~VerilatedDeserialize() {
close();
if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL);
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
}
// METHODS
bool isOpen() const { return m_isOpen; }
@@ -159,19 +156,18 @@ private:
class VerilatedSave : public VerilatedSerialize {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd = -1; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
VerilatedSave()
: m_fd(-1) {}
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
VerilatedSave() {}
virtual ~VerilatedSave() override { close(); }
// METHODS
/// Open the file; call isOpen() to see if errors
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
virtual void close() override VL_MT_UNSAFE_ONE;
virtual void flush() override VL_MT_UNSAFE_ONE;
};
//=============================================================================
@@ -180,21 +176,20 @@ public:
class VerilatedRestore : public VerilatedDeserialize {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd = -1; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
VerilatedRestore()
: m_fd(-1) {}
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
VerilatedRestore() {}
virtual ~VerilatedRestore() override { close(); }
// METHODS
/// Open the file; call isOpen() to see if errors
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
virtual void fill() VL_OVERRIDE VL_MT_UNSAFE_ONE;
virtual void close() override VL_MT_UNSAFE_ONE;
virtual void flush() override VL_MT_UNSAFE_ONE {}
virtual void fill() override VL_MT_UNSAFE_ONE;
};
//=============================================================================
@@ -257,10 +252,9 @@ VerilatedSerialize& operator<<(VerilatedSerialize& os, VlAssocArray<T_Key, T_Val
os << rhs.atDefault();
vluint32_t len = rhs.size();
os << len;
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = rhs.begin(); it != rhs.end();
++it) {
T_Key index = it->first; // Copy to get around const_iterator
T_Value value = it->second;
for (const auto& i : rhs) {
T_Key index = i.first; // Copy to get around const_iterator
T_Value value = i.second;
os << index << value;
}
return os;
+43 -40
View File
@@ -44,11 +44,11 @@ protected:
friend class VerilatedVarProps;
friend class VerilatedScope;
VerilatedRange()
: m_left(0)
, m_right(0) {}
: m_left{0}
, m_right{0} {}
VerilatedRange(int left, int right)
: m_left(left)
, m_right(right) {}
: m_left{left}
, m_right{right} {}
void init(int left, int right) {
m_left = left;
m_right = right;
@@ -92,48 +92,48 @@ class VerilatedVarProps {
protected:
friend class VerilatedScope;
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(vlflags)
, m_pdims(pdims)
, m_udims(udims) {
initUnpacked(NULL);
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags{vlflags}
, m_pdims{pdims}
, m_udims{udims} {
initUnpacked(nullptr);
}
public:
class Unpacked {};
// Without packed
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(0) {}
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
, m_pdims{0}
, m_udims{0} {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(udims) {
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
, m_pdims{0}
, m_udims{udims} {
initUnpacked(ulims);
}
// With packed
class Packed {};
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(0)
, m_packed(pl, pr) {}
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
, m_pdims{1}
, m_udims{0}
, m_packed{pl, pr} {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int udims, const int* ulims)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(udims)
, m_packed(pl, pr) {
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
, m_pdims{1}
, m_udims{udims}
, m_packed{pl, pr} {
initUnpacked(ulims);
}
@@ -196,11 +196,11 @@ class VerilatedDpiOpenVar {
public:
// CONSTRUCTORS
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
: m_propsp(propsp)
, m_datap(datap) {}
: m_propsp{propsp}
, m_datap{datap} {}
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap)
: m_propsp(propsp)
, m_datap(const_cast<void*>(datap)) {}
: m_propsp{propsp}
, m_datap{const_cast<void*>(datap)} {}
~VerilatedDpiOpenVar() {}
// METHODS
void* datap() const { return m_datap; }
@@ -232,13 +232,15 @@ class VerilatedVar : public VerilatedVarProps {
void* m_datap; // Location of data
const char* m_namep; // Name - slowpath
protected:
bool m_isParam;
friend class VerilatedScope;
// CONSTRUCTORS
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
VerilatedVarFlags vlflags, int dims)
: VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0))
, m_datap(datap)
, m_namep(namep) {}
VerilatedVarFlags vlflags, int dims, bool isParam)
: VerilatedVarProps{vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)}
, m_datap{datap}
, m_namep{namep}
, m_isParam{isParam} {}
public:
~VerilatedVar() {}
@@ -247,6 +249,7 @@ public:
const VerilatedRange& range() const { return packed(); } // Deprecated
const VerilatedRange& array() const { return unpacked(); } // Deprecated
const char* name() const { return m_namep; }
bool isParam() const { return m_isParam; }
};
#endif // Guard
+20 -24
View File
@@ -21,14 +21,14 @@
std::atomic<vluint64_t> VlMTaskVertex::s_yields;
VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = NULL;
VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = nullptr;
//=============================================================================
// VlMTaskVertex
VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
: m_upstreamDepsDone(0)
, m_upstreamDepCount(upstreamDepCount) {
: m_upstreamDepsDone{0}
, m_upstreamDepCount{upstreamDepCount} {
assert(atomic_is_lock_free(&m_upstreamDepsDone));
}
@@ -36,13 +36,11 @@ VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
// VlWorkerThread
VlWorkerThread::VlWorkerThread(VlThreadPool* poolp, bool profiling)
: m_waiting(false)
, m_ready_size(0)
, m_poolp(poolp)
, m_profiling(profiling)
, m_exiting(false)
// Must init this last -- after setting up fields that it might read:
, m_cthread(startWorker, this) {}
: m_waiting{false}
, m_poolp{poolp}
, m_profiling{profiling} // Must init this last -- after setting up fields that it might read:
, m_exiting{false}
, m_cthread{startWorker, this} {}
VlWorkerThread::~VlWorkerThread() {
m_exiting.store(true, std::memory_order_release);
@@ -55,7 +53,7 @@ void VlWorkerThread::workerLoop() {
if (VL_UNLIKELY(m_profiling)) m_poolp->setupProfilingClientThread();
ExecRec work;
work.m_fnp = NULL;
work.m_fnp = nullptr;
while (true) {
if (VL_LIKELY(!work.m_fnp)) dequeWork(&work);
@@ -65,7 +63,7 @@ void VlWorkerThread::workerLoop() {
if (VL_LIKELY(work.m_fnp)) {
work.m_fnp(work.m_evenCycle, work.m_sym);
work.m_fnp = NULL;
work.m_fnp = nullptr;
}
}
@@ -78,7 +76,7 @@ void VlWorkerThread::startWorker(VlWorkerThread* workerp) { workerp->workerLoop(
// VlThreadPool
VlThreadPool::VlThreadPool(int nThreads, bool profiling)
: m_profiling(profiling) {
: m_profiling{profiling} {
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
unsigned cpus = std::thread::hardware_concurrency();
if (cpus < nThreads + 1) {
@@ -110,7 +108,7 @@ VlThreadPool::~VlThreadPool() {
void VlThreadPool::tearDownProfilingClientThread() {
assert(t_profilep);
delete t_profilep;
t_profilep = NULL;
t_profilep = nullptr;
}
void VlThreadPool::setupProfilingClientThread() {
@@ -127,9 +125,9 @@ void VlThreadPool::setupProfilingClientThread() {
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
const VerilatedLockGuard lk(m_mutex);
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
for (const auto& profilep : m_allProfiles) {
// Every thread's profile trace gets a copy of rec.
(*it)->emplace_back(rec);
profilep->emplace_back(rec);
}
}
@@ -141,7 +139,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
@@ -154,13 +152,12 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n", VlMTaskVertex::yields());
vluint32_t thread_id = 0;
for (ProfileSet::const_iterator pit = m_allProfiles.begin(); pit != m_allProfiles.end();
++pit) {
for (const auto& pi : m_allProfiles) {
++thread_id;
bool printing = false; // False while in warmup phase
for (ProfileTrace::const_iterator eit = (*pit)->begin(); eit != (*pit)->end(); ++eit) {
switch (eit->m_type) {
for (const auto& ei : *pi) {
switch (ei.m_type) {
case VlProfileRec::TYPE_BARRIER: //
printing = true;
break;
@@ -170,9 +167,8 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
"VLPROF mtask %d"
" start %" VL_PRI64 "u end %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
" predict_time %u cpu %u on thread %u\n",
eit->m_mtaskId, eit->m_startTime, eit->m_endTime,
(eit->m_endTime - eit->m_startTime), eit->m_predictTime, eit->m_cpu,
thread_id);
ei.m_mtaskId, ei.m_startTime, ei.m_endTime,
(ei.m_endTime - ei.m_startTime), ei.m_predictTime, ei.m_cpu, thread_id);
break;
default: assert(false); break; // LCOV_EXCL_LINE
}
+21 -19
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>
@@ -119,23 +128,16 @@ class VlProfileRec {
protected:
friend class VlThreadPool;
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
VlProfileE m_type; // Record type
vluint32_t m_mtaskId; // Mtask we're logging
vluint32_t m_predictTime; // How long scheduler predicted would take
vluint64_t m_startTime; // Tick at start of execution
vluint64_t m_endTime; // Tick at end of execution
VlProfileE m_type = TYPE_BARRIER; // Record type
vluint32_t m_mtaskId = 0; // Mtask we're logging
vluint32_t m_predictTime = 0; // How long scheduler predicted would take
vluint64_t m_startTime = 0; // Tick at start of execution
vluint64_t m_endTime = 0; // Tick at end of execution
unsigned m_cpu; // Execution CPU number (at start anyways)
public:
class Barrier {};
VlProfileRec() {}
explicit VlProfileRec(Barrier) {
m_type = TYPE_BARRIER;
m_mtaskId = 0;
m_predictTime = 0;
m_startTime = 0;
m_endTime = 0;
m_cpu = getcpu();
}
explicit VlProfileRec(Barrier) { m_cpu = getcpu(); }
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
m_type = VlProfileRec::TYPE_MTASK_RUN;
m_mtaskId = mtask;
@@ -174,13 +176,13 @@ private:
VlThrSymTab m_sym; // Symbol table to execute
bool m_evenCycle; // Even/odd for flag alternation
ExecRec()
: m_fnp(NULL)
, m_sym(NULL)
, m_evenCycle(false) {}
: m_fnp{nullptr}
, m_sym{nullptr}
, m_evenCycle{false} {}
ExecRec(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym)
: m_fnp(fnp)
, m_sym(sym)
, m_evenCycle(evenCycle) {}
: m_fnp{fnp}
, m_sym{sym}
, m_evenCycle{evenCycle} {}
};
// MEMBERS
+10 -5
View File
@@ -87,7 +87,7 @@ class VerilatedTraceCommand {
public:
// These must all fit in 4 bit at the moment, as the tracing routines
// pack parameters in the top bits.
enum {
enum : vluint8_t {
CHG_BIT_0 = 0x0,
CHG_BIT_1 = 0x1,
CHG_CDATA = 0x2,
@@ -130,11 +130,11 @@ private:
};
void* m_userp; // The user pointer to pass to the callback (the symbol table)
CallbackRecord(initCb_t cb, void* userp)
: m_initCb(cb)
, m_userp(userp) {}
: m_initCb{cb}
, m_userp{userp} {}
CallbackRecord(dumpCb_t cb, void* userp)
: m_dumpCb(cb)
, m_userp(userp) {}
: m_dumpCb{cb}
, m_userp{userp} {}
};
vluint32_t* m_sigs_oldvalp; ///< Old value store
@@ -158,6 +158,11 @@ private:
// to access duck-typed functions to avoid a virtual function call.
T_Derived* self() { return static_cast<T_Derived*>(this); }
// Flush any remaining data for this file
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
// Close the file on termination
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
#ifdef VL_TRACE_THREADED
// Number of total trace buffers that have been allocated
vluint32_t m_numTraceBuffers;
+33 -12
View File
@@ -39,7 +39,7 @@
// Static utility functions
static double timescaleToDouble(const char* unitp) {
char* endp = NULL;
char* endp = nullptr;
double value = strtod(unitp, &endp);
// On error so we allow just "ns" to return 1e-9.
if (value == 0.0 && endp == unitp) value = 1;
@@ -258,22 +258,37 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flush() {
#endif
}
//=============================================================================
// Callbacks to run on global events
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
// Note this calls 'flush' on the derived class
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
}
template <> void VerilatedTrace<VL_DERIVED_T>::onExit(void* selfp) {
// Note this calls 'close' on the derived class
reinterpret_cast<VL_DERIVED_T*>(selfp)->close();
}
//=============================================================================
// VerilatedTrace
template <>
VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
: m_sigs_oldvalp(NULL)
, m_timeLastDump(0)
, m_fullDump(true)
, m_nextCode(0)
, m_numSignals(0)
, m_maxBits(0)
, m_scopeEscape('.')
, m_timeRes(1e-9)
, m_timeUnit(1e-9)
: m_sigs_oldvalp{nullptr}
, m_timeLastDump{0}
, m_fullDump{true}
, m_nextCode{0}
, m_numSignals{0}
, m_maxBits{0}
, m_scopeEscape{'.'}
, m_timeRes{1e-9}
, m_timeUnit {
1e-9
}
#ifdef VL_TRACE_THREADED
, m_numTraceBuffers(0)
, m_numTraceBuffers { 0 }
#endif
{
set_time_unit(Verilated::timeunitString());
@@ -281,7 +296,9 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
}
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = nullptr);
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED
close();
#endif
@@ -318,6 +335,10 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
// holding previous signal values.
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
// Set callback so flush/abort will flush this file
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED
// Compute trace buffer size. we need to be able to store a new value for
// each signal, which is 'nextCode()' entries after the init callbacks
-501
View File
@@ -1,501 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: pre-C++11 replacements for std::unordered_set
// and std::unordered_map.
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
//*************************************************************************
// This file has clones of the std::unordered_set and std::unordered_map
// hash table types. They are here so that Verilator can use hash tables
// in pre-C++11 compilers, and the same client code can link against the
// std:: types when they are available.
//
// The implementations in this file do not implement the complete APIs
// of the std:: types. Nor are they correct in every detail,
// notably, the const_iterators do not enforce constness. We can extend
// these implementations to cover more of the std API as needed.
//
// TODO: In the future, when Verilator requires C++11 to compile,
// remove this entire file and switch to the std:: types.
//
//*************************************************************************
#ifndef _VERILATED_UNORDERED_SET_MAP_H_
#define _VERILATED_UNORDERED_SET_MAP_H_
#include "verilatedos.h"
#include <list>
#include <stdexcept>
#include <string>
// Abstract 'vl_hash' and 'vl_equal_to' templates.
template <typename T> struct vl_hash { size_t operator()(const T& k) const; };
template <typename T> struct vl_equal_to { bool operator()(const T& a, const T& b) const; };
// Specializations of 'vl_hash' and 'vl_equal_to'.
inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
const vluint8_t* bufp = static_cast<const vluint8_t*>(vbufp);
size_t hash = 0;
for (size_t i = 0; i < nbytes; i++) {
hash = bufp[i] + 31U * hash; // the K&R classic!
}
return hash;
}
template <> inline size_t vl_hash<int>::operator()(const int& k) const { return k; }
template <> inline bool vl_equal_to<int>::operator()(const int& a, const int& b) const {
return a == b;
}
template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const {
return k;
}
template <>
inline bool vl_equal_to<unsigned int>::operator()(const unsigned int& a,
const unsigned int& b) const {
return a == b;
}
template <> inline size_t vl_hash<std::string>::operator()(const std::string& k) const {
return vl_hash_bytes(k.data(), k.size());
}
template <>
inline bool vl_equal_to<std::string>::operator()(const std::string& a,
const std::string& b) const {
// Don't scan the strings if the sizes are different.
if (a.size() != b.size()) return false;
return (0 == a.compare(b)); // Must scan.
}
template <typename T> struct vl_hash<T*> {
size_t operator()(T* kp) const {
return ((sizeof(size_t) == sizeof(kp)) ? reinterpret_cast<size_t>(kp)
: vl_hash_bytes(&kp, sizeof(kp)));
}
};
template <typename T> struct vl_equal_to<T*> {
bool operator()(T* ap, T* bp) const { return ap == bp; }
};
//===================================================================
//
/// Functional clone of the std::unordered_set hash table.
template <class T_Key, class T_Hash = vl_hash<T_Key>, class T_Equal = vl_equal_to<T_Key> >
class vl_unordered_set {
public:
// TYPES
typedef std::list<T_Key> Bucket;
enum RehashType { GROW, SHRINK };
template <class KK, class VV, class HH, class EQ> friend class vl_unordered_map;
class iterator {
protected:
// MEMBERS
size_t m_bucketIdx; // Bucket this iterator points into
typename Bucket::iterator m_bit; // Bucket-local iterator
const vl_unordered_set* m_setp; // The containing set
public:
// CONSTRUCTORS
iterator(size_t bucketIdx, typename Bucket::iterator bit, const vl_unordered_set* setp)
: m_bucketIdx(bucketIdx)
, m_bit(bit)
, m_setp(setp) {}
// METHODS
const T_Key& operator*() const { return *m_bit; }
// This should really be 'const T_Key*' type for unordered_set,
// however this iterator is shared with unordered_map whose
// operator-> returns a non-const ValueType*, so keep this
// non-const to avoid having to define a whole separate iterator
// for unordered_map.
T_Key* operator->() const { return &(*m_bit); }
bool operator==(const iterator& other) const {
return ((m_bucketIdx == other.m_bucketIdx) && (m_bit == other.m_bit));
}
bool operator!=(const iterator& other) const { return (!this->operator==(other)); }
void advanceUntilValid() {
while (true) {
if (m_bit != m_setp->m_bucketsp[m_bucketIdx].end()) {
// Valid iterator in this bucket; we're done.
return;
}
// Try the next bucket?
m_bucketIdx++;
if (m_bucketIdx == m_setp->numBuckets()) {
// Ran past the end of buckets, set to end().
*this = m_setp->end();
return;
}
m_bit = m_setp->m_bucketsp[m_bucketIdx].begin();
}
}
void operator++() {
++m_bit;
advanceUntilValid();
}
typename Bucket::iterator bit() const { return m_bit; }
};
// TODO: there's no real const enforcement on the 'const_iterator'.
typedef iterator const_iterator;
private:
// MEMBERS
size_t m_numElements; // Number of entries present.
size_t m_log2Buckets; // Log-base-2 of the number of buckets.
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
// // we'll allocate it on the fly when
// // the first entries are created.
Bucket m_emptyBucket; // A fake bucket, used to construct end().
T_Hash m_hash; // Hash function provider.
T_Equal m_equal; // Equal-to function provider.
public:
// CONSTRUCTORS
vl_unordered_set()
: m_numElements(0)
, m_log2Buckets(initLog2Buckets())
, m_bucketsp(NULL)
, m_hash()
, m_equal() {}
vl_unordered_set(const vl_unordered_set& other)
: m_numElements(other.m_numElements)
, m_log2Buckets(other.m_log2Buckets)
, m_bucketsp(NULL)
, m_hash()
, m_equal() {
if (other.m_bucketsp) {
m_bucketsp = new Bucket[numBuckets()];
for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i];
}
}
~vl_unordered_set() { VL_DO_DANGLING(delete[] m_bucketsp, m_bucketsp); }
vl_unordered_set& operator=(const vl_unordered_set& other) {
if (this != &other) {
clear();
delete[] m_bucketsp;
m_numElements = other.m_numElements;
m_log2Buckets = other.m_log2Buckets;
if (other.m_bucketsp) {
m_bucketsp = new Bucket[numBuckets()];
for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i];
} else {
m_bucketsp = NULL;
}
}
return *this;
}
// METHODS
static size_t initLog2Buckets() { return 4; }
iterator begin() {
if (m_numElements) {
initBuckets();
iterator result = iterator(0, m_bucketsp[0].begin(), this);
result.advanceUntilValid();
return result;
}
return end();
}
const_iterator begin() const {
if (m_numElements) {
initBuckets();
const_iterator result = iterator(0, m_bucketsp[0].begin(), this);
result.advanceUntilValid();
return result;
}
return end();
}
const_iterator end() const {
return iterator(0xFFFFFFFFFFFFFFFFULL, const_cast<Bucket&>(m_emptyBucket).begin(), this);
}
bool empty() const { return m_numElements == 0; }
size_t size() const { return m_numElements; }
size_t count(const T_Key& key) const { return (find(key) == end()) ? 0 : 1; }
size_t hashToBucket(size_t hashVal) const { return hashToBucket(hashVal, m_log2Buckets); }
static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) {
// Fibonacci hashing, see
// https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization
// -that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
//
// * The magic numbers below are UINT_MAX/phi where phi is the
// golden ratio number (1.618...) for either 64- or 32-bit
// values of UINT_MAX.
//
// * Fibonacci hashing mixes the result of the client's hash
// function further. This permits the use of very fast client
// hash funcs (like just returning the int or pointer value as
// is!) and tolerates crappy client hash functions pretty well.
size_t mult = hashVal * ((sizeof(size_t) == 8) ? 11400714819323198485ULL : 2654435769lu);
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
return result;
}
iterator find_internal(const T_Key& key, size_t& bucketIdxOut) {
size_t hash = m_hash.operator()(key);
bucketIdxOut = hashToBucket(hash);
initBuckets();
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
for (typename Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) {
if (m_equal.operator()(*it, key)) return iterator(bucketIdxOut, it, this);
}
return end();
}
const_iterator find(const T_Key& key) const {
size_t bucketIdx;
return const_cast<vl_unordered_set*>(this)->find_internal(key, bucketIdx);
}
iterator find(const T_Key& key) {
size_t bucketIdx;
return find_internal(key, bucketIdx);
}
std::pair<iterator, bool> insert(const T_Key& val) {
size_t bucketIdx;
iterator existIt = find_internal(val, bucketIdx);
if (existIt != end()) {
// Collision with existing element.
//
// An element may be inserted only if it is not
// equal to an existing element. So fail.
return std::pair<iterator, bool>(end(), false);
}
// No collision, so insert it.
m_numElements++;
m_bucketsp[bucketIdx].push_front(val);
// Compute result iterator. This pointer will be valid
// if we don't rehash:
iterator result_it(bucketIdx, m_bucketsp[bucketIdx].begin(), this);
if (needToRehash(GROW)) {
rehash(GROW);
// ... since we rehashed, do a lookup to get the result iterator.
result_it = find(val);
}
return std::pair<iterator, bool>(result_it, true);
}
iterator erase(iterator it) {
iterator next_it = it;
++next_it;
erase(*it);
return next_it;
}
size_t erase(const T_Key& key) {
size_t bucketIdx;
iterator it = find_internal(key, bucketIdx);
if (it != end()) {
m_bucketsp[bucketIdx].erase(it.bit());
m_numElements--;
// Rehashing to handle a shrinking data set is important
// for the Scoreboard in V3Partition, which begins tracking
// a huge number of vertices and then tracks a successively
// smaller number over time.
if (needToRehash(SHRINK)) rehash(SHRINK);
return 1;
}
return 0;
}
void clear() {
if (m_bucketsp) {
delete[] m_bucketsp;
m_bucketsp = NULL;
}
m_numElements = 0;
m_log2Buckets = initLog2Buckets();
}
private:
size_t numBuckets() const { return (1ULL << m_log2Buckets); }
Bucket* getBucket(size_t idx) {
initBuckets();
return &m_bucketsp[idx];
}
void initBuckets() const {
if (!m_bucketsp) m_bucketsp = new Bucket[numBuckets()];
}
bool needToRehash(RehashType rt) const {
if (rt == GROW) {
return ((4 * numBuckets()) < m_numElements);
} else {
return (numBuckets() > (4 * m_numElements));
}
}
void rehash(RehashType rt) {
size_t new_log2Buckets;
if (rt == GROW) {
new_log2Buckets = m_log2Buckets + 2;
} else {
if (m_log2Buckets <= 4) {
// On shrink, saturate m_log2Buckets at its
// initial size of 2^4 == 16 buckets. Don't risk
// underflowing!
return;
}
new_log2Buckets = m_log2Buckets - 2;
}
size_t new_num_buckets = 1ULL << new_log2Buckets;
Bucket* new_bucketsp = new Bucket[new_num_buckets];
for (size_t i = 0; i < numBuckets(); i++) {
while (!m_bucketsp[i].empty()) {
typename Bucket::iterator bit = m_bucketsp[i].begin();
size_t hash = m_hash.operator()(*bit);
size_t new_idx = hashToBucket(hash, new_log2Buckets);
// Avoid mallocing one list elem and freeing another;
// splice just moves it over.
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(), m_bucketsp[i], bit);
}
}
delete[] m_bucketsp;
m_bucketsp = new_bucketsp;
m_log2Buckets = new_log2Buckets;
}
};
//===================================================================
//
/// Functional clone of the std::unordered_map hash table.
template <class T_Key, class T_Value, class T_Hash = vl_hash<T_Key>,
class T_Equal = vl_equal_to<T_Key> >
class vl_unordered_map {
private:
// TYPES
typedef std::pair<T_Key, T_Value> KeyValPair;
class KeyHash {
private:
T_Hash key_hash;
public:
KeyHash() {}
size_t operator()(const KeyValPair& kv_pair) const {
return key_hash.operator()(kv_pair.first);
}
};
class KeyEqual {
private:
T_Equal key_eq;
public:
KeyEqual() {}
bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const {
return key_eq.operator()(kv_a.first, kv_b.first);
}
};
// MEMBERS
typedef vl_unordered_set<KeyValPair, KeyHash, KeyEqual> MapSet;
MapSet m_set; // Wrap this vl_unordered_set which holds all state.
public:
// CONSTRUCTORS
vl_unordered_map() {}
~vl_unordered_map() {}
typedef typename MapSet::iterator iterator;
typedef typename MapSet::const_iterator const_iterator;
// METHODS
iterator begin() { return m_set.begin(); }
const_iterator begin() const { return m_set.begin(); }
const_iterator end() const { return m_set.end(); }
bool empty() const { return m_set.empty(); }
iterator find(const T_Key& k) {
// We can't assume that T_Value() is defined.
// ie, this does not work:
// return m_set.find(std::make_pair(k, T_Value()));
// So, do this instead:
T_Hash mapHash;
T_Equal mapEq;
size_t hash = mapHash.operator()(k);
size_t bucketIdxOut = m_set.hashToBucket(hash);
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
for (typename MapSet::Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) {
if (mapEq.operator()(it->first, k)) return iterator(bucketIdxOut, it, &m_set);
}
return end();
}
const_iterator find(const T_Key& k) const {
return const_cast<vl_unordered_map*>(this)->find(k);
}
std::pair<iterator, bool> insert(const KeyValPair& val) { return m_set.insert(val); }
iterator erase(iterator it) { return m_set.erase(it); }
size_t erase(const T_Key& k) {
iterator it = find(k);
if (it == end()) return 0;
m_set.erase(it);
return 1;
}
T_Value& operator[](const T_Key& k) {
// Here we can assume T_Value() is defined, as
// std::unordered_map::operator[] relies on it too.
KeyValPair dummy = std::make_pair(k, T_Value());
iterator it = m_set.find(dummy);
if (it == m_set.end()) it = m_set.insert(dummy).first;
// For the 'set', it's generally not safe to modify
// the value after deref. For the 'map' though, we know
// it's safe to modify the value field and we can allow it:
return it->second;
}
T_Value& at(const T_Key& k) {
iterator it = find(k);
if (it == end()) { throw std::out_of_range("sorry"); }
return it->second;
}
const T_Value& at(const T_Key& k) const {
iterator it = find(k);
if (it == end()) { throw std::out_of_range("sorry"); }
return it->second;
}
void clear() { m_set.clear(); }
size_t size() const { return m_set.size(); }
};
#endif
+19 -77
View File
@@ -51,13 +51,14 @@
// This size comes form VCD allowing use of printable ASCII characters between
// '!' and '~' inclusive, which are a total of 94 different values. Encoding a
// 32 bit code hence needs a maximum of ceil(log94(2**32-1)) == 5 bytes.
#define VL_TRACE_MAX_VCD_CODE_SIZE 5 ///< Maximum length of a VCD string code
constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; ///< Maximum length of a VCD string code
// We use 8 bytes per code in a suffix buffer array.
// 1 byte optional separator + VL_TRACE_MAX_VCD_CODE_SIZE bytes for code
// + 1 byte '\n' + 1 byte suffix size. This luckily comes out to a power of 2,
// meaning the array can be aligned such that entries never straddle multiple
// cache-lines.
#define VL_TRACE_SUFFIX_ENTRY_SIZE 8 ///< Size of a suffix entry
constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; ///< Size of a suffix entry
//=============================================================================
// Specialization of the generics for this trace format
@@ -66,47 +67,6 @@
#include "verilated_trace_imp.cpp"
#undef VL_DERIVED_T
//=============================================================================
// VerilatedVcdImp
/// Base class to hold some static state
/// This is an internally used class
class VerilatedVcdSingleton {
private:
typedef std::vector<VerilatedVcd*> VcdVec;
struct Singleton {
VerilatedMutex s_vcdMutex; ///< Protect the singleton
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
};
static Singleton& singleton() {
static Singleton s;
return s;
}
public:
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
const VerilatedLockGuard lock(singleton().s_vcdMutex);
singleton().s_vcdVecp.push_back(vcdp);
}
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
const VerilatedLockGuard lock(singleton().s_vcdMutex);
VcdVec::iterator pos
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
}
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
// Thread safety: Although this function is protected by a mutex so
// perhaps in the future we can allow tracing in separate threads,
// vcdp->flush() assumes call from single thread
const VerilatedLockGuard lock(singleton().s_vcdMutex);
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
it != singleton().s_vcdVecp.end(); ++it) {
VerilatedVcd* vcdp = *it;
vcdp->flush();
}
}
};
//=============================================================================
//=============================================================================
//=============================================================================
@@ -129,21 +89,15 @@ ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE {
//=============================================================================
// Opening/Closing
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
: m_isOpen(false)
, m_rolloverMB(0)
, m_modDepth(0) {
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) {
// Not in header to avoid link issue if header is included without this .cpp file
m_fileNewed = (filep == NULL);
m_fileNewed = (filep == nullptr);
m_filep = m_fileNewed ? new VerilatedVcdFile : filep;
m_namemapp = NULL;
m_evcd = false;
m_wrChunkSize = 8 * 1024;
m_wrBufp = new char[m_wrChunkSize * 8];
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
m_writep = m_wrBufp;
m_wroteBytes = 0;
m_suffixesp = NULL;
m_suffixesp = nullptr;
}
void VerilatedVcd::open(const char* filename) {
@@ -152,13 +106,7 @@ void VerilatedVcd::open(const char* filename) {
// Set member variables
m_filename = filename; // "" is ok, as someone may overload open
VerilatedVcdSingleton::pushVcd(this);
// SPDIFF_OFF
// Set callback so an early exit will flush us
Verilated::flushCb(&flush_all);
// SPDIFF_ON
openNext(m_rolloverMB != 0);
if (!isOpen()) return;
@@ -238,15 +186,15 @@ void VerilatedVcd::makeNameMap() {
// If no scope was specified, prefix everything with a "top"
// This comes from user instantiations with no name - IE Vtop("").
bool nullScope = false;
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
const std::string& hiername = it->first;
for (const auto& i : *m_namemapp) {
const std::string& hiername = i.first;
if (!hiername.empty() && hiername[0] == '\t') nullScope = true;
}
if (nullScope) {
NameMap* newmapp = new NameMap;
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
const std::string& hiername = it->first;
const std::string& decl = it->second;
for (const auto& i : *m_namemapp) {
const std::string& hiername = i.first;
const std::string& decl = i.second;
std::string newname = std::string("top");
if (hiername[0] != '\t') newname += ' ';
newname += hiername;
@@ -258,15 +206,14 @@ void VerilatedVcd::makeNameMap() {
}
void VerilatedVcd::deleteNameMap() {
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = NULL);
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = nullptr);
}
VerilatedVcd::~VerilatedVcd() {
close();
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL);
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = nullptr);
deleteNameMap();
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL);
VerilatedVcdSingleton::removeVcd(this);
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = nullptr);
}
void VerilatedVcd::closePrev() {
@@ -334,7 +281,7 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
m_writep = m_wrBufp + (m_writep - oldbufp);
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
VL_DO_CLEAR(delete[] oldbufp, oldbufp = NULL);
VL_DO_CLEAR(delete[] oldbufp, oldbufp = nullptr);
}
}
@@ -398,7 +345,7 @@ void VerilatedVcd::printIndent(int level_change) {
void VerilatedVcd::dumpHeader() {
printStr("$version Generated by VerilatedVcd $end\n");
time_t time_str = time(NULL);
time_t time_str = time(nullptr);
printStr("$date ");
printStr(ctime(&time_str));
printStr(" $end\n");
@@ -421,9 +368,9 @@ void VerilatedVcd::dumpHeader() {
// Print the signal names
const char* lastName = "";
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
const std::string& hiernamestr = it->first;
const std::string& decl = it->second;
for (const auto& i : *m_namemapp) {
const std::string& hiernamestr = i.first;
const std::string& decl = i.second;
// Determine difference between the old and new names
const char* hiername = hiernamestr.c_str();
@@ -823,11 +770,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
#endif // VL_TRACE_VCD_OLD_API
//======================================================================
// Static members
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); }
//======================================================================
//======================================================================
//======================================================================
+15 -19
View File
@@ -36,11 +36,10 @@ class VerilatedVcd;
class VerilatedVcdFile {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd = 0; ///< File descriptor we're writing to
public:
// METHODS
VerilatedVcdFile()
: m_fd(0) {}
VerilatedVcdFile() {}
virtual ~VerilatedVcdFile() {}
virtual bool open(const std::string& name) VL_MT_UNSAFE;
virtual void close() VL_MT_UNSAFE;
@@ -62,23 +61,23 @@ private:
VerilatedVcdFile* m_filep; ///< File we're writing to
bool m_fileNewed; ///< m_filep needs destruction
bool m_isOpen; ///< True indicates open file
bool m_evcd; ///< True for evcd format
bool m_isOpen = false; ///< True indicates open file
bool m_evcd = false; ///< True for evcd format
std::string m_filename; ///< Filename we're writing to (if open)
vluint64_t m_rolloverMB; ///< MB of file size to rollover at
int m_modDepth; ///< Depth of module hierarchy
vluint64_t m_rolloverMB = 0; ///< MB of file size to rollover at
int m_modDepth = 0; ///< Depth of module hierarchy
char* m_wrBufp; ///< Output buffer
char* m_wrFlushp; ///< Output buffer flush trigger location
char* m_writep; ///< Write pointer into output buffer
vluint64_t m_wrChunkSize; ///< Output buffer size
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
vluint64_t m_wroteBytes = 0; ///< Number of bytes written to this file
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;
NameMap* m_namemapp; ///< List of names for the header
NameMap* m_namemapp = nullptr; ///< List of names for the header
void bufferResize(vluint64_t minsize);
void bufferFlush() VL_MT_UNSAFE_ONE;
@@ -101,13 +100,10 @@ private:
void dumpHeader();
char* writeCode(char* writep, vluint32_t code);
static char* writeCode(char* writep, vluint32_t code);
void finishLine(vluint32_t code, char* writep);
/// Flush any remaining data from all files
static void flush_all() VL_MT_UNSAFE_ONE;
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedVcd);
@@ -116,11 +112,11 @@ protected:
// Implementation of VerilatedTrace interface
// Implementations of protected virtual methods for VerilatedTrace
void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;
virtual void emitTimeChange(vluint64_t timeui) override;
// Hooks called from VerilatedTrace
bool preFullDump() VL_OVERRIDE { return isOpen(); }
bool preChangeDump() VL_OVERRIDE;
virtual bool preFullDump() override { return isOpen(); }
virtual bool preChangeDump() override;
// Implementations of duck-typed methods for VerilatedTrace. These are
// called from only one place (namely full*) so always inline them.
@@ -136,7 +132,7 @@ public:
//=========================================================================
// External interface to client code
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
explicit VerilatedVcd(VerilatedVcdFile* filep = nullptr);
~VerilatedVcd();
// ACCESSORS
@@ -340,8 +336,8 @@ class VerilatedVcdC {
VL_UNCOPYABLE(VerilatedVcdC);
public:
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
: m_sptrace(filep) {}
explicit VerilatedVcdC(VerilatedVcdFile* filep = nullptr)
: m_sptrace{filep} {}
~VerilatedVcdC() { close(); }
/// Routines can only be called from one thread; allow next call from different thread
void changeThread() { spTrace()->changeThread(); }
+7 -94
View File
@@ -25,22 +25,21 @@
//======================================================================
//--------------------------------------------------
#if (SYSTEMC_VERSION >= 20050714)
// SystemC 2.1.v1
// cppcheck-suppress unusedFunction
void VerilatedVcdSc::write_comment(const std::string&) {}
void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**) {}
// clang-format off
# define DECL_TRACE_METHOD_A(tp) \
#define DECL_TRACE_METHOD_A(tp) \
void VerilatedVcdSc::trace(const tp& object, const std::string& name) {}
# define DECL_TRACE_METHOD_B(tp) \
#define DECL_TRACE_METHOD_B(tp) \
void VerilatedVcdSc::trace(const tp& object, const std::string& name, int width) {}
# if (SYSTEMC_VERSION >= 20171012)
// clang-format off
#if (SYSTEMC_VERSION >= 20171012)
DECL_TRACE_METHOD_A( sc_event )
DECL_TRACE_METHOD_A( sc_time )
# endif
#endif
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
@@ -50,9 +49,9 @@ void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
# ifdef SYSTEMC_64BIT_PATCHES
#ifdef SYSTEMC_64BIT_PATCHES
DECL_TRACE_METHOD_B( unsigned long long)
# endif
#endif
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
@@ -76,92 +75,6 @@ void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
// clang-format on
//--------------------------------------------------
#elif (SYSTEMC_VERSION > 20011000)
// SystemC 2.0.1
// cppcheck-suppress unusedFunction
void VerilatedVcdSc::write_comment(const sc_string&) {}
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
#define DECL_TRACE_METHOD_A(tp) \
void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {}
#define DECL_TRACE_METHOD_B(tp) \
void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {}
// clang-format off
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_bit )
DECL_TRACE_METHOD_A( sc_logic )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
#ifdef SYSTEMC_64BIT_PATCHES
DECL_TRACE_METHOD_B( unsigned long long)
#endif
#if (SYSTEMC_VERSION > 20041000)
DECL_TRACE_METHOD_B( unsigned long long)
DECL_TRACE_METHOD_B( long long)
#endif
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_int_base )
DECL_TRACE_METHOD_A( sc_uint_base )
DECL_TRACE_METHOD_A( sc_signed )
DECL_TRACE_METHOD_A( sc_unsigned )
DECL_TRACE_METHOD_A( sc_fxval )
DECL_TRACE_METHOD_A( sc_fxval_fast )
DECL_TRACE_METHOD_A( sc_fxnum )
DECL_TRACE_METHOD_A( sc_fxnum_fast )
DECL_TRACE_METHOD_A( sc_bv_base )
DECL_TRACE_METHOD_A( sc_lv_base )
// clang-format on
//--------------------------------------------------
#else
// SystemC 1.2.1beta
// cppcheck-suppress unusedFunction
void VerilatedVcdSc::write_comment(const sc_string&) {}
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
#define DECL_TRACE_METHOD_A(tp) \
void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {}
#define DECL_TRACE_METHOD_B(tp) \
void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {}
// clang-format off
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( short unsigned int )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( long unsigned int )
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short int )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long int )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_bit )
DECL_TRACE_METHOD_A( sc_logic )
DECL_TRACE_METHOD_A( sc_bool_vector )
DECL_TRACE_METHOD_A( sc_logic_vector )
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
DECL_TRACE_METHOD_A( sc_uint_base )
DECL_TRACE_METHOD_A( sc_int_base )
DECL_TRACE_METHOD_A( sc_unsigned )
DECL_TRACE_METHOD_A( sc_signed )
DECL_TRACE_METHOD_A( sc_signal_resolved )
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
// clang-format on
#endif
#undef DECL_TRACE_METHOD_A
#undef DECL_TRACE_METHOD_B
+8 -108
View File
@@ -38,7 +38,6 @@ class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC {
public:
VerilatedVcdSc() {
sc_get_curr_simcontext()->add_trace_file(this);
#if (SYSTEMC_VERSION >= 20060505)
// We want to avoid a depreciated warning, but still be back compatible.
// Turning off the message just for this still results in an
// annoying "to turn off" message.
@@ -48,25 +47,13 @@ public:
spTrace()->set_time_unit(tunits.to_string());
}
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
#elif (SYSTEMC_VERSION > 20011000)
// To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string
// we allow both flavors with overloaded set_time_* functions.
spTrace()->set_time_unit(sc_get_default_time_unit().to_string());
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
#endif
}
virtual ~VerilatedVcdSc() { close(); }
// METHODS
/// Called by SystemC simulate()
virtual void cycle(bool delta_cycle) {
#if (SYSTEMC_VERSION > 20011000)
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
#else
// VCD files must have integer timestamps, so we write all times in
// increments of time_resolution
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
#endif
}
private:
@@ -76,26 +63,23 @@ private:
// Cadence Incisive has these as abstract functions so we must create them
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
#endif
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100)
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
#endif
//--------------------------------------------------
#if (SYSTEMC_VERSION >= 20050714)
// SystemC 2.1.v1
// clang-format off
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
# define DECL_TRACE_METHOD_B(tp) \
// SystemC 2.1.v1
#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
#define DECL_TRACE_METHOD_B(tp) \
virtual void trace(const tp& object, const std::string& name, int width);
virtual void write_comment(const std::string&);
virtual void trace(const unsigned int&, const std::string&, const char**);
// clang-format off
// Formatting matches that of sc_trace.h
# if (SYSTEMC_VERSION >= 20171012)
#if (SYSTEMC_VERSION >= 20171012)
DECL_TRACE_METHOD_A( sc_event )
DECL_TRACE_METHOD_A( sc_time )
# endif
#endif
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
@@ -105,9 +89,9 @@ private:
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
# ifdef SYSTEMC_64BIT_PATCHES
#ifdef SYSTEMC_64BIT_PATCHES
DECL_TRACE_METHOD_B( unsigned long long)
# endif
#endif
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
@@ -131,90 +115,6 @@ private:
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
// clang-format on
//--------------------------------------------------
#elif (SYSTEMC_VERSION > 20011000)
// SystemC 2.0.1
// clang-format off
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name);
# define DECL_TRACE_METHOD_B(tp) \
virtual void trace(const tp& object, const sc_string& name, int width);
virtual void write_comment(const sc_string&);
virtual void trace(const unsigned int&, const sc_string&, const char**);
virtual void delta_cycles(bool) {}
virtual void space(int n) {}
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_bit )
DECL_TRACE_METHOD_A( sc_logic )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
# ifdef SYSTEMC_64BIT_PATCHES
DECL_TRACE_METHOD_B( unsigned long long)
# endif
# if (SYSTEMC_VERSION > 20041000)
DECL_TRACE_METHOD_B( unsigned long long)
DECL_TRACE_METHOD_B( long long)
# endif
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_int_base )
DECL_TRACE_METHOD_A( sc_uint_base )
DECL_TRACE_METHOD_A( sc_signed )
DECL_TRACE_METHOD_A( sc_unsigned )
DECL_TRACE_METHOD_A( sc_fxval )
DECL_TRACE_METHOD_A( sc_fxval_fast )
DECL_TRACE_METHOD_A( sc_fxnum )
DECL_TRACE_METHOD_A( sc_fxnum_fast )
DECL_TRACE_METHOD_A( sc_bv_base )
DECL_TRACE_METHOD_A( sc_lv_base )
// clang-format on
//--------------------------------------------------
#else
// SystemC 1.2.1beta
// clang-format off
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name);
# define DECL_TRACE_METHOD_B(tp) \
virtual void trace(const tp& object, const sc_string& name, int width);
virtual void write_comment(const sc_string&);
virtual void trace(const unsigned int&, const sc_string&, const char**);
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( short unsigned int )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( long unsigned int )
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short int )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long int )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_bit )
DECL_TRACE_METHOD_A( sc_logic )
DECL_TRACE_METHOD_A( sc_bool_vector )
DECL_TRACE_METHOD_A( sc_logic_vector )
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
DECL_TRACE_METHOD_A( sc_uint_base )
DECL_TRACE_METHOD_A( sc_int_base )
DECL_TRACE_METHOD_A( sc_unsigned )
DECL_TRACE_METHOD_A( sc_signed )
DECL_TRACE_METHOD_A( sc_signal_resolved )
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
# endif
// clang-format on
#undef DECL_TRACE_METHOD_A
#undef DECL_TRACE_METHOD_B
};
+566 -619
View File
File diff suppressed because it is too large Load Diff
+22 -26
View File
@@ -122,7 +122,7 @@
# if defined(_MSC_VER) && _MSC_VER >= 1900
# define VL_THREAD_LOCAL thread_local
# elif defined(__GNUC__)
# if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING)
# if (__cplusplus < 201103L)
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
# endif
# else
@@ -152,14 +152,14 @@
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__) || __cplusplus < 201103L
# define VL_DANGLING(var)
#else
/// After e.g. delete, set variable to NULL to indicate must not use later
/// After e.g. delete, set variable to nullptr to indicate must not use later
# define VL_DANGLING(var) \
do { \
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = NULL; \
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = nullptr; \
} while (false)
#endif
/// Perform an e.g. delete, then set variable to NULL to indicate must not use later.
/// Perform an e.g. delete, then set variable to nullptr to indicate must not use later.
/// Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
#define VL_DO_DANGLING(stmt, var) \
do { \
@@ -169,7 +169,7 @@
VL_DANGLING(var); \
} while (false)
/// Perform an e.g. delete, then set variable to NULL as a requirement
/// Perform an e.g. delete, then set variable to nullptr as a requirement
#define VL_DO_CLEAR(stmt, stmt2) \
do { \
do { \
@@ -184,30 +184,18 @@
// C++-2011
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK)
// These are deprecated historical defines. We leave them in case users referenced them.
# define VL_EQ_DELETE = delete
# define vl_unique_ptr std::unique_ptr
// By default we use std:: types in C++11.
// Define VL_USE_UNORDERED_TYPES to test these pre-C++11 classes
# ifdef VL_USE_UNORDERED_TYPES
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
# else
# define vl_unordered_map std::unordered_map
# define vl_unordered_set std::unordered_set
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
# endif
# define vl_unordered_map std::unordered_map
# define vl_unordered_set std::unordered_set
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
# define VL_FINAL final
# define VL_MUTABLE mutable
# define VL_OVERRIDE override
#else
# define VL_EQ_DELETE
# define vl_unique_ptr std::auto_ptr
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
# define VL_FINAL
# define VL_MUTABLE
# define VL_OVERRIDE
# error "Verilator requires a C++11 or newer compiler"
#endif
//=========================================================================
@@ -388,8 +376,8 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
// Used to declare a class as uncopyable; put after a private:
#define VL_UNCOPYABLE(Type) \
Type(const Type& other) VL_EQ_DELETE; \
Type& operator=(const Type&) VL_EQ_DELETE
Type(const Type& other) = delete; \
Type& operator=(const Type&) = delete
//=========================================================================
// Verilated function size macros
@@ -435,7 +423,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
// Performance counters
/// The vluint64_t argument is loaded with a high-performance counter for profiling
/// or 0x0 if not implemeted on this platform
/// or 0x0 if not implemented on this platform
#if defined(__i386__) || defined(__x86_64__)
#define VL_RDTSC(val) \
{ \
@@ -500,6 +488,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#define VL_STRINGIFY(x) VL_STRINGIFY2(x)
#define VL_STRINGIFY2(x) #x
//=========================================================================
// Conversions
namespace vlstd {
// C++17's std::as_const
template <class T> T const& as_const(T& v) { return v; }
}; // namespace vlstd
//=========================================================================
#endif // Guard
+5 -1
View File
@@ -46,13 +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\(\))/x);
exclude_branch_regexp(qr/(\bdebug\(\)
|\bassert\(
|\bSELF_CHECK)/x);
1;
+11 -6
View File
@@ -69,16 +69,21 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
endif
endif
prefiles::
prefiles:: config_rev.h
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
config_rev.h: ${srcdir}/config_rev.pl ${srcdir}/../.git/logs/HEAD
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
else
config_rev.h: ${srcdir}/config_rev.pl
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
endif
# Human convenience
clang-format:
$(MAKE) -C .. $@
maintainer-copy::
clean mostlyclean distclean maintainer-clean::
+1 -1
View File
@@ -203,6 +203,7 @@ RAW_OBJS = \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hashed.o \
V3HierBlock.o \
V3Inline.o \
V3Inst.o \
V3InstrCount.o \
@@ -278,7 +279,6 @@ V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
$(TGT): $(PREDEP_H) $(OBJS)
@echo " Linking $@..."
-rm -rf $@ [email protected]
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
V3Number_test: V3Number_test.o
+51 -71
View File
@@ -36,7 +36,7 @@
#include "V3Const.h"
#include "V3SenTree.h" // for SenTreeSet
#include VL_INCLUDE_UNORDERED_MAP
#include <unordered_map>
//***** See below for main transformation engine
@@ -51,36 +51,36 @@ protected:
class ActiveNamer : public ActiveBaseVisitor {
private:
// STATE
AstScope* m_scopep; // Current scope to add statement to
AstActive* m_iActivep; // For current scope, the IActive we're building
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
AstScope* m_scopep = nullptr; // Current scope to add statement to
AstActive* m_iActivep = nullptr; // For current scope, the IActive we're building
AstActive* m_cActivep = nullptr; // For current scope, the SActive(combo) we're building
SenTreeSet m_activeSens; // Sen lists for each active we've made
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
typedef std::unordered_map<AstSenTree*, AstActive*> ActiveMap;
ActiveMap m_activeMap; // Map sentree to active, for folding.
// METHODS
void addActive(AstActive* nodep) {
UASSERT_OBJ(m_scopep, nodep, "NULL scope");
UASSERT_OBJ(m_scopep, nodep, "nullptr scope");
m_scopep->addActivep(nodep);
}
// VISITORS
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
m_scopep = nodep;
m_iActivep = NULL;
m_cActivep = NULL;
m_iActivep = nullptr;
m_cActivep = nullptr;
m_activeSens.clear();
m_activeMap.clear();
iterateChildren(nodep);
// Don't clear scopep, the namer persists beyond this visit
}
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
virtual void visit(AstSenTree* nodep) override {
// Simplify sensitivity list
VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep);
}
//--------------------
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeStmt*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// METHODS
@@ -106,10 +106,10 @@ public:
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
// Return a sentree in this scope that matches given sense list.
AstActive* activep = NULL;
AstActive* activep = nullptr;
AstSenTree* activeSenp = m_activeSens.find(sensesp);
if (activeSenp) {
ActiveMap::iterator it = m_activeMap.find(activeSenp);
const auto it = m_activeMap.find(activeSenp);
UASSERT(it != m_activeMap.end(), "Corrupt active map");
activep = it->second;
}
@@ -129,14 +129,9 @@ public:
return activep;
}
public:
// CONSTRUCTORS
ActiveNamer() {
m_scopep = NULL;
m_iActivep = NULL;
m_cActivep = NULL;
}
virtual ~ActiveNamer() {}
ActiveNamer() {}
virtual ~ActiveNamer() override {}
void main(AstScope* nodep) { iterate(nodep); }
};
@@ -145,14 +140,14 @@ public:
class ActiveDlyVisitor : public ActiveBaseVisitor {
public:
enum CheckType { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
private:
CheckType m_check; // Combo logic or other
AstNode* m_alwaysp; // Always we're under
AstNode* m_assignp; // In assign
AstNode* m_assignp = nullptr; // In assign
// VISITORS
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
virtual void visit(AstAssignDly* nodep) override {
if (m_check != CT_SEQ) {
// Convert to a non-delayed assignment
UINFO(5, " ASSIGNDLY " << nodep << endl);
@@ -174,7 +169,7 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
virtual void visit(AstAssign* nodep) VL_OVERRIDE {
virtual void visit(AstAssign* nodep) override {
if (m_check == CT_SEQ) {
AstNode* las = m_assignp;
m_assignp = nodep;
@@ -182,7 +177,7 @@ private:
m_assignp = las;
}
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
AstVar* varp = nodep->varp();
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
&& !varp->isTemp()) {
@@ -201,17 +196,16 @@ private:
}
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
ActiveDlyVisitor(AstNode* nodep, CheckType check) {
m_alwaysp = nodep;
m_check = check;
m_assignp = NULL;
ActiveDlyVisitor(AstNode* nodep, CheckType check)
: m_check{check}
, m_alwaysp{nodep} {
iterate(nodep);
}
virtual ~ActiveDlyVisitor() {}
virtual ~ActiveDlyVisitor() override {}
};
//######################################################################
@@ -225,23 +219,23 @@ private:
// STATE
ActiveNamer m_namer; // Tracking of active names
AstCFunc* m_scopeFinalp; // Final function for this scope
bool m_itemCombo; // Found a SenItem combo
bool m_itemSequent; // Found a SenItem sequential
AstCFunc* m_scopeFinalp = nullptr; // Final function for this scope
bool m_itemCombo = false; // Found a SenItem combo
bool m_itemSequent = false; // Found a SenItem sequential
// VISITORS
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
// Create required actives and add to scope
UINFO(4, " SCOPE " << nodep << endl);
// Clear last scope's names, and collect this scope's existing names
m_namer.main(nodep);
m_scopeFinalp = NULL;
m_scopeFinalp = nullptr;
iterateChildren(nodep);
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
// Actives are being formed, so we can ignore any already made
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
virtual void visit(AstInitial* nodep) override {
// Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl);
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL);
@@ -249,28 +243,28 @@ private:
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
virtual void visit(AstAssignAlias* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
virtual void visit(AstAssignW* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
virtual void visit(AstCoverToggle* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " COVERTOGGLE " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
virtual void visit(AstFinal* nodep) override {
// Relink to CFUNC for the final
UINFO(4, " FINAL " << nodep << endl);
if (!nodep->bodysp()) { // Empty, Kill it.
@@ -316,14 +310,12 @@ private:
if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*)
if (combo && sequent) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity "
"(no edge) sensitive activity list");
}
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Mixed edge (pos/negedge) and activity "
"(no edge) sensitive activity list");
sequent = false;
}
AstActive* wantactivep = NULL;
AstActive* wantactivep = nullptr;
if (combo && !sequent) {
// Combo: Relink to ACTIVE(combo)
wantactivep = m_namer.getCActive(nodep->fileline());
@@ -360,7 +352,7 @@ private:
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_SEQ);
}
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
virtual void visit(AstAlways* nodep) override {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALW " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
@@ -372,21 +364,13 @@ private:
}
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
virtual void visit(AstAlwaysPublic* nodep) override {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALWPub " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
AstSenItem* subitemp = nodep->sensesp();
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
nodep, "Strange activity type under SenGate");
iterateChildren(nodep);
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
virtual void visit(AstSenItem* nodep) override {
if (nodep->varrefp()) {
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
if (basicp->isEventValue()) {
@@ -405,8 +389,9 @@ private:
} else if (nodep->varrefp()) {
// V3LinkResolve should have cleaned most of these up
if (!nodep->varrefp()->width1()) {
nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
<< nodep->varrefp()->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
<< nodep->varrefp()->prettyNameQ());
}
m_itemSequent = true;
nodep->varrefp()->varp()->usedClock(true);
@@ -414,19 +399,14 @@ private:
}
//--------------------
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstVarScope*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ActiveVisitor(AstNetlist* nodep)
: m_scopeFinalp(NULL)
, m_itemCombo(false)
, m_itemSequent(false) {
iterate(nodep);
}
virtual ~ActiveVisitor() {}
explicit ActiveVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ActiveVisitor() override {}
};
//######################################################################
+16 -19
View File
@@ -45,31 +45,31 @@ private:
AstUser1InUse m_inuser1;
// STATE
AstTopScope* m_topscopep; // Top scope for adding sentrees under
AstTopScope* m_topscopep = nullptr; // Top scope for adding sentrees under
SenTreeFinder m_finder; // Find global sentree's and add them
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
virtual void visit(AstTopScope* nodep) override {
m_topscopep = nodep;
m_finder.main(m_topscopep);
m_finder.init(m_topscopep);
iterateChildren(nodep);
m_topscopep = NULL;
m_topscopep = nullptr;
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
// Create required actives and add to module
// We can start ordering at a module, or a scope
UINFO(4, " MOD " << nodep << endl);
iterateChildren(nodep);
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
UINFO(4, " ACTIVE " << nodep << endl);
// Remove duplicate clocks and such; sensesp() may change!
V3Const::constifyExpensiveEdit(nodep);
AstSenTree* sensesp = nodep->sensesp();
UASSERT_OBJ(sensesp, nodep, "NULL");
UASSERT_OBJ(sensesp, nodep, "nullptr");
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
// Never executing. Kill it.
@@ -108,30 +108,27 @@ private:
// No need to do statements under it, they're already moved.
// iterateChildren(nodep);
}
virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
virtual void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
virtual void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
virtual void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
virtual void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
//--------------------
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstVarScope*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ActiveTopVisitor(AstNetlist* nodep)
: m_topscopep(NULL) {
iterate(nodep);
}
virtual ~ActiveTopVisitor() {}
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ActiveTopVisitor() override {}
};
//######################################################################
+37 -45
View File
@@ -34,9 +34,9 @@ private:
AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp; // Last module
AstBegin* m_beginp; // Last begin
unsigned m_modPastNum; // Module past numbering
AstNodeModule* m_modp = nullptr; // Last module
AstBegin* m_beginp = nullptr; // Last begin
unsigned m_modPastNum = 0; // Module past numbering
VDouble0 m_statCover; // Statistic tracking
VDouble0 m_statAsNotImm; // Statistic tracking
VDouble0 m_statAsImm; // Statistic tracking
@@ -74,15 +74,15 @@ private:
(v3Global.opt.assertOn()
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
nodep, NULL);
nodep, nullptr);
newp->user1(true); // Don't assert/cover this if
return newp;
}
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
// Like newFireAssert() but omits the asserts-on check
AstDisplay* dispp
= new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message,
nullptr, nullptr);
AstNode* bodysp = dispp;
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
bodysp->addNext(new AstStop(nodep->fileline(), true));
@@ -112,9 +112,9 @@ private:
sentreep->unlinkFrBack();
}
//
AstNode* bodysp = NULL;
AstNode* bodysp = nullptr;
bool selfDestruct = false;
AstIf* ifp = NULL;
AstIf* ifp = nullptr;
if (AstCover* snodep = VN_CAST(nodep, Cover)) {
++m_statCover;
if (!v3Global.opt.coverageUser()) {
@@ -129,7 +129,7 @@ private:
}
if (bodysp && passsp) bodysp = bodysp->addNext(passsp);
ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL);
ifp = new AstIf(nodep->fileline(), propp, bodysp, nullptr);
bodysp = ifp;
} else if (VN_IS(nodep, Assert)) {
if (nodep->immediate()) {
@@ -141,7 +141,7 @@ private:
if (failsp) failsp = newIfAssertOn(failsp);
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
ifp = new AstIf(nodep->fileline(), propp, passsp, failsp);
// It's more LIKELY that we'll take the NULL if clause
// It's more LIKELY that we'll take the nullptr if clause
// than the sim-killing else clause:
ifp->branchPred(VBranchPred::BP_LIKELY);
bodysp = newIfAssertOn(ifp);
@@ -169,11 +169,11 @@ private:
}
// VISITORS
virtual void visit(AstIf* nodep) VL_OVERRIDE {
virtual void visit(AstIf* nodep) override {
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
AstNode* propp = NULL;
AstNode* propp = nullptr;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
@@ -226,7 +226,7 @@ private:
}
//========== Case assertions
virtual void visit(AstCase* nodep) VL_OVERRIDE {
virtual void visit(AstCase* nodep) override {
iterateChildren(nodep);
if (!nodep->user1SetOnce()) {
bool has_default = false;
@@ -239,7 +239,7 @@ private:
++m_statAsFull;
if (!has_default) {
nodep->addItemsp(new AstCaseItem(
nodep->fileline(), NULL /*DEFAULT*/,
nodep->fileline(), nullptr /*DEFAULT*/,
newFireAssert(nodep, "synthesis full_case, but non-match found")));
}
}
@@ -250,7 +250,7 @@ private:
if (!has_default && !nodep->itemsp()) {
// Not parallel, but harmlessly so.
} else {
AstNode* propp = NULL;
AstNode* propp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
@@ -287,7 +287,7 @@ private:
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep,
"synthesis parallel_case, but multiple matches found"),
NULL);
nullptr);
ifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->addNotParallelp(ifp);
}
@@ -296,7 +296,7 @@ private:
}
//========== Past
virtual void visit(AstPast* nodep) VL_OVERRIDE {
virtual void visit(AstPast* nodep) override {
iterateChildren(nodep);
uint32_t ticks = 1;
if (nodep->ticksp()) {
@@ -306,32 +306,33 @@ private:
}
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
AstNode* inp = nodep->exprp()->unlinkFrBack();
AstVar* invarp = NULL;
AstVar* invarp = nullptr;
AstSenTree* sentreep = nodep->sentreep();
sentreep->unlinkFrBack();
AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, NULL);
AstAlways* alwaysp
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
m_modp->addStmtp(alwaysp);
for (uint32_t i = 0; i < ticks; ++i) {
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
inp->dtypep());
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);
}
virtual void visit(AstSampled* nodep) VL_OVERRIDE {
virtual void visit(AstSampled* nodep) override {
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
//========== Statements
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
virtual void visit(AstDisplay* nodep) override {
iterateChildren(nodep);
// Replace the special types with standard text
if (nodep->displayType() == AstDisplayType::DT_INFO) {
@@ -344,54 +345,45 @@ private:
}
}
virtual void visit(AstAssert* nodep) VL_OVERRIDE {
virtual void visit(AstAssert* nodep) override {
iterateChildren(nodep);
newPslAssertion(nodep, nodep->failsp());
}
virtual void visit(AstCover* nodep) VL_OVERRIDE {
virtual void visit(AstCover* nodep) override {
iterateChildren(nodep);
newPslAssertion(nodep, NULL);
newPslAssertion(nodep, nullptr);
}
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
virtual void visit(AstRestrict* nodep) override {
iterateChildren(nodep);
// IEEE says simulator ignores these
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
unsigned origPastNum = m_modPastNum;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
VL_RESTORER(m_modPastNum);
{
m_modp = nodep;
m_modPastNum = 0;
iterateChildren(nodep);
}
m_modp = origModp;
m_modPastNum = origPastNum;
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
virtual void visit(AstBegin* nodep) override {
// This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin
AstBegin* lastp = m_beginp;
VL_RESTORER(m_beginp);
{
m_beginp = nodep;
iterateChildren(nodep);
}
m_beginp = lastp;
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit AssertVisitor(AstNetlist* nodep) {
m_beginp = NULL;
m_modp = NULL;
m_modPastNum = 0;
// Process
iterate(nodep);
}
virtual ~AssertVisitor() {
explicit AssertVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~AssertVisitor() override {
V3Stats::addStat("Assertions, assert non-immediate statements", m_statAsNotImm);
V3Stats::addStat("Assertions, assert immediate statements", m_statAsImm);
V3Stats::addStat("Assertions, cover statements", m_statCover);
+87 -22
View File
@@ -34,35 +34,40 @@ private:
// NODE STATE/TYPES
// STATE
// Reset each module:
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
AstSenItem* m_seniDefaultp = nullptr; // Default sensitivity (from AstDefClock)
// Reset each assertion:
AstNodeSenItem* m_senip; // Last sensitivity
AstSenItem* m_senip = nullptr; // Last sensitivity
// Reset each always:
AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
// Reset each assertion:
AstNode* m_disablep = nullptr; // Last disable
// METHODS
VL_DEBUG_FUNC; // Declare debug()
AstSenTree* newSenTree(AstNode* nodep) {
// Create sentree based on clocked or default clock
// Return NULL for always
AstSenTree* newp = NULL;
AstNodeSenItem* senip = m_senip;
// Return nullptr for always
AstSenTree* newp = nullptr;
AstSenItem* senip = m_senip;
if (!senip) senip = m_seniDefaultp;
if (!senip) senip = m_seniAlwaysp;
if (!senip) {
nodep->v3error("Unsupported: Unclocked assertion");
newp = new AstSenTree(nodep->fileline(), NULL);
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
newp = new AstSenTree(nodep->fileline(), nullptr);
} else {
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
}
return newp;
}
void clearAssertInfo() { m_senip = NULL; }
void clearAssertInfo() {
m_senip = nullptr;
m_disablep = nullptr;
}
// VISITORS
//========== Statements
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
virtual void visit(AstClocking* nodep) override {
UINFO(8, " CLOCKING" << nodep << endl);
// Store the new default clock, reset on new module
m_seniDefaultp = nodep->sensesp();
@@ -74,14 +79,14 @@ private:
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
virtual void visit(AstAlways* nodep) override {
iterateAndNextNull(nodep->sensesp());
if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp();
iterateAndNextNull(nodep->bodysp());
m_seniAlwaysp = NULL;
m_seniAlwaysp = nullptr;
}
virtual void visit(AstNodeCoverOrAssert* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCoverOrAssert* nodep) override {
if (nodep->sentreep()) return; // Already processed
clearAssertInfo();
// Find Clocking's buried under nodep->exprsp
@@ -89,18 +94,80 @@ private:
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
clearAssertInfo();
}
virtual void visit(AstPast* nodep) VL_OVERRIDE {
virtual void visit(AstFell* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
exprp->dtypeSetLogicBool();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstPast* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
nodep->sentreep(newSenTree(nodep));
}
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
virtual void visit(AstRose* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
exprp->dtypeSetLogicBool();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstStable* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
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));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstPropClocked* nodep) override {
// No need to iterate the body, once replace will get iterated
iterateAndNextNull(nodep->sensesp());
if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
if (m_senip)
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
// 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(),
@@ -116,23 +183,21 @@ private:
nodep->replaceWith(blockp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
iterateChildren(nodep);
// Reset defaults
m_seniDefaultp = NULL;
m_seniDefaultp = nullptr;
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit AssertPreVisitor(AstNetlist* nodep) {
m_seniDefaultp = NULL;
m_seniAlwaysp = NULL;
clearAssertInfo();
// Process
iterate(nodep);
}
virtual ~AssertPreVisitor() {}
virtual ~AssertPreVisitor() override {}
};
//######################################################################
+54 -57
View File
@@ -58,19 +58,20 @@ 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 = NULL;
m_nextp = NULL;
m_backp = NULL;
m_nextp = nullptr;
m_backp = nullptr;
m_headtailp = this; // When made, we're a list of only a single element
m_op1p = NULL;
m_op2p = NULL;
m_op3p = NULL;
m_op4p = NULL;
m_iterpp = NULL;
m_dtypep = NULL;
m_clonep = NULL;
m_op1p = nullptr;
m_op2p = nullptr;
m_op3p = nullptr;
m_op4p = nullptr;
m_iterpp = nullptr;
m_dtypep = nullptr;
m_clonep = nullptr;
m_cloneCnt = 0;
// Attributes
m_didWidth = false;
@@ -275,8 +276,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
// New tail needs the head
AstNode* newtailp = newp->m_headtailp;
AstNode* headp = oldtailp->m_headtailp;
oldtailp->m_headtailp = NULL; // May be written again as new head
newp->m_headtailp = NULL; // May be written again as new tail
oldtailp->m_headtailp = nullptr; // May be written again as new head
newp->m_headtailp = nullptr; // May be written again as new tail
newtailp->m_headtailp = headp;
headp->m_headtailp = newtailp;
newp->editCountInc();
@@ -321,17 +322,17 @@ void AstNode::addNextHere(AstNode* newp) {
// tail (oldheadtailp && !oldnextp) // this was tail of list, might also
// be head of one-node list
//
newp->m_headtailp = NULL; // Not at head any longer
addlastp->m_headtailp = NULL; // Presume middle of list
newp->m_headtailp = nullptr; // Not at head any longer
addlastp->m_headtailp = nullptr; // Presume middle of list
// newp might happen to be head/tail after all, if so will be set again below
if (oldheadtailp) { // else in middle of list, no change
if (oldheadtailp == this) { // this was one node
this->m_headtailp = addlastp; // Was head/tail, now a tail
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or nullptr)
} else if (!oldnextp) { // this was tail
this->m_headtailp = NULL; // No longer a tail
this->m_headtailp = nullptr; // No longer a tail
oldheadtailp->m_headtailp = addlastp; // Head gets new tail
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or nullptr)
} // else is head, and we're inserting into the middle, so no other change
}
@@ -470,7 +471,7 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
}
}
if (backp->m_nextp == oldp) {
backp->m_nextp = NULL;
backp->m_nextp = nullptr;
// Old list gets truncated
// New list becomes a list upon itself
// Most common case is unlinking a entire operand tree
@@ -486,21 +487,21 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
oldp->m_headtailp = oldtailp;
oldp->m_headtailp->m_headtailp = oldp;
} else if (backp->m_op1p == oldp) {
backp->m_op1p = NULL;
backp->m_op1p = nullptr;
} else if (backp->m_op2p == oldp) {
backp->m_op2p = NULL;
backp->m_op2p = nullptr;
} else if (backp->m_op3p == oldp) {
backp->m_op3p = NULL;
backp->m_op3p = nullptr;
} else if (backp->m_op4p == oldp) {
backp->m_op4p = NULL;
backp->m_op4p = nullptr;
} else {
this->v3fatalSrc("Unlink of node with back not pointing to it.");
}
// Relink
oldp->m_backp = NULL;
oldp->m_backp = nullptr;
// Iterator fixup
if (oldp->m_iterpp) *(oldp->m_iterpp) = NULL;
oldp->m_iterpp = NULL;
if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr;
oldp->m_iterpp = nullptr;
oldp->debugTreeChange("-unlinkWNextOut: ", __LINE__, true);
return oldp;
}
@@ -561,10 +562,10 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
// Iterator fixup
if (oldp->m_iterpp) *(oldp->m_iterpp) = oldp->m_nextp;
// Relink
oldp->m_nextp = NULL;
oldp->m_backp = NULL;
oldp->m_nextp = nullptr;
oldp->m_backp = nullptr;
oldp->m_headtailp = this;
oldp->m_iterpp = NULL;
oldp->m_iterpp = nullptr;
oldp->debugTreeChange("-unlinkFrBkOut: ", __LINE__, true);
return oldp;
}
@@ -598,7 +599,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
}
// Relink
newp->m_backp = backp;
linkerp->m_backp = NULL;
linkerp->m_backp = nullptr;
// Iterator fixup
if (linkerp->m_iterpp) {
// If we're iterating over a next() link, we need to follow links off the
@@ -610,7 +611,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
newp->m_iterpp = linkerp->m_iterpp;
}
// Empty the linker so not used twice accidentally
linkerp->m_backp = NULL;
linkerp->m_backp = nullptr;
this->debugTreeChange("-relinkOut: ", __LINE__, true);
}
@@ -633,8 +634,8 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
newlistlastp->m_nextp = pointpr;
pointpr->m_backp = newlistlastp;
// Head/tail
pointpr->m_headtailp = NULL; // Old head
newlistlastp->m_headtailp = NULL; // Old tail
pointpr->m_headtailp = nullptr; // Old head
newlistlastp->m_headtailp = nullptr; // Old tail
newp->m_headtailp = oldlistlastp; // Head points to tail
oldlistlastp->m_headtailp = newp; // Tail points to head
}
@@ -668,7 +669,7 @@ AstNode* AstNode::cloneTreeIter() {
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList());
newp->m_iterpp = NULL;
newp->m_iterpp = nullptr;
newp->clonep(this); // Save pointers to/from both to simplify relinking.
this->clonep(newp); // Save pointers to/from both to simplify relinking.
return newp;
@@ -676,12 +677,12 @@ AstNode* AstNode::cloneTreeIter() {
AstNode* AstNode::cloneTreeIterList() {
// private: Clone list of nodes, set m_headtailp
AstNode* newheadp = NULL;
AstNode* newtailp = NULL;
// Audited to make sure this is never NULL
AstNode* newheadp = nullptr;
AstNode* newtailp = nullptr;
// Audited to make sure this is never nullptr
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
AstNode* newp = oldp->cloneTreeIter();
newp->m_headtailp = NULL;
newp->m_headtailp = nullptr;
newp->m_backp = newtailp;
if (newtailp) newtailp->m_nextp = newp;
if (!newheadp) newheadp = newp;
@@ -700,10 +701,10 @@ AstNode* AstNode::cloneTree(bool cloneNextLink) {
newp = cloneTreeIterList();
} else {
newp = cloneTreeIter();
newp->m_nextp = NULL;
newp->m_nextp = nullptr;
newp->m_headtailp = newp;
}
newp->m_backp = NULL;
newp->m_backp = nullptr;
newp->cloneRelinkTree();
newp->debugTreeChange("-cloneOut: ", __LINE__, true);
return newp;
@@ -739,7 +740,7 @@ void AstNode::deleteNode() {
void AstNode::deleteTreeIter() {
// private: Delete list of nodes. Publicly call deleteTree() instead.
// Audited to make sure this is never NULL
// Audited to make sure this is never nullptr
for (AstNode *nodep = this, *nnextp; nodep; nodep = nnextp) {
nnextp = nodep->m_nextp;
// MUST be depth first!
@@ -747,8 +748,8 @@ void AstNode::deleteTreeIter() {
if (nodep->m_op2p) nodep->m_op2p->deleteTreeIter();
if (nodep->m_op3p) nodep->m_op3p->deleteTreeIter();
if (nodep->m_op4p) nodep->m_op4p->deleteTreeIter();
nodep->m_nextp = NULL;
nodep->m_backp = NULL;
nodep->m_nextp = nullptr;
nodep->m_backp = nullptr;
nodep->deleteNode();
}
}
@@ -831,11 +832,11 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
niterp->m_iterpp = &niterp;
niterp->accept(v);
// accept may do a replaceNode and change niterp on us...
// niterp maybe NULL, so need cast if printing
// niterp maybe nullptr, so need cast if printing
// if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
// <<" now into "<<cvtToHex(niterp)<<endl);
if (!niterp) return; // Perhaps node deleted inside accept
niterp->m_iterpp = NULL;
niterp->m_iterpp = nullptr;
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
nodep = niterp;
} else { // Unchanged node, just continue loop
@@ -853,7 +854,7 @@ void AstNode::iterateListBackwards(AstNVisitor& v) {
if (nodep->backp()->m_nextp == nodep) {
nodep = nodep->backp();
} else {
nodep = NULL;
nodep = nullptr;
} // else: backp points up the tree.
}
}
@@ -900,7 +901,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
} else {
// Use back to determine who's pointing at us (IE assume new node
// grafts into same place as old one)
AstNode** nextnodepp = NULL;
AstNode** nextnodepp = nullptr;
if (this->m_backp->m_op1p == this) {
nextnodepp = &(this->m_backp->m_op1p);
} else if (this->m_backp->m_op2p == this) {
@@ -974,9 +975,7 @@ std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
V3Hash::V3Hash(const string& name) {
uint32_t val = 0;
for (string::const_iterator it = name.begin(); it != name.end(); ++it) {
val = val * 31 + *it;
}
for (const auto& c : name) val = val * 31 + c;
setBoth(1, val);
}
@@ -999,7 +998,7 @@ void AstNode::checkTreeIter(AstNode* backp) {
void AstNode::checkTreeIterList(AstNode* backp) {
// private: Check a (possible) list of nodes, this is always the head of the list
// Audited to make sure this is never NULL
// Audited to make sure this is never nullptr
AstNode* headp = this;
AstNode* tailp = this;
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
@@ -1052,7 +1051,7 @@ void AstNode::checkIter() const {
if (m_iterpp) {
dumpPtrs(cout);
// Perhaps something forgot to clear m_iterpp?
this->v3fatalSrc("Iteration link should be NULL");
this->v3fatalSrc("Iteration link should be nullptr");
}
}
@@ -1108,7 +1107,7 @@ void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) con
}
void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDepth) const {
// Audited to make sure this is never NULL
// Audited to make sure this is never nullptr
for (const AstNode* nodep = this; nodep; nodep = nodep->nextp()) {
nodep->dumpTree(os, indent, maxDepth);
}
@@ -1119,7 +1118,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
if (doDump) {
{ // Write log & close
UINFO(2, "Dumping " << filename << endl);
const vl_unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
const std::unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
if (logsp->fail()) v3fatal("Can't write " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">" << endl;
@@ -1267,8 +1266,6 @@ AstNodeDType* AstNode::findVoidDType() const {
// AstNVisitor
void AstNVisitor::doDeletes() {
for (std::vector<AstNode*>::iterator it = m_deleteps.begin(); it != m_deleteps.end(); ++it) {
(*it)->deleteTree();
}
for (AstNode* nodep : m_deleteps) nodep->deleteTree();
m_deleteps.clear();
}
+421 -382
View File
File diff suppressed because it is too large Load Diff
+117 -67
View File
@@ -22,6 +22,7 @@
#include "V3Global.h"
#include "V3Graph.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3String.h"
#include "V3EmitCBase.h"
#include <iomanip>
@@ -35,7 +36,7 @@ const char* AstIfaceRefDType::broken() const {
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
return NULL;
return nullptr;
}
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
@@ -45,7 +46,7 @@ AstIface* AstIfaceRefDType::ifaceViaCellp() const {
const char* AstNodeVarRef::broken() const {
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
BROKEN_RTN(m_varp && !m_varp->brokeExists());
return NULL;
return nullptr;
}
void AstNodeVarRef::cloneRelink() {
@@ -73,7 +74,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
}
const char* AstNodeUOrStructDType::broken() const {
vl_unordered_set<AstMemberDType*> exists;
std::unordered_set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
exists.insert(itemp);
}
@@ -83,11 +84,13 @@ const char* AstNodeUOrStructDType::broken() const {
return "member broken";
}
}
return NULL;
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);
@@ -100,7 +103,7 @@ void AstNodeCCall::cloneRelink() {
}
const char* AstNodeCCall::broken() const {
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
return NULL;
return nullptr;
}
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
string AstNodeCCall::hiernameProtect() const {
@@ -211,7 +214,7 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
AstExecGraph::AstExecGraph(FileLine* fileline)
: AstNode(AstType::atExecGraph, fileline) {
: AstNode{AstType::atExecGraph, fileline} {
m_depGraphp = new V3Graph;
}
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
@@ -225,6 +228,36 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode
return newp;
}
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
bool success = false;
if (literal[0] == '"') {
// This is a string
string v = literal.substr(1, literal.find('"', 1) - 1);
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
} else if (literal.find_first_of(".eEpP") != string::npos) {
// This may be a real
double v = VString::parseDouble(literal, &success);
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
}
if (!success) {
// This is either an integer or an error
// We first try to convert it as C literal. If strtol returns
// 0 this is either an error or 0 was parsed. But in any case
// we will try to parse it as a verilog literal, hence having
// the false negative for 0 is okay. If anything remains in
// the string after the number, this is invalid C and we try
// the Verilog literal parser.
char* endp;
int v = strtol(literal.c_str(), &endp, 0);
if ((v != 0) && (endp[0] == 0)) { // C literal
return new AstConst(fl, AstConst::WidthedValue(), 32, v);
} else { // Try a Verilog literal (fatals if not)
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
}
}
return nullptr;
}
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
VTimescale prec = v3Global.opt.timeComputePrec(value);
if (prec.isNone() || prec == m_timeprecision) {
@@ -284,7 +317,7 @@ 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) {
string render(const string& name) const {
string out;
out += m_type;
out += " ";
@@ -300,7 +333,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
string oname;
if (named) {
@@ -431,7 +464,7 @@ string AstVar::vlEnumDir() const {
return out;
}
string AstVar::vlPropDecl(string propName) const {
string AstVar::vlPropDecl(const string& propName) const {
string out;
std::vector<int> ulims; // Unpacked dimension limits
@@ -450,9 +483,9 @@ string AstVar::vlPropDecl(string propName) const {
out += "static const int " + propName + "__ulims[";
out += cvtToStr(ulims.size());
out += "] = {";
std::vector<int>::const_iterator it = ulims.begin();
auto it = ulims.cbegin();
out += cvtToStr(*it);
while (++it != ulims.end()) {
while (++it != ulims.cend()) {
out += ", ";
out += cvtToStr(*it);
}
@@ -495,8 +528,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
}
if (isWide()) {
if (forReturn) {
v3error("Unsupported: Public functions with >64 bit outputs; "
"make an output of a public task instead");
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
"make an output of a public task instead");
}
arg += " (& " + name();
arg += ")[" + cvtToStr(widthWords()) + "]";
@@ -573,13 +606,13 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
if (anodep->isSc()) {
return anodep;
} else {
return NULL;
return nullptr;
}
} else if (VN_IS(nodep, VarRef)) {
if (VN_CAST(nodep, VarRef)->varp()->isSc()) {
return VN_CAST(nodep, VarRef)->varp();
} else {
return NULL;
return nullptr;
}
} else if (VN_IS(nodep, ArraySel)) {
if (nodep->op1p()) {
@@ -595,15 +628,13 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
}
}
return NULL;
return nullptr;
}
string AstVar::mtasksString() const {
std::ostringstream os;
os << "all: ";
for (MTaskIdSet::const_iterator it = m_mtaskIds.begin(); it != m_mtaskIds.end(); ++it) {
os << *it << " ";
}
for (const auto& id : m_mtaskIds) os << id << " ";
return os.str();
}
@@ -633,17 +664,17 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
if (adtypep->isRanged()) {
if ((dim++) == dimension) return adtypep;
}
return NULL;
return nullptr;
} else if (AstNodeUOrStructDType* adtypep = VN_CAST(dtypep, NodeUOrStructDType)) {
if (adtypep->packed()) {
if ((dim++) == dimension) return adtypep;
}
return NULL;
return nullptr;
}
// Node no ->next in loop; use continue where necessary
break;
}
return NULL;
return nullptr;
}
uint32_t AstNodeDType::arrayUnpackedElements() {
@@ -730,7 +761,7 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) {
const char* AstJumpBlock::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return NULL;
return nullptr;
}
void AstJumpBlock::cloneRelink() {
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
@@ -741,7 +772,7 @@ const char* AstScope::broken() const {
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
BROKEN_RTN(!m_modp);
BROKEN_RTN(m_modp && !m_modp->brokeExists());
return NULL;
return nullptr;
}
void AstScope::cloneRelink() {
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
@@ -784,28 +815,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
bool AstSenTree::hasClocked() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isClocked()) return true;
}
return false;
}
bool AstSenTree::hasSettle() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isSettle()) return true;
}
return false;
}
bool AstSenTree::hasInitial() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isInitial()) return true;
}
return false;
}
bool AstSenTree::hasCombo() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isCombo()) return true;
}
return false;
@@ -815,7 +846,7 @@ 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] = NULL;
m_basicps[i] = nullptr;
}
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
@@ -873,8 +904,9 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
return newp;
}
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, VNumRange range,
int widthMin, VSigning numeric) {
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
const VNumRange& range, int widthMin,
VSigning numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) {
@@ -889,7 +921,7 @@ AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange());
DetailedMap& mapr = m_detailedMap;
DetailedMap::const_iterator it = mapr.find(key);
const auto it = mapr.find(key);
if (it != mapr.end()) return it->second;
mapr.insert(make_pair(key, nodep));
nodep->generic(true);
@@ -1005,8 +1037,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() << "]";
}
@@ -1027,8 +1061,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 {
@@ -1048,10 +1086,12 @@ void AstCellInline::dump(std::ostream& str) const {
const char* AstClassPackage::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
BROKEN_RTN(m_classp && !m_classp->brokeExists());
return NULL;
return nullptr;
}
void AstClass::insertCache(AstNode* nodep) {
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeFTask) || VN_IS(nodep, EnumItemRef)) {
bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_CAST(nodep, NodeFTask)->isExternProto()));
if (doit) {
if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
} else {
@@ -1063,7 +1103,11 @@ void AstClass::repairCache() {
clearCache();
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); }
}
void AstClass::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstClass::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isExtended()) str << " [EXT]";
if (isVirtual()) str << " [VIRT]";
}
AstClass* AstClassExtends::classp() const {
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
UASSERT_OBJ(refp, this, "class extends non-ref");
@@ -1083,15 +1127,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);
@@ -1131,7 +1175,7 @@ void AstInitArray::dump(std::ostream& str) const {
}
}
void AstJumpGo::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (labelp()) {
labelp()->dump(str);
@@ -1140,7 +1184,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);
@@ -1149,7 +1193,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);
@@ -1158,7 +1202,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()) {
@@ -1199,27 +1243,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 {
@@ -1316,15 +1363,16 @@ void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
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 {
@@ -1392,10 +1440,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);
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
@@ -1411,9 +1460,9 @@ void AstVarXRef::dump(std::ostream& str) const {
}
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
@@ -1462,19 +1511,19 @@ void AstParseRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << expect().ascii() << "]";
}
void AstPackageRef::dump(std::ostream& str) const {
void AstClassOrPackageRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (classOrPackagep()) { str << " cpkg=" << nodeAddr(classOrPackagep()); }
str << " -> ";
if (packagep()) {
packagep()->dump(str);
if (classOrPackagep()) {
classOrPackagep()->dump(str);
} else {
str << "UNLINKED";
}
}
void AstDot::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (colon()) str << "[::]";
if (colon()) str << " [::]";
}
void AstActive::dump(std::ostream& str) const {
this->AstNode::dump(str);
@@ -1486,7 +1535,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() << " "; }
@@ -1518,7 +1567,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()) {
@@ -1529,7 +1578,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);
@@ -1542,7 +1591,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);
@@ -1561,10 +1610,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]";
}
+3017 -2677
View File
File diff suppressed because it is too large Load Diff
+31 -39
View File
@@ -42,11 +42,10 @@ private:
// Entire netlist:
// AstNodeFTask::user1 -> bool, 1=processed
AstUser1InUse m_inuser1;
bool m_anyFuncInBegin;
bool m_anyFuncInBegin = false;
public:
BeginState()
: m_anyFuncInBegin(false) {}
BeginState() {}
~BeginState() {}
void userMarkChanged(AstNode* nodep) {
nodep->user1(true);
@@ -61,25 +60,24 @@ class BeginVisitor : public AstNVisitor {
private:
// STATE
BeginState* m_statep; // Current global state
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth; // Current if depth
int m_ifDepth = 0; // Current if depth
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
virtual void visit(AstNodeFTask* nodep) override {
UINFO(8, " " << nodep << endl);
// Rename it
if (m_unnamedScope != "") {
@@ -92,19 +90,17 @@ private:
// naming; so that any begin's inside the function will rename
// inside the function.
// Process children
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
m_namedScope = "";
m_unnamedScope = "";
m_ftaskp = nodep;
iterateChildren(nodep);
m_ftaskp = NULL;
m_ftaskp = nullptr;
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
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;
@@ -147,7 +143,7 @@ private:
m_unnamedScope = oldUnnamed;
// Cleanup
AstNode* addsp = NULL;
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
@@ -163,7 +159,7 @@ private:
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstVar* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
@@ -177,7 +173,7 @@ private:
}
}
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
virtual void visit(AstTypedef* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
@@ -192,7 +188,7 @@ private:
}
}
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
virtual void visit(AstCell* nodep) override {
UINFO(8, " CELL " << nodep << endl);
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
@@ -205,14 +201,14 @@ private:
}
iterateChildren(nodep);
}
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
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);
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
virtual void visit(AstScopeName* nodep) override {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's
@@ -225,15 +221,15 @@ private:
}
iterateChildren(nodep);
}
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
virtual void visit(AstCoverDecl* nodep) override {
// Don't need to fix path in coverage statements, they're not under
// any BEGINs, but V3Coverage adds them all under the module itself.
iterateChildren(nodep);
}
// VISITORS - LINT CHECK
virtual void visit(AstIf* nodep) VL_OVERRIDE { // not AstNodeIf; other types not covered
virtual void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered
// Check IFDEPTH warning - could be in other transform files if desire
int prevIfDepth = m_ifDepth;
VL_RESTORER(m_ifDepth);
if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
m_ifDepth = -1;
@@ -244,20 +240,16 @@ private:
m_ifDepth = -1;
}
iterateChildren(nodep);
m_ifDepth = prevIfDepth;
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
BeginVisitor(AstNetlist* nodep, BeginState* statep) {
m_statep = statep;
m_modp = NULL;
m_ftaskp = NULL;
m_ifDepth = 0;
BeginVisitor(AstNetlist* nodep, BeginState* statep)
: m_statep{statep} {
iterate(nodep);
}
virtual ~BeginVisitor() {}
virtual ~BeginVisitor() override {}
};
//######################################################################
@@ -270,21 +262,21 @@ private:
// AstNodeFTask::user1p // Node replaced, rename it
// VISITORS
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeFTaskRef* nodep) override {
if (nodep->taskp()->user1()) { // It was converted
UINFO(9, " relinkFTask " << nodep << endl);
nodep->name(nodep->taskp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef " << nodep << endl);
nodep->name(nodep->varp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
virtual void visit(AstIfaceRefDType* nodep) override {
// May have changed cell names
// TypeTable is always after all modules, so names are stable
UINFO(8, " IFACEREFDTYPE " << nodep << endl);
@@ -293,12 +285,12 @@ private:
iterateChildren(nodep);
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
virtual ~BeginRelinkVisitor() {}
virtual ~BeginRelinkVisitor() override {}
};
//######################################################################
+8 -11
View File
@@ -65,10 +65,10 @@ private:
}
// VISITORS
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
virtual void visit(AstNodeIf* nodep) override {
UINFO(4, " IF: " << nodep << endl);
int lastLikely = m_likely;
int lastUnlikely = m_unlikely;
VL_RESTORER(m_likely);
VL_RESTORER(m_unlikely);
{
// Do if
reset();
@@ -88,28 +88,25 @@ private:
nodep->branchPred(VBranchPred::BP_UNLIKELY);
} // else leave unknown
}
m_likely = lastLikely;
m_unlikely = lastUnlikely;
}
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCCall* nodep) override {
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
checkUnlikely(nodep);
iterateChildren(nodep);
}
// METHODS
void calc_tasks() {
for (CFuncVec::iterator it = m_cfuncsp.begin(); it != m_cfuncsp.end(); ++it) {
AstCFunc* nodep = *it;
for (AstCFunc* nodep : m_cfuncsp) {
if (!nodep->dontInline()) nodep->isInline(true);
}
}
@@ -121,7 +118,7 @@ public:
iterateChildren(nodep);
calc_tasks();
}
virtual ~BranchVisitor() {}
virtual ~BranchVisitor() override {}
};
//######################################################################
+19 -19
View File
@@ -32,7 +32,7 @@
#include "V3AstConstOnly.h"
#include <algorithm>
#include VL_INCLUDE_UNORDERED_MAP
#include <unordered_map>
//######################################################################
@@ -41,7 +41,7 @@ class BrokenTable : public AstNVisitor {
private:
// MEMBERS
// For each node, we keep if it exists or not.
typedef vl_unordered_map<const AstNode*, int> NodeMap; // Performance matters (when --debug)
typedef std::unordered_map<const AstNode*, int> NodeMap; // Performance matters (when --debug)
static NodeMap s_nodes; // Set of all nodes that exist
// BITMASK
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
@@ -49,12 +49,13 @@ private:
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
public:
// METHODS
static void deleted(const AstNode* nodep) {
// Called by operator delete on any node - only if VL_LEAK_CHECKS
if (debug() >= 9) cout << "-nodeDel: " << cvtToHex(nodep) << endl;
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
UASSERT_OBJ(!(iter == s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
reinterpret_cast<const AstNode*>(nodep),
"Deleting AstNode object that was never tracked or already deleted");
@@ -67,7 +68,7 @@ public:
static void addNewed(const AstNode* nodep) {
// Called by operator new on any node - only if VL_LEAK_CHECKS
if (debug() >= 9) cout << "-nodeNew: " << cvtToHex(nodep) << endl;
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
UASSERT_OBJ(!(iter != s_nodes.end() && (iter->second & FLAG_ALLOCATED)), nodep,
"Newing AstNode object that is already allocated");
if (iter == s_nodes.end()) {
@@ -78,7 +79,7 @@ public:
static void setUnder(const AstNode* nodep, bool flag) {
// Called by BrokenCheckVisitor when each node entered/exited
if (!okIfLinkedTo(nodep)) return;
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
if (iter != s_nodes.end()) {
iter->second &= ~FLAG_UNDER_NOW;
if (flag) iter->second |= FLAG_UNDER_NOW;
@@ -89,7 +90,7 @@ public:
// cppcheck-suppress knownConditionTrueFalse
if (!linkable) return; // save some time, else the map will get huge!
#endif
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
if (VL_UNCOVERABLE(iter == s_nodes.end())) {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
@@ -113,7 +114,7 @@ public:
// Some generic node has a pointer to this node. Is it allocated?
// Use this when might not be in tree; otherwise use okIfLinkedTo().
#ifdef VL_LEAK_CHECKS
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if (!(iter->second & FLAG_ALLOCATED)) return false;
#endif
@@ -121,7 +122,7 @@ public:
}
static bool okIfLinkedTo(const AstNode* nodep) {
// Some node in tree has a pointer to this node. Is it kosher?
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
#ifdef VL_LEAK_CHECKS
if (!(iter->second & FLAG_ALLOCATED)) return false;
@@ -133,7 +134,7 @@ public:
static bool okIfAbove(const AstNode* nodep) {
// Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false;
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if ((iter->second & FLAG_UNDER_NOW)) return false;
return true;
@@ -141,7 +142,7 @@ public:
static bool okIfBelow(const AstNode* nodep) {
// Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false;
NodeMap::iterator iter = s_nodes.find(nodep);
const auto iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if (!(iter->second & FLAG_UNDER_NOW)) return false;
return true;
@@ -188,10 +189,9 @@ public:
}
}
public:
// CONSTRUCTORS
BrokenTable() {}
virtual ~BrokenTable() {}
virtual ~BrokenTable() override {}
};
BrokenTable::NodeMap BrokenTable::s_nodes;
@@ -223,7 +223,7 @@ private:
iterateChildrenConst(nodep);
}
// VISITORS
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
// Process not just iterate
processAndIterate(nodep);
}
@@ -231,7 +231,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenMarkVisitor() {}
virtual ~BrokenMarkVisitor() override {}
};
//######################################################################
@@ -239,7 +239,7 @@ public:
class BrokenCheckVisitor : public AstNVisitor {
private:
void checkWidthMin(const AstNode* nodep) {
static void checkWidthMin(const AstNode* nodep) {
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
nodep, "Width != WidthMin");
@@ -271,14 +271,14 @@ private:
iterateChildrenConst(nodep);
BrokenTable::setUnder(nodep, false);
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
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().isWrite()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
// Process not just iterate
processAndIterate(nodep);
}
@@ -286,7 +286,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenCheckVisitor() {}
virtual ~BrokenCheckVisitor() override {}
};
//######################################################################
+12 -9
View File
@@ -48,11 +48,11 @@ private:
public:
void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_funcp = NULL;
m_funcp = nullptr;
}
if (!m_funcp) {
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum),
NULL, "void");
nullptr, "void");
m_funcp->isStatic(false);
m_funcp->declPrivate(true);
m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
@@ -78,7 +78,7 @@ public:
m_modp = nodep;
m_numStmts = 0;
m_funcNum = 0;
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void");
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void");
m_tlFuncp->declPrivate(true);
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
@@ -97,7 +97,7 @@ private:
void V3CCtors::evalAsserts() {
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module wrapper
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", NULL, "void");
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", nullptr, "void");
funcp->declPrivate(true);
funcp->isStatic(false);
funcp->slow(false);
@@ -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)));
}
}
}
@@ -170,10 +171,12 @@ void V3CCtors::cctorsAll() {
}
}
}
if (VN_IS(modp, Class)) {
AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", NULL, "");
if (AstClass* classp = VN_CAST(modp, Class)) {
AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", nullptr, "");
funcp->isDestructor(true);
funcp->isStatic(false);
// If can be referred to by base pointer, need virtual delete
funcp->isVirtual(classp->isExtended());
funcp->slow(false);
modp->addStmtp(funcp);
}
+25 -19
View File
@@ -32,7 +32,7 @@
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include VL_INCLUDE_UNORDERED_MAP
#include <unordered_map>
//######################################################################
@@ -67,7 +67,7 @@ public:
// CONSTRUCTORS
explicit CUseState(AstNodeModule* nodep)
: m_modInsertp(nodep) {}
: m_modInsertp{nodep} {}
virtual ~CUseState() {}
VL_UNCOPYABLE(CUseState);
};
@@ -78,27 +78,26 @@ public:
class CUseDTypeVisitor : public AstNVisitor {
// MEMBERS
CUseState& m_stater; // State for inserter
bool m_impOnly; // In details needed only for implementation
bool m_impOnly = false; // In details needed only for implementation
// METHODS
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
virtual void visit(AstClassRefDType* nodep) override {
if (nodep->user2SetOnce()) return; // Process once
if (!m_impOnly) m_stater.newUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
// No class.h, it's inside the class package's h file
m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->packagep()->name());
// Need to include extends() when we implement, but no need for pointers to know
bool oldImpOnly = m_impOnly;
VL_RESTORER(m_impOnly);
{
m_impOnly = true;
iterateChildren(nodep->classp()); // This also gets all extend classes
}
m_impOnly = oldImpOnly;
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
virtual void visit(AstNodeDType* nodep) override {
if (nodep->user2SetOnce()) return; // Process once
if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep());
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
if (nodep->user2SetOnce()) return; // Process once
if (nodep->dtypep() && !nodep->dtypep()->user2()) iterate(nodep->dtypep());
iterateChildren(nodep);
@@ -107,11 +106,10 @@ class CUseDTypeVisitor : public AstNVisitor {
public:
// CONSTRUCTORS
explicit CUseDTypeVisitor(AstNodeModule* nodep, CUseState& stater)
: m_stater(stater)
, m_impOnly(false) {
: m_stater(stater) { // Need () or GCC 4.8 false warning
iterate(nodep);
}
virtual ~CUseDTypeVisitor() {}
virtual ~CUseDTypeVisitor() override {}
VL_UNCOPYABLE(CUseDTypeVisitor);
};
@@ -132,7 +130,7 @@ class CUseVisitor : public AstNVisitor {
}
}
void makeVlToString(AstClass* nodep) {
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "VL_TO_STRING", NULL, "std::string");
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "VL_TO_STRING", nullptr, "std::string");
funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep)
+ ">& obj");
funcp->isMethod(false);
@@ -145,7 +143,7 @@ class CUseVisitor : public AstNVisitor {
nodep->addStmtp(funcp);
}
void makeToString(AstClass* nodep) {
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string", NULL, "std::string");
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string", nullptr, "std::string");
funcp->isConst(true);
funcp->isStatic(false);
funcp->protect(false);
@@ -156,7 +154,8 @@ class CUseVisitor : public AstNVisitor {
nodep->addStmtp(funcp);
}
void makeToStringMiddle(AstClass* nodep) {
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string_middle", NULL, "std::string");
AstCFunc* funcp
= new AstCFunc(nodep->fileline(), "to_string_middle", nullptr, "std::string");
funcp->isConst(true);
funcp->isStatic(false);
funcp->protect(false);
@@ -168,7 +167,14 @@ class CUseVisitor : public AstNVisitor {
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + VL_TO_STRING(";
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
@@ -189,7 +195,7 @@ class CUseVisitor : public AstNVisitor {
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
if (v3Global.opt.trace()) {
AstCUse* usep
= m_state.newUse(nodep, VUseType::INT_FWD_CLASS, v3Global.opt.traceClassBase());
@@ -203,15 +209,15 @@ class CUseVisitor : public AstNVisitor {
makeToStringMiddle(classp);
}
}
virtual void visit(AstNode*) VL_OVERRIDE {} // All in AstNodeModule
virtual void visit(AstNode*) override {} // All in AstNodeModule
public:
// CONSTRUCTORS
explicit CUseVisitor(AstNodeModule* nodep)
: m_state(nodep) {
: m_state{nodep} {
iterate(nodep);
}
virtual ~CUseVisitor() {}
virtual ~CUseVisitor() override {}
VL_UNCOPYABLE(CUseVisitor);
};
+29 -33
View File
@@ -52,12 +52,13 @@
class CaseLintVisitor : public AstNVisitor {
private:
AstNodeCase* m_caseExprp; // Under a CASE value node, if so the relevant case statement
AstNodeCase* m_caseExprp
= nullptr; // Under a CASE value node, if so the relevant case statement
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCase* nodep) override {
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
@@ -81,10 +82,10 @@ private:
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
iterateAndNextNull(itemp->condsp());
}
m_caseExprp = NULL;
m_caseExprp = nullptr;
}
}
virtual void visit(AstConst* nodep) VL_OVERRIDE {
virtual void visit(AstConst* nodep) override {
// See also neverItem
if (m_caseExprp && nodep->num().isFourState()) {
if (VN_IS(m_caseExprp, GenCase)) {
@@ -105,15 +106,12 @@ private:
}
}
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) {
m_caseExprp = NULL;
iterate(nodep);
}
virtual ~CaseLintVisitor() {}
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
virtual ~CaseLintVisitor() override {}
};
//######################################################################
@@ -131,9 +129,9 @@ private:
VDouble0 m_statCaseSlow; // Statistic tracking
// Per-CASE
int m_caseWidth; // Width of valueItems
int m_caseItems; // Number of caseItem unique values
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
int m_caseWidth = 0; // Width of valueItems
int m_caseItems = 0; // Number of caseItem unique values
bool m_caseNoOverlapsAllCovered = false; // Proven to be synopsys parallel_case compliant
// For each possible value, the case branch we need
AstNode* m_valueItem[1 << CASE_OVERLAP_WIDTH];
@@ -161,7 +159,7 @@ private:
}
UINFO(8, "Simple case statement: " << nodep << endl);
// Zero list of items for each value
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) m_valueItem[i] = NULL;
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) m_valueItem[i] = nullptr;
// Now pick up the values for each assignment
// We can cheat and use uint32_t's because we only support narrow case's
bool bitched = false;
@@ -218,7 +216,7 @@ private:
}
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
// Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
}
@@ -324,13 +322,13 @@ private:
hadDefault = true;
} else {
// Expressioned clause
AstNode* icondNextp = NULL;
AstNode* ifexprp = NULL; // If expression to test
AstNode* icondNextp = nullptr;
AstNode* ifexprp = nullptr; // If expression to test
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondNextp) {
icondNextp = icondp->nextp();
icondp->unlinkFrBack();
AstNode* condp = NULL; // Default is to use and1p/and2p
AstNode* condp = nullptr; // Default is to use and1p/and2p
AstConst* iconstp = VN_CAST(icondp, Const);
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
@@ -377,8 +375,9 @@ private:
if (!hadDefault) {
// If there was no default, add a empty one, this greatly simplifies below code
// and constant propagation will just eliminate it for us later.
nodep->addItemsp(new AstCaseItem(
nodep->fileline(), new AstConst(nodep->fileline(), AstConst::LogicTrue()), NULL));
nodep->addItemsp(
new AstCaseItem(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::LogicTrue()), nullptr));
}
if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: ");
// Now build the IF statement tree
@@ -388,9 +387,9 @@ private:
// should pull out the most common item from here and instead make
// it the first IF branch.
int depth = 0;
AstNode* grouprootp = NULL;
AstIf* groupnextp = NULL;
AstIf* itemnextp = NULL;
AstNode* grouprootp = nullptr;
AstIf* groupnextp = nullptr;
AstIf* itemnextp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
@@ -400,9 +399,9 @@ private:
{ // Prepare for next group
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = NULL;
itemnextp = nullptr;
AstIf* newp
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL);
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), nullptr, nullptr);
if (groupnextp) {
groupnextp->addElsesp(newp);
} else {
@@ -422,7 +421,7 @@ private:
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
if (itemnextp) {
itemnextp->addElsesp(newp);
} else {
@@ -467,7 +466,7 @@ private:
}
// VISITORS
virtual void visit(AstCase* nodep) VL_OVERRIDE {
virtual void visit(AstCase* nodep) override {
V3Case::caseLint(nodep);
iterateChildren(nodep);
if (debug() >= 9) nodep->dumpTree(cout, " case_old: ");
@@ -482,18 +481,15 @@ private:
}
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CaseVisitor(AstNetlist* nodep) {
m_caseWidth = 0;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = false;
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = NULL;
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr;
iterate(nodep);
}
virtual ~CaseVisitor() {
virtual ~CaseVisitor() override {
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
}
+17 -17
View File
@@ -109,25 +109,25 @@ private:
}
// VISITORS
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeUniop* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeBiop* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeTriop* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
}
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeQuadop* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
| nodep->fhsp()->user1());
@@ -136,12 +136,12 @@ private:
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
}
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
virtual void visit(AstCCast* nodep) override {
iterateChildren(nodep);
ensureLower32Cast(nodep);
nodep->user1(1);
}
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
virtual void visit(AstNegate* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin() == 1) {
@@ -153,17 +153,17 @@ private:
ensureCast(nodep->lhsp());
}
}
virtual void visit(AstVarRef* nodep) VL_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())) {
virtual void visit(AstVarRef* nodep) override {
if (nodep->access().isRead() && !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));
}
nodep->user1(1);
}
virtual void visit(AstConst* nodep) VL_OVERRIDE {
virtual void visit(AstConst* nodep) override {
// Constants are of unknown size if smaller than 33 bits, because
// we're too lazy to wrap every constant in the universe in
// ((IData)#).
@@ -171,29 +171,29 @@ private:
}
// Null dereference protection
virtual void visit(AstNullCheck* nodep) VL_OVERRIDE {
virtual void visit(AstNullCheck* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
}
virtual void visit(AstCMethodCall* nodep) VL_OVERRIDE {
virtual void visit(AstCMethodCall* nodep) override {
iterateChildren(nodep);
ensureNullChecked(nodep->fromp());
}
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
virtual void visit(AstMemberSel* nodep) override {
iterateChildren(nodep);
ensureNullChecked(nodep->fromp());
}
// NOPs
virtual void visit(AstVar*) VL_OVERRIDE {}
virtual void visit(AstVar*) override {}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CastVisitor() {}
virtual ~CastVisitor() override {}
};
//######################################################################
+87 -112
View File
@@ -37,7 +37,7 @@
#include <iomanip>
#include <memory>
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic
//######################################################################
@@ -52,25 +52,23 @@ public:
class CdcEitherVertex : public V3GraphVertex {
AstScope* m_scopep;
AstNode* m_nodep;
AstSenTree* m_srcDomainp;
AstSenTree* m_dstDomainp;
AstSenTree* m_srcDomainp = nullptr;
AstSenTree* m_dstDomainp = nullptr;
bool m_srcDomainSet : 1;
bool m_dstDomainSet : 1;
bool m_asyncPath : 1;
public:
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
: V3GraphVertex(graphp)
, m_scopep(scopep)
, m_nodep(nodep)
, m_srcDomainp(NULL)
, m_dstDomainp(NULL)
, m_srcDomainSet(false)
, m_dstDomainSet(false)
, m_asyncPath(false) {}
virtual ~CdcEitherVertex() {}
: V3GraphVertex{graphp}
, m_scopep{scopep}
, m_nodep{nodep}
, m_srcDomainSet{false}
, m_dstDomainSet{false}
, m_asyncPath{false} {}
virtual ~CdcEitherVertex() override {}
// ACCESSORS
virtual FileLine* fileline() const { return nodep()->fileline(); }
virtual FileLine* fileline() const override { return nodep()->fileline(); }
AstScope* scopep() const { return m_scopep; }
AstNode* nodep() const { return m_nodep; }
AstSenTree* srcDomainp() const { return m_srcDomainp; }
@@ -87,20 +85,18 @@ public:
class CdcVarVertex : public CdcEitherVertex {
AstVarScope* m_varScp;
int m_cntAsyncRst;
bool m_fromFlop;
int m_cntAsyncRst = 0;
bool m_fromFlop = false;
public:
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: CdcEitherVertex(graphp, scopep, varScp)
, m_varScp(varScp)
, m_cntAsyncRst(0)
, m_fromFlop(false) {}
virtual ~CdcVarVertex() {}
: CdcEitherVertex{graphp, scopep, varScp}
, m_varScp{varScp} {}
virtual ~CdcVarVertex() override {}
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
virtual string dotColor() const {
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
virtual string dotColor() const override {
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
}
int cntAsyncRst() const { return m_cntAsyncRst; }
@@ -115,16 +111,18 @@ class CdcLogicVertex : public CdcEitherVertex {
public:
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
: CdcEitherVertex(graphp, scopep, nodep)
, m_hazard(false)
, m_isFlop(false) {
: CdcEitherVertex{graphp, scopep, nodep}
, m_hazard{false}
, m_isFlop{false} {
srcDomainp(sensenodep);
dstDomainp(sensenodep);
}
virtual ~CdcLogicVertex() {}
virtual ~CdcLogicVertex() override {}
// ACCESSORS
virtual string name() const { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
virtual string dotColor() const { return hazard() ? "black" : "yellow"; }
virtual string name() const override {
return (cvtToHex(nodep()) + "@" + scopep()->prettyName());
}
virtual string dotColor() const override { return hazard() ? "black" : "yellow"; }
bool hazard() const { return m_hazard; }
void setHazard(AstNode* nodep) {
m_hazard = true;
@@ -145,7 +143,7 @@ private:
std::ofstream* m_ofp; // Output file
string m_prefix;
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
*m_ofp << m_prefix;
if (nodep->user3()) {
*m_ofp << " %%";
@@ -167,22 +165,22 @@ private:
public:
// CONSTRUCTORS
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix) {
m_ofp = ofp;
m_prefix = prefix;
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix)
: m_ofp{ofp}
, m_prefix{prefix} {
iterate(nodep);
}
virtual ~CdcDumpVisitor() {}
virtual ~CdcDumpVisitor() override {}
};
//######################################################################
class CdcWidthVisitor : public CdcBaseVisitor {
private:
int m_maxLineno;
size_t m_maxFilenameLen;
int m_maxLineno = 0;
size_t m_maxFilenameLen = 0;
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
iterateChildren(nodep);
// Keeping line+filename lengths separate is much faster than calling ascii().length()
if (nodep->fileline()->lineno() >= m_maxLineno) {
@@ -195,14 +193,10 @@ private:
public:
// CONSTRUCTORS
explicit CdcWidthVisitor(AstNode* nodep) {
m_maxLineno = 0;
m_maxFilenameLen = 0;
iterate(nodep);
}
virtual ~CdcWidthVisitor() {}
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~CdcWidthVisitor() override {}
// ACCESSORS
int maxWidth() {
int maxWidth() const {
size_t width = 1;
width += m_maxFilenameLen;
width += 1; // The :
@@ -229,16 +223,16 @@ private:
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
AstScope* m_scopep; // Current scope being processed
AstNodeModule* m_modp; // Current module
AstSenTree* m_domainp; // Current sentree
bool m_inDly; // In delayed assign
int m_inSenItem; // Number of senitems
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
AstScope* m_scopep = nullptr; // Current scope being processed
AstNodeModule* m_modp = nullptr; // Current module
AstSenTree* m_domainp = nullptr; // Current sentree
bool m_inDly = false; // In delayed assign
int m_inSenItem = 0; // Number of senitems
string m_ofFilename; // Output filename
std::ofstream* m_ofp; // Output file
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
int m_filelineWidth; // Characters in longest fileline
uint32_t m_userGeneration = 0; // Generation count to avoid slow userClearVertices
int m_filelineWidth = 0; // Characters in longest fileline
// METHODS
void iterateNewStmt(AstNode* nodep) {
@@ -253,7 +247,7 @@ private:
m_logicVertexp->dstDomainSet(true);
}
iterateChildren(nodep);
m_logicVertexp = NULL;
m_logicVertexp = nullptr;
if (false && debug() >= 9) {
UINFO(9, "Trace Logic:\n");
@@ -273,7 +267,7 @@ private:
// Create IO vertex - note it's relative to the pointed to var, not where we are
// now This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), nullptr);
if (varscp->varp()->isWritable()) {
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
} else {
@@ -364,7 +358,7 @@ private:
UINFO(8, " Trace One async: " << vvertexp << endl);
// Twice, as we need to detect, then propagate
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
if (markp) { // Mark is non-NULL if something bad on this path
if (markp) { // Mark is non-nullptr if something bad on this path
UINFO(9, " Trace One bad! " << vvertexp << endl);
m_userGeneration++; // Effectively a userClearVertices()
traceAsyncRecurse(vvertexp, true);
@@ -377,12 +371,12 @@ private:
}
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
// First pass: Return vertex of any hazardous stuff attached, or NULL if OK
// First pass: Return vertex of any hazardous stuff attached, or nullptr if OK
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
if (vertexp->user() >= m_userGeneration) return NULL; // Processed - prevent loop
if (vertexp->user() >= m_userGeneration) return nullptr; // Processed - prevent loop
vertexp->user(m_userGeneration);
CdcEitherVertex* mark_outp = NULL;
CdcEitherVertex* mark_outp = nullptr;
UINFO(9, " Trace: " << vertexp << endl);
// Clear out in prep for marking next path
@@ -401,7 +395,7 @@ private:
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return NULL;
return nullptr;
}
// Also ok if from flop, but partially trace the flop so more obvious to users
if (vvertexp->fromFlop()) {
@@ -409,7 +403,7 @@ private:
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return NULL;
return nullptr;
}
}
@@ -514,7 +508,7 @@ private:
}
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
if (ofp->fail()) v3fatal("Can't write " << filename);
*ofp << "Edge Report for " << v3Global.opt.prefix() << endl;
@@ -549,9 +543,7 @@ private:
}
}
stable_sort(report.begin(), report.end());
for (std::deque<string>::iterator it = report.begin(); it != report.end(); ++it) {
*ofp << *it;
}
for (const auto& line : report) *ofp << line;
}
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
@@ -594,7 +586,7 @@ private:
}
// Convert list of senses into one sense node
AstSenTree* senoutp = NULL;
AstSenTree* senoutp = nullptr;
bool senedited = false;
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
if (!senoutp) {
@@ -633,22 +625,21 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
m_logicVertexp = NULL;
m_logicVertexp = nullptr;
iterateChildren(nodep);
m_scopep = NULL;
m_scopep = nullptr;
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
// Create required blocks and add to module
UINFO(4, " BLOCK " << nodep << endl);
AstNode::user2ClearTree();
@@ -657,10 +648,10 @@ private:
|| m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
iterateNewStmt(nodep);
}
m_domainp = NULL;
m_domainp = nullptr;
AstNode::user2ClearTree();
}
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
@@ -670,7 +661,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().isWrite()) {
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
if (m_inDly) {
varvertexp->fromFlop(true);
@@ -688,71 +679,55 @@ private:
}
}
}
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
virtual void visit(AstAssignDly* nodep) override {
m_inDly = true;
iterateChildren(nodep);
m_inDly = false;
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
// Note we look at only AstSenItems, not AstSenGate's
// The gating term of a AstSenGate is normal logic
virtual void visit(AstSenItem* nodep) override {
m_inSenItem = true;
iterateChildren(nodep);
m_inSenItem = false;
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
virtual void visit(AstAlways* nodep) override { iterateNewStmt(nodep); }
virtual void visit(AstAlwaysPublic* nodep) override {
// CDC doesn't care about public variables
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); }
virtual void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
virtual void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); }
// Math that shouldn't cause us to clear hazard
virtual void visit(AstConst*) VL_OVERRIDE {}
virtual void visit(AstReplicate* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstConcat* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNot* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstSel* nodep) VL_OVERRIDE {
virtual void visit(AstConst*) override {}
virtual void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
virtual void visit(AstConcat* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNot* nodep) override { iterateChildren(nodep); }
virtual void visit(AstSel* nodep) override {
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNodeSel* nodep) VL_OVERRIDE {
virtual void visit(AstNodeSel* nodep) override {
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
}
// Ignores
virtual void visit(AstInitial*) VL_OVERRIDE {}
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstCoverToggle*) VL_OVERRIDE {}
virtual void visit(AstNodeDType*) VL_OVERRIDE {}
virtual void visit(AstInitial*) override {}
virtual void visit(AstTraceDecl*) override {}
virtual void visit(AstCoverToggle*) override {}
virtual void visit(AstNodeDType*) override {}
//--------------------
// Default
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
virtual void visit(AstNodeMath* nodep) override {
setNodeHazard(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CdcVisitor(AstNode* nodep) {
m_logicVertexp = NULL;
m_scopep = NULL;
m_modp = NULL;
m_domainp = NULL;
m_inDly = false;
m_inSenItem = 0;
m_userGeneration = 0;
m_filelineWidth = 0;
// Make report of all signal names and what clock edges they have
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt";
m_ofp = V3File::new_ofstream(filename);
@@ -770,12 +745,12 @@ public:
if (debug() >= 1) edgeReport(); // Not useful to users at the moment
if (false) {
*m_ofp << "\nDBG-test-dumper\n";
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, NULL, true);
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true);
*m_ofp << endl;
}
}
virtual ~CdcVisitor() {
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
virtual ~CdcVisitor() override {
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
}
};
+40 -47
View File
@@ -41,21 +41,14 @@
class ChangedState {
public:
// STATE
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstCFunc* m_chgFuncp; // Change function we're building
AstCFunc* m_tlChgFuncp; // Top level change function we're building
int m_numStmts; // Number of statements added to m_chgFuncp
int m_funcNum; // Number of change functions emitted
AstNodeModule* m_topModp = nullptr; // Top module
AstScope* m_scopetopp = nullptr; // Scope under TOPSCOPE
AstCFunc* m_chgFuncp = nullptr; // Change function we're building
AstCFunc* m_tlChgFuncp = nullptr; // Top level change function we're building
int m_numStmts = 0; // Number of statements added to m_chgFuncp
int m_funcNum = 0; // Number of change functions emitted
ChangedState() {
m_topModp = NULL;
m_chgFuncp = NULL;
m_scopetopp = NULL;
m_tlChgFuncp = NULL;
m_numStmts = 0;
m_funcNum = 0;
}
ChangedState() {}
~ChangedState() {}
void maybeCreateChgFuncp() {
@@ -142,34 +135,33 @@ private:
m_statep->m_numStmts += visitor.count();
}
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { //
virtual void visit(AstBasicDType*) override { //
newChangeDet();
}
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE { //
virtual void visit(AstPackArrayDType*) override { //
newChangeDet();
}
virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE {
virtual void visit(AstUnpackArrayDType* nodep) override {
for (int index = 0; index < nodep->elementsConst(); ++index) {
AstNode* origVEp = m_varEqnp;
AstNode* origNLEp = m_newLvEqnp;
AstNode* origNREp = m_newRvEqnp;
VL_RESTORER(m_varEqnp);
VL_RESTORER(m_newLvEqnp);
VL_RESTORER(m_newRvEqnp);
{
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
m_newLvEqnp
= new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
m_newRvEqnp
= new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
iterate(nodep->subDTypep()->skipRefp());
iterate(nodep->subDTypep()->skipRefp());
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
m_varEqnp = origVEp;
m_newLvEqnp = origNLEp;
m_newRvEqnp = origNREp;
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
}
}
}
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
virtual void visit(AstNodeUOrStructDType* nodep) override {
if (nodep->packedUnsup()) {
newChangeDet();
} else {
@@ -179,7 +171,7 @@ private:
<< m_vscp->varp()->prettyNameQ());
}
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
iterateChildren(nodep);
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
@@ -207,16 +199,16 @@ public:
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
m_statep->m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, VAccess::READ);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::WRITE);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::READ);
}
iterate(vscp->dtypep()->skipRefp());
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
}
virtual ~ChangedInsertVisitor() {}
virtual ~ChangedInsertVisitor() override {}
VL_UNCOPYABLE(ChangedInsertVisitor);
};
@@ -242,13 +234,13 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
if (nodep->isTop()) m_statep->m_topModp = nodep;
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
virtual void visit(AstTopScope* nodep) override {
UINFO(4, " TS " << nodep << endl);
// Clearing
AstNode::user1ClearTree();
@@ -267,27 +259,28 @@ private:
// Each change detection function needs at least one AstChangeDet
// to ensure that V3EmitC outputs the necessary code.
m_statep->maybeCreateChgFuncp();
m_statep->m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false));
m_statep->m_chgFuncp->addStmtsp(
new AstChangeDet(nodep->fileline(), nullptr, nullptr, false));
iterateChildren(nodep);
}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
virtual void visit(AstVarScope* nodep) override {
if (nodep->isCircular()) {
UINFO(8, " CIRC " << nodep << endl);
if (!nodep->user1SetOnce()) genChangeDet(nodep);
}
}
//--------------------
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
ChangedVisitor(AstNetlist* nodep, ChangedState* statep) {
m_statep = statep;
ChangedVisitor(AstNetlist* nodep, ChangedState* statep)
: m_statep{statep} {
iterate(nodep);
}
virtual ~ChangedVisitor() {}
virtual ~ChangedVisitor() override {}
};
//######################################################################
+16 -21
View File
@@ -34,8 +34,8 @@ private:
// MEMBERS
AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep; // Package moving scopes into
typedef std::vector<std::pair<AstNode*, AstScope*> > MoveVector;
AstScope* m_classScopep = nullptr; // Package moving scopes into
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
MoveVector m_moves;
// NODE STATE
@@ -44,7 +44,7 @@ private:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstClass* nodep) VL_OVERRIDE {
virtual void visit(AstClass* nodep) override {
if (nodep->user1SetOnce()) return;
// Move this class
nodep->name(m_prefix + nodep->name());
@@ -59,12 +59,12 @@ private:
v3Global.rootp()->addModulep(packagep);
// Add package to hierarchy
AstCell* cellp = new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
packagep->name(), NULL, NULL, NULL);
packagep->name(), nullptr, nullptr, nullptr);
cellp->modp(packagep);
v3Global.rootp()->topModulep()->addStmtp(cellp);
// Find class's scope
// Alternative would be to move this and related to V3Scope
AstScope* classScopep = NULL;
AstScope* classScopep = nullptr;
for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) {
if ((classScopep = VN_CAST(itp, Scope))) break;
}
@@ -75,25 +75,23 @@ private:
classScopep->aboveScopep(), classScopep->aboveCellp());
packagep->addStmtp(scopep);
// Iterate
string prevPrefix = m_prefix;
VL_RESTORER(m_prefix);
{
m_classScopep = classScopep;
m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep);
}
m_prefix = prevPrefix;
m_classScopep = NULL;
m_classScopep = nullptr;
}
virtual void visit(AstPackage* nodep) VL_OVERRIDE {
string prevPrefix = m_prefix;
virtual void visit(AstPackage* nodep) override {
VL_RESTORER(m_prefix);
{
m_prefix = nodep->name() + "__03a__03a"; // ::
iterateChildren(nodep);
}
m_prefix = prevPrefix;
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstVar* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move class statics only
@@ -101,7 +99,7 @@ private:
// m_moves.push_back(make_pair(nodep, m_classScopep));
//}
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move function statics only
@@ -110,17 +108,14 @@ private:
//}
}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Short circuit
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {} // Short circuit
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeMath* nodep) override {} // Short circuit
virtual void visit(AstNodeStmt* nodep) override {} // Short circuit
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ClassVisitor(AstNetlist* nodep)
: m_classScopep(NULL) {
iterate(nodep);
}
virtual ~ClassVisitor() {
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());
}
+32 -36
View File
@@ -47,10 +47,10 @@ private:
AstUser3InUse m_inuser3;
// TYPES
enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
enum CleanState : uint8_t { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
// STATE
AstNodeModule* m_modp;
AstNodeModule* m_modp = nullptr;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -170,65 +170,64 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeUniop* nodep) override {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeBiop* nodep) override {
operandBiop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstAnd* nodep) VL_OVERRIDE {
virtual void visit(AstAnd* nodep) override {
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
}
virtual void visit(AstXor* nodep) VL_OVERRIDE {
virtual void visit(AstXor* nodep) override {
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
}
virtual void visit(AstOr* nodep) VL_OVERRIDE {
virtual void visit(AstOr* nodep) override {
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
}
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeQuadop* nodep) override {
operandQuadop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
virtual void visit(AstNodeMath* nodep) override {
iterateChildren(nodep);
computeCppWidth(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
}
virtual void visit(AstText* nodep) VL_OVERRIDE { //
virtual void visit(AstText* nodep) override { //
setClean(nodep, true);
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE { //
virtual void visit(AstScopeName* nodep) override { //
setClean(nodep, true);
}
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
virtual void visit(AstCNew* nodep) override {
iterateChildren(nodep);
setClean(nodep, true);
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
virtual void visit(AstSel* nodep) override {
operandTriop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstUCFunc* nodep) override {
iterateChildren(nodep);
computeCppWidth(nodep);
setClean(nodep, false);
@@ -236,75 +235,72 @@ private:
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
ensureCleanAndNext(nodep->bodysp());
}
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
virtual void visit(AstTraceDecl* nodep) override {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE {
virtual void visit(AstTraceInc* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->valuep());
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
virtual void visit(AstTypedef* nodep) override {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
virtual void visit(AstParamTypeDType* nodep) override {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
// Control flow operators
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCond* nodep) override {
iterateChildren(nodep);
ensureClean(nodep->condp());
setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p()));
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
virtual void visit(AstWhile* nodep) override {
iterateChildren(nodep);
ensureClean(nodep->condp());
}
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
virtual void visit(AstNodeIf* nodep) override {
iterateChildren(nodep);
ensureClean(nodep->condp());
}
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
virtual void visit(AstSFormatF* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->exprsp());
setClean(nodep, true); // generates a string, so not relevant
}
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
virtual void visit(AstUCStmt* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->bodysp());
}
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCCall* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->argsp());
setClean(nodep, true);
}
virtual void visit(AstCMethodHard* nodep) VL_OVERRIDE {
virtual void visit(AstCMethodHard* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->pinsp());
setClean(nodep, true);
}
virtual void visit(AstIntfRef* nodep) VL_OVERRIDE {
virtual void visit(AstIntfRef* nodep) override {
iterateChildren(nodep);
setClean(nodep, true); // generates a string, so not relevant
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
iterateChildren(nodep);
computeCppWidth(nodep);
}
public:
// CONSTRUCTORS
explicit CleanVisitor(AstNetlist* nodep) {
m_modp = NULL;
iterate(nodep);
}
virtual ~CleanVisitor() {}
explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CleanVisitor() override {}
};
//######################################################################
+110 -88
View File
@@ -48,16 +48,16 @@ private:
AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp; // Current module
AstTopScope* m_topScopep; // Current top scope
AstScope* m_scopep; // Current scope
AstCFunc* m_evalFuncp; // Top eval function we are creating
AstCFunc* m_initFuncp; // Top initial function we are creating
AstCFunc* m_finalFuncp; // Top final function we are creating
AstCFunc* m_settleFuncp; // Top settlement function we are creating
AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates.
AstIf* m_lastIfp; // Last sensitivity if active to add more under
AstMTaskBody* m_mtaskBodyp; // Current mtask body
AstNodeModule* m_modp = nullptr; // Current module
AstTopScope* m_topScopep = nullptr; // Current top scope
AstScope* m_scopep = nullptr; // Current scope
AstCFunc* m_evalFuncp = nullptr; // Top eval function we are creating
AstCFunc* m_initFuncp = nullptr; // Top initial function we are creating
AstCFunc* m_finalFuncp = nullptr; // Top final function we are creating
AstCFunc* m_settleFuncp = nullptr; // Top settlement function we are creating
AstSenTree* m_lastSenp = nullptr; // Last sensitivity match, so we can detect duplicates.
AstIf* m_lastIfp = nullptr; // Last sensitivity if active to add more under
AstMTaskBody* m_mtaskBodyp = nullptr; // Current mtask body
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -66,8 +66,8 @@ private:
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
AstVar* varp = vscp->varp();
if (!varp->width1()) {
varp->v3error(
"Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ());
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
<< varp->prettyNameQ());
}
string newvarname
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
@@ -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);
@@ -101,60 +101,49 @@ private:
// BOTHEDGE: var ^ var_last
// HIGHEDGE: var
// LOWEDGE: ~var
AstNode* newp = NULL;
AstNode* newp = nullptr;
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error(
"Unsupported: Complicated event expression in sensitive activity list");
}
return NULL;
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Complicated event expression in sensitive activity list");
return nullptr;
}
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
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");
}
return newp;
}
AstNode* createSenGateEquation(AstSenGate* nodep) {
AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()),
nodep->rhsp()->cloneTree(true));
return newp;
}
AstNode* createSenseEquation(AstNodeSenItem* nodesp) {
AstNode* createSenseEquation(AstSenItem* nodesp) {
// Nodep may be a list of elements; we need to walk it
AstNode* senEqnp = NULL;
for (AstNodeSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
AstNode* senOnep = NULL;
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
senOnep = createSenItemEquation(itemp);
} else if (AstSenGate* itemp = VN_CAST(senp, SenGate)) {
senOnep = createSenGateEquation(itemp);
} else {
senp->v3fatalSrc("Strange node under sentree");
}
AstNode* senEqnp = nullptr;
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
AstNode* const senOnep = createSenItemEquation(senp);
if (senEqnp) {
// Add new OR to the sensitivity list equation
senEqnp = new AstOr(senp->fileline(), senEqnp, senOnep);
@@ -167,16 +156,53 @@ private:
AstIf* makeActiveIf(AstSenTree* sensesp) {
AstNode* senEqnp = createSenseEquation(sensesp->sensesp());
UASSERT_OBJ(senEqnp, sensesp, "No sense equation, shouldn't be in sequent activation.");
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, NULL, NULL);
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
return newifp;
}
void clearLastSen() {
m_lastSenp = NULL;
m_lastIfp = NULL;
m_lastSenp = nullptr;
m_lastIfp = nullptr;
}
void splitCheck(AstCFunc* ofuncp) {
if (!v3Global.opt.outputSplitCFuncs() || !ofuncp->stmtsp()) return;
if (EmitCBaseCounterVisitor(ofuncp->stmtsp()).count() < v3Global.opt.outputSplitCFuncs())
return;
int funcnum = 0;
int func_stmts = 0;
AstCFunc* funcp = nullptr;
// Unlink all statements, then add item by item to new sub-functions
AstBegin* tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext()};
if (ofuncp->finalsp()) tempp->addStmtsp(ofuncp->finalsp()->unlinkFrBackWithNext());
while (tempp->stmtsp()) {
AstNode* itemp = tempp->stmtsp()->unlinkFrBack();
int stmts = EmitCBaseCounterVisitor(itemp).count();
if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) {
// Make a new function
funcp = new AstCFunc{ofuncp->fileline(), ofuncp->name() + cvtToStr(++funcnum),
m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->slow(ofuncp->slow());
m_topScopep->scopep()->addActivep(funcp);
//
AstCCall* callp = new AstCCall{funcp->fileline(), funcp};
callp->argTypes("vlSymsp");
ofuncp->addStmtsp(callp);
func_stmts = 0;
}
funcp->addStmtsp(itemp);
func_stmts += stmts;
}
VL_DO_DANGLING(tempp->deleteTree(), tempp);
}
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
virtual void visit(AstTopScope* nodep) override {
UINFO(4, " TOPSCOPE " << nodep << endl);
m_topScopep = nodep;
m_scopep = nodep->scopep();
@@ -186,28 +212,29 @@ private:
AstNode::user1ClearTree();
// Make top functions
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval", m_scopep);
AstCFunc* funcp = new AstCFunc{nodep->fileline(), "_eval", m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_evalFuncp = funcp;
}
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_initial", m_scopep);
AstCFunc* funcp
= new AstCFunc{nodep->fileline(), "_eval_initial", m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->slow(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_initFuncp = funcp;
}
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "final", m_scopep);
AstCFunc* funcp = new AstCFunc{nodep->fileline(), "final", m_topScopep->scopep()};
funcp->skipDecl(true);
funcp->dontCombine(true);
funcp->slow(true);
@@ -218,38 +245,44 @@ private:
+ " = this->__VlSymsp;\n"));
funcp->addInitsp(
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_finalFuncp = funcp;
}
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_settle", m_scopep);
AstCFunc* funcp
= new AstCFunc{nodep->fileline(), "_eval_settle", m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->slow(true);
funcp->isStatic(true);
funcp->symProlog(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_settleFuncp = funcp;
}
// Process the activates
iterateChildren(nodep);
UINFO(4, " TOPSCOPE iter done " << nodep << endl);
// Split large functions
splitCheck(m_evalFuncp);
splitCheck(m_initFuncp);
splitCheck(m_finalFuncp);
splitCheck(m_settleFuncp);
// Done, clear so we can detect errors
UINFO(4, " TOPSCOPEDONE " << nodep << endl);
clearLastSen();
m_topScopep = NULL;
m_scopep = NULL;
m_topScopep = nullptr;
m_scopep = nullptr;
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
// UINFO(4, " MOD " << nodep << endl);
AstNodeModule* origModp = m_modp;
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
// UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
iterateChildren(nodep);
@@ -258,9 +291,9 @@ private:
movep->unlinkFrBackWithNext();
m_evalFuncp->addFinalsp(movep);
}
m_scopep = NULL;
m_scopep = nullptr;
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
virtual void visit(AstAlways* nodep) override {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
@@ -269,7 +302,7 @@ private:
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstAlwaysPost* nodep) VL_OVERRIDE {
virtual void visit(AstAlwaysPost* nodep) override {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
@@ -278,7 +311,7 @@ private:
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
virtual void visit(AstCoverToggle* nodep) override {
// nodep->dumpTree(cout, "ct:");
// COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
@@ -286,7 +319,7 @@ private:
AstNode* origp = nodep->origp()->unlinkFrBack();
AstNode* changep = nodep->changep()->unlinkFrBack();
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changep),
incp, NULL);
incp, nullptr);
// We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though versus a potential memory miss.
// We'll go with the miss.
@@ -295,7 +328,7 @@ private:
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
virtual void visit(AstInitial* nodep) override {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
@@ -304,7 +337,7 @@ private:
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Link to global function
if (nodep->formCallTree()) {
@@ -314,7 +347,7 @@ private:
m_finalFuncp->addStmtsp(callp);
}
}
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
virtual void visit(AstSenTree* nodep) override {
// Delete it later; Actives still pointing to it
nodep->unlinkFrBack();
pushDeletep(nodep);
@@ -328,7 +361,7 @@ private:
void addToInitial(AstNode* stmtsp) {
m_initFuncp->addStmtsp(stmtsp); // add to top level function
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
// Careful if adding variables here, ACTIVES can be under other ACTIVES
// Need to save and restore any member state in AstUntilStable block
if (!m_topScopep || !nodep->stmtsp()) {
@@ -396,7 +429,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
}
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
virtual void visit(AstExecGraph* nodep) override {
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
clearLastSen();
@@ -411,28 +444,17 @@ private:
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ClockVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_evalFuncp = NULL;
m_initFuncp = NULL;
m_finalFuncp = NULL;
m_settleFuncp = NULL;
m_topScopep = NULL;
m_lastSenp = NULL;
m_lastIfp = NULL;
m_scopep = NULL;
m_mtaskBodyp = NULL;
//
iterate(nodep);
// Allow downstream modules to find _eval()
// easily without iterating through the tree.
nodep->evalp(m_evalFuncp);
}
virtual ~ClockVisitor() {}
virtual ~ClockVisitor() override {}
};
//######################################################################
+45 -50
View File
@@ -45,7 +45,9 @@
//######################################################################
#define COMBINE_MIN_STATEMENTS 50 // Min # of statements to be worth making a function
#ifdef VL_COMBINE_STATEMENTS
constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth making a function
#endif
//######################################################################
@@ -54,7 +56,7 @@ protected:
// STATE
// METHODS
virtual ~CombBaseVisitor() {}
virtual ~CombBaseVisitor() override {}
VL_DEBUG_FUNC; // Declare debug()
};
@@ -108,8 +110,8 @@ public:
void deleteCall(AstCCall* nodep) {
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
= m_callMmap.equal_range(nodep->funcp());
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
CallMmap::iterator eqit = nextit++;
for (auto nextit = eqrange.first; nextit != eqrange.second;) {
const auto eqit = nextit++;
AstCCall* callp = eqit->second;
if (callp == nodep) {
m_callMmap.erase(eqit);
@@ -121,16 +123,16 @@ public:
private:
// VISITORS
virtual void visit(AstCCall* nodep) VL_OVERRIDE { addCall(nodep); }
virtual void visit(AstCCall* nodep) override { addCall(nodep); }
// Speed things up
virtual void visit(AstNodeAssign*) VL_OVERRIDE {}
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeAssign*) override {}
virtual void visit(AstNodeMath*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
CombCallVisitor() {}
virtual ~CombCallVisitor() {}
virtual ~CombCallVisitor() override {}
void main(AstNetlist* nodep) { iterate(nodep); }
};
@@ -143,7 +145,7 @@ private:
// OUTPUT:
// AstNode::user3() -> bool. True to indicate duplicated
// VISITORS
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
nodep->user3(true);
iterateChildren(nodep);
}
@@ -151,7 +153,7 @@ private:
public:
// CONSTRUCTORS
explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~CombMarkVisitor() {}
virtual ~CombMarkVisitor() override {}
};
//######################################################################
@@ -171,15 +173,17 @@ private:
// AstUser4InUse part of V3Hashed
// STATE
typedef enum { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState;
typedef enum : uint8_t { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState;
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state; // Major state
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function
CombineState m_state = STATE_IDLE; // Major state
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs; // Number of functions made
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
AstNode* m_walkLast2p; // Final node that is the same in duplicate list
int m_modNFuncs = 0; // Number of functions made
#ifdef VL_COMBINE_STATEMENTS
AstNode* m_walkLast1p = nullptr; // Final node that is the same in duplicate list
#endif
AstNode* m_walkLast2p = nullptr; // Final node that is the same in duplicate list
V3Hashed m_hashed; // Hash for every node in module
// METHODS
@@ -191,12 +195,11 @@ private:
#ifdef VL_COMBINE_STATEMENTS
void hashFunctions(AstCFunc* nodep) {
// Compute hash of all statement trees in the function
CombineState oldState = m_state;
VL_RESTORER(m_state);
{
m_state = STATE_HASH;
iterate(nodep);
}
m_state = oldState;
}
#endif
void walkEmptyFuncs() {
@@ -208,7 +211,7 @@ private:
<< oldfuncp << endl);
// Mark user3p on entire old tree, so we don't process it more
CombMarkVisitor visitor(oldfuncp);
m_call.replaceFunc(oldfuncp, NULL);
m_call.replaceFunc(oldfuncp, nullptr);
oldfuncp->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
}
@@ -251,8 +254,8 @@ private:
void replaceOnlyCallFunc(AstCCall* nodep) {
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
// oldfuncp->dumpTree(cout, "MAYDEL: ");
if (nodep->nextp() == NULL && oldfuncp->initsp() == NULL && oldfuncp->stmtsp() == nodep
&& oldfuncp->finalsp() == NULL) {
if (nodep->nextp() == nullptr && oldfuncp->initsp() == nullptr
&& oldfuncp->stmtsp() == nodep && oldfuncp->finalsp() == nullptr) {
UINFO(9, " Function only has call " << oldfuncp << endl);
m_call.deleteCall(nodep);
CombMarkVisitor visitor(oldfuncp);
@@ -266,9 +269,9 @@ private:
// UINFO(4," STMT " << hashval << " " << node1p << endl);
//
int bestDepth = 0; // Best substitution found in the search
AstNode* bestNode2p = NULL;
AstNode* bestLast1p = NULL;
AstNode* bestLast2p = NULL;
AstNode* bestNode2p = nullptr;
AstNode* bestLast1p = nullptr;
AstNode* bestLast2p = nullptr;
//
std::pair<V3Hashed::iterator, V3Hashed::iterator> eqrange
= m_hashed.mmap().equal_range(hashval);
@@ -279,8 +282,8 @@ private:
// We need to mark iteration to prevent matching code inside
// code (abab matching in ababab)
AstNode::user1ClearTree(); // user1p() used on entire tree
m_walkLast1p = NULL;
m_walkLast2p = NULL;
m_walkLast1p = nullptr;
m_walkLast2p = nullptr;
int depth = walkDupCodeNext(node1p, node2p, 1);
if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) {
bestDepth = depth;
@@ -332,7 +335,7 @@ private:
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
AstCFunc* newfuncp = new AstCFunc(node1p->fileline(),
oldname + "_common" + cvtToStr(++m_modNFuncs), NULL);
oldname + "_common" + cvtToStr(++m_modNFuncs), nullptr);
m_modp->addStmtp(newfuncp);
// Create calls
AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp);
@@ -381,7 +384,7 @@ private:
#endif
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
// Track all callers of each function
m_call.main(nodep);
//
@@ -390,11 +393,11 @@ private:
// Required so that a module instantiating another can benefit from collapsing.
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
m_modp = nodep;
m_modNFuncs = 0;
m_walkLast2p = NULL;
m_walkLast2p = nullptr;
m_hashed.clear();
// Compute hash of all statement trees in the function
m_state = STATE_HASH;
@@ -417,9 +420,9 @@ private:
m_state = STATE_IDLE;
}
#endif
m_modp = NULL;
m_modp = nullptr;
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) {
@@ -431,9 +434,9 @@ private:
}
#endif
}
m_funcp = NULL;
m_funcp = nullptr;
}
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
@@ -450,23 +453,15 @@ private:
//--------------------
// Default: Just iterate
virtual void visit(AstVar*) VL_OVERRIDE {}
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {}
virtual void visit(AstTraceDecl*) override {}
virtual void visit(AstTraceInc*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CombineVisitor(AstNetlist* nodep) {
m_state = STATE_IDLE;
m_modp = NULL;
m_funcp = NULL;
m_modNFuncs = 0;
m_walkLast1p = NULL;
m_walkLast2p = NULL;
iterate(nodep);
}
virtual ~CombineVisitor() { //
explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CombineVisitor() override { //
V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs);
}
};
+35 -36
View File
@@ -60,10 +60,10 @@ public:
// Access an entity and resolve wildcards that match it
T* resolve(const string& name) {
// Lookup if it was resolved before, typically not
typename Map::iterator it = m_mapResolved.find(name);
auto it = m_mapResolved.find(name);
if (VL_UNLIKELY(it != m_mapResolved.end())) { return &it->second; }
T* newp = NULL;
T* newp = nullptr;
// Cannot be resolved, create if matched
// Update this entity with all matches in the wildcards
@@ -87,8 +87,8 @@ public:
AstAttrType m_type; // Type of attribute
AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw
V3ConfigVarAttr(AstAttrType type, AstSenTree* sentreep)
: m_type(type)
, m_sentreep(sentreep) {}
: m_type{type}
, m_sentreep{sentreep} {}
};
// Overload vector with the required update function and to apply all entries
@@ -105,7 +105,7 @@ public:
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
varp->addAttrsp(newp);
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, NULL));
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, nullptr));
}
}
}
@@ -118,15 +118,12 @@ typedef V3ConfigWildcardResolver<V3ConfigVar> V3ConfigVarResolver;
class V3ConfigFTask {
V3ConfigVarResolver m_vars; // Variables in function/task
bool m_isolate; // Isolate function return
bool m_noinline; // Don't inline function/task
bool m_public; // Public function/task
bool m_isolate = false; // Isolate function return
bool m_noinline = false; // Don't inline function/task
bool m_public = false; // Public function/task
public:
V3ConfigFTask()
: m_isolate(false)
, m_noinline(false)
, m_public(false) {}
V3ConfigFTask() {}
void update(const V3ConfigFTask& f) {
// Don't overwrite true with false
if (f.m_isolate) m_isolate = true;
@@ -141,7 +138,7 @@ public:
void setNoInline(bool set) { m_noinline = set; }
void setPublic(bool set) { m_public = set; }
void apply(AstNodeFTask* ftaskp) {
void apply(AstNodeFTask* ftaskp) const {
if (m_noinline)
ftaskp->addStmtsp(new AstPragma(ftaskp->fileline(), AstPragmaType::NO_INLINE_TASK));
if (m_public)
@@ -157,33 +154,31 @@ typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
// Modules have tasks, variables, named blocks and properties
class V3ConfigModule {
typedef vl_unordered_set<string> StringSet;
typedef std::unordered_set<string> StringSet;
typedef std::set<AstPragmaType> PragmaSet;
V3ConfigFTaskResolver m_tasks; // Functions/tasks in module
V3ConfigVarResolver m_vars; // Variables in module
StringSet m_coverageOffBlocks; // List of block names for coverage_off
bool m_inline; // Whether to force the inline
bool m_inlineValue; // The inline value (on/off)
bool m_public; // Public module
PragmaSet m_modPragmas; // List of Pragmas for modules
bool m_inline = false; // Whether to force the inline
bool m_inlineValue = false; // The inline value (on/off)
public:
V3ConfigModule()
: m_inline(false)
, m_inlineValue(false)
, m_public(false) {}
V3ConfigModule() {}
void update(const V3ConfigModule& m) {
m_tasks.update(m.m_tasks);
m_vars.update(m.m_vars);
for (StringSet::const_iterator it = m.m_coverageOffBlocks.begin();
it != m.m_coverageOffBlocks.end(); ++it) {
m_coverageOffBlocks.insert(*it);
}
for (const string& i : m.m_coverageOffBlocks) m_coverageOffBlocks.insert(i);
if (!m_inline) {
m_inline = m.m_inline;
m_inlineValue = m.m_inlineValue;
}
if (!m_public) m_public = m.m_public;
for (PragmaSet::const_iterator it = m.m_modPragmas.begin(); it != m.m_modPragmas.end();
++it) {
m_modPragmas.insert(*it);
}
}
V3ConfigFTaskResolver& ftasks() { return m_tasks; }
@@ -194,7 +189,7 @@ public:
m_inline = true;
m_inlineValue = set;
}
void setPublic(bool set) { m_public = set; }
void addModulePragma(AstPragmaType pragma) { m_modPragmas.insert(pragma); }
void apply(AstNodeModule* modp) {
if (m_inline) {
@@ -203,8 +198,8 @@ public:
AstNode* nodep = new AstPragma(modp->fileline(), type);
modp->addStmtp(nodep);
}
if (m_public) {
AstNode* nodep = new AstPragma(modp->fileline(), AstPragmaType::PUBLIC_MODULE);
for (PragmaSet::const_iterator it = m_modPragmas.begin(); it != m_modPragmas.end(); ++it) {
AstNode* nodep = new AstPragma(modp->fileline(), *it);
modp->addStmtp(nodep);
}
}
@@ -212,9 +207,8 @@ public:
void applyBlock(AstNodeBlock* nodep) {
AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF;
if (!nodep->unnamed()) {
for (StringSet::const_iterator it = m_coverageOffBlocks.begin();
it != m_coverageOffBlocks.end(); ++it) {
if (VString::wildmatch(nodep->name(), *it)) {
for (const string& i : m_coverageOffBlocks) {
if (VString::wildmatch(nodep->name(), i)) {
nodep->addStmtsp(new AstPragma(nodep->fileline(), pragma));
}
}
@@ -236,9 +230,9 @@ public:
V3ErrorCode m_code; // Error code
bool m_on; // True to enable message
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
: m_lineno(lineno)
, m_code(code)
, m_on(on) {}
: m_lineno{lineno}
, m_code{code}
, m_on{on} {}
~V3ConfigIgnoresLine() {}
inline bool operator<(const V3ConfigIgnoresLine& rh) const {
if (m_lineno < rh.m_lineno) return true;
@@ -408,6 +402,10 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int
}
}
void V3Config::addModulePragma(const string& module, AstPragmaType pragma) {
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
}
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
if (ftask.empty()) {
V3ConfigResolver::s().modules().at(module).setInline(on);
@@ -439,7 +437,8 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
} else if (attr == AstAttrType::VAR_PUBLIC) {
if (ftask.empty()) {
// public module, this is the only exception from var here
V3ConfigResolver::s().modules().at(module).setPublic(true);
V3ConfigResolver::s().modules().at(module).addModulePragma(
AstPragmaType::PUBLIC_MODULE);
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
}
+1
View File
@@ -34,6 +34,7 @@ public:
static void addCoverageBlockOff(const string& module, const string& blockname);
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
static void addModulePragma(const string& module, AstPragmaType pragma);
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
static void addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& signal, AstAttrType type, AstSenTree* nodep);
+134 -199
View File
@@ -41,10 +41,10 @@ class ConstVarMarkVisitor : public AstNVisitor {
// AstVar::user4p -> bool, Var marked, 0=not set yet
private:
// VISITORS
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
if (nodep->varp()) nodep->varp()->user4(1);
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
@@ -52,29 +52,26 @@ public:
AstNode::user4ClearTree(); // Check marked InUse before we're called
iterate(nodep);
}
virtual ~ConstVarMarkVisitor() {}
virtual ~ConstVarMarkVisitor() override {}
};
class ConstVarFindVisitor : public AstNVisitor {
// NODE STATE
// AstVar::user4p -> bool, input from ConstVarMarkVisitor
// MEMBERS
bool m_found;
bool m_found = false;
private:
// VISITORS
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
if (nodep->varp() && nodep->varp()->user4()) m_found = true;
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ConstVarFindVisitor(AstNode* nodep) {
m_found = false;
iterateAndNextNull(nodep);
}
virtual ~ConstVarFindVisitor() {}
explicit ConstVarFindVisitor(AstNode* nodep) { iterateAndNextNull(nodep); }
virtual ~ConstVarFindVisitor() override {}
// METHODS
bool found() const { return m_found; }
};
@@ -92,20 +89,20 @@ private:
// AstEnum::user4 -> bool. Recursing.
// STATE
bool m_params; // If true, propagate parameterized and true numbers only
bool m_required; // If true, must become a constant
bool m_wremove; // Inside scope, no assignw removal
bool m_warn; // Output warnings
bool m_doExpensive; // Enable computationally expensive optimizations
bool m_doNConst; // Enable non-constant-child simplifications
bool m_doShort; // Remove expressions that short circuit
bool m_doV; // Verilog, not C++ conversion
bool m_doGenerate; // Postpone width checking inside generate
bool m_hasJumpDelay; // JumpGo or Delay under this while
AstNodeModule* m_modp; // Current module
AstArraySel* m_selp; // Current select
AstNode* m_scopep; // Current scope
AstAttrOf* m_attrp; // Current attribute
bool m_params = false; // If true, propagate parameterized and true numbers only
bool m_required = false; // If true, must become a constant
bool m_wremove = true; // Inside scope, no assignw removal
bool m_warn = false; // Output warnings
bool m_doExpensive = false; // Enable computationally expensive optimizations
bool m_doNConst = false; // Enable non-constant-child simplifications
bool m_doShort = true; // Remove expressions that short circuit
bool m_doV = false; // Verilog, not C++ conversion
bool m_doGenerate = false; // Postpone width checking inside generate
bool m_hasJumpDelay = false; // JumpGo or Delay under this while
AstNodeModule* m_modp = nullptr; // Current module
AstArraySel* m_selp = nullptr; // Current select
AstNode* m_scopep = nullptr; // Current scope
AstAttrOf* m_attrp = nullptr; // Current attribute
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -317,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().isWrite()
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
}
@@ -588,6 +585,7 @@ private:
}
return false;
}
bool operandsSameSize(AstNode* lhsp, AstNode* rhsp) { return lhsp->width() == rhsp->width(); }
//----------------------------------------
// Constant Replacement functions.
@@ -1114,7 +1112,7 @@ private:
AstSel* sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2 - lsb2 + 1);
// Make new assigns of same flavor as old one
//*** Not cloneTree; just one node.
AstNode* newp = NULL;
AstNode* newp = nullptr;
if (!need_temp) {
AstNodeAssign* asn1ap = VN_CAST(nodep->cloneType(lc1p, sel1p), NodeAssign);
AstNodeAssign* asn2ap = VN_CAST(nodep->cloneType(lc2p, sel2p), NodeAssign);
@@ -1134,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);
@@ -1281,32 +1283,31 @@ private:
//----------------------------------------
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
// Iterate modules backwards, in bottom-up order. That's faster
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
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;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
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 = NULL;
m_scopep = nullptr;
}
void swapSides(AstNodeBiCom* nodep) {
@@ -1372,16 +1373,16 @@ private:
}
// Special cases
virtual void visit(AstConst*) VL_OVERRIDE {} // Already constant
virtual void visit(AstConst*) override {} // Already constant
virtual void visit(AstCell* nodep) VL_OVERRIDE {
virtual void visit(AstCell* nodep) override {
if (m_params) {
iterateAndNextNull(nodep->paramsp());
} else {
iterateChildren(nodep);
}
}
virtual void visit(AstPin* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstPin* nodep) override { iterateChildren(nodep); }
void replaceLogEq(AstLogEq* nodep) {
// LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}}
@@ -1562,14 +1563,15 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
AstAttrOf* oldAttr = m_attrp;
m_attrp = nodep;
iterateChildren(nodep);
m_attrp = oldAttr;
virtual void visit(AstAttrOf* nodep) override {
VL_RESTORER(m_attrp);
{
m_attrp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
virtual void visit(AstArraySel* nodep) override {
iterateAndNextNull(nodep->bitp());
if (VN_IS(nodep->bitp(), Const)
&& VN_IS(nodep->fromp(), VarRef)
@@ -1593,9 +1595,9 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
m_selp = NULL;
m_selp = nullptr;
}
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep);
UASSERT_OBJ(nodep->varp(), nodep, "Not linked");
bool did = false;
@@ -1603,7 +1605,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().isWrite()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
@@ -1649,7 +1651,7 @@ private:
<< nodep->varp()->prettyNameQ());
}
}
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
virtual void visit(AstEnumItemRef* nodep) override {
iterateChildren(nodep);
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
bool did = false;
@@ -1674,15 +1676,15 @@ private:
}
}
// virtual void visit(AstCvtPackString* nodep) VL_OVERRIDE {
// virtual void visit(AstCvtPackString* nodep) override {
// Not constant propagated (for today) because AstNodeMath::isOpaque is set
// Someday if lower is constant, convert to quoted "string".
bool onlySenItemInSenTree(AstNodeSenItem* nodep) {
bool onlySenItemInSenTree(AstSenItem* nodep) {
// Only one if it's not in a list
return (!nodep->nextp() && nodep->backp()->nextp() != nodep);
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
virtual void visit(AstSenItem* nodep) override {
iterateChildren(nodep);
if (m_doNConst
&& (VN_IS(nodep->sensp(), Const) || VN_IS(nodep->sensp(), EnumItemRef)
@@ -1722,61 +1724,34 @@ private:
"Null sensitivity variable");
}
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) {
if (constp->isZero()) {
UINFO(4, "SENGATE(...,0)->NEVER" << endl);
if (onlySenItemInSenTree(nodep)) {
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
} else {
UINFO(4, "SENGATE(SENITEM,0)->ALWAYS SENITEM" << endl);
AstNode* senitemp = nodep->sensesp()->unlinkFrBack();
nodep->replaceWith(senitemp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
}
struct SenItemCmp {
inline bool operator()(AstNodeSenItem* lhsp, AstNodeSenItem* rhsp) const {
inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
if (lhsp->type() < rhsp->type()) return true;
if (lhsp->type() > rhsp->type()) return false;
const AstSenItem* litemp = VN_CAST_CONST(lhsp, SenItem);
const AstSenItem* ritemp = VN_CAST_CONST(rhsp, SenItem);
if (litemp && ritemp) {
// Looks visually better if we keep sorted by name
if (!litemp->varrefp() && ritemp->varrefp()) return true;
if (litemp->varrefp() && !ritemp->varrefp()) return false;
if (litemp->varrefp() && ritemp->varrefp()) {
if (litemp->varrefp()->name() < ritemp->varrefp()->name()) return true;
if (litemp->varrefp()->name() > ritemp->varrefp()->name()) return false;
// But might be same name with different scopes
if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) {
return true;
}
if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) {
return false;
}
// Or rarely, different data types
if (litemp->varrefp()->dtypep() < ritemp->varrefp()->dtypep()) return true;
if (litemp->varrefp()->dtypep() > ritemp->varrefp()->dtypep()) return false;
}
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
// note the SenTree optimizer requires this order (more
// general first, less general last)
if (litemp->edgeType() < ritemp->edgeType()) return true;
if (litemp->edgeType() > ritemp->edgeType()) return false;
// Looks visually better if we keep sorted by name
if (!lhsp->varrefp() && rhsp->varrefp()) return true;
if (lhsp->varrefp() && !rhsp->varrefp()) return false;
if (lhsp->varrefp() && rhsp->varrefp()) {
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
// But might be same name with different scopes
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) { return true; }
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) { return false; }
// Or rarely, different data types
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
}
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
// note the SenTree optimizer requires this order (more
// general first, less general last)
if (lhsp->edgeType() < rhsp->edgeType()) return true;
if (lhsp->edgeType() > rhsp->edgeType()) return false;
return false;
}
};
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
virtual void visit(AstSenTree* nodep) override {
iterateChildren(nodep);
if (m_doExpensive) {
// cout<<endl; nodep->dumpTree(cout, "ssin: ");
@@ -1792,30 +1767,10 @@ private:
{
AstUser4InUse m_inuse4;
// Mark x in SENITEM(x)
for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
senp = VN_CAST(senp->nextp(), NodeSenItem)) {
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
if (itemp->varrefp() && itemp->varrefp()->varScopep()) {
itemp->varrefp()->varScopep()->user4(1);
}
}
}
// Find x in SENTREE(SENITEM(x))
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
senp = nextp) {
nextp = VN_CAST(senp->nextp(), NodeSenItem);
if (AstSenGate* gatep = VN_CAST(senp, SenGate)) {
if (AstSenItem* itemp = VN_CAST(gatep->sensesp(), SenItem)) {
if (itemp->varrefp() && itemp->varrefp()->varScopep()) {
if (itemp->varrefp()->varScopep()->user4()) {
// Found, push this item up to the top
itemp->unlinkFrBack();
nodep->addSensesp(itemp);
VL_DO_DANGLING(gatep->unlinkFrBack()->deleteTree(), gatep);
VL_DANGLING(senp);
}
}
}
for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->varrefp() && senp->varrefp()->varScopep()) {
senp->varrefp()->varScopep()->user4(1);
}
}
}
@@ -1823,40 +1778,33 @@ private:
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
// Make things a little faster; check first if we need a sort
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = nextp) {
nextp = VN_CAST(senp->nextp(), NodeSenItem);
nextp = VN_CAST(senp->nextp(), SenItem);
// cppcheck-suppress unassignedVariable // cppcheck bug
SenItemCmp cmp;
if (nextp && !cmp(senp, nextp)) {
// Something's out of order, sort it
senp = NULL;
std::vector<AstNodeSenItem*> vec;
for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
senp = VN_CAST(senp->nextp(), NodeSenItem)) {
senp = nullptr;
std::vector<AstSenItem*> vec;
for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = VN_CAST(senp->nextp(), SenItem)) {
vec.push_back(senp);
}
stable_sort(vec.begin(), vec.end(), SenItemCmp());
for (std::vector<AstNodeSenItem*>::iterator it = vec.begin(); it != vec.end();
++it) {
(*it)->unlinkFrBack();
}
for (std::vector<AstNodeSenItem*>::iterator it = vec.begin(); it != vec.end();
++it) {
nodep->addSensesp(*it);
}
for (const auto& ip : vec) ip->unlinkFrBack();
for (const auto& ip : vec) nodep->addSensesp(ip);
break;
}
}
// Pass2, remove dup edges
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = nextp) {
nextp = VN_CAST(senp->nextp(), NodeSenItem);
AstNodeSenItem* cmpp = nextp;
AstSenItem* litemp = VN_CAST(senp, SenItem);
AstSenItem* ritemp = VN_CAST(cmpp, SenItem);
if (litemp && ritemp) {
nextp = VN_CAST(senp->nextp(), SenItem);
AstSenItem* const litemp = senp;
AstSenItem* const ritemp = nextp;
if (ritemp) {
if ((litemp->varrefp() && ritemp->varrefp()
&& litemp->varrefp()->sameGateTree(ritemp->varrefp()))
|| (!litemp->varrefp() && !ritemp->varrefp())) {
@@ -1876,7 +1824,7 @@ private:
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
// Remove redundant node
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
VL_DANGLING(cmpp);
VL_DANGLING(ritemp);
// Try to collapse again
nextp = litemp;
}
@@ -1889,17 +1837,17 @@ private:
//-----
// Zero elimination
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
iterateChildren(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return;
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
virtual void visit(AstAssignAlias* nodep) override {
// Don't perform any optimizations, keep the alias around
}
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
virtual void visit(AstAssignVarScope* nodep) override {
// Don't perform any optimizations, the node won't be linked yet
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
virtual void visit(AstAssignW* nodep) override {
iterateChildren(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return;
AstNodeVarRef* varrefp = VN_CAST(
@@ -1926,17 +1874,20 @@ private:
}
}
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
virtual void visit(AstNodeIf* nodep) override {
iterateChildren(nodep);
if (m_doNConst) {
if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) {
AstNode* keepp = NULL;
AstNode* keepp = nullptr;
if (constp->isZero()) {
UINFO(4, "IF(0,{any},{x}) => {x}: " << nodep << endl);
keepp = nodep->elsesp();
} else {
} else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog
UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl);
keepp = nodep->ifsp();
} else {
UINFO(4, "IF condition is X, retaining: " << nodep << endl);
return;
}
if (keepp) {
keepp->unlinkFrBackWithNext();
@@ -1951,7 +1902,7 @@ private:
// effects in the condition itself
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (!afterComment(nodep->ifsp())) {
UINFO(4, "IF({x}) NULL {...} => IF(NOT{x}}: " << nodep << endl);
UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl);
AstNode* condp = nodep->condp();
AstNode* elsesp = nodep->elsesp();
condp->unlinkFrBackWithNext();
@@ -2002,7 +1953,7 @@ private:
}
}
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
virtual void visit(AstDisplay* nodep) override {
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
iterateChildren(nodep);
if (stmtDisplayDisplay(nodep)) return;
@@ -2047,7 +1998,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return true;
}
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
virtual void visit(AstSFormatF* nodep) override {
// Substitute constants into displays. The main point of this is to
// simplify assertion methodologies which call functions with display's.
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
@@ -2066,8 +2017,7 @@ private:
bool inPct = false;
AstNode* argp = nodep->exprsp();
string text = nodep->text();
for (string::const_iterator it = text.begin(); it != text.end(); ++it) {
char ch = *it;
for (const char ch : text) {
if (!inPct && ch == '%') {
inPct = true;
fmt = ch;
@@ -2115,17 +2065,17 @@ private:
}
}
virtual void visit(AstFuncRef* nodep) VL_OVERRIDE {
virtual void visit(AstFuncRef* nodep) override {
iterateChildren(nodep);
if (m_params) { // Only parameters force us to do constant function call propagation
replaceWithSimulation(nodep);
}
}
virtual void visit(AstArg* nodep) VL_OVERRIDE {
virtual void visit(AstArg* nodep) override {
// replaceWithSimulation on the Arg's parent FuncRef replaces these
iterateChildren(nodep);
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
virtual void visit(AstWhile* nodep) override {
bool oldHasJumpDelay = m_hasJumpDelay;
m_hasJumpDelay = false;
{ iterateChildren(nodep); }
@@ -2151,22 +2101,22 @@ private:
}
}
}
virtual void visit(AstInitArray* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstInitItem* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstUnbounded* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstInitArray* nodep) override { iterateChildren(nodep); }
virtual void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
virtual void visit(AstUnbounded* nodep) override { iterateChildren(nodep); }
// These are converted by V3Param. Don't constify as we don't want the
// from() VARREF to disappear, if any.
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
virtual void visit(AstNodePreSel*) VL_OVERRIDE {}
virtual void visit(AstNodePreSel*) override {}
// Ignored, can eliminate early
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
virtual void visit(AstSysIgnore* nodep) override {
iterateChildren(nodep);
if (m_doNConst) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); }
}
// Simplify
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
virtual void visit(AstBasicDType* nodep) override {
iterateChildren(nodep);
nodep->cvtRangeConst();
}
@@ -2174,11 +2124,11 @@ private:
//-----
// Jump elimination
virtual void visit(AstDelay* nodep) VL_OVERRIDE {
virtual void visit(AstDelay* nodep) override {
iterateChildren(nodep);
m_hasJumpDelay = true;
}
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
virtual void visit(AstJumpGo* nodep) override {
iterateChildren(nodep);
// Jump to label where label immediately follows label is not useful
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
@@ -2209,7 +2159,7 @@ private:
m_hasJumpDelay = true;
}
virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE {
virtual void visit(AstJumpBlock* nodep) override {
// Because JumpLabels disable many optimizations,
// remove JumpLabels that are not pointed to by any AstJumpGos
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
@@ -2217,7 +2167,7 @@ private:
// AstJumpGo's below here that point to this node will set user4
if (m_doExpensive && !nodep->user4()) {
UINFO(4, "JUMPLABEL => unused " << nodep << endl);
AstNode* underp = NULL;
AstNode* underp = nullptr;
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
if (underp) {
nodep->replaceWith(underp);
@@ -2263,8 +2213,8 @@ private:
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
// Generic constants on both side. Do this first to avoid other replacements
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)");
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque(), nodep->isPredictOptimizable()}", "replaceConst(nodep)");
TREEOPC("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)");
// Zero on one side or the other
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
@@ -2322,7 +2272,7 @@ private:
TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP ("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
TREEOP ("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstMul {operandIsPowTwo($lhsp), operandsSameSize($lhsp,,$rhsp)}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
@@ -2563,7 +2513,7 @@ private:
// Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101
//-----
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
// Default: Just iterate
if (m_required) {
if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range)) {
@@ -2581,7 +2531,7 @@ private:
public:
// Processing Mode Enum
enum ProcMode {
enum ProcMode : uint8_t {
PROC_PARAMS,
PROC_GENERATE,
PROC_LIVE,
@@ -2593,21 +2543,6 @@ public:
// CONSTRUCTORS
explicit ConstVisitor(ProcMode pmode) {
m_params = false;
m_required = false;
m_doExpensive = false;
m_doNConst = false;
m_doShort = true; // Presently always done
m_doV = false;
m_doGenerate = false; // Inside generate conditionals
m_hasJumpDelay = false;
m_warn = false;
m_wremove = true; // Overridden in visitors
m_modp = NULL;
m_selp = NULL;
m_scopep = NULL;
m_attrp = NULL;
//
// clang-format off
switch (pmode) {
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true;
@@ -2623,7 +2558,7 @@ public:
}
// clang-format on
}
virtual ~ConstVisitor() {}
virtual ~ConstVisitor() override {}
AstNode* mainAcceptEdit(AstNode* nodep) {
// Operate starting at a random place
return iterateSubtreeReturnEdits(nodep);
+45 -62
View File
@@ -32,7 +32,7 @@
#include "V3Ast.h"
#include <map>
#include VL_INCLUDE_UNORDERED_MAP
#include <unordered_map>
//######################################################################
// Coverage state, as a visitor of each AstNode
@@ -40,41 +40,37 @@
class CoverageVisitor : public AstNVisitor {
private:
// TYPES
typedef vl_unordered_map<string, int> VarNameMap;
typedef std::unordered_map<string, int> VarNameMap;
typedef std::set<int> LinenoSet;
typedef vl_unordered_map<int, LinenoSet> HandleLines;
typedef std::unordered_map<int, LinenoSet> HandleLines;
struct ToggleEnt {
string m_comment; // Comment for coverage dump
AstNode* m_varRefp; // How to get to this element
AstNode* m_chgRefp; // How to get to this element
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
: m_comment(comment)
, m_varRefp(vp)
, m_chgRefp(cp) {}
: m_comment{comment}
, m_varRefp{vp}
, m_chgRefp{cp} {}
~ToggleEnt() {}
void cleanup() {
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = NULL);
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = NULL);
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = nullptr);
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = nullptr);
}
};
struct CheckState { // State save-restored on each new coverage scope/block
bool m_on; // Should this block get covered?
bool m_inModOff; // In module with no coverage
int m_handle; // Opaque handle for index into line tracking
const AstNode* m_nodep; // Node establishing this state
CheckState()
: m_on(false)
, m_inModOff(false)
, m_handle(0)
, m_nodep(NULL) {}
bool lineCoverageOn(const AstNode* nodep) {
bool m_on = false; // Should this block get covered?
bool m_inModOff = false; // In module with no coverage
int m_handle = 0; // Opaque handle for index into line tracking
const AstNode* m_nodep = nullptr; // Node establishing this state
CheckState() {}
bool lineCoverageOn(const AstNode* nodep) const {
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
&& v3Global.opt.coverageLine();
}
};
int m_nextHandle;
int m_nextHandle = 0;
// NODE STATE
// Entire netlist:
@@ -83,8 +79,8 @@ private:
// STATE
CheckState m_state; // State save-restored on each new coverage scope/block
AstNodeModule* m_modp; // Current module to add statement to
bool m_inToggleOff; // In function/task etc
AstNodeModule* m_modp = nullptr; // Current module to add statement to
bool m_inToggleOff = false; // In function/task etc
VarNameMap m_varnames; // Uniquification of inserted variable names
string m_beginHier; // AstBegin hier name for user coverage points
HandleLines m_handleLines; // All line numbers for a given m_stateHandle
@@ -106,7 +102,7 @@ private:
}
// We allow this, though tracing doesn't
// if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
return NULL;
return nullptr;
}
AstCoverInc* newCoverInc(FileLine* fl, const string& hier, const string& page_prefix,
@@ -134,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);
}
@@ -144,7 +140,7 @@ private:
string traceNameForLine(AstNode* nodep, const string& type) {
string name = "vlCoverageLineTrace_" + nodep->fileline()->filebasenameNoExt() + "__"
+ cvtToStr(nodep->fileline()->lineno()) + "_" + type;
VarNameMap::iterator it = m_varnames.find(name);
const auto it = m_varnames.find(name);
if (it == m_varnames.end()) {
m_varnames.insert(make_pair(name, 1));
} else {
@@ -212,9 +208,9 @@ private:
}
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
AstNodeModule* origModp = m_modp;
CheckState lastState = m_state;
VL_RESTORER(m_state);
{
createHandle(nodep);
m_modp = nodep;
@@ -228,17 +224,16 @@ private:
iterateChildren(nodep);
}
m_modp = origModp;
m_state = lastState;
}
virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { iterateProcedure(nodep); }
virtual void visit(AstWhile* nodep) VL_OVERRIDE { iterateProcedure(nodep); }
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
virtual void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
virtual void visit(AstWhile* nodep) override { iterateProcedure(nodep); }
virtual void visit(AstNodeFTask* nodep) override {
if (!nodep->dpiImport()) iterateProcedure(nodep);
}
void iterateProcedure(AstNode* nodep) {
CheckState lastState = m_state;
bool oldtog = m_inToggleOff;
VL_RESTORER(m_state);
VL_RESTORER(m_inToggleOff);
{
m_inToggleOff = true;
createHandle(nodep);
@@ -259,12 +254,10 @@ private:
}
}
}
m_state = lastState;
m_inToggleOff = oldtog;
}
// VISITORS - TOGGLE COVERAGE
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstVar* nodep) override {
iterateChildren(nodep);
if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn()
&& v3Global.opt.coverageToggle()) {
@@ -295,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();
}
@@ -387,7 +381,7 @@ private:
// VISITORS - LINE COVERAGE
// Note not AstNodeIf; other types don't get covered
virtual void visit(AstIf* nodep) VL_OVERRIDE {
virtual void visit(AstIf* nodep) override {
UINFO(4, " IF: " << nodep << endl);
if (m_state.m_on) {
// An else-if. When we iterate the if, use "elsif" marking
@@ -463,12 +457,12 @@ private:
}
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
}
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
virtual void visit(AstCaseItem* nodep) override {
// We don't add an explicit "default" coverage if not provided,
// as we already have a warning when there is no default.
UINFO(4, " CASEI: " << nodep << endl);
if (m_state.lineCoverageOn(nodep)) {
CheckState lastState = m_state;
VL_RESTORER(m_state);
{
createHandle(nodep);
iterateAndNextNull(nodep->bodysp());
@@ -480,12 +474,11 @@ private:
traceNameForLine(nodep, "case")));
}
}
m_state = lastState;
}
}
virtual void visit(AstCover* nodep) VL_OVERRIDE {
virtual void visit(AstCover* nodep) override {
UINFO(4, " COVER: " << nodep << endl);
CheckState lastState = m_state;
VL_RESTORER(m_state);
{
m_state.m_on = true; // Always do cover blocks, even if there's a $stop
createHandle(nodep);
@@ -498,13 +491,12 @@ private:
m_beginHier + "_vlCoverageUserTrace"));
}
}
m_state = lastState;
}
virtual void visit(AstStop* nodep) VL_OVERRIDE {
virtual void visit(AstStop* nodep) override {
UINFO(4, " STOP: " << nodep << endl);
m_state.m_on = false;
}
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
virtual void visit(AstPragma* nodep) override {
if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
// Skip all NEXT nodes under this block, and skip this if/case branch
UINFO(4, " OFF: h" << m_state.m_handle << " " << nodep << endl);
@@ -515,14 +507,14 @@ private:
lineTrack(nodep);
}
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
virtual void visit(AstBegin* nodep) override {
// Record the hierarchy of any named begins, so we can apply to user
// coverage points. This is because there may be cov points inside
// generate blocks; each point should get separate consideration.
// (Currently ignored for line coverage, since any generate iteration
// covers the code in that line.)
string oldHier = m_beginHier;
bool oldtog = m_inToggleOff;
VL_RESTORER(m_beginHier);
VL_RESTORER(m_inToggleOff);
{
m_inToggleOff = true;
if (nodep->name() != "") {
@@ -531,27 +523,18 @@ private:
iterateChildren(nodep);
lineTrack(nodep);
}
m_beginHier = oldHier;
m_inToggleOff = oldtog;
}
// VISITORS - BOTH
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
iterateChildren(nodep);
lineTrack(nodep);
}
public:
// CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) {
// Operate on all modules
m_nextHandle = 0;
m_modp = NULL;
m_beginHier = "";
m_inToggleOff = false;
iterateChildren(rootp);
}
virtual ~CoverageVisitor() {}
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }
virtual ~CoverageVisitor() override {}
};
//######################################################################
+8 -12
View File
@@ -54,20 +54,16 @@ private:
// Note uses user4
V3Hashed hashed; // Duplicate code detection
// Hash all of the original signals we toggle cover
for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) {
AstCoverToggle* nodep = *it;
hashed.hashAndInsert(nodep->origp());
}
for (AstCoverToggle* nodep : m_toggleps) hashed.hashAndInsert(nodep->origp());
// Find if there are any duplicates
for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) {
AstCoverToggle* nodep = *it;
for (AstCoverToggle* nodep : m_toggleps) {
// nodep->backp() is null if we already detected it's a duplicate and unlinked it.
if (nodep->backp()) {
// Want to choose a base node, and keep finding duplicates that are identical.
// This prevents making chains where a->b, then c->d, then b->c, as we'll
// find a->b, a->c, a->d directly.
while (true) {
V3Hashed::iterator dupit = hashed.findDuplicate(nodep->origp());
const auto dupit = hashed.findDuplicate(nodep->origp());
if (dupit == hashed.end()) break;
//
AstNode* duporigp = hashed.iteratorNodep(dupit);
@@ -97,24 +93,24 @@ private:
}
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
// Find all Coverage's
iterateChildren(nodep);
// Simplify
detectDuplicates();
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
virtual void visit(AstCoverToggle* nodep) override {
m_toggleps.push_back(nodep);
iterateChildren(nodep);
}
//--------------------
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CoverageJoinVisitor() {
virtual ~CoverageJoinVisitor() override {
V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins);
}
};
+47 -45
View File
@@ -25,7 +25,7 @@
// The following nodes have package pointers and are cleaned up here:
// AstRefDType, AstEnumItemRef, AstNodeVarRef, AstNodeFTask
// These have packagep but will not exist at this stage
// AstPackageImport, AstDot, AstPackageRef
// AstPackageImport, AstDot, AstClassOrPackageRef
//
// Note on packagep: After the V3Scope/V3LinkDotScoped stage, package links
// are no longer used, but their presence prevents us from removing empty
@@ -52,18 +52,18 @@ private:
// NODE STATE
// ** Shared with DeadVisitor **
// VISITORS
virtual void visit(AstCell* nodep) VL_OVERRIDE {
virtual void visit(AstCell* nodep) override {
iterateChildren(nodep);
nodep->modp()->user1Inc(-1);
}
//-----
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); }
virtual ~DeadModVisitor() {}
virtual ~DeadModVisitor() override {}
};
//######################################################################
@@ -119,8 +119,8 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
if (!nodep->dead()) {
@@ -135,14 +135,13 @@ private:
}
}
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc();
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc();
@@ -153,14 +152,14 @@ private:
m_scopesp.push_back(nodep);
}
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
virtual void visit(AstCell* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
m_cellsp.push_back(nodep);
nodep->modp()->user1Inc();
}
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->varScopep()) {
@@ -170,28 +169,28 @@ private:
if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->packagep()) {
if (m_elimCells) {
nodep->packagep(NULL);
nodep->packagep(nullptr);
} else {
nodep->packagep()->user1Inc();
}
}
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeFTaskRef* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) {
nodep->packagep(NULL);
nodep->packagep(nullptr);
} else {
nodep->packagep()->user1Inc();
}
}
}
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
virtual void visit(AstMethodCall* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
}
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
virtual void visit(AstRefDType* nodep) override {
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
@@ -199,49 +198,49 @@ private:
"RefDType should point to data type before typedefs removed");
if (nodep->packagep()) {
if (m_elimCells) {
nodep->packagep(NULL);
nodep->packagep(nullptr);
} else {
nodep->packagep()->user1Inc();
}
}
}
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
virtual void visit(AstClassRefDType* nodep) override {
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) {
nodep->packagep(NULL);
nodep->packagep(nullptr);
} else {
nodep->packagep()->user1Inc();
}
}
if (nodep->classp()) nodep->classp()->user1Inc();
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
virtual void visit(AstNodeDType* nodep) override {
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
}
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
virtual void visit(AstEnumItemRef* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) {
nodep->packagep(NULL);
nodep->packagep(nullptr);
} else {
nodep->packagep()->user1Inc();
}
}
checkAll(nodep);
}
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
virtual void visit(AstMemberSel* nodep) override {
iterateChildren(nodep);
if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref
checkAll(nodep);
}
virtual void visit(AstModport* nodep) VL_OVERRIDE {
virtual void visit(AstModport* nodep) override {
iterateChildren(nodep);
if (m_elimCells) {
if (!nodep->varsp()) {
@@ -251,7 +250,7 @@ private:
}
checkAll(nodep);
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
virtual void visit(AstTypedef* nodep) override {
iterateChildren(nodep);
if (m_elimCells && !nodep->attrPublic()) {
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
@@ -262,19 +261,19 @@ private:
// Normal modules may disappear, e.g. if they are parameterized then removed
if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
virtual void visit(AstVarScope* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc();
if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep);
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstVar* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
if (mightElimVar(nodep)) m_varsp.push_back(nodep);
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
// See if simple assignments to variables may be eliminated because
// that variable is never used.
// Similar code in V3Life
@@ -294,7 +293,7 @@ private:
}
//-----
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
if (nodep->isOutputter()) m_sideEffect = true;
iterateChildren(nodep);
checkAll(nodep);
@@ -326,11 +325,16 @@ private:
}
}
bool mightElimVar(AstVar* nodep) {
return (!nodep->isSigPublic() // Can't elim publics!
&& !nodep->isIO() && !nodep->isClassMember()
&& ((nodep->isTemp() && !nodep->isTrace())
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|| m_elimUserVars)); // Post-Trace can kill most anything
if (nodep->isSigPublic()) return false; // Can't elim publics!
if (nodep->isIO() || nodep->isClassMember()) return false;
if (nodep->isTemp() && !nodep->isTrace()) return true;
if (nodep->isParam()) {
const bool overriddenForHierBlock
= m_modp && m_modp->hierBlock() && nodep->overriddenParam();
if (!nodep->isTrace() && !overriddenForHierBlock && !v3Global.opt.xmlOnly())
return true;
}
return m_elimUserVars; // Post-Trace can kill most anything
}
void deadCheckScope() {
@@ -345,7 +349,7 @@ private:
scp->aboveScopep()->user1Inc(-1);
if (scp->dtypep()) scp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp);
*it = NULL;
*it = nullptr;
retry = true;
}
}
@@ -353,8 +357,7 @@ private:
}
void deadCheckCells() {
for (std::vector<AstCell*>::iterator it = m_cellsp.begin(); it != m_cellsp.end(); ++it) {
AstCell* cellp = *it;
for (AstCell* cellp : m_cellsp) {
if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) {
cellp->modp()->user1Inc(-1);
VL_DO_DANGLING(cellp->unlinkFrBack()->deleteTree(), cellp);
@@ -366,12 +369,12 @@ private:
retry = false;
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
++it) {
if (AstClass* nodep = *it) { // NULL if deleted earlier
if (AstClass* nodep = *it) { // 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 = NULL;
*it = nullptr;
retry = true;
}
}
@@ -381,8 +384,7 @@ private:
void deadCheckVar() {
// Delete any unused varscopes
for (std::vector<AstVarScope*>::iterator it = m_vscsp.begin(); it != m_vscsp.end(); ++it) {
AstVarScope* vscp = *it;
for (AstVarScope* vscp : m_vscsp) {
if (vscp->user1() == 0) {
UINFO(4, " Dead " << vscp << endl);
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
@@ -407,7 +409,7 @@ private:
UINFO(4, " Dead " << varp << endl);
if (varp->dtypep()) varp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
*it = NULL;
*it = nullptr;
retry = true;
}
}
@@ -438,7 +440,7 @@ public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
bool elimCells) {
m_modp = NULL;
m_modp = nullptr;
m_elimCells = elimCells;
m_elimUserVars = elimUserVars;
m_elimDTypes = elimDTypes;
@@ -460,7 +462,7 @@ public:
// We may have removed some datatypes, cleanup
nodep->typeTablep()->repairCache();
}
virtual ~DeadVisitor() {}
virtual ~DeadVisitor() override {}
};
//######################################################################
+77 -75
View File
@@ -86,15 +86,15 @@ private:
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
enum VarUsage { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 };
enum VarUsage : uint8_t { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 };
// STATE
AstActive* m_activep; // Current activate
AstCFunc* m_cfuncp; // Current public C Function
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
bool m_inDly; // True in delayed assignments
bool m_inLoop; // True in for loops
bool m_inInitial; // True in initial blocks
AstActive* m_activep = nullptr; // Current activate
AstCFunc* m_cfuncp = nullptr; // Current public C Function
AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
bool m_inInitial = false; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
@@ -120,7 +120,7 @@ private:
AstVar* varp;
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
VarMap::iterator it = m_modVarMap.find(make_pair(addmodp, name));
const auto it = m_modVarMap.find(make_pair(addmodp, name));
if (it != m_modVarMap.end()) {
// Created module's AstVar earlier under some other scope
varp = it->second;
@@ -171,8 +171,8 @@ private:
UINFO(4, " Act: " << m_activep << endl);
UINFO(4, " Act: " << oldactivep << endl);
// Make a new sensitivity list, which is the combination of both blocks
AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena);
if (senb) treep->addSensesp(senb);
if (AstSenTree* storep = oldactivep->sensesStorep()) {
@@ -189,9 +189,9 @@ private:
// See top of this file for transformation
// Return the new LHS for the assignment, Null = unlink
// Find selects
AstNode* newlhsp = NULL; // NULL = unlink old assign
AstSel* bitselp = NULL;
AstArraySel* arrayselp = NULL;
AstNode* newlhsp = nullptr; // nullptr = unlink old assign
AstSel* bitselp = nullptr;
AstArraySel* arrayselp = nullptr;
if (VN_IS(lhsp, Sel)) {
bitselp = VN_CAST(lhsp, Sel);
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
@@ -226,16 +226,17 @@ private:
string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), NULL);
= 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));
}
}
//
//=== Bitselect: __Vdlyvlsb__
AstNode* bitreadp = NULL; // Code to read Vdlyvlsb
AstNode* bitreadp = nullptr; // Code to read Vdlyvlsb
if (bitselp) {
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
if (VN_IS(bitselp->fromp(), Const)) {
@@ -245,11 +246,12 @@ private:
string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
+ cvtToStr(modVecNum));
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), NULL);
= 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,13 +265,13 @@ 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__
AstVarScope* setvscp;
AstAssignPre* setinitp = NULL;
AstAssignPre* setinitp = nullptr;
if (nodep->user3p()) {
// Simplistic optimization. If the previous statement in same scope was also a =>,
@@ -281,13 +283,13 @@ private:
} else { // Create new one
string setvarname
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, NULL);
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
@@ -316,7 +318,7 @@ private:
checkActivePost(varrefp, oldactivep);
if (setinitp) oldactivep->addStmtsp(setinitp);
} else { // first time we've dealt with this memory
finalp = new AstAlwaysPost(nodep->fileline(), NULL /*sens*/, NULL /*body*/);
finalp = new AstAlwaysPost(nodep->fileline(), nullptr /*sens*/, nullptr /*body*/);
UINFO(9, " Created " << finalp << endl);
AstActive* newactp = createActivePost(varrefp);
newactp->addStmtsp(finalp);
@@ -333,7 +335,8 @@ private:
"Delayed assignment misoptimized; prev var found w/o associated IF");
} else {
postLogicp = new AstIf(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, false), NULL, NULL);
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
@@ -344,36 +347,38 @@ private:
}
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
// VV***** We reset all userp() on the netlist
m_modVarMap.clear();
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
UINFO(4, " MOD " << nodep << endl);
AstNode::user3ClearTree();
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
m_cfuncp = nodep;
iterateChildren(nodep);
m_cfuncp = NULL;
m_cfuncp = nullptr;
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
bool oldinit = m_inInitial;
m_inInitial = nodep->hasInitial();
AstNode::user3ClearTree(); // Two sets to same variable in different
// actives must use different vars.
iterateChildren(nodep);
m_inInitial = oldinit;
VL_RESTORER(m_inInitial);
{
m_inInitial = nodep->hasInitial();
// Two sets to same variable in different actives must use different vars.
AstNode::user3ClearTree();
iterateChildren(nodep);
}
}
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
virtual void visit(AstAssignDly* nodep) override {
m_inDly = true;
m_nextDlyp
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe nullptr.
if (m_cfuncp) {
nodep->v3error("Unsupported: Delayed assignment inside public function/task");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Delayed assignment inside public function/task");
}
if (VN_IS(nodep->lhsp(), ArraySel)
|| (VN_IS(nodep->lhsp(), Sel)
@@ -385,7 +390,9 @@ private:
"loops (non-delayed is ok - see docs)");
}
AstBasicDType* basicp = lhsp->dtypep()->basicp();
if (basicp && basicp->isEventValue()) nodep->v3error("Unsupported: event arrays");
if (basicp && basicp->isEventValue()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays");
}
if (newlhsp) {
nodep->lhsp(newlhsp);
} else {
@@ -396,12 +403,12 @@ private:
iterateChildren(nodep);
}
m_inDly = false;
m_nextDlyp = NULL;
m_nextDlyp = nullptr;
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->lvalue()) {
if (m_inDly && nodep->access().isWrite()) {
UINFO(4, "AssignDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_DLY);
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
@@ -418,22 +425,25 @@ private:
}
if (!dlyvscp) { // First use of this delayed variable
string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL);
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
AstNodeAssign* prep;
AstBasicDType* basicp = oldvscp->dtypep()->basicp();
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
@@ -442,11 +452,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().isWrite()) {
// UINFO(9, "NBA " << nodep << endl);
if (!m_inInitial) {
UINFO(4, "AssignNDlyVar: " << nodep << endl);
@@ -456,33 +466,25 @@ private:
}
}
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc(
"For statements should have been converted to while statements in V3Begin");
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
bool oldloop = m_inLoop;
m_inLoop = true;
iterateChildren(nodep);
m_inLoop = oldloop;
virtual void visit(AstWhile* nodep) override {
VL_RESTORER(m_inLoop);
{
m_inLoop = true;
iterateChildren(nodep);
}
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit DelayedVisitor(AstNetlist* nodep) {
m_inDly = false;
m_activep = NULL;
m_cfuncp = NULL;
m_nextDlyp = NULL;
m_inLoop = false;
m_inInitial = false;
iterate(nodep);
}
virtual ~DelayedVisitor() {
explicit DelayedVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DelayedVisitor() override {
V3Stats::addStat("Optimizations, Delayed shared-sets", m_statSharedSet);
}
};
+23 -32
View File
@@ -39,11 +39,11 @@ private:
// NODE STATE
// STATE
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current block
AstNode* m_stmtp; // Current statement
int m_depth; // How deep in an expression
int m_maxdepth; // Maximum depth in an expression
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = 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
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -64,11 +64,11 @@ private:
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
m_funcp->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);
@@ -76,31 +76,30 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
AstNodeModule* origModp = m_modp;
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_funcp = NULL;
m_funcp = nullptr;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
m_funcp = NULL;
m_funcp = nullptr;
}
void visitStmt(AstNodeStmt* nodep) {
m_depth = 0;
m_maxdepth = 0;
m_stmtp = nodep;
iterateChildren(nodep);
m_stmtp = NULL;
m_stmtp = nullptr;
}
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
} else {
@@ -108,8 +107,8 @@ private:
}
}
// Operators
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
virtual void visit(AstNodeTermop* nodep) override {}
virtual void visit(AstNodeMath* nodep) override {
// We have some operator defines that use 2 parens, so += 2.
m_depth += 2;
if (m_depth > m_maxdepth) m_maxdepth = m_depth;
@@ -135,32 +134,24 @@ private:
m_funcp->isStatic(false);
}
}
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstUCFunc* nodep) override {
needNonStaticFunc(nodep);
iterateChildren(nodep);
}
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
virtual void visit(AstUCStmt* nodep) override {
needNonStaticFunc(nodep);
visitStmt(nodep);
}
//--------------------
// Default: Just iterate
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit DepthVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_funcp = NULL;
m_stmtp = NULL;
m_depth = 0;
m_maxdepth = 0;
//
iterate(nodep);
}
virtual ~DepthVisitor() {}
explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DepthVisitor() override {}
};
//######################################################################
+16 -26
View File
@@ -37,10 +37,10 @@ private:
// NODE STATE
// STATE
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function
int m_depth; // How deep in an expression
int m_deepNum; // How many functions made
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
int m_depth = 0; // How deep in an expression
int m_deepNum = 0; // How many functions made
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -50,7 +50,7 @@ private:
nodep->unlinkFrBack(&relinkHandle);
// Create function
string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum);
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL);
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr);
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->symProlog(true);
funcp->slow(m_funcp->slow());
@@ -66,27 +66,24 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
AstNodeModule* origModp = m_modp;
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_deepNum = 0;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
// We recurse into this.
int lastDepth = m_depth;
AstCFunc* lastFuncp = m_funcp;
VL_RESTORER(m_depth);
VL_RESTORER(m_funcp);
{
m_depth = 0;
m_funcp = nodep;
iterateChildren(nodep);
}
m_depth = lastDepth;
m_funcp = lastFuncp;
}
void visitStmt(AstNodeStmt* nodep) {
m_depth++;
@@ -104,7 +101,7 @@ private:
}
m_depth--;
}
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
} else {
@@ -112,22 +109,15 @@ private:
}
}
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNodeMath*) override {} // Accelerate
//--------------------
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit DepthBlockVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_funcp = NULL;
m_depth = 0;
m_deepNum = 0;
//
iterate(nodep);
}
virtual ~DepthBlockVisitor() {}
explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DepthBlockVisitor() override {}
};
//######################################################################
+28 -35
View File
@@ -45,11 +45,11 @@ private:
typedef std::multimap<string, AstCFunc*> FuncMmap;
// STATE
AstNodeModule* m_modp; // Current module
AstScope* m_scopep; // Current scope
bool m_modSingleton; // m_modp is only instanced once
bool m_allowThis; // Allow function non-static
bool m_needThis; // Make function non-static
AstNodeModule* m_modp = nullptr; // Current module
AstScope* m_scopep = nullptr; // Current scope
bool m_modSingleton = false; // m_modp is only instanced once
bool m_allowThis = false; // Allow function non-static
bool m_needThis = false; // Make function non-static
FuncMmap m_modFuncs; // Name of public functions added
// METHODS
@@ -76,7 +76,7 @@ private:
// Sets 'hierThisr' true if the object is local to this scope
// (and could be made into a function-local later in V3Localize),
// false if the object is in another scope.
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = NULL) {
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = nullptr) {
UASSERT(scopep, "Var/Func not scoped");
hierThisr = (scopep == m_scopep);
@@ -148,7 +148,7 @@ private:
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
string name = it->first;
AstCFunc* topFuncp = it->second;
FuncMmap::iterator nextIt1 = it;
auto nextIt1 = it;
++nextIt1;
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
if (moreOfSame1) {
@@ -171,7 +171,7 @@ private:
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
it = eachIt;
AstCFunc* funcp = eachIt->second;
FuncMmap::iterator nextIt2 = eachIt;
auto nextIt2 = eachIt;
++nextIt2;
bool moreOfSame = (nextIt2 != m_modFuncs.end() && nextIt2->first == name);
UASSERT_OBJ(funcp->scopep(), funcp, "Not scoped");
@@ -180,12 +180,13 @@ private:
UINFO(6,
" at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl);
funcp->declPrivate(true);
AstNode* argsp = NULL;
AstNode* argsp = nullptr;
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;
}
}
@@ -202,7 +203,7 @@ private:
new AstCMath(funcp->fileline(),
string("&(") + funcp->scopep()->nameVlSym() + ")",
64)),
returnp, NULL);
returnp, nullptr);
newfuncp->addStmtsp(ifp);
} else {
newfuncp->addStmtsp(returnp);
@@ -213,7 +214,7 @@ private:
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
// AstDisplayType::DT_WARNING,
// string("%%Error: ")+name+"() called with bad
// scope", NULL));
// scope", nullptr));
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
if (debug() >= 9) newfuncp->dumpTree(cout, " newfunc: ");
} else {
@@ -225,8 +226,8 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_modFuncs.clear();
@@ -234,19 +235,18 @@ private:
iterateChildren(nodep);
makePublicFuncWrappers();
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
m_scopep = nodep;
iterateChildren(nodep);
m_scopep = NULL;
m_scopep = nullptr;
}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
virtual void visit(AstVarScope* nodep) override {
// Delete the varscope when we're finished
nodep->unlinkFrBack();
pushDeletep(nodep);
}
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep);
// Convert the hierch name
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
@@ -254,9 +254,9 @@ private:
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis /*ref*/,
nodep->varScopep()->varp()));
nodep->hierThis(hierThis);
nodep->varScopep(NULL);
nodep->varScopep(nullptr);
}
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCCall* nodep) override {
// UINFO(9, " " << nodep << endl);
iterateChildren(nodep);
// Convert the hierch name
@@ -265,9 +265,9 @@ private:
bool hierThis;
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis /*ref*/));
// Can't do this, as we may have more calls later
// nodep->funcp()->scopep(NULL);
// nodep->funcp()->scopep(nullptr);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
if (!nodep->user1()) {
m_needThis = false;
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
@@ -288,20 +288,13 @@ private:
}
}
}
virtual void visit(AstVar*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit DescopeVisitor(AstNetlist* nodep)
: m_modp(NULL)
, m_scopep(NULL)
, m_modSingleton(false)
, m_allowThis(false)
, m_needThis(false) {
iterate(nodep);
}
virtual ~DescopeVisitor() {}
explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DescopeVisitor() override {}
};
//######################################################################
+264 -266
View File
File diff suppressed because it is too large Load Diff
+8 -14
View File
@@ -33,8 +33,8 @@
class EmitCBaseVisitor : public AstNVisitor {
public:
// STATE
V3OutCFile* m_ofp;
bool m_trackText; // Always track AstText nodes
V3OutCFile* m_ofp = nullptr;
bool m_trackText = false; // Always track AstText nodes
// METHODS
V3OutCFile* ofp() const { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
@@ -106,11 +106,8 @@ public:
}
// CONSTRUCTORS
EmitCBaseVisitor() {
m_ofp = NULL;
m_trackText = false;
}
virtual ~EmitCBaseVisitor() {}
EmitCBaseVisitor() {}
virtual ~EmitCBaseVisitor() override {}
};
//######################################################################
@@ -119,20 +116,17 @@ public:
class EmitCBaseCounterVisitor : public AstNVisitor {
private:
// MEMBERS
int m_count; // Number of statements
int m_count = 0; // Number of statements
// VISITORS
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
m_count++;
iterateChildren(nodep);
}
public:
// CONSTRUCTORS
explicit EmitCBaseCounterVisitor(AstNode* nodep) {
m_count = 0;
iterate(nodep);
}
virtual ~EmitCBaseCounterVisitor() {}
explicit EmitCBaseCounterVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~EmitCBaseCounterVisitor() override {}
int count() const { return m_count; }
};
+6 -6
View File
@@ -35,24 +35,24 @@ class EmitCInlines : EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstClass* nodep) VL_OVERRIDE {
virtual void visit(AstClass* nodep) override {
checkHeavy(nodep);
v3Global.needC11(true);
iterateChildren(nodep);
}
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
virtual void visit(AstCNew* nodep) override {
checkHeavy(nodep);
if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new");
if (v3Global.opt.savable())
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
iterateChildren(nodep);
}
virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {
virtual void visit(AstDumpCtl* nodep) override {
checkHeavy(nodep);
if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
iterateChildren(nodep);
}
//---------------------------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
checkHeavy(nodep);
iterateChildren(nodep);
}
+2 -2
View File
@@ -31,11 +31,11 @@ class EmitCMain : EmitCBaseVisitor {
// VISITORS
// This visitor doesn't really iterate, but exist to appease base class
virtual void visit(AstNode* nodep) { iterateChildren(nodep); } // LCOV_EXCL_LINE
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE
public:
// CONSTRUCTORS
explicit EmitCMain(AstNetlist* nodep) { emitInt(); }
explicit EmitCMain(AstNetlist*) { emitInt(); }
private:
// MAIN METHOD
+64 -6
View File
@@ -21,6 +21,7 @@
#include "V3Os.h"
#include "V3EmitCMake.h"
#include "V3EmitCBase.h"
#include "V3HierBlock.h"
#include <memory>
@@ -39,11 +40,11 @@ class CMakeEmitter {
string s;
if (strs.begin() != strs.end()) {
s.append("\"");
s.append(*strs.begin());
s.append(VString::quoteAny(*strs.begin(), '"', '\\'));
s.append("\"");
for (typename List::const_iterator it = ++strs.begin(); it != strs.end(); ++it) {
s.append(" \"");
s.append(*it);
s.append(VString::quoteAny(*it, '"', '\\'));
s.append("\"");
}
}
@@ -77,7 +78,7 @@ class CMakeEmitter {
}
static void emitOverallCMake() {
const vl_unique_ptr<std::ofstream> of(
const std::unique_ptr<std::ofstream> of(
V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake"));
string name = v3Global.opt.prefix();
@@ -124,7 +125,11 @@ class CMakeEmitter {
: "0");
*of << "\n### Sources...\n";
std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global;
std::vector<string> classes_fast;
std::vector<string> classes_slow;
std::vector<string> support_fast;
std::vector<string> support_slow;
std::vector<string> global;
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
@@ -163,8 +168,9 @@ class CMakeEmitter {
+ "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, "
"use VCD format.");
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");
@@ -194,6 +200,58 @@ class CMakeEmitter {
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
if (const V3HierBlockPlan* planp = v3Global.hierPlanp()) {
*of << "# Verilate hierarchical blocks\n";
// Sorted hierarchical blocks in order of leaf-first.
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
*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(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
if (!children.empty()) {
*of << "target_link_libraries(" << prefix << " INTERFACE";
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
child != children.end(); ++child) {
*of << " " << (*child)->hierPrefix();
}
*of << ")\n";
}
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
<< hblockp->modp()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES ";
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
child != children.end(); ++child) {
*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) << " ";
*of << " VERILATOR_ARGS ";
*of << "-f " << deslash(hblockp->commandArgsFileName(true))
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
// with .so
<< ")\n";
}
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) {
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + it->second->hierWrapper(true));
}
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
*of << " VERILATOR_ARGS ";
*of << "-f " << deslash(planp->topCommandArgsFileName(true));
*of << ")\n";
}
}
public:
+73 -65
View File
@@ -43,19 +43,19 @@ class EmitCSyms : EmitCBaseVisitor {
string m_type;
ScopeData(const string& symName, const string& prettyName, int timeunit,
const string& type)
: m_symName(symName)
, m_prettyName(prettyName)
, m_timeunit(timeunit)
, m_type(type) {}
: m_symName{symName}
, m_prettyName{prettyName}
, m_timeunit{timeunit}
, m_type{type} {}
};
struct ScopeFuncData {
AstScopeName* m_scopep;
AstCFunc* m_funcp;
AstNodeModule* m_modp;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
: m_scopep(scopep)
, m_funcp(funcp)
, m_modp(modp) {}
: m_scopep{scopep}
, m_funcp{funcp}
, m_modp{modp} {}
};
struct ScopeVarData {
string m_scopeName;
@@ -65,11 +65,11 @@ class EmitCSyms : EmitCBaseVisitor {
AstScope* m_scopep;
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp,
AstNodeModule* modp, AstScope* scopep)
: m_scopeName(scopeName)
, m_varBasePretty(varBasePretty)
, m_varp(varp)
, m_modp(modp)
, m_scopep(scopep) {}
: m_scopeName{scopeName}
, m_varBasePretty{varBasePretty}
, m_varp{varp}
, m_modp{modp}
, m_scopep{scopep} {}
};
typedef std::map<string, ScopeFuncData> ScopeFuncs;
typedef std::map<string, ScopeVarData> ScopeVars;
@@ -94,8 +94,8 @@ class EmitCSyms : EmitCBaseVisitor {
};
// STATE
AstCFunc* m_funcp; // Current function
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp = 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
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
@@ -104,11 +104,11 @@ class EmitCSyms : EmitCBaseVisitor {
ScopeVars m_scopeVars; // Each {scope,public-var}
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
int m_coverBins; // Coverage bin number
int m_coverBins = 0; // Coverage bin number
bool m_dpiHdrOnly; // Only emit the DPI header
int m_numStmts; // Number of statements output
int m_funcNum; // CFunc split function number
V3OutCFile* m_ofpBase; // Base (not split) C file
int m_numStmts = 0; // Number of statements output
int m_funcNum = 0; // CFunc split function number
V3OutCFile* m_ofpBase = nullptr; // Base (not split) C file
std::map<int, bool> m_usesVfinal; // Split method uses __Vfinal
// METHODS
@@ -120,7 +120,7 @@ class EmitCSyms : EmitCBaseVisitor {
void emitDpiHdr();
void emitDpiImp();
void nameCheck(AstNode* nodep) {
static void nameCheck(AstNode* nodep) {
// Prevent GCC compile time error; name check all things that reach C++ code
if (nodep->name() != ""
&& !(VN_IS(nodep, CFunc)
@@ -139,7 +139,7 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
string scopeSymString(const string& scpname) {
static string scopeSymString(const string& scpname) {
string out = scpname;
string::size_type pos;
while ((pos = out.find("__PVT__")) != string::npos) out.replace(pos, 7, "");
@@ -150,7 +150,7 @@ class EmitCSyms : EmitCBaseVisitor {
return out;
}
string scopeDecodeIdentifier(const string& scpname) {
static string scopeDecodeIdentifier(const string& scpname) {
string out = scpname;
// Remove hierarchy
string::size_type pos = out.rfind('.');
@@ -168,7 +168,7 @@ class EmitCSyms : EmitCBaseVisitor {
void varHierarchyScopes(string scp) {
while (!scp.empty()) {
ScopeNames::const_iterator scpit = m_vpiScopeCandidates.find(scp);
const auto scpit = m_vpiScopeCandidates.find(scp);
if ((scpit != m_vpiScopeCandidates.end())
&& (m_scopeNames.find(scp) == m_scopeNames.end())) {
m_scopeNames.insert(make_pair(scpit->second.m_symName, scpit->second));
@@ -252,7 +252,7 @@ class EmitCSyms : EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
// Collect list of scopes
iterateChildren(nodep);
varsExpand();
@@ -274,16 +274,15 @@ class EmitCSyms : EmitCBaseVisitor {
if (!m_dpiHdrOnly) emitDpiImp();
}
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
nameCheck(nodep);
AstNodeModule* origModp = m_modp;
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
virtual void visit(AstCellInline* nodep) override {
if (v3Global.opt.vpi()) {
string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE";
string name = nodep->scopep()->name() + "__DOT__" + nodep->name();
@@ -293,7 +292,7 @@ class EmitCSyms : EmitCBaseVisitor {
make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type)));
}
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
nameCheck(nodep);
@@ -307,7 +306,7 @@ class EmitCSyms : EmitCBaseVisitor {
timeunit, "SCOPE_MODULE")));
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
virtual void visit(AstScopeName* nodep) override {
string name = nodep->scopeSymName();
// UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()
// <<" ss"<<name<<endl);
@@ -329,43 +328,32 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstVar* nodep) override {
nameCheck(nodep);
iterateChildren(nodep);
if (nodep->isSigUserRdPublic()
// The VPI functions require a pointer to allow modification,
// but parameters are constants
&& !nodep->isParam()) {
m_modVars.push_back(make_pair(m_modp, nodep));
}
if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); }
}
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
virtual void visit(AstCoverDecl* nodep) override {
// Assign numbers to all bins, so we know how big of an array to use
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
nodep->binNum(m_coverBins++);
}
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
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 = NULL;
m_funcp = nullptr;
}
//---------------------------------------
virtual void visit(AstConst*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstConst*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly)
: m_dpiHdrOnly(dpiHdrOnly) {
m_funcp = NULL;
m_modp = NULL;
m_coverBins = 0;
m_numStmts = 0;
m_funcNum = 0;
m_ofpBase = NULL;
: m_dpiHdrOnly{dpiHdrOnly} {
iterate(nodep);
}
};
@@ -501,14 +489,14 @@ void EmitCSyms::emitSymHdr() {
puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n");
ofp()->putsEndGuard();
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
}
void EmitCSyms::closeSplit() {
if (!m_ofp || m_ofp == m_ofpBase) return;
puts("}\n");
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
}
void EmitCSyms::checkSplit(bool usesVfinal) {
@@ -622,7 +610,7 @@ void EmitCSyms::emitSymImp() {
puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed
if (v3Global.needTraceDumper()) {
puts(" , __Vm_dumping(false)\n");
puts(" , __Vm_dumperp(NULL)\n");
puts(" , __Vm_dumperp(nullptr)\n");
}
if (v3Global.opt.trace()) {
puts(" , __Vm_activity(false)\n");
@@ -715,8 +703,8 @@ void EmitCSyms::emitSymImp() {
++lit) {
string fromname = scopeSymString(it->first);
string toname = scopeSymString(*lit);
ScopeNames::const_iterator from = m_scopeNames.find(fromname);
ScopeNames::const_iterator to = m_scopeNames.find(toname);
const auto from = vlstd::as_const(m_scopeNames).find(fromname);
const auto to = vlstd::as_const(m_scopeNames).find(toname);
UASSERT(from != m_scopeNames.end(), fromname + " not in m_scopeNames");
UASSERT(to != m_scopeNames.end(), toname + " not in m_scopeNames");
puts("__Vhier.add(");
@@ -794,16 +782,38 @@ void EmitCSyms::emitSymImp() {
}
puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,");
putsQuoted(protect(it->second.m_varBasePretty));
puts(", &(");
std::string varName;
if (modp->isTop()) {
puts(protectIf(scopep->nameDotless() + "p", scopep->protect()));
puts("->");
varName += (protectIf(scopep->nameDotless() + "p", scopep->protect()) + "->");
} else {
puts(protectIf(scopep->nameDotless(), scopep->protect()));
puts(".");
varName += (protectIf(scopep->nameDotless(), scopep->protect()) + ".");
}
puts(varp->nameProtect());
puts("), ");
if (varp->isParam()) {
varName += protect("var_" + varp->name());
} else {
varName += protect(varp->name());
}
if (varp->isParam()) {
if (varp->vlEnumType() == "VLVT_STRING") {
puts(", const_cast<void*>(static_cast<const void*>(");
puts(varName);
puts(".c_str())), ");
} else {
puts(", const_cast<void*>(static_cast<const void*>(&(");
puts(varName);
puts("))), ");
}
} else {
puts(", &(");
puts(varName);
puts("), ");
}
puts(varp->isParam() ? "true" : "false");
puts(", ");
puts(varp->vlEnumType()); // VLVT_UINT32 etc
puts(",");
puts(varp->vlEnumDir()); // VLVD_IN etc
@@ -818,7 +828,7 @@ void EmitCSyms::emitSymImp() {
m_ofpBase->puts("}\n");
closeSplit();
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
}
//######################################################################
@@ -848,8 +858,7 @@ void EmitCSyms::emitDpiHdr() {
int firstExp = 0;
int firstImp = 0;
for (std::vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) {
AstCFunc* nodep = *it;
for (AstCFunc* nodep : m_dpis) {
if (nodep->dpiExportWrapper()) {
if (!firstExp++) puts("\n// DPI EXPORTS\n");
puts("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n");
@@ -898,8 +907,7 @@ void EmitCSyms::emitDpiImp() {
puts("#include \"" + topClassName() + ".h\"\n");
puts("\n");
for (std::vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) {
AstCFunc* nodep = *it;
for (AstCFunc* nodep : m_dpis) {
if (nodep->dpiExportWrapper()) {
puts("#ifndef _VL_DPIDECL_" + nodep->name() + "\n");
puts("#define _VL_DPIDECL_" + nodep->name() + "\n");
+178 -31
View File
@@ -18,6 +18,7 @@
#include "verilatedos.h"
#include "V3Global.h"
#include "V3HierBlock.h"
#include "V3Os.h"
#include "V3EmitMk.h"
#include "V3EmitCBase.h"
@@ -46,11 +47,8 @@ public:
of.puts("# See " + v3Global.opt.prefix() + ".mk" + " for the caller.\n");
of.puts("\n### Switches...\n");
of.puts("# C11 constructs required? 0/1 (from --threads, "
"--trace-threads or use of classes)\n");
of.puts("VM_C11 = ");
of.puts(v3Global.needC11() || v3Global.opt.threads() ? "1" : "0");
of.puts("\n");
of.puts("# C11 constructs required? 0/1 (always on now)\n");
of.puts("VM_C11 = 1\n");
of.puts("# Coverage output mode? 0/1 (from --coverage)\n");
of.puts("VM_COVERAGE = ");
of.puts(v3Global.opt.coverage() ? "1" : "0");
@@ -67,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()));
@@ -94,7 +96,10 @@ public:
of.puts(support == 2 ? "VM_GLOBAL" : support == 1 ? "VM_SUPPORT" : "VM_CLASSES");
of.puts(slow ? "_SLOW" : "_FAST");
of.puts(" += \\\n");
if (support == 2 && !slow) {
if (support == 2 && v3Global.opt.hierChild()) {
// Do nothing because VM_GLOBAL is necessary per executable. Top module will
// have them.
} else if (support == 2 && !slow) {
putMakeClassEntry(of, "verilated.cpp");
if (v3Global.dpi()) { putMakeClassEntry(of, "verilated_dpi.cpp"); }
if (v3Global.opt.vpi()) { putMakeClassEntry(of, "verilated_vpi.cpp"); }
@@ -104,8 +109,9 @@ public:
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported "
"in SystemC, use VCD format.");
v3warn(E_UNSUPPORTED,
"Unsupported: This trace format is not supported "
"in SystemC, use VCD format.");
} else {
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
}
@@ -188,25 +194,20 @@ public:
of.puts("VM_USER_CFLAGS = \\\n");
if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n");
const V3StringList& cFlags = v3Global.opt.cFlags();
for (V3StringList::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
of.puts("\t" + *it + " \\\n");
}
for (const string& i : cFlags) of.puts("\t" + i + " \\\n");
of.puts("\n");
of.puts("# User LDLIBS (from -LDFLAGS on Verilator command line)\n");
of.puts("VM_USER_LDLIBS = \\\n");
const V3StringList& ldLibs = v3Global.opt.ldLibs();
for (V3StringList::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) {
of.puts("\t" + *it + " \\\n");
}
for (const string& i : ldLibs) of.puts("\t" + i + " \\\n");
of.puts("\n");
V3StringSet dirs;
of.puts("# User .cpp files (from .cpp's on Verilator command line)\n");
of.puts("VM_USER_CLASSES = \\\n");
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
for (const auto& cppfile : cppFiles) {
of.puts("\t" + V3Os::filenameNonExt(cppfile) + " \\\n");
string dir = V3Os::filenameDir(cppfile);
dirs.insert(dir);
@@ -215,14 +216,16 @@ public:
of.puts("# User .cpp directories (from .cpp's on Verilator command line)\n");
of.puts("VM_USER_DIR = \\\n");
for (V3StringSet::iterator it = dirs.begin(); it != dirs.end(); ++it) {
of.puts("\t" + *it + " \\\n");
}
for (const auto& i : dirs) of.puts("\t" + i + " \\\n");
of.puts("\n");
of.puts("\n### Default rules...\n");
of.puts("# Include list of all generated classes\n");
of.puts("include " + v3Global.opt.prefix() + "_classes.mk\n");
if (v3Global.opt.hierTop()) {
of.puts("# Include rules for hierarchical blocks\n");
of.puts("include " + v3Global.opt.prefix() + "_hier.mk\n");
}
of.puts("# Include global rules\n");
of.puts("include $(VERILATOR_ROOT)/include/verilated.mk\n");
@@ -230,8 +233,7 @@ public:
of.puts("\n### Executable rules... (from --exe)\n");
of.puts("VPATH += $(VM_USER_DIR)\n");
of.puts("\n");
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
for (const string& cppfile : cppFiles) {
string basename = V3Os::filenameNonExt(cppfile);
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
of.puts(basename + ".o: " + cppfile + "\n");
@@ -240,24 +242,39 @@ public:
of.puts("\n### Link rules... (from --exe)\n");
of.puts(v3Global.opt.exeName()
+ ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n");
+ ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a $(VM_HIER_LIBS)\n");
of.puts("\t$(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) $(LIBS) $(SC_LIBS) -o $@\n");
of.puts("\n");
}
if (!v3Global.opt.protectLib().empty()) {
const string protectLibDeps
= "$(VK_OBJS) $(VK_GLOBAL_OBJS) " + v3Global.opt.protectLib() + ".o";
const string protectLibDeps = "$(VK_OBJS) $(VK_GLOBAL_OBJS) "
+ v3Global.opt.protectLib() + ".o $(VM_HIER_LIBS)";
of.puts("\n### Library rules from --protect-lib\n");
// The rule to create .a is defined in verilated.mk, so just define dependency here.
of.puts(v3Global.opt.protectLibName(false) + ": " + protectLibDeps + "\n");
of.puts("\tar rc $@ $^\n");
of.puts("\n");
of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n");
of.puts("\n");
of.puts("lib" + v3Global.opt.protectLib() + ": " + v3Global.opt.protectLibName(false)
+ " " + v3Global.opt.protectLibName(true) + "\n");
if (v3Global.opt.hierChild()) {
// Hierarchical child does not need .so because hierTop() will create .so from .a
of.puts("lib" + v3Global.opt.protectLib() + ": "
+ v3Global.opt.protectLibName(false) + "\n");
} else {
of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n");
// Linker on mac emits an error if all symbols are not found here,
// but some symbols that are referred as "DPI-C" can not be found at this moment.
// So add dynamic_lookup
of.puts("ifeq ($(shell uname -s),Darwin)\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -undefined "
"dynamic_lookup -shared -flat_namespace -o $@ $^\n");
of.puts("else\n");
of.puts(
"\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n");
of.puts("endif\n");
of.puts("\n");
of.puts("lib" + v3Global.opt.protectLib() + ": "
+ v3Global.opt.protectLibName(false) + " "
+ v3Global.opt.protectLibName(true) + "\n");
}
}
of.puts("\n");
@@ -272,6 +289,131 @@ public:
virtual ~EmitMk() {}
};
//######################################################################
class EmitMkHierVerilation {
const V3HierBlockPlan* const m_planp;
const string m_makefile; // path of this makefile
void emitCommonOpts(V3OutMkFile& of) const {
const string cwd = V3Os::filenameRealPath(".");
of.puts("# Verilation of hierarchical blocks are executed in this directory\n");
of.puts("VM_HIER_RUN_DIR := " + cwd + "\n");
of.puts("# Common options for hierarchical blocks\n");
const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.bin());
const string perl_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
of.puts("VM_HIER_VERILATOR := " + perl_wrapper + "\n");
of.puts("VM_HIER_INPUT_FILES := \\\n");
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles) of.puts("\t" + V3Os::filenameRealPath(i) + " \\\n");
of.puts("\n");
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
of.puts("VM_HIER_VERILOG_LIBS := \\\n");
for (const string& i : libraryFiles) {
of.puts("\t" + V3Os::filenameRealPath(i) + " \\\n");
}
of.puts("\n");
}
void emitOpts(V3OutMkFile& of, const V3StringList& opts) const {
for (const string& i : opts) { of.puts("\t\t" + i + " \\\n"); }
}
void emitLaunchVerilator(V3OutMkFile& of, const string& argsFile) const {
of.puts("\t@$(MAKE) -C $(VM_HIER_RUN_DIR) -f " + m_makefile
+ " hier_launch_verilator \\\n");
of.puts("\t\tVM_HIER_LAUNCH_VERILATOR_ARGSFILE=\"" + argsFile + "\"\n");
}
void emit(V3OutMkFile& of) const {
of.puts("# Hierarchical Verilation -*- Makefile -*-\n");
of.puts("# DESCR"
"IPTION: Verilator output: Makefile for hierarchical verilatrion\n");
of.puts("#\n");
of.puts("# The main makefile " + v3Global.opt.prefix() + ".mk calls this makefile\n");
of.puts("\n");
of.puts("ifndef VM_HIER_VERILATION_INCLUDED\n");
of.puts("VM_HIER_VERILATION_INCLUDED = 1\n\n");
of.puts(".SUFFIXES:\n");
of.puts(".PHONY: hier_build hier_verilation hier_launch_verilator\n");
of.puts("# Libraries of hierarchical blocks\n");
of.puts("VM_HIER_LIBS := \\\n");
const V3HierBlockPlan::HierVector blocks
= m_planp->hierBlocksSorted(); // leaf comes first
// List in order of leaf-last order so that linker can resolve dependency
for (auto it = blocks.rbegin(); it != blocks.rend(); ++it) {
of.puts("\t" + (*it)->hierLib(true) + " \\\n");
}
of.puts("\n");
// Build hierarchical libraries as soon as possible to get maximum parallelism
of.puts("hier_build: $(VM_HIER_LIBS) " + v3Global.opt.prefix() + ".mk\n");
of.puts("\t$(MAKE) -f " + v3Global.opt.prefix() + ".mk\n");
of.puts("hier_verilation: " + v3Global.opt.prefix() + ".mk\n");
emitCommonOpts(of);
// Instead of direct execute of "cd $(VM_HIER_RUN_DIR) && $(VM_HIER_VERILATOR)",
// call via make to get message of "Entering directory" and "Leaving directory".
// This will make some editors and IDEs happy when viewing a logfile.
of.puts("# VM_HIER_LAUNCH_VERILATOR_ARGSFILE must be passed as a command argument\n");
of.puts("hier_launch_verilator:\n");
of.puts("\t$(VM_HIER_VERILATOR) -f $(VM_HIER_LAUNCH_VERILATOR_ARGSFILE)\n");
// Top level module
{
const string argsFile = v3Global.hierPlanp()->topCommandArgsFileName(false);
of.puts("\n# Verilate the top module\n");
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) + " ");
}
of.puts("\n");
emitLaunchVerilator(of, argsFile);
}
// Rules to process hierarchical blocks
of.puts("\n# Verilate hierarchical blocks\n");
for (V3HierBlockPlan::const_iterator it = m_planp->begin(); it != m_planp->end(); ++it) {
const string prefix = it->second->hierPrefix();
const string argsFile = it->second->commandArgsFileName(false);
of.puts(it->second->hierGenerated(true));
of.puts(": $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
of.puts(V3Os::filenameNonDir(argsFile) + " ");
const V3HierBlock::HierBlockSet& children = it->second->children();
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
child != children.end(); ++child) {
of.puts((*child)->hierWrapper(true) + " ");
}
of.puts("\n");
emitLaunchVerilator(of, argsFile);
// Rule to build lib*.a
of.puts(it->second->hierLib(true));
of.puts(": ");
of.puts(it->second->hierMk(true));
of.puts(" ");
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
child != children.end(); ++child) {
of.puts((*child)->hierLib(true));
of.puts(" ");
}
of.puts("\n\t$(MAKE) -f " + it->second->hierMk(false) + " -C " + prefix);
of.puts(" VM_PREFIX=" + prefix);
of.puts("\n\n");
}
of.puts("endif # Guard\n");
}
public:
explicit EmitMkHierVerilation(const V3HierBlockPlan* planp)
: m_planp{planp}
, m_makefile{v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_hier.mk"} {
V3OutMkFile of(m_makefile);
emit(of);
}
VL_DEBUG_FUNC; // Declare debug()
};
//######################################################################
// Gate class functions
@@ -279,3 +421,8 @@ void V3EmitMk::emitmk() {
UINFO(2, __FUNCTION__ << ": " << endl);
EmitMk emitter;
}
void V3EmitMk::emitHierVerilation(const V3HierBlockPlan* planp) {
UINFO(2, __FUNCTION__ << ": " << endl);
EmitMkHierVerilation emitter(planp);
}
+3
View File
@@ -20,11 +20,14 @@
#include "config_build.h"
#include "verilatedos.h"
class V3HierBlockPlan;
//============================================================================
class V3EmitMk {
public:
static void emitmk();
static void emitHierVerilation(const V3HierBlockPlan* planp);
};
#endif // Guard
+165 -161
View File
@@ -30,8 +30,9 @@
class EmitVBaseVisitor : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi;
AstSenTree* m_sensesp;
bool m_suppressSemi = false;
bool m_suppressUnknown = false;
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -51,13 +52,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
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(AstNodeFTask* nodep) VL_OVERRIDE {
virtual void visit(AstPort* nodep) override {}
virtual void visit(AstNodeFTask* nodep) override {
putfs(nodep, nodep->isFunction() ? "function" : "task");
puts(" ");
puts(nodep->prettyName());
@@ -68,7 +70,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putqs(nodep, "end\n");
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
virtual void visit(AstBegin* nodep) override {
if (nodep->name() == "") {
putbs("begin\n");
} else {
@@ -77,7 +79,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateChildren(nodep);
puts("end\n");
}
virtual void visit(AstFork* nodep) VL_OVERRIDE {
virtual void visit(AstFork* nodep) override {
if (nodep->name() == "") {
putbs("fork\n");
} else {
@@ -87,17 +89,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(nodep->joinType().verilogKwd());
puts("\n");
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
virtual void visit(AstFinal* nodep) override {
putfs(nodep, "final begin\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
virtual void visit(AstInitial* nodep) override {
putfs(nodep, "initial begin\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
virtual void visit(AstAlways* nodep) override {
putfs(nodep, "always ");
if (m_sensesp) {
iterateAndNextNull(m_sensesp);
@@ -109,7 +111,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
virtual void visit(AstAlwaysPublic* nodep) override {
putfs(nodep, "/*verilator public_flat_rw ");
if (m_sensesp) {
iterateAndNextNull(m_sensesp);
@@ -121,37 +123,37 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "*/\n");
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " " + nodep->verilogKwd() + " ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
virtual void visit(AstAssignDly* nodep) override {
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " <= ");
iterateAndNextNull(nodep->rhsp());
puts(";\n");
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
virtual void visit(AstAssignAlias* nodep) override {
putbs("alias ");
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " = ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
virtual void visit(AstAssignW* nodep) override {
putfs(nodep, "assign ");
iterateAndNextNull(nodep->lhsp());
putbs(" = ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
virtual void visit(AstBreak*) override {
putbs("break");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
virtual void visit(AstSenTree* nodep) override {
// AstSenItem is called for dumping in isolation by V3Order
putfs(nodep, "@(");
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
@@ -160,16 +162,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(")");
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp());
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
virtual void visit(AstSenItem* nodep) override {
putfs(nodep, "");
puts(nodep->edgeType().verilogKwd());
if (nodep->sensp()) puts(" ");
iterateChildren(nodep);
}
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCase* nodep) override {
putfs(nodep, "");
if (const AstCase* casep = VN_CAST(nodep, Case)) {
if (casep->priorityPragma()) puts("priority ");
@@ -190,7 +189,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->itemsp());
putqs(nodep, "endcase\n");
}
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
virtual void visit(AstCaseItem* nodep) override {
if (nodep->condsp()) {
iterateAndNextNull(nodep->condsp());
} else {
@@ -200,118 +199,116 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstComment* nodep) VL_OVERRIDE {
virtual void visit(AstComment* nodep) override {
puts(string("// ") + nodep->name() + "\n");
iterateChildren(nodep);
}
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
virtual void visit(AstContinue*) override {
putbs("continue");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstCoverDecl*) VL_OVERRIDE {} // N/A
virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A
virtual void visit(AstCoverDecl*) override {} // N/A
virtual void visit(AstCoverInc*) override {} // N/A
virtual void visit(AstCoverToggle*) override {} // N/A
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");
}
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
putbs("disable " + nodep->name() + ";\n");
}
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
virtual void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); }
virtual void visit(AstDisplay* nodep) override {
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, NULL, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
virtual void visit(AstElabDisplay* nodep) override {
visitNodeDisplay(nodep, nullptr, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstFScanF* nodep) VL_OVERRIDE {
virtual void visit(AstFScanF* nodep) override {
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSScanF* nodep) VL_OVERRIDE {
virtual void visit(AstSScanF* nodep) override {
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSFormat* nodep) VL_OVERRIDE {
virtual void visit(AstSFormat* nodep) override {
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
virtual void visit(AstSFormatF* nodep) override {
visitNodeDisplay(nodep, nullptr, nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
virtual void visit(AstFOpen* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs("(");
iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->modep());
puts(");\n");
}
virtual void visit(AstFOpenMcd* nodep) VL_OVERRIDE {
virtual void visit(AstFOpenMcd* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs("(");
iterateAndNextNull(nodep->filenamep());
puts(");\n");
}
virtual void visit(AstFClose* nodep) VL_OVERRIDE {
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) VL_OVERRIDE {
virtual void visit(AstFFlush* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE {
virtual void visit(AstJumpBlock* nodep) override {
putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n");
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
puts("end\n");
}
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
virtual void visit(AstJumpGo* nodep) override {
putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
}
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
virtual void visit(AstJumpLabel* nodep) override {
putbs("// " + cvtToStr(nodep->blockp()) + ":\n");
}
virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE {
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");
}
virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE {
virtual void visit(AstSysFuncAsTask* nodep) override {
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
virtual void visit(AstSysIgnore* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
iterateAndNextNull(nodep->exprsp());
puts(");\n");
}
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
virtual void visit(AstNodeFor* nodep) override {
putfs(nodep, "for (");
m_suppressSemi = true;
iterateAndNextNull(nodep->initsp());
@@ -324,14 +321,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstRepeat* nodep) VL_OVERRIDE {
virtual void visit(AstRepeat* nodep) override {
putfs(nodep, "repeat (");
iterateAndNextNull(nodep->countp());
puts(") begin\n");
iterateAndNextNull(nodep->bodysp());
putfs(nodep, "end\n");
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
virtual void visit(AstWhile* nodep) override {
iterateAndNextNull(nodep->precondsp());
putfs(nodep, "while (");
iterateAndNextNull(nodep->condp());
@@ -341,7 +338,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
putfs(nodep, "end\n");
}
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
virtual void visit(AstNodeIf* nodep) override {
putfs(nodep, "");
if (const AstIf* ifp = VN_CAST(nodep, If)) {
if (ifp->priorityPragma()) puts("priority ");
@@ -359,62 +356,62 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
putqs(nodep, "end\n");
}
virtual void visit(AstPast* nodep) VL_OVERRIDE {
virtual void visit(AstPast* nodep) override {
putfs(nodep, "$past(");
iterateAndNextNull(nodep->exprp());
if (nodep->ticksp()) {
puts(",");
puts(", ");
iterateAndNextNull(nodep->ticksp());
}
puts(")");
}
virtual void visit(AstReturn* nodep) VL_OVERRIDE {
virtual void visit(AstReturn* nodep) override {
putfs(nodep, "return ");
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstStop* nodep) VL_OVERRIDE { putfs(nodep, "$stop;\n"); }
virtual void visit(AstFinish* nodep) VL_OVERRIDE { putfs(nodep, "$finish;\n"); }
virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE {
virtual void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); }
virtual void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); }
virtual void visit(AstNodeSimpleText* nodep) override {
if (nodep->tracking() || m_trackText) {
puts(nodep->text());
} else {
putsNoTracking(nodep->text());
}
}
virtual void visit(AstTextBlock* nodep) VL_OVERRIDE {
virtual void visit(AstTextBlock* nodep) override {
visit(VN_CAST(nodep, NodeSimpleText));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {}
virtual void visit(AstCStmt* nodep) VL_OVERRIDE {
virtual void visit(AstScopeName* nodep) override {}
virtual void visit(AstCStmt* nodep) override {
putfs(nodep, "$_CSTMT(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstCMath* nodep) VL_OVERRIDE {
virtual void visit(AstCMath* nodep) override {
putfs(nodep, "$_CMATH(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
virtual void visit(AstUCStmt* nodep) override {
putfs(nodep, "$c(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstUCFunc* nodep) override {
putfs(nodep, "$c(");
iterateAndNextNull(nodep->bodysp());
puts(")");
}
// Operators
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = NULL,
AstNode* rhsp = NULL, AstNode* thsp = NULL,
AstNode* fhsp = NULL) {
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr,
AstNode* rhsp = nullptr, AstNode* thsp = nullptr,
AstNode* fhsp = nullptr) {
// Look at emitVerilog() format for term/uni/dual/triops,
// and write out appropriate text.
// %f Potential fileline-if-change and line break
@@ -426,16 +423,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
// %k Potential line break
bool inPct = false;
putbs("");
for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
if (pos[0] == '%') {
for (const char c : format) {
if (c == '%') {
inPct = true;
} else if (!inPct) { // Normal text
string s;
s += pos[0];
s += c;
puts(s);
} else { // Format character
inPct = false;
switch (*pos) {
switch (c) {
case '%': puts("%"); break;
case 'f': putfs(nodep, ""); break;
case 'k': putbs(""); break;
@@ -464,35 +461,35 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->dtypep());
break;
}
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << pos[0]); break;
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << c); break;
}
}
}
}
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeTermop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog());
}
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeUniop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeBiop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
virtual void visit(AstNodeTriop* nodep) override {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(),
nodep->thsp());
}
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
virtual void visit(AstAttrOf* nodep) override {
putfs(nodep, "$_ATTROF(");
iterateAndNextNull(nodep->fromp());
if (nodep->dimp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->dimp());
}
puts(")");
}
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
virtual void visit(AstInitArray* nodep) override {
putfs(nodep, "`{");
int comma = 0;
const AstInitArray::KeyItemMap& mapr = nodep->map();
@@ -505,7 +502,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts("}");
}
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCond* nodep) override {
putbs("(");
iterateAndNextNull(nodep->condp());
putfs(nodep, " ? ");
@@ -514,7 +511,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->expr2p());
puts(")");
}
virtual void visit(AstRange* nodep) VL_OVERRIDE {
virtual void visit(AstRange* nodep) override {
puts("[");
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
@@ -529,7 +526,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts("]");
}
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
virtual void visit(AstSel* nodep) override {
iterateAndNextNull(nodep->fromp());
puts("[");
if (VN_IS(nodep->lsbp(), Const)) {
@@ -553,18 +550,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts("]");
}
virtual void visit(AstSliceSel* nodep) VL_OVERRIDE {
virtual void visit(AstSliceSel* nodep) override {
iterateAndNextNull(nodep->fromp());
puts(cvtToStr(nodep->declRange()));
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
virtual void visit(AstTypedef* nodep) override {
putfs(nodep, "typedef ");
iterateAndNextNull(nodep->dtypep());
puts(" ");
puts(nodep->prettyName());
puts(";\n");
}
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
virtual void visit(AstBasicDType* nodep) override {
if (nodep->isSigned()) putfs(nodep, "signed ");
putfs(nodep, nodep->prettyName());
if (nodep->rangep()) {
@@ -577,28 +574,28 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(":0] ");
}
}
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
virtual void visit(AstConstDType* nodep) override {
putfs(nodep, "const ");
iterate(nodep->subDTypep());
}
virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE {
virtual void visit(AstNodeArrayDType* nodep) override {
iterate(nodep->subDTypep());
iterateAndNextNull(nodep->rangep());
}
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
virtual void visit(AstNodeUOrStructDType* nodep) override {
puts(nodep->verilogKwd() + " ");
if (nodep->packed()) puts("packed ");
puts("\n");
iterateAndNextNull(nodep->membersp());
puts("}");
}
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
virtual void visit(AstMemberDType* nodep) override {
iterate(nodep->subDTypep());
puts(" ");
puts(nodep->name());
puts("}");
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeFTaskRef* nodep) override {
if (nodep->dotted() != "") {
putfs(nodep, nodep->dotted());
puts(".");
@@ -610,9 +607,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->pinsp());
puts(")");
}
virtual void visit(AstArg* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->exprp()); }
virtual void visit(AstArg* nodep) override { iterateAndNextNull(nodep->exprp()); }
// Terminals
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
if (nodep->varScopep()) {
putfs(nodep, nodep->varScopep()->prettyName());
} else {
@@ -620,19 +617,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(nodep->varp()->prettyName());
}
}
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarXRef* nodep) override {
putfs(nodep, nodep->dotted());
puts(".");
puts(nodep->varp()->prettyName());
}
virtual void visit(AstConst* nodep) VL_OVERRIDE {
putfs(nodep, nodep->num().ascii(true, true));
}
virtual void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); }
// Just iterate
virtual void visit(AstTopScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstTopScope* nodep) override { iterateChildren(nodep); }
virtual void visit(AstScope* nodep) override { iterateChildren(nodep); }
virtual void visit(AstVar* nodep) override {
putfs(nodep, nodep->verilogKwd());
puts(" ");
iterate(nodep->dtypep());
@@ -644,35 +639,35 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts("\n");
}
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
m_sensesp = nodep->sensesp();
iterateAndNextNull(nodep->stmtsp());
m_sensesp = NULL;
m_sensesp = nullptr;
}
virtual void visit(AstVarScope*) VL_OVERRIDE {}
virtual void visit(AstNodeText*) VL_OVERRIDE {}
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
virtual void visit(AstVarScope*) override {}
virtual void visit(AstNodeText*) override {}
virtual void visit(AstTraceDecl*) override {}
virtual void visit(AstTraceInc*) override {}
// NOPs
virtual void visit(AstPragma*) VL_OVERRIDE {}
virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class
virtual void visit(AstPragma*) override {}
virtual void visit(AstCell*) override {} // Handled outside the Visit class
// Default
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
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; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(AstSenTree* domainp = NULL) {
// Domain for printing one a ALWAYS under a ACTIVE
m_suppressSemi = false;
m_suppressVarSemi = false;
m_sensesp = domainp;
}
virtual ~EmitVBaseVisitor() {}
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
: m_suppressUnknown{suppressUnknown}
, m_sensesp{domainp} {}
virtual ~EmitVBaseVisitor() override {}
};
//######################################################################
@@ -683,21 +678,22 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
V3OutFile* m_ofp;
// METHODS
V3OutFile* ofp() const { return m_ofp; }
virtual void puts(const string& str) { ofp()->puts(str); }
virtual void putbs(const string& str) { ofp()->putbs(str); }
virtual void putfs(AstNode*, const string& str) { putbs(str); }
virtual void putqs(AstNode*, const string& str) { putbs(str); }
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
virtual void puts(const string& str) override { ofp()->puts(str); }
virtual void putbs(const string& str) override { ofp()->putbs(str); }
virtual void putfs(AstNode*, const string& str) override { putbs(str); }
virtual void putqs(AstNode*, const string& str) override { putbs(str); }
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;
iterate(nodep);
}
virtual ~EmitVFileVisitor() {}
virtual ~EmitVFileVisitor() override {}
};
//######################################################################
@@ -707,18 +703,19 @@ class EmitVStreamVisitor : public EmitVBaseVisitor {
// MEMBERS
std::ostream& m_os;
// METHODS
virtual void putsNoTracking(const string& str) { m_os << str; }
virtual void puts(const string& str) { putsNoTracking(str); }
virtual void putbs(const string& str) { puts(str); }
virtual void putfs(AstNode*, const string& str) { putbs(str); }
virtual void putqs(AstNode*, const string& str) { putbs(str); }
virtual void putsNoTracking(const string& str) override { m_os << str; }
virtual void puts(const string& str) override { putsNoTracking(str); }
virtual void putbs(const string& str) override { puts(str); }
virtual void putfs(AstNode*, const string& str) override { putbs(str); }
virtual void putqs(AstNode*, const string& str) override { putbs(str); }
public:
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
: m_os(os) {
: EmitVBaseVisitor{false, nullptr}
, m_os(os) { // Need () or GCC 4.8 false warning
iterate(nodep);
}
virtual ~EmitVStreamVisitor() {}
virtual ~EmitVStreamVisitor() override {}
};
//######################################################################
@@ -731,7 +728,7 @@ class EmitVPrefixedFormatter : public V3OutFormatter {
int m_column; // Rough location; need just zero or non-zero
FileLine* m_prefixFl;
// METHODS
virtual void putcOutput(char chr) {
virtual void putcOutput(char chr) override {
if (chr == '\n') {
m_column = 0;
m_os << chr;
@@ -753,15 +750,15 @@ public:
FileLine* prefixFl() const { return m_prefixFl; }
int column() const { return m_column; }
EmitVPrefixedFormatter(std::ostream& os, const string& prefix, int flWidth)
: V3OutFormatter("__STREAM", V3OutFormatter::LA_VERILOG)
, m_os(os)
, m_prefix(prefix)
, m_flWidth(flWidth) {
: V3OutFormatter{"__STREAM", V3OutFormatter::LA_VERILOG}
, m_os(os) // Need () or GCC 4.8 false warning
, m_prefix{prefix}
, m_flWidth{flWidth} {
m_column = 0;
m_prefixFl = v3Global.rootp()
->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
// avoid nullptr checks
}
virtual ~EmitVPrefixedFormatter() {
virtual ~EmitVPrefixedFormatter() override {
if (m_column) puts("\n");
}
};
@@ -771,13 +768,13 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the
// inheritance is another unused V3OutFormatter)
// METHODS
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) { m_formatter.puts(str); }
virtual void putsNoTracking(const string& str) override { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) override { m_formatter.puts(str); }
// We don't use m_formatter's putbs because the tokens will change filelines
// and insert returns at the proper locations
virtual void putbs(const string& str) { m_formatter.puts(str); }
virtual void putfs(AstNode* nodep, const string& str) { putfsqs(nodep, str, false); }
virtual void putqs(AstNode* nodep, const string& str) { putfsqs(nodep, str, true); }
virtual void putbs(const string& str) override { m_formatter.puts(str); }
virtual void putfs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, false); }
virtual void putqs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, true); }
void putfsqs(AstNode* nodep, const string& str, bool quiet) {
if (m_formatter.prefixFl() != nodep->fileline()) {
m_formatter.prefixFl(nodep->fileline());
@@ -790,12 +787,12 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp)
, m_formatter(os, prefix, flWidth) {
: EmitVBaseVisitor{false, domainp}
, m_formatter{os, prefix, flWidth} {
if (user3mark) { AstUser3InUse::check(); }
iterate(nodep);
}
virtual ~EmitVPrefixedVisitor() {}
virtual ~EmitVPrefixedVisitor() override {}
};
//######################################################################
@@ -817,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
+40 -45
View File
@@ -35,7 +35,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
// MEMBERS
V3OutFile* m_ofp;
uint64_t m_id;
uint64_t m_id = 0;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -100,11 +100,11 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
// VISITORS
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
virtual void visit(AstAssignW* nodep) override {
outputTag(nodep, "contassign"); // IEEE: vpiContAssign
outputChildrenEnd(nodep, "contassign");
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
virtual void visit(AstCell* nodep) override {
outputTag(nodep, "instance"); // IEEE: vpiInstance
puts(" defName=");
putsQuoted(nodep->modName()); // IEEE vpiDefName
@@ -112,12 +112,12 @@ class EmitXmlFileVisitor : public AstNVisitor {
putsQuoted(nodep->origName());
outputChildrenEnd(nodep, "instance");
}
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
puts("<netlist>\n");
iterateChildren(nodep);
puts("</netlist>\n");
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
outputTag(nodep, "");
puts(" origName=");
putsQuoted(nodep->origName());
@@ -127,7 +127,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
if (nodep->modPublic()) puts(" public=\"true\"");
outputChildrenEnd(nodep, "");
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
virtual void visit(AstVar* nodep) override {
AstVarType typ = nodep->varType();
string kw = nodep->verilogKwd();
string vt = nodep->dtypep()->name();
@@ -144,25 +144,26 @@ class EmitXmlFileVisitor : public AstNVisitor {
puts(" origName=");
putsQuoted(nodep->origName());
// Attributes
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES)
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
puts(" clocker=\"true\"");
else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO)
} else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO) {
puts(" clocker=\"false\"");
}
if (nodep->attrClockEn()) puts(" clock_enable=\"true\"");
if (nodep->attrIsolateAssign()) puts(" isolate_assignments=\"true\"");
if (nodep->isSigPublic()) puts(" public=\"true\"");
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
if (nodep->isGParam())
if (nodep->isGParam()) {
puts(" param=\"true\"");
else if (nodep->isParam())
} else if (nodep->isParam()) {
puts(" localparam=\"true\"");
}
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
if (nodep->attrScClocked()) puts(" sc_clock=\"true\"");
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
outputChildrenEnd(nodep, "");
}
virtual void visit(AstPin* nodep) VL_OVERRIDE {
virtual void visit(AstPin* nodep) override {
// What we call a pin in verilator is a port in the IEEE spec.
outputTag(nodep, "port"); // IEEE: vpiPort
if (nodep->modVarp()->isIO()) {
@@ -172,12 +173,12 @@ class EmitXmlFileVisitor : public AstNVisitor {
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
outputChildrenEnd(nodep, "port");
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
virtual void visit(AstSenItem* nodep) override {
outputTag(nodep, "");
puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule
outputChildrenEnd(nodep, "");
}
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstModportVarRef* nodep) override {
// Dump direction for Modport references
string kw = nodep->direction().xmlKwd();
outputTag(nodep, "");
@@ -185,7 +186,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
putsQuoted(kw);
outputChildrenEnd(nodep, "");
}
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarXRef* nodep) override {
outputTag(nodep, "");
puts(" dotted=");
putsQuoted(nodep->dotted());
@@ -193,7 +194,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
// Data types
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
virtual void visit(AstBasicDType* nodep) override {
outputTag(nodep, "basicdtype");
if (nodep->isRanged()) {
puts(" left=\"" + cvtToStr(nodep->left()) + "\"");
@@ -201,7 +202,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
puts("/>\n");
}
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
virtual void visit(AstIfaceRefDType* nodep) override {
string mpn;
outputTag(nodep, "");
if (nodep->isModport()) mpn = nodep->modportName();
@@ -209,19 +210,19 @@ class EmitXmlFileVisitor : public AstNVisitor {
putsQuoted(mpn);
outputChildrenEnd(nodep, "");
}
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
virtual void visit(AstDisplay* nodep) override {
outputTag(nodep, "");
puts(" displaytype=");
putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, "");
}
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
virtual void visit(AstElabDisplay* nodep) override {
outputTag(nodep, "");
puts(" displaytype=");
putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, "");
}
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
virtual void visit(AstExtend* nodep) override {
outputTag(nodep, "");
puts(" width=");
putsQuoted(cvtToStr(nodep->width()));
@@ -229,7 +230,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
outputChildrenEnd(nodep, "");
}
virtual void visit(AstExtendS* nodep) VL_OVERRIDE {
virtual void visit(AstExtendS* nodep) override {
outputTag(nodep, "");
puts(" width=");
putsQuoted(cvtToStr(nodep->width()));
@@ -239,18 +240,17 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
// Default
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
outputTag(nodep, "");
outputChildrenEnd(nodep, "");
}
public:
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) {
m_ofp = ofp;
m_id = 0;
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp)
: m_ofp{ofp} {
iterate(nodep);
}
virtual ~EmitXmlFileVisitor() {}
virtual ~EmitXmlFileVisitor() override {}
};
//######################################################################
@@ -267,11 +267,11 @@ private:
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
// Children are iterated backwards to ensure correct compilation order
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
// Only list modules and interfaces
// Assumes modules and interfaces list is already sorted level wise
if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
@@ -280,28 +280,25 @@ private:
}
}
//-----
virtual void visit(AstNode*) VL_OVERRIDE {
virtual void visit(AstNode*) override {
// All modules are present at root so no need to iterate on children
}
public:
// CONSTRUCTORS
ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os)
: m_os(os)
, m_modulesCovered()
, m_nodeModules() {
: m_os(os) { // Need () or GCC 4.8 false warning
// Operate on whole netlist
nodep->accept(*this);
// Xml output
m_os << "<module_files>\n";
for (std::deque<FileLine*>::iterator it = m_nodeModules.begin(); it != m_nodeModules.end();
++it) {
m_os << "<file id=\"" << (*it)->filenameLetters() << "\" filename=\""
<< (*it)->filename() << "\" language=\"" << (*it)->language().ascii() << "\"/>\n";
for (const FileLine* ifp : m_nodeModules) {
m_os << "<file id=\"" << ifp->filenameLetters() << "\" filename=\"" << ifp->filename()
<< "\" language=\"" << ifp->language().ascii() << "\"/>\n";
}
m_os << "</module_files>\n";
}
virtual ~ModuleFilesXmlVisitor() {}
virtual ~ModuleFilesXmlVisitor() override {}
};
//######################################################################
@@ -312,13 +309,13 @@ private:
// MEMBERS
std::ostream& m_os;
std::string m_hier;
bool m_hasChildren;
bool m_hasChildren = false;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
if (nodep->level() >= 0
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
m_os << "<cells>\n";
@@ -337,7 +334,7 @@ private:
m_os << "</cells>\n";
}
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
virtual void visit(AstCell* nodep) override {
if (nodep->modp()->dead()) { return; }
if (!m_hasChildren) m_os << ">\n";
m_os << "<cell " << nodep->fileline()->xml() << " "
@@ -357,18 +354,16 @@ private:
m_hasChildren = true;
}
//-----
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os)
: m_os(os)
, m_hier("")
, m_hasChildren(false) {
: m_os(os) { // Need () or GCC 4.8 false warning
// Operate on whole netlist
nodep->accept(*this);
}
virtual ~HierCellsXmlVisitor() {}
virtual ~HierCellsXmlVisitor() override {}
};
//######################################################################
+4 -6
View File
@@ -40,7 +40,7 @@ bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX];
bool V3Error::s_describedWarnings = false;
bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX];
V3Error::MessagesSet V3Error::s_messages;
V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
V3Error::ErrorExitCb V3Error::s_errorExitCb = nullptr;
struct v3errorIniter {
v3errorIniter() { V3Error::init(); }
@@ -174,12 +174,10 @@ void V3Error::vlAbort() {
// Global Functions
void V3Error::suppressThisWarning() {
if (s_errorCode >= V3ErrorCode::EC_MIN) {
#ifndef _V3ERROR_NO_GLOBAL_
V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1);
V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1);
#endif
s_errorSuppressed = true;
}
s_errorSuppressed = true;
}
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
@@ -212,7 +210,7 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
s_messages.insert(msg);
if (!locationStr.empty()) {
string locationMsg = warnMore() + locationStr + "\n";
size_t pos = msg.find("\n");
size_t pos = msg.find('\n');
msg.insert(pos + 1, locationMsg);
}
// Output
+17 -11
View File
@@ -35,7 +35,7 @@
class V3ErrorCode {
public:
// clang-format off
enum en {
enum en: uint8_t {
EC_MIN=0, // Keep first
//
EC_INFO, // General information out
@@ -44,6 +44,7 @@ public:
EC_FATALSRC, // Kill the program, for internal source errors
EC_ERROR, // General error out, can't suppress
// Boolean information we track per-line, but aren't errors
I_CELLDEFINE, // Inside cell define from `celldefine/`endcelldefine
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
I_LINT, // All lint messages
@@ -51,6 +52,7 @@ public:
// Error codes:
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
E_UNSUPPORTED, // Error: Unsupported (generally)
E_TASKNSVAR, // Error: Task I/O not simple
//
// Warning codes:
@@ -78,6 +80,7 @@ public:
DEPRECATED, // Feature will be deprecated
ENDLABEL, // End lable name mismatch
GENCLK, // Generated Clock
HIERBLOCK, // Ignored hierarchical block setting
IFDEPTH, // If statements too deep
IGNOREDRETURN, // Ignoring return value (function as task)
IMPERFECTSCH, // Imperfect schedule (disabled by default)
@@ -95,6 +98,7 @@ public:
PINMISSING, // Cell pin not specified
PINNOCONNECT, // Cell pin not connected
PINCONNECTEMPTY,// Cell pin connected by name with empty reference
PKGNODECL, // Error: Package/class needs to be predeclared
PROCASSWIRE, // Procedural assignment on wire
REALCVT, // Real conversion
REDEFMACRO, // Redefining existing define macro
@@ -126,13 +130,13 @@ public:
// clang-format on
enum en m_e;
inline V3ErrorCode()
: m_e(EC_MIN) {}
: m_e{EC_MIN} {}
// cppcheck-suppress noExplicitConstructor
inline V3ErrorCode(en _e)
: m_e(_e) {}
: m_e{_e} {}
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
explicit inline V3ErrorCode(int _e)
: m_e(static_cast<en>(_e)) {}
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
const char* ascii() const {
// clang-format off
@@ -140,9 +144,9 @@ public:
// Leading spaces indicate it can't be disabled.
" MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR",
// Boolean
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
" I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
// Errors
"DETECTARRAY", "PORTSHORT", "TASKNSVAR",
"DETECTARRAY", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR",
// Warnings
" EC_FIRST_WARN",
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
@@ -150,13 +154,13 @@ public:
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CLKDATA",
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
"DEFPARAM", "DECLFILENAME", "DEPRECATED",
"ENDLABEL", "GENCLK",
"ENDLABEL", "GENCLK", "HIERBLOCK",
"IFDEPTH", "IGNOREDRETURN",
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
"LITENDIAN", "MODDUP",
"MULTIDRIVEN", "MULTITOP",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PKGNODECL", "PROCASSWIRE",
"REALCVT", "REDEFMACRO",
"SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"TICKCOUNT", "TIMESCALEMOD",
@@ -170,14 +174,16 @@ public:
return names[m_e];
}
// Warnings that default to off
bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); }
bool defaultsOff() const {
return (m_e == IMPERFECTSCH || m_e == I_CELLDEFINE || styleError());
}
// Warnings that warn about nasty side effects
bool dangerous() const { return (m_e == COMBDLY); }
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const {
return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG
|| m_e == IMPURE || m_e == PROCASSWIRE //
|| m_e == IMPURE || m_e == PKGNODECL || m_e == PROCASSWIRE //
|| m_e == TIMESCALEMOD); // Says IEEE
}
// Warnings to mention manual
@@ -234,7 +240,7 @@ private:
static MessagesSet s_messages; // What errors we've outputted
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
static constexpr unsigned MAX_ERRORS = 50; // Fatal after this may errors
V3Error() {
std::cerr << ("Static class");
+34 -37
View File
@@ -44,7 +44,7 @@ private:
AstUser1InUse m_inuser1;
// STATE
AstNode* m_stmtp; // Current statement
AstNode* m_stmtp = nullptr; // Current statement
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -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());
@@ -206,8 +206,8 @@ private:
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
if (rhsp->num().isFourState()) {
rhsp->v3error( // LCOV_EXCL_LINE // impossible?
"Unsupported: 4-state numbers in this context");
rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible?
"Unsupported: 4-state numbers in this context");
}
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(
@@ -292,7 +292,7 @@ private:
}
// VISITORS
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
virtual void visit(AstExtend* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->isWide()) {
@@ -318,7 +318,7 @@ private:
}
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
virtual void visit(AstSel* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
@@ -341,7 +341,7 @@ private:
AstNode* lowp = new AstShiftR(nodep->fileline(), lowwordp, newSelBitBit(nodep->lsbp()),
nodep->width());
// If > 1 bit, we might be crossing the word boundary
AstNode* midp = NULL;
AstNode* midp = nullptr;
V3Number zero(nodep, longOrQuadWidth(nodep));
if (nodep->widthConst() > 1) {
AstNode* midwordp = // SEL(from,[1+wordnum])
@@ -378,7 +378,7 @@ private:
}
}
// If > 32 bits, we might be crossing the second word boundary
AstNode* hip = NULL;
AstNode* hip = nullptr;
if (nodep->widthConst() > VL_EDATASIZE) {
AstNode* hiwordp = // SEL(from,[2+wordnum])
newWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
@@ -600,7 +600,7 @@ private:
}
}
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
virtual void visit(AstConcat* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->isWide()) {
@@ -642,7 +642,7 @@ private:
return true;
}
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
virtual void visit(AstReplicate* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->isWide()) {
@@ -705,16 +705,16 @@ private:
return true;
}
virtual void visit(AstChangeXor* nodep) VL_OVERRIDE {
virtual void visit(AstChangeXor* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
UINFO(8, " Wordize ChangeXor " << nodep << endl);
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
AstNode* newp = NULL;
AstNode* newp = nullptr;
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
newAstWordSelClone(nodep->rhsp(), w));
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
newp = (newp == nullptr) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
@@ -725,11 +725,11 @@ private:
if (nodep->lhsp()->isWide()) {
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
AstNode* newp = NULL;
AstNode* newp = nullptr;
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
newAstWordSelClone(nodep->rhsp(), w));
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
newp = (newp == nullptr) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
if (VN_IS(nodep, Neq)) {
newp
@@ -742,19 +742,19 @@ private:
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
virtual void visit(AstEq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
virtual void visit(AstNeq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
virtual void visit(AstEq* nodep) override { visitEqNeq(nodep); }
virtual void visit(AstNeq* nodep) override { visitEqNeq(nodep); }
virtual void visit(AstRedOr* nodep) VL_OVERRIDE {
virtual void visit(AstRedOr* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8, " Wordize REDOR " << nodep << endl);
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
AstNode* newp = NULL;
AstNode* newp = nullptr;
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
newp = (newp == nullptr) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
newp = new AstNeq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
@@ -769,13 +769,13 @@ private:
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
virtual void visit(AstRedAnd* nodep) VL_OVERRIDE {
virtual void visit(AstRedAnd* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8, " Wordize REDAND " << nodep << endl);
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
AstNode* newp = NULL;
AstNode* newp = nullptr;
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
if (w == nodep->lhsp()->widthWords() - 1) {
@@ -787,7 +787,7 @@ private:
// cppcheck-suppress memleak
eqp);
}
newp = (newp == NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
newp = (newp == nullptr) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
}
newp = new AstEq(
nodep->fileline(),
@@ -802,16 +802,16 @@ private:
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
virtual void visit(AstRedXor* nodep) VL_OVERRIDE {
virtual void visit(AstRedXor* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8, " Wordize REDXOR " << nodep << endl);
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
AstNode* newp = NULL;
AstNode* newp = nullptr;
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
newp = (newp == NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
newp = (newp == nullptr) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
}
newp = new AstRedXor(nodep->fileline(), newp);
UINFO(8, " Wordize REDXORnew " << newp << endl);
@@ -821,7 +821,7 @@ private:
// which the inlined function does nicely.
}
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
virtual void visit(AstNodeStmt* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (!nodep->isStatement()) {
iterateChildren(nodep);
@@ -829,9 +829,9 @@ private:
}
m_stmtp = nodep;
iterateChildren(nodep);
m_stmtp = NULL;
m_stmtp = nullptr;
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
m_stmtp = nodep;
iterateChildren(nodep);
@@ -869,20 +869,17 @@ private:
}
// Cleanup common code
if (did) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
m_stmtp = NULL;
m_stmtp = nullptr;
}
//--------------------
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ExpandVisitor(AstNetlist* nodep) {
m_stmtp = NULL;
iterate(nodep);
}
virtual ~ExpandVisitor() {}
explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ExpandVisitor() override {}
};
//----------------------------------------------------------------------
+61 -79
View File
@@ -56,8 +56,8 @@
// If change this code, run a test with the below size set very small
//#define INFILTER_IPC_BUFSIZ 16
#define INFILTER_IPC_BUFSIZ (64 * 1024) // For debug, try this as a small number
#define INFILTER_CACHE_MAX (64 * 1024) // Maximum bytes to cache if same file read twice
constexpr int INFILTER_IPC_BUFSIZ = (64 * 1024); // For debug, try this as a small number
constexpr int INFILTER_CACHE_MAX = (64 * 1024); // Maximum bytes to cache if same file read twice
//######################################################################
// V3File Internal state
@@ -72,9 +72,9 @@ class V3FileDependImp {
struct stat m_stat; // Stat information
public:
DependFile(const string& filename, bool target)
: m_target(target)
, m_exists(true)
, m_filename(filename) {
: m_target{target}
, m_exists{true}
, m_filename{filename} {
m_stat.st_ctime = 0;
m_stat.st_mtime = 0;
}
@@ -146,29 +146,26 @@ V3FileDependImp dependImp; // Depend implementation class
// V3FileDependImp
inline void V3FileDependImp::writeDepend(const string& filename) {
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
if (ofp->fail()) v3fatal("Can't write " << filename);
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
iter != m_filenameList.end(); ++iter) {
if (iter->target()) { *ofp << iter->filename() << " "; }
for (const DependFile& i : m_filenameList) {
if (i.target()) *ofp << i.filename() << " ";
}
*ofp << " : ";
*ofp << v3Global.opt.bin();
*ofp << " ";
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
iter != m_filenameList.end(); ++iter) {
if (!iter->target()) { *ofp << iter->filename() << " "; }
for (const DependFile& i : m_filenameList) {
if (!i.target()) *ofp << i.filename() << " ";
}
*ofp << endl;
if (v3Global.opt.makePhony()) {
*ofp << endl;
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
iter != m_filenameList.end(); ++iter) {
if (!iter->target()) { *ofp << iter->filename() << ":" << endl; }
for (const DependFile& i : m_filenameList) {
if (!i.target()) *ofp << i.filename() << ":" << endl;
}
}
}
@@ -183,7 +180,7 @@ inline std::vector<string> V3FileDependImp::getAllDeps() const {
}
inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) {
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
if (ofp->fail()) v3fatal("Can't write " << filename);
string cmdline = stripQuotes(cmdlineIn);
@@ -219,7 +216,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
}
inline bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) {
const vl_unique_ptr<std::ifstream> ifp(V3File::new_ifstream_nodepend(filename));
const std::unique_ptr<std::ifstream> ifp(V3File::new_ifstream_nodepend(filename));
if (ifp->fail()) {
UINFO(2, " --check-times failed: no input " << filename << endl);
return false;
@@ -326,6 +323,7 @@ void V3File::createMakeDir() {
if (!created) {
created = true;
V3Os::createDir(v3Global.opt.makeDir());
if (v3Global.opt.hierTop()) { V3Os::createDir(v3Global.opt.hierTopDataDir()); }
}
}
@@ -337,16 +335,16 @@ class VInFilterImp {
typedef VInFilter::StrList StrList;
FileContentsMap m_contentsMap; // Cache of file contents
bool m_readEof; // Received EOF on read
bool m_readEof = false; // Received EOF on read
#ifdef INFILTER_PIPE
pid_t m_pid; // fork() process id
pid_t m_pid = 0; // fork() process id
#else
int m_pid; // fork() process id - always zero as disabled
int m_pid = 0; // fork() process id - always zero as disabled
#endif
bool m_pidExited;
int m_pidStatus;
int m_writeFd; // File descriptor TO filter
int m_readFd; // File descriptor FROM filter
bool m_pidExited = false;
int m_pidStatus = 0;
int m_writeFd = 0; // File descriptor TO filter
int m_readFd = 0; // File descriptor FROM filter
private:
// METHODS
@@ -522,7 +520,7 @@ private:
dup2(fd_stdout[P_WR], 1);
// And stderr comes from parent
execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char*>(NULL));
execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char*>(nullptr));
// Don't use v3fatal, we don't share the common structures any more
fprintf(stderr, "--pipe-filter: exec failed: %s\n", strerror(errno));
_exit(1);
@@ -575,7 +573,7 @@ protected:
friend class VInFilter;
// Read file contents and return it
bool readWholefile(const string& filename, StrList& outl) {
FileContentsMap::iterator it = m_contentsMap.find(filename);
const auto it = m_contentsMap.find(filename);
if (it != m_contentsMap.end()) {
outl.push_back(it->second);
return true;
@@ -591,24 +589,16 @@ protected:
}
size_t listSize(StrList& sl) {
size_t out = 0;
for (StrList::iterator it = sl.begin(); it != sl.end(); ++it) out += it->length();
for (const string& i : sl) out += i.length();
return out;
}
string listString(StrList& sl) {
string out;
for (StrList::iterator it = sl.begin(); it != sl.end(); ++it) out += *it;
for (const string& i : sl) out += i;
return out;
}
// CONSTRUCTORS
explicit VInFilterImp(const string& command) {
m_readEof = false;
m_pid = 0;
m_pidExited = false;
m_pidStatus = 0;
m_writeFd = 0;
m_readFd = 0;
start(command);
}
explicit VInFilterImp(const string& command) { start(command); }
~VInFilterImp() { stop(); }
};
@@ -618,7 +608,7 @@ protected:
VInFilter::VInFilter(const string& command) { m_impp = new VInFilterImp(command); }
VInFilter::~VInFilter() {
if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = NULL);
if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = nullptr);
}
bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) {
@@ -630,14 +620,8 @@ bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl)
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
V3OutFormatter::V3OutFormatter(const string& filename, V3OutFormatter::Language lang)
: m_filename(filename)
, m_lang(lang)
, m_lineno(1)
, m_column(0)
, m_nobreak(false)
, m_prependIndent(true)
, m_indentLevel(0)
, m_bracketLevel(0) {
: m_filename{filename}
, m_lang{lang} {
m_blockIndent = v3Global.opt.decoration() ? 4 : 1;
m_commaWidth = v3Global.opt.decoration() ? 50 : 150;
}
@@ -844,14 +828,12 @@ void V3OutFormatter::putsQuoted(const string& strg) {
// Don't use to quote a filename for #include - #include doesn't \ escape.
putcNoTracking('"');
string quoted = quoteNameControls(strg);
for (string::const_iterator cp = quoted.begin(); cp != quoted.end(); ++cp) {
putcNoTracking(*cp);
}
for (const char c : quoted) putcNoTracking(c);
putcNoTracking('"');
}
void V3OutFormatter::putsNoTracking(const string& strg) {
// Don't track {}'s, probably because it's a $display format string
for (string::const_iterator cp = strg.begin(); cp != strg.end(); ++cp) putcNoTracking(*cp);
for (const char c : strg) putcNoTracking(c);
}
void V3OutFormatter::putcNoTracking(char chr) {
@@ -880,43 +862,43 @@ string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::L
string out;
if (lang == LA_XML) {
// Encode chars into XML string
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
if (pos[0] == '"') {
for (const char c : namein) {
if (c == '"') {
out += string("&quot;");
} else if (pos[0] == '\'') {
} else if (c == '\'') {
out += string("&apos;");
} else if (pos[0] == '<') {
} else if (c == '<') {
out += string("&lt;");
} else if (pos[0] == '>') {
} else if (c == '>') {
out += string("&gt;");
} else if (pos[0] == '&') {
} else if (c == '&') {
out += string("&amp;");
} else if (isprint(pos[0])) {
out += pos[0];
} else if (isprint(c)) {
out += c;
} else {
char decimal[10];
sprintf(decimal, "&#%u;", (unsigned char)pos[0]);
sprintf(decimal, "&#%u;", (unsigned char)c);
out += decimal;
}
}
} else {
// Encode control chars into C style escapes
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
if (pos[0] == '\\' || pos[0] == '"') {
out += string("\\") + pos[0];
} else if (pos[0] == '\n') {
for (const char c : namein) {
if (c == '\\' || c == '"') {
out += string("\\") + c;
} else if (c == '\n') {
out += "\\n";
} else if (pos[0] == '\r') {
} else if (c == '\r') {
out += "\\r";
} else if (pos[0] == '\t') {
} else if (c == '\t') {
out += "\\t";
} else if (isprint(pos[0])) {
out += pos[0];
} else if (isprint(c)) {
out += c;
} else {
// This will also cover \a etc
// Can't use %03o as messes up when signed
char octal[10];
sprintf(octal, "\\%o%o%o", (pos[0] >> 6) & 3, (pos[0] >> 3) & 7, pos[0] & 7);
sprintf(octal, "\\%o%o%o", (c >> 6) & 3, (c >> 3) & 7, c & 7);
out += octal;
}
}
@@ -940,20 +922,20 @@ void V3OutFormatter::printf(const char* fmt...) {
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang)
: V3OutFormatter(filename, lang) {
if ((m_fp = V3File::new_fopen_w(filename)) == NULL) { v3fatal("Cannot write " << filename); }
: V3OutFormatter{filename, lang} {
if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) {
v3fatal("Cannot write " << filename);
}
}
V3OutFile::~V3OutFile() {
if (m_fp) fclose(m_fp);
m_fp = NULL;
m_fp = nullptr;
}
void V3OutFile::putsForceIncs() {
const V3StringList& forceIncs = v3Global.opt.forceIncs();
for (V3StringList::const_iterator it = forceIncs.begin(); it != forceIncs.end(); ++it) {
puts("#include \"" + *it + "\"\n");
}
for (const string& i : forceIncs) { puts("#include \"" + i + "\"\n"); }
}
void V3OutCFile::putsGuard() {
@@ -974,7 +956,7 @@ class VIdProtectImp {
// MEMBERS
typedef std::map<string, string> IdMap;
IdMap m_nameMap; // Map of old name into new name
typedef vl_unordered_set<std::string> IdSet;
typedef std::unordered_set<std::string> IdSet;
IdSet m_newIdSet; // Which new names exist
protected:
// CONSTRUCTORS
@@ -995,7 +977,7 @@ public:
// METHODS
string passthru(const string& old) {
if (!v3Global.opt.protectIds()) return old;
IdMap::iterator it = m_nameMap.find(old);
const auto it = m_nameMap.find(old);
if (it != m_nameMap.end()) {
// No way to go back and correct the older crypt name
UASSERT(old == it->second,
@@ -1008,10 +990,10 @@ public:
}
string protectIf(const string& old, bool doIt) {
if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old;
IdMap::iterator it = m_nameMap.find(old);
if (it != m_nameMap.end())
const auto it = m_nameMap.find(old);
if (it != m_nameMap.end()) {
return it->second;
else {
} else {
string out;
if (v3Global.opt.debugProtect()) {
// This lets us see the symbol being protected to debug cases
+24 -25
View File
@@ -101,10 +101,10 @@ public:
class V3OutFormatter {
// TYPES
enum MiscConsts { MAXSPACE = 80 }; // After this indent, stop indenting more
static constexpr int MAXSPACE = 80; // After this indent, stop indenting more
public:
enum AlignClass { AL_AUTO = 0, AL_STATIC = 1 };
enum Language {
enum AlignClass : uint8_t { AL_AUTO = 0, AL_STATIC = 1 };
enum Language : uint8_t {
LA_C = 0,
LA_VERILOG = 1,
LA_MK = 2,
@@ -117,13 +117,13 @@ private:
Language m_lang; // Indenting Verilog code
int m_blockIndent; // Characters per block indent
int m_commaWidth; // Width after which to break at ,'s
int m_lineno;
int m_column;
int m_nobreak; // Basic operator or begin paren, don't break next
bool m_prependIndent;
int m_indentLevel; // Current {} indentation
int m_lineno = 1;
int m_column = 0;
int m_nobreak = false; // Basic operator or begin paren, don't break next
bool m_prependIndent = true;
int m_indentLevel = 0; // Current {} indentation
std::stack<int> m_parenVec; // Stack of columns where last ( was
int m_bracketLevel; // Intenting = { block, indicates number of {'s seen.
int m_bracketLevel = 0; // Intenting = { block, indicates number of {'s seen.
int endLevels(const char* strg);
void putcNoTracking(char chr);
@@ -182,24 +182,23 @@ class V3OutFile : public V3OutFormatter {
public:
V3OutFile(const string& filename, V3OutFormatter::Language lang);
virtual ~V3OutFile();
virtual ~V3OutFile() override;
void putsForceIncs();
private:
// CALLBACKS
virtual void putcOutput(char chr) { fputc(chr, m_fp); }
virtual void putcOutput(char chr) override { fputc(chr, m_fp); }
};
class V3OutCFile : public V3OutFile {
int m_guard; // Created header guard
int m_guard = false; // Created header guard
int m_private; // 1 = Most recently emitted private:, 2 = public:
public:
explicit V3OutCFile(const string& filename)
: V3OutFile(filename, V3OutFormatter::LA_C)
, m_guard(false) {
: V3OutFile{filename, V3OutFormatter::LA_C} {
resetPrivate();
}
virtual ~V3OutCFile() {}
virtual ~V3OutCFile() override {}
virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); }
virtual void putsIntTopInclude() { putsForceIncs(); }
virtual void putsGuard();
@@ -222,10 +221,10 @@ public:
class V3OutScFile : public V3OutCFile {
public:
explicit V3OutScFile(const string& filename)
: V3OutCFile(filename) {}
virtual ~V3OutScFile() {}
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() {
: V3OutCFile{filename} {}
virtual ~V3OutScFile() override {}
virtual void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() override {
putsForceIncs();
puts("#include \"systemc.h\"\n");
puts("#include \"verilated_sc.h\"\n");
@@ -235,26 +234,26 @@ public:
class V3OutVFile : public V3OutFile {
public:
explicit V3OutVFile(const string& filename)
: V3OutFile(filename, V3OutFormatter::LA_VERILOG) {}
virtual ~V3OutVFile() {}
: V3OutFile{filename, V3OutFormatter::LA_VERILOG} {}
virtual ~V3OutVFile() override {}
virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); }
};
class V3OutXmlFile : public V3OutFile {
public:
explicit V3OutXmlFile(const string& filename)
: V3OutFile(filename, V3OutFormatter::LA_XML) {
: V3OutFile{filename, V3OutFormatter::LA_XML} {
blockIndent(2);
}
virtual ~V3OutXmlFile() {}
virtual ~V3OutXmlFile() override {}
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
};
class V3OutMkFile : public V3OutFile {
public:
explicit V3OutMkFile(const string& filename)
: V3OutFile(filename, V3OutFormatter::LA_MK) {}
virtual ~V3OutMkFile() {}
: V3OutFile{filename, V3OutFormatter::LA_MK} {}
virtual ~V3OutMkFile() override {}
virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); }
// No automatic indentation yet.
void puts(const char* strg) { putsNoTracking(strg); }
+15 -20
View File
@@ -31,7 +31,7 @@
#include <algorithm>
#include <iomanip>
#include VL_INCLUDE_UNORDERED_SET
#include <unordered_set>
//######################################################################
// FileLineSingleton class functions
@@ -58,7 +58,7 @@ string FileLineSingleton::filenameLetters(int fileno) {
//! We associate a language with each source file, so we also set the default
//! for this.
int FileLineSingleton::nameToNumber(const string& filename) {
FileNameNumMap::const_iterator it = m_namemap.find(filename);
const auto it = vlstd::as_const(m_namemap).find(filename);
if (VL_LIKELY(it != m_namemap.end())) return it->second;
int num = m_names.size();
m_names.push_back(filename);
@@ -142,16 +142,16 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp) {
//######################################################################
// FileLine class functions
FileLine::FileLine(FileLine::EmptySecret) {
// Sort of a singleton
m_firstLineno = 0;
m_lastLineno = 0;
m_firstColumn = 0;
m_lastColumn = 0;
// Sort of a singleton
FileLine::FileLine(FileLine::EmptySecret)
: m_firstLineno{0}
, m_firstColumn{0}
, m_lastLineno{0}
, m_lastColumn{0}
, m_contentLineno{0}
, m_contentp{nullptr}
, m_parent{nullptr} {
m_filenameno = singleton().nameToNumber(FileLine::builtInFilename());
m_contentp = NULL;
m_contentLineno = 0;
m_parent = NULL;
m_warnOn = 0;
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
@@ -250,7 +250,7 @@ FileLine* FileLine::copyOrSameFileLine() {
#ifndef _V3ERROR_NO_GLOBAL_
V3Config::applyIgnores(this); // Toggle warnings based on global config file
#endif
static FileLine* lastNewp = NULL;
static FileLine* lastNewp = nullptr;
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
return lastNewp;
}
@@ -310,11 +310,6 @@ bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code(msg.c_str());
if (code < V3ErrorCode::EC_FIRST_WARN) {
return false;
#ifndef _V3ERROR_NO_GLOBAL_
} else if (v3Global.opt.lintOnly() // Lint mode is allowed to suppress some errors
&& code < V3ErrorCode::EC_MIN) {
return false;
#endif
} else {
warnOff(code, flag);
return true;
@@ -442,7 +437,7 @@ string FileLine::warnContext(bool secondary) const {
}
#ifdef VL_LEAK_CHECKS
typedef vl_unordered_set<FileLine*> FileLineCheckSet;
typedef std::unordered_set<FileLine*> FileLineCheckSet;
FileLineCheckSet fileLineLeakChecks;
void* FileLine::operator new(size_t size) {
@@ -454,7 +449,7 @@ void* FileLine::operator new(size_t size) {
void FileLine::operator delete(void* objp, size_t size) {
if (!objp) return;
FileLine* flp = static_cast<FileLine*>(objp);
FileLineCheckSet::iterator it = fileLineLeakChecks.find(flp);
const auto it = fileLineLeakChecks.find(flp);
if (it != fileLineLeakChecks.end()) {
fileLineLeakChecks.erase(it);
} else {
@@ -470,7 +465,7 @@ void FileLine::deleteAllRemaining() {
// that way. Unfortunately this makes our leak checking a big mess, so
// only when leak checking we'll track them all and cleanup.
while (true) {
FileLineCheckSet::iterator it = fileLineLeakChecks.begin();
const auto it = fileLineLeakChecks.begin();
if (it == fileLineLeakChecks.end()) break;
delete *it;
// Operator delete will remove the iterated object from the list.
+38 -21
View File
@@ -89,7 +89,7 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp);
//! language is held in tables in the FileLineSingleton class.
class FileLine {
// CONSTANTS
enum { SHOW_SOURCE_MAX_LENGTH = 400 }; // Don't show source lines > this long
static constexpr unsigned SHOW_SOURCE_MAX_LENGTH = 400; // Don't show source lines > this long
// MEMBERS
// Columns here means number of chars from beginning (i.e. tabs count as one)
@@ -126,27 +126,27 @@ private:
public:
explicit FileLine(const string& filename)
: m_firstLineno(0)
, m_firstColumn(0)
, m_lastLineno(0)
, m_lastColumn(0)
, m_filenameno(singleton().nameToNumber(filename))
, m_contentLineno(0)
, m_contentp(NULL)
, m_parent(NULL)
, m_warnOn(defaultFileLine().m_warnOn)
, m_waive(false) {}
: m_firstLineno{0}
, m_firstColumn{0}
, m_lastLineno{0}
, m_lastColumn{0}
, m_filenameno{singleton().nameToNumber(filename)}
, m_contentLineno{0}
, m_contentp{nullptr}
, m_parent{nullptr}
, m_warnOn{defaultFileLine().m_warnOn}
, m_waive{false} {}
explicit FileLine(FileLine* fromp)
: m_firstLineno(fromp->m_firstLineno)
, m_firstColumn(fromp->m_firstColumn)
, m_lastLineno(fromp->m_lastLineno)
, m_lastColumn(fromp->m_lastColumn)
, m_filenameno(fromp->m_filenameno)
, m_contentLineno(fromp->m_contentLineno)
, m_contentp(fromp->m_contentp)
, m_parent(fromp->m_parent)
, m_warnOn(fromp->m_warnOn)
, m_waive(fromp->m_waive) {}
: m_firstLineno{fromp->m_firstLineno}
, m_firstColumn{fromp->m_firstColumn}
, m_lastLineno{fromp->m_lastLineno}
, m_lastColumn{fromp->m_lastColumn}
, m_filenameno{fromp->m_filenameno}
, m_contentLineno{fromp->m_contentLineno}
, m_contentp{fromp->m_contentp}
, m_parent{fromp->m_parent}
, m_warnOn{fromp->m_warnOn}
, m_waive{fromp->m_waive} {}
struct EmptySecret {}; // Constructor selection
explicit FileLine(EmptySecret);
FileLine* copyOrSameFileLine();
@@ -218,6 +218,8 @@ public:
bool lastWarnWaived() { return m_waive; }
// Specific flag ACCESSORS/METHODS
bool celldefineOn() const { return m_warnOn.test(V3ErrorCode::I_CELLDEFINE); }
void celldefineOn(bool flag) { warnOn(V3ErrorCode::I_CELLDEFINE, flag); }
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); }
bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
@@ -265,6 +267,21 @@ public:
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
&& m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn);
}
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
// equivalent.
int operatorCompare(const FileLine& rhs) const {
if (m_filenameno != rhs.m_filenameno) return (m_filenameno < rhs.m_filenameno) ? -1 : 1;
if (m_firstLineno != rhs.m_firstLineno)
return (m_firstLineno < rhs.m_firstLineno) ? -1 : 1;
if (m_firstColumn != rhs.m_firstColumn)
return (m_firstColumn < rhs.m_firstColumn) ? -1 : 1;
if (m_lastLineno != rhs.m_lastLineno) return (m_lastLineno < rhs.m_lastLineno) ? -1 : 1;
if (m_lastColumn != rhs.m_lastColumn) return (m_lastColumn < rhs.m_lastColumn) ? -1 : 1;
for (size_t i = 0; i < m_warnOn.size(); ++i) {
if (m_warnOn[i] != rhs.m_warnOn[i]) return (m_warnOn[i] < rhs.m_warnOn[i]) ? -1 : 1;
}
return 0; // (*this) and rhs are equivalent
}
private:
string warnContext(bool secondary) const;
+173 -212
View File
@@ -35,11 +35,11 @@
#include <algorithm>
#include <list>
#include <map>
#include VL_INCLUDE_UNORDERED_SET
#include <unordered_set>
typedef std::list<AstNodeVarRef*> GateVarRefList;
#define GATE_DEDUP_MAX_DEPTH 20
constexpr int GATE_DEDUP_MAX_DEPTH = 20;
//######################################################################
@@ -56,7 +56,7 @@ class GateGraphBaseVisitor {
public:
V3Graph* m_graphp; // Graph this class is visiting
explicit GateGraphBaseVisitor(V3Graph* graphp)
: m_graphp(graphp) {}
: m_graphp{graphp} {}
virtual ~GateGraphBaseVisitor() {}
virtual VNUser visit(GateLogicVertex* vertexp, VNUser vu = VNUser(0)) = 0;
virtual VNUser visit(GateVarVertex* vertexp, VNUser vu = VNUser(0)) = 0;
@@ -68,19 +68,16 @@ public:
class GateEitherVertex : public V3GraphVertex {
AstScope* m_scopep; // Scope vertex refers to
bool m_reducible; // True if this node should be able to be eliminated
bool m_dedupable; // True if this node should be able to be deduped
bool m_consumed; // Output goes to something meaningful
bool m_reducible = true; // True if this node should be able to be eliminated
bool m_dedupable = true; // True if this node should be able to be deduped
bool m_consumed = false; // Output goes to something meaningful
public:
GateEitherVertex(V3Graph* graphp, AstScope* scopep)
: V3GraphVertex(graphp)
, m_scopep(scopep)
, m_reducible(true)
, m_dedupable(true)
, m_consumed(false) {}
virtual ~GateEitherVertex() {}
: V3GraphVertex{graphp}
, m_scopep{scopep} {}
virtual ~GateEitherVertex() override {}
// ACCESSORS
virtual string dotStyle() const { return m_consumed ? "" : "dotted"; }
virtual string dotStyle() const override { return m_consumed ? "" : "dotted"; }
AstScope* scopep() const { return m_scopep; }
bool reducible() const { return m_reducible; }
bool dedupable() const { return m_dedupable; }
@@ -116,7 +113,7 @@ public:
// iterateInEdges() will stop traversing edges if one is deleted
VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) {
VNUser ret = VNUser(0);
V3GraphEdge* next_edgep = NULL;
V3GraphEdge* next_edgep = nullptr;
for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) {
// Need to find the next edge before visiting in case the edge is deleted
next_edgep = edgep->outNextp();
@@ -128,23 +125,19 @@ public:
class GateVarVertex : public GateEitherVertex {
AstVarScope* m_varScp;
bool m_isTop;
bool m_isClock;
AstNode* m_rstSyncNodep; // Used as reset and not in SenItem, in clocked always
AstNode* m_rstAsyncNodep; // Used as reset and in SenItem, in clocked always
bool m_isTop = false;
bool m_isClock = false;
AstNode* m_rstSyncNodep = nullptr; // Used as reset and not in SenItem, in clocked always
AstNode* m_rstAsyncNodep = nullptr; // Used as reset and in SenItem, in clocked always
public:
GateVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: GateEitherVertex(graphp, scopep)
, m_varScp(varScp)
, m_isTop(false)
, m_isClock(false)
, m_rstSyncNodep(NULL)
, m_rstAsyncNodep(NULL) {}
virtual ~GateVarVertex() {}
: GateEitherVertex{graphp, scopep}
, m_varScp{varScp} {}
virtual ~GateVarVertex() override {}
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
virtual string dotColor() const { return "blue"; }
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
virtual string dotColor() const override { return "blue"; }
bool isTop() const { return m_isTop; }
void setIsTop() { m_isTop = true; }
bool isClock() const { return m_isClock; }
@@ -165,29 +158,35 @@ public:
setIsClock();
}
}
VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { return v.visit(this, vu); }
virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) override {
return v.visit(this, vu);
}
};
class GateLogicVertex : public GateEitherVertex {
AstNode* m_nodep;
AstActive* m_activep; // Under what active; NULL is ok (under cfunc or such)
AstActive* m_activep; // Under what active; nullptr is ok (under cfunc or such)
bool m_slow; // In slow block
public:
GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep,
bool slow)
: GateEitherVertex(graphp, scopep)
, m_nodep(nodep)
, m_activep(activep)
, m_slow(slow) {}
virtual ~GateLogicVertex() {}
: GateEitherVertex{graphp, scopep}
, m_nodep{nodep}
, m_activep{activep}
, m_slow{slow} {}
virtual ~GateLogicVertex() override {}
// ACCESSORS
virtual string name() const { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); }
virtual string dotColor() const { return "purple"; }
virtual FileLine* fileline() const { return nodep()->fileline(); }
virtual string name() const override {
return (cvtToHex(m_nodep) + "@" + scopep()->prettyName());
}
virtual string dotColor() const override { return "purple"; }
virtual FileLine* fileline() const override { return nodep()->fileline(); }
AstNode* nodep() const { return m_nodep; }
AstActive* activep() const { return m_activep; }
bool slow() const { return m_slow; }
VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { return v.visit(this, vu); }
virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) override {
return v.visit(this, vu);
}
};
//######################################################################
@@ -196,14 +195,14 @@ public:
class GateOkVisitor : public GateBaseVisitor {
private:
// RETURN STATE
bool m_isSimple; // Set false when we know it isn't simple
bool m_isSimple = true; // Set false when we know it isn't simple
GateVarRefList m_rhsVarRefs; // VarRefs on rhs of assignment
AstNode* m_substTreep; // What to replace the variable with
AstNode* m_substTreep = nullptr; // What to replace the variable with
// STATE
bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks)
AstNodeVarRef* m_lhsVarRef; // VarRef on lhs of assignment (what we're replacing)
AstNodeVarRef* m_lhsVarRef = nullptr; // VarRef on lhs of assignment (what we're replacing)
bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable
int m_ops; // Operation count
int m_ops = 0; // Operation count
// METHODS
void clearSimple(const char* because) {
@@ -213,7 +212,7 @@ private:
}
}
// VISITORS
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
++m_ops;
iterateChildren(nodep);
// We only allow a LHS ref for the var being set, and a RHS ref for
@@ -221,7 +220,7 @@ 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().isWrite()) {
if (m_lhsVarRef) clearSimple(">1 lhs varRefs");
m_lhsVarRef = nodep;
} else {
@@ -237,7 +236,7 @@ private:
m_rhsVarRefs.push_back(nodep);
}
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
m_substTreep = nodep->rhsp();
if (!VN_IS(nodep->lhsp(), NodeVarRef)) {
clearSimple("ASSIGN(non-VARREF)");
@@ -260,7 +259,7 @@ private:
}
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
// *** Special iterator
if (!m_isSimple) return; // Fastpath
if (++m_ops > v3Global.opt.gateStmts()) { clearSimple("--gate-stmts exceeded"); }
@@ -276,12 +275,8 @@ private:
public:
// CONSTRUCTORS
GateOkVisitor(AstNode* nodep, bool buffersOnly, bool dedupe) {
m_isSimple = true;
m_substTreep = NULL;
m_buffersOnly = buffersOnly;
m_lhsVarRef = NULL;
m_dedupe = dedupe;
m_ops = 0;
// Iterate
iterate(nodep);
// Check results
@@ -294,7 +289,7 @@ public:
}
if (debug() >= 9 && !m_isSimple) nodep->dumpTree(cout, " gate!Ok: ");
}
virtual ~GateOkVisitor() {}
virtual ~GateOkVisitor() override {}
// PUBLIC METHODS
bool isSimple() const { return m_isSimple; }
AstNode* substTree() const { return m_substTreep; }
@@ -318,13 +313,13 @@ private:
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
GateLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
AstScope* m_scopep; // Current scope being processed
AstNodeModule* m_modp; // Current module
AstActive* m_activep; // Current active
bool m_activeReducible; // Is activation block reducible?
bool m_inSenItem; // Underneath AstSenItem; any varrefs are clocks
bool m_inSlow; // Inside a slow structure
GateLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
AstScope* m_scopep = nullptr; // Current scope being processed
AstNodeModule* m_modp = nullptr; // Current module
AstActive* m_activep = nullptr; // Current active
bool m_activeReducible = true; // Is activation block reducible?
bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks
bool m_inSlow = false; // Inside a slow structure
VDouble0 m_statSigs; // Statistic tracking
VDouble0 m_statRefs; // Statistic tracking
VDouble0 m_statDedupLogic; // Statistic tracking
@@ -346,7 +341,7 @@ private:
if (consumeReason) m_logicVertexp->setConsumed(consumeReason);
if (VN_IS(nodep, SenItem)) m_logicVertexp->setConsumed("senItem");
iterateChildren(nodep);
m_logicVertexp = NULL;
m_logicVertexp = nullptr;
}
}
@@ -385,7 +380,7 @@ private:
void decomposeClkVectors();
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
virtual void visit(AstNetlist* nodep) override {
iterateChildren(nodep);
// if (debug() > 6) m_graph.dump();
if (debug() > 6) m_graph.dumpDotFilePrefixed("gate_pre");
@@ -416,23 +411,22 @@ private:
consumedMove();
replaceAssigns();
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_activeReducible = true;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
virtual void visit(AstScope* nodep) override {
UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
m_logicVertexp = NULL;
m_logicVertexp = nullptr;
iterateChildren(nodep);
m_scopep = NULL;
m_scopep = nullptr;
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
// Create required blocks and add to module
UINFO(4, " BLOCK " << nodep << endl);
m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible
@@ -440,10 +434,10 @@ private:
AstNode::user2ClearTree();
iterateChildren(nodep);
AstNode::user2ClearTree();
m_activep = NULL;
m_activep = nullptr;
m_activeReducible = true;
}
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
@@ -454,7 +448,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().isWrite()) {
if (varscp->user2()) {
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
} else {
@@ -463,63 +457,60 @@ 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().isWrite()) {
new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1);
} else {
new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1);
}
}
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? NULL : "Multiple Stmts"), NULL);
virtual void visit(AstAlways* nodep) override {
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"), nullptr);
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, "AlwaysPublic", NULL);
m_inSlow = lastslow;
virtual void visit(AstAlwaysPublic* nodep) override {
VL_RESTORER(m_inSlow);
{
m_inSlow = true;
iterateNewStmt(nodep, "AlwaysPublic", nullptr);
}
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
iterateNewStmt(nodep, "User C Function", "User C Function");
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
// Note we look at only AstSenItems, not AstSenGate's
// The gating term of a AstSenGate is normal logic
virtual void visit(AstSenItem* nodep) override {
m_inSenItem = true;
if (m_logicVertexp) { // Already under logic; presumably a SenGate
iterateChildren(nodep);
} else { // Standalone item, probably right under a SenTree
iterateNewStmt(nodep, NULL, NULL);
iterateNewStmt(nodep, nullptr, nullptr);
}
m_inSenItem = false;
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep, "Clock gater", "Clock gater");
virtual void visit(AstInitial* nodep) override {
VL_RESTORER(m_inSlow);
{
m_inSlow = true;
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"),
nullptr);
}
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? NULL : "Multiple Stmts"), NULL);
m_inSlow = lastslow;
virtual void visit(AstAssignAlias* nodep) override { //
iterateNewStmt(nodep, nullptr, nullptr);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { //
iterateNewStmt(nodep, NULL, NULL);
virtual void visit(AstAssignW* nodep) override { //
iterateNewStmt(nodep, nullptr, nullptr);
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { //
iterateNewStmt(nodep, NULL, NULL);
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
virtual void visit(AstCoverToggle* nodep) override {
iterateNewStmt(nodep, "CoverToggle", "CoverToggle");
}
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
const bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, "Tracing", "Tracing");
m_inSlow = lastslow;
virtual void visit(AstTraceDecl* nodep) override {
VL_RESTORER(m_inSlow);
{
m_inSlow = true;
iterateNewStmt(nodep, "Tracing", "Tracing");
}
}
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
virtual void visit(AstConcat* nodep) override {
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)
&& VN_CAST(nodep->backp(), NodeAssign)->lhsp() == nodep),
nodep, "Concat on LHS of assignment; V3Const should have deleted it");
@@ -527,25 +518,15 @@ private:
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE {
virtual void visit(AstNode* nodep) override {
iterateChildren(nodep);
if (nodep->isOutputter() && m_logicVertexp) m_logicVertexp->setConsumed("outputter");
}
public:
// CONSTRUCTORS
explicit GateVisitor(AstNode* nodep) {
AstNode::user1ClearTree();
m_logicVertexp = NULL;
m_scopep = NULL;
m_modp = NULL;
m_activep = NULL;
m_activeReducible = true;
m_inSenItem = false;
m_inSlow = false;
iterate(nodep);
}
virtual ~GateVisitor() {
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);
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
@@ -682,7 +663,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
// optimize it further
logicp->unlinkFrBack();
vvertexp->varScp()->valuep(logicp);
logicp = NULL;
logicp = nullptr;
// Mark the vertex so we don't mark it as being
// unconsumed in the next step
vvertexp->user(true);
@@ -700,7 +681,7 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
// Return true if can optimize
// Return false if the consuming logic has an output signal that the
// replacement logic has as an input
typedef vl_unordered_set<AstVarScope*> VarScopeSet;
typedef std::unordered_set<AstVarScope*> VarScopeSet;
// Use map to find duplicates between two lists
VarScopeSet varscopes;
// Replacement logic usually has shorter input list, so faster to build list based on it
@@ -794,7 +775,7 @@ void GateVisitor::consumedMove() {
}
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
AstNode* nodep = lvertexp->nodep();
AstActive* oldactp = lvertexp->activep(); // NULL under cfunc
AstActive* oldactp = lvertexp->activep(); // nullptr under cfunc
if (!lvertexp->consumed() && oldactp) {
// Eventually: Move the statement to a new active block
// with "tracing-on" sensitivity
@@ -855,13 +836,13 @@ private:
void hashReplace(AstNode* oldp, AstNode* newp);
// VISITORS
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
if (nodep->varScopep() == m_elimVarScp) {
// Substitute in the new tree
// 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().isWrite(), nodep,
"Can't replace lvalue assignments with const var");
AstNode* substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(
@@ -875,17 +856,18 @@ 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);
}
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
virtual ~GateElimVisitor() {}
virtual ~GateElimVisitor() override {}
GateElimVisitor(AstNode* nodep, AstVarScope* varscp, AstNode* replaceTreep,
GateDedupeVarVisitor* varVisp) {
UINFO(9, " elimvisitor " << nodep << endl);
@@ -902,7 +884,7 @@ public:
void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) {
if (debug() >= 5) consumerp->dumpTree(cout, " elimUsePre: ");
GateElimVisitor elimVisitor(consumerp, varscp, substp, NULL);
GateElimVisitor elimVisitor(consumerp, varscp, substp, nullptr);
if (elimVisitor.didReplace()) {
if (debug() >= 9) consumerp->dumpTree(cout, " elimUseCns: ");
// Caution: Can't let V3Const change our handle to consumerp, such as by
@@ -927,9 +909,9 @@ private:
// NODE STATE
// Ast*::user2p -> parent AstNodeAssign* for this rhsp
// Ast*::user3p -> AstActive* of assign, for isSame() in test for duplicate
// Set to NULL if this assign's tree was later replaced
// Set to nullptr if this assign's tree was later replaced
// Ast*::user5p -> AstNode* of assign if condition, for isSame() in test for duplicate
// Set to NULL if this assign's tree was later replaced
// Set to nullptr if this assign's tree was later replaced
// AstUser1InUse m_inuser1; (Allocated for use in GateVisitor)
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
AstUser3InUse m_inuser3;
@@ -942,7 +924,7 @@ private:
VL_DEBUG_FUNC; // Declare debug()
void hash(AstNode* nodep) {
// !NULL && the object is hashable
// !nullptr && the object is hashable
if (nodep && !nodep->sameHash().isIllegal()) m_hashed.hash(nodep);
}
bool sameHash(AstNode* node1p, AstNode* node2p) {
@@ -992,7 +974,8 @@ public:
}
AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) {
// Legal for extra1p/2p to be NULL, we'll compare with other assigns with extras also NULL
// Legal for extra1p/2p to be nullptr, we'll compare with other assigns with extras also
// nullptr
AstNode* rhsp = assignp->rhsp();
rhsp->user2p(assignp);
rhsp->user3p(extra1p);
@@ -1001,8 +984,8 @@ public:
hash(extra1p);
hash(extra2p);
V3Hashed::iterator inserted = m_hashed.hashAndInsert(rhsp);
V3Hashed::iterator dupit = m_hashed.findDuplicate(rhsp, this);
const auto inserted = m_hashed.hashAndInsert(rhsp);
const auto dupit = m_hashed.findDuplicate(rhsp, this);
// Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't
// return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate)
// So dupit is either a different, duplicate rhsp, or the end of the hash.
@@ -1011,7 +994,7 @@ public:
return VN_CAST(m_hashed.iteratorNodep(dupit)->user2p(), NodeAssign);
}
// Retain new inserted information
return NULL;
return nullptr;
}
void check() {
@@ -1049,13 +1032,13 @@ class GateDedupeVarVisitor : public GateBaseVisitor {
private:
// STATE
GateDedupeHash m_ghash; // Hash used to find dupes of rhs of assign
AstNodeAssign* m_assignp; // Assign found for dedupe
AstNode* m_ifCondp; // IF condition that assign is under
bool m_always; // Assign is under an always
bool m_dedupable; // Determined the assign to be dedupable
AstNodeAssign* m_assignp = nullptr; // Assign found for dedupe
AstNode* m_ifCondp = nullptr; // IF condition that assign is under
bool m_always = false; // Assign is under an always
bool m_dedupable = true; // Determined the assign to be dedupable
// VISITORS
virtual void visit(AstNodeAssign* assignp) VL_OVERRIDE {
virtual void visit(AstNodeAssign* assignp) override {
if (m_dedupable) {
// I think we could safely dedupe an always block with multiple
// non-blocking statements, but erring on side of caution here
@@ -1066,7 +1049,7 @@ private:
}
}
}
virtual void visit(AstAlways* alwaysp) VL_OVERRIDE {
virtual void visit(AstAlways* alwaysp) override {
if (m_dedupable) {
if (!m_always) {
m_always = true;
@@ -1080,7 +1063,7 @@ private:
// always @(...)
// if (...)
// foo = ...; // or foo <= ...;
virtual void visit(AstNodeIf* ifp) VL_OVERRIDE {
virtual void visit(AstNodeIf* ifp) override {
if (m_dedupable) {
if (m_always && !m_ifCondp && !ifp->elsesp()) {
// we're under an always, this is the first IF, and there's no else
@@ -1092,25 +1075,20 @@ private:
}
}
virtual void visit(AstComment*) VL_OVERRIDE {} // NOP
virtual void visit(AstComment*) override {} // NOP
//--------------------
virtual void visit(AstNode*) VL_OVERRIDE { //
virtual void visit(AstNode*) override { //
m_dedupable = false;
}
public:
// CONSTRUCTORS
GateDedupeVarVisitor() {
m_assignp = NULL;
m_ifCondp = NULL;
m_always = false;
m_dedupable = true;
}
GateDedupeVarVisitor() {}
~GateDedupeVarVisitor() {}
// PUBLIC METHODS
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
m_assignp = NULL;
m_ifCondp = NULL;
m_assignp = nullptr;
m_ifCondp = nullptr;
m_always = false;
m_dedupable = true;
iterate(nodep);
@@ -1125,7 +1103,7 @@ public:
}
}
}
return NULL;
return nullptr;
}
void hashReplace(AstNode* oldp, AstNode* newp) { m_ghash.hashReplace(oldp, newp); }
};
@@ -1147,9 +1125,9 @@ private:
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
VDouble0 m_numDeduped; // Statistic tracking
GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic
int m_depth; // Iteration depth
int m_depth = 0; // Iteration depth
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) {
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) override {
// Check that we haven't been here before
if (m_depth > GATE_DEDUP_MAX_DEPTH)
return VNUser(0); // Break loops; before user2 set so hit this vertex later
@@ -1164,7 +1142,7 @@ private:
V3GraphEdge* edgep = vvertexp->inBeginp();
GateLogicVertex* lvertexp = static_cast<GateLogicVertex*>(edgep->fromp());
UASSERT_OBJ(vvertexp->dedupable(), vvertexp->varScp(),
"GateLogicVertex* visit should have returned NULL "
"GateLogicVertex* visit should have returned nullptr "
"if consumer var vertex is not dedupable.");
GateOkVisitor okVisitor(lvertexp->nodep(), false, true);
if (okVisitor.isSimple()) {
@@ -1204,7 +1182,7 @@ private:
AstNode* lvertexNodep = lvertexp->nodep();
lvertexNodep->unlinkFrBack();
vvertexp->varScp()->valuep(lvertexNodep);
lvertexNodep = NULL;
lvertexNodep = nullptr;
vvertexp->user(true);
lvertexp->user(true);
}
@@ -1215,8 +1193,8 @@ private:
}
// Given iterated logic, starting at vu which was consumer's GateVarVertex
// Returns a varref that has the same logic input; or NULL if none
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) {
// Returns a varref that has the same logic input; or nullptr if none
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
lvertexp->iterateInEdges(*this);
GateVarVertex* consumerVvertexpp = static_cast<GateVarVertex*>(vu.toGraphVertex());
@@ -1235,8 +1213,7 @@ private:
public:
explicit GateDedupeGraphVisitor(V3Graph* graphp)
: GateGraphBaseVisitor(graphp)
, m_depth(0) {}
: GateGraphBaseVisitor{graphp} {}
void dedupeTree(GateVarVertex* vvertexp) { vvertexp->accept(*this); }
VDouble0 numDeduped() { return m_numDeduped; }
};
@@ -1271,9 +1248,9 @@ void GateVisitor::dedupe() {
class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
AstNodeAssign* m_assignp;
AstActive* m_activep;
GateLogicVertex* m_logicvp;
AstNodeAssign* m_assignp = nullptr;
AstActive* m_activep = nullptr;
GateLogicVertex* m_logicvp = nullptr;
VDouble0 m_numMergedAssigns; // Statistic tracking
// assemble two Sel into one if possible
@@ -1281,22 +1258,22 @@ private:
AstVarRef* preVarRefp = VN_CAST(pre->fromp(), VarRef);
AstVarRef* curVarRefp = VN_CAST(cur->fromp(), VarRef);
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) {
return NULL; // not the same var
return nullptr; // not the same var
}
const AstConst* pstart = VN_CAST(pre->lsbp(), Const);
const AstConst* pwidth = VN_CAST(pre->widthp(), Const);
const AstConst* cstart = VN_CAST(cur->lsbp(), Const);
const AstConst* cwidth = VN_CAST(cur->widthp(), Const);
if (!pstart || !pwidth || !cstart || !cwidth) return NULL; // too complicated
if (!pstart || !pwidth || !cstart || !cwidth) return nullptr; // too complicated
if (cur->lsbConst() + cur->widthConst() == pre->lsbConst()) {
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false),
cur->lsbConst(), pre->widthConst() + cur->widthConst());
} else {
return NULL;
return nullptr;
}
}
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) {
virtual VNUser visit(GateVarVertex* vvertexp, VNUser) override {
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) {
V3GraphEdge* oldedgep = edgep;
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
@@ -1369,18 +1346,14 @@ private:
}
return VNUser(0);
}
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) { //
virtual VNUser visit(GateLogicVertex*, VNUser vu) override { //
return VNUser(0);
}
public:
explicit GateMergeAssignsGraphVisitor(V3Graph* graphp)
: GateGraphBaseVisitor(graphp) {
m_assignp = NULL;
m_activep = NULL;
m_logicvp = NULL;
m_numMergedAssigns = 0;
m_graphp = graphp;
: GateGraphBaseVisitor{graphp} {
m_graphp = graphp; // In base
}
void mergeAssignsTree(GateVarVertex* vvertexp) { vvertexp->accept(*this); }
VDouble0 numMergedAssigns() { return m_numMergedAssigns; }
@@ -1405,13 +1378,13 @@ void GateVisitor::mergeAssigns() {
class GateConcatVisitor : public GateBaseVisitor {
private:
// STATE
AstVarScope* m_vscp; // Varscope we're trying to find
int m_offset; // Current offset of varscope
int m_found_offset; // Found offset of varscope
bool m_found; // Offset found
AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
int m_offset = 0; // Current offset of varscope
int m_found_offset = 0; // Found offset of varscope
bool m_found = false; // Offset found
// VISITORS
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstNodeVarRef* nodep) override {
UINFO(9, "CLK DECOMP Concat search var (off = " << m_offset << ") - " << nodep << endl);
if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) {
// A concatenation may use the same var multiple times
@@ -1423,23 +1396,18 @@ private:
}
m_offset += nodep->dtypep()->width();
}
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
virtual void visit(AstConcat* nodep) override {
UINFO(9, "CLK DECOMP Concat search (off = " << m_offset << ") - " << nodep << endl);
iterate(nodep->rhsp());
iterate(nodep->lhsp());
}
//--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
GateConcatVisitor() {
m_vscp = NULL;
m_offset = 0;
m_found_offset = 0;
m_found = false;
}
virtual ~GateConcatVisitor() {}
GateConcatVisitor() {}
virtual ~GateConcatVisitor() override {}
// PUBLIC METHODS
bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) {
m_vscp = vscp;
@@ -1462,10 +1430,9 @@ class GateClkDecompState {
public:
int m_offset;
AstVarScope* m_last_vsp;
GateClkDecompState(int offset, AstVarScope* vsp) {
m_offset = offset;
m_last_vsp = vsp;
}
GateClkDecompState(int offset, AstVarScope* vsp)
: m_offset{offset}
, m_last_vsp{vsp} {}
virtual ~GateClkDecompState() {}
};
@@ -1473,14 +1440,14 @@ class GateClkDecompGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
// AstVarScope::user2p -> bool: already visited
int m_seen_clk_vectors;
AstVarScope* m_clk_vsp;
GateVarVertex* m_clk_vvertexp;
int m_seen_clk_vectors = 0;
AstVarScope* m_clk_vsp = nullptr;
GateVarVertex* m_clk_vvertexp = nullptr;
GateConcatVisitor m_concat_visitor;
int m_total_seen_clk_vectors;
int m_total_decomposed_clk_vectors;
int m_total_seen_clk_vectors = 0;
int m_total_decomposed_clk_vectors = 0;
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) {
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) override {
// Check that we haven't been here before
AstVarScope* vsp = vvertexp->varScp();
if (vsp->user2SetOnce()) return VNUser(0);
@@ -1497,7 +1464,7 @@ private:
return VNUser(0); // Unused
}
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) {
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
GateClkDecompState* currState = reinterpret_cast<GateClkDecompState*>(vu.c());
int clk_offset = currState->m_offset;
if (const AstAssignW* assignp = VN_CAST(lvertexp->nodep(), AssignW)) {
@@ -1545,7 +1512,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);
}
@@ -1563,14 +1530,8 @@ private:
public:
explicit GateClkDecompGraphVisitor(V3Graph* graphp)
: GateGraphBaseVisitor(graphp) {
m_seen_clk_vectors = 0;
m_clk_vsp = NULL;
m_clk_vvertexp = NULL;
m_total_seen_clk_vectors = 0;
m_total_decomposed_clk_vectors = 0;
}
virtual ~GateClkDecompGraphVisitor() {
: GateGraphBaseVisitor{graphp} {}
virtual ~GateClkDecompGraphVisitor() override {
V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors);
V3Stats::addStat("Optimizations, Clocker decomposed vectors",
m_total_decomposed_clk_vectors);
@@ -1610,7 +1571,7 @@ void GateVisitor::decomposeClkVectors() {
class GateDeassignVisitor : public GateBaseVisitor {
private:
// VISITORS
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
virtual void visit(AstVarScope* nodep) override {
if (AstNodeAssign* assp = VN_CAST(nodep->valuep(), NodeAssign)) {
UINFO(5, " Removeassign " << assp << endl);
AstNode* valuep = assp->rhsp();
@@ -1620,14 +1581,14 @@ private:
}
}
// Speedups
virtual void visit(AstVar*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstActive*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {} // Accelerate
virtual void visit(AstActive*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit GateDeassignVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~GateDeassignVisitor() {}
virtual ~GateDeassignVisitor() override {}
};
//######################################################################
+33 -41
View File
@@ -47,9 +47,9 @@ private:
AstUser3InUse m_inuser3;
// STATE
AstActive* m_activep; // Inside activate statement
AstActive* m_activep = nullptr; // Inside activate statement
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstScope* m_scopetopp = nullptr; // Scope under TOPSCOPE
// METHODS
AstVarScope* genInpClk(AstVarScope* vscp) {
@@ -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);
@@ -78,7 +78,7 @@ private:
}
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
virtual void visit(AstTopScope* nodep) override {
AstNode::user2ClearTree(); // user2p() used on entire tree
AstScope* scopep = nodep->scopep();
@@ -88,7 +88,7 @@ private:
iterateChildren(nodep);
}
//----
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
@@ -98,33 +98,31 @@ 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);
}
}
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterateChildren(nodep->sensesp()); // iterateAndNext?
m_activep = NULL;
m_activep = nullptr;
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); }
//-----
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
GenClkRenameVisitor(AstTopScope* nodep, AstNodeModule* topModp) {
m_topModp = topModp;
m_scopetopp = NULL;
m_activep = NULL;
GenClkRenameVisitor(AstTopScope* nodep, AstNodeModule* topModp)
: m_topModp{topModp} {
iterate(nodep);
}
virtual ~GenClkRenameVisitor() {}
virtual ~GenClkRenameVisitor() override {}
};
//######################################################################
@@ -138,13 +136,13 @@ private:
AstUser1InUse m_inuser1;
// STATE
AstActive* m_activep; // Inside activate statement
bool m_tracingCall; // Iterating into a call to a cfunc
AstNodeAssign* m_assignp; // Inside assigndly statement
AstNodeModule* m_topModp; // Top module
bool m_tracingCall = false; // Iterating into a call to a cfunc
AstActive* m_activep = nullptr; // Inside activate statement
AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
AstNodeModule* m_topModp = nullptr; // Top module
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
virtual void visit(AstTopScope* nodep) override {
AstNode::user1ClearTree(); // user1p() used on entire tree
iterateChildren(nodep);
{
@@ -153,14 +151,14 @@ private:
GenClkRenameVisitor visitor(nodep, m_topModp);
}
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
virtual void visit(AstNodeModule* nodep) override {
// Only track the top scopes, not lower level functions
if (nodep->isTop()) {
m_topModp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
virtual void visit(AstNodeCCall* nodep) override {
iterateChildren(nodep);
if (!nodep->funcp()->entryPoint()) {
// Enter the function and trace it
@@ -168,7 +166,7 @@ private:
iterate(nodep->funcp());
}
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
virtual void visit(AstCFunc* nodep) override {
if (!m_tracingCall && !nodep->entryPoint()) {
// Only consider logic within a CFunc when looking
// at the call to it, and not when scanning whatever
@@ -180,7 +178,7 @@ private:
}
//----
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
@@ -188,42 +186,36 @@ private:
UINFO(8, " VarAct " << nodep << endl);
vscp->user1(true);
}
if (m_assignp && nodep->lvalue() && vscp->user1()) {
if (m_assignp && nodep->access().isWrite() && vscp->user1()) {
// Variable was previously used as a clock, and is now being set
// Thus a unordered generated clock...
UINFO(8, " VarSetAct " << nodep << endl);
vscp->circular(true);
}
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
virtual void visit(AstNodeAssign* nodep) override {
// UINFO(8, "ASS " << nodep << endl);
m_assignp = nodep;
iterateChildren(nodep);
m_assignp = NULL;
m_assignp = nullptr;
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
virtual void visit(AstActive* nodep) override {
UINFO(8, "ACTIVE " << nodep << endl);
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterateChildren(nodep->sensesp()); // iterateAndNext?
m_activep = NULL;
m_activep = nullptr;
iterateChildren(nodep);
}
//-----
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar*) override {} // Don't want varrefs under it
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit GenClkReadVisitor(AstNetlist* nodep)
: m_activep(NULL)
, m_tracingCall(false)
, m_assignp(NULL)
, m_topModp(NULL) {
iterate(nodep);
}
virtual ~GenClkReadVisitor() {}
explicit GenClkReadVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~GenClkReadVisitor() override {}
};
//######################################################################
+15 -6
View File
@@ -20,6 +20,7 @@
#include "V3Global.h"
#include "V3Ast.h"
#include "V3File.h"
#include "V3HierBlock.h"
#include "V3LinkCells.h"
#include "V3Parse.h"
#include "V3ParseSym.h"
@@ -34,7 +35,17 @@ AstNetlist* V3Global::makeNetlist() {
return newp;
}
void V3Global::checkTree() { rootp()->checkTree(); }
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
}
void V3Global::checkTree() const { rootp()->checkTree(); }
void V3Global::readFiles() {
// NODE STATE
@@ -47,8 +58,7 @@ void V3Global::readFiles() {
V3Parse parser(v3Global.rootp(), &filter, &parseSyms);
// Read top module
const V3StringList& vFiles = v3Global.opt.vFiles();
for (V3StringList::const_iterator it = vFiles.begin(); it != vFiles.end(); ++it) {
string filename = *it;
for (const string& filename : vFiles) {
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, false,
"Cannot find file containing module: ");
}
@@ -57,8 +67,7 @@ void V3Global::readFiles() {
// To be compatible with other simulators,
// this needs to be done after the top file is read
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
for (V3StringSet::const_iterator it = libraryFiles.begin(); it != libraryFiles.end(); ++it) {
string filename = *it;
for (const string& filename : libraryFiles) {
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, true,
"Cannot find file containing library module: ");
}
@@ -78,7 +87,7 @@ void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool
}
const std::string& V3Global::ptrToId(const void* p) {
PtrToIdMap::iterator it = m_ptrToId.find(p);
auto it = m_ptrToId.find(p);
if (it == m_ptrToId.end()) {
std::ostringstream os;
if (p) {
+48 -29
View File
@@ -31,26 +31,47 @@
#include "V3Options.h"
#include <string>
#include VL_INCLUDE_UNORDERED_MAP
#include <unordered_map>
class AstNetlist;
class V3HierBlockPlan;
//======================================================================
// Statics
// Restorer
/// Save a given variable's value on the stack, restoring it at
/// end-of-stope.
// Object must be named, or it will not persist until end-of-scope.
// Constructor needs () or GCC 4.8 false warning.
#define VL_RESTORER(var) const VRestorer<decltype(var)> restorer_##var(var);
// Object used by VL_RESTORER. This object must be an auto variable, not
// allocated on the heap or otherwise.
template <typename T> class VRestorer {
T& m_ref; // Reference to object we're saving and restoring
const T m_saved; // Value saved, for later restore
public:
VRestorer(T& permr)
: m_ref(permr)
, m_saved(permr) {}
~VRestorer() { m_ref = m_saved; }
VL_UNCOPYABLE(VRestorer);
};
//######################################################################
class VWidthMinUsage {
public:
enum en { LINT_WIDTH, MATCHES_WIDTH, VERILOG_WIDTH };
enum en : uint8_t { LINT_WIDTH, MATCHES_WIDTH, VERILOG_WIDTH };
enum en m_e;
inline VWidthMinUsage()
: m_e(LINT_WIDTH) {}
: m_e{LINT_WIDTH} {}
// cppcheck-suppress noExplicitConstructor
inline VWidthMinUsage(en _e)
: m_e(_e) {}
: m_e{_e} {}
explicit inline VWidthMinUsage(int _e)
: m_e(static_cast<en>(_e)) {}
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
};
inline bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) {
@@ -69,19 +90,19 @@ inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
class V3Global {
// Globals
AstNetlist* m_rootp; // Root of entire netlist
V3HierBlockPlan* m_hierPlanp; // Hierarchical verilation plan, nullptr unless hier_block
VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
int m_debugFileNumber; // Number to append to debug files created
bool m_assertDTypesResolved; // Tree should have dtypep()'s
bool m_constRemoveXs; // Const needs to strip any Xs
bool m_needC11; // Need C++11
bool m_needHeavy; // Need verilated_heavy.h include
bool m_needTraceDumper; // Need __Vm_dumperp in symbols
bool m_dpi; // Need __Dpi include files
bool m_useParallelBuild; // Use parallel build for model
int m_debugFileNumber = 0; // Number to append to debug files created
bool m_assertDTypesResolved = false; // Tree should have dtypep()'s
bool m_constRemoveXs = false; // Const needs to strip any Xs
bool m_needHeavy = false; // Need verilated_heavy.h include
bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols
bool m_dpi = false; // Need __Dpi include files
bool m_useParallelBuild = false; // Use parallel build for model
// Memory address to short string mapping (for debug)
typedef vl_unordered_map<const void*, std::string> PtrToIdMap; // The map type
typedef std::unordered_map<const void*, std::string> PtrToIdMap; // The map type
PtrToIdMap m_ptrToId; // The actual 'address' <=> 'short string' bijection
public:
@@ -90,21 +111,16 @@ public:
// CONSTRUCTORS
V3Global()
: m_rootp(NULL) // created by makeInitNetlist() so static constructors run first
, m_widthMinUsage(VWidthMinUsage::LINT_WIDTH)
, m_debugFileNumber(0)
, m_assertDTypesResolved(false)
, m_constRemoveXs(false)
, m_needC11(false)
, m_needHeavy(false)
, m_needTraceDumper(false)
, m_dpi(false)
, m_useParallelBuild(false) {}
: m_rootp{nullptr} // created by makeInitNetlist(} so static constructors run first
, m_hierPlanp{nullptr} // Set via hierPlanp(V3HierBlockPlan*} when use hier_block
, m_widthMinUsage{VWidthMinUsage::LINT_WIDTH} {}
AstNetlist* makeNetlist();
void boot() {
UASSERT(!m_rootp, "call once");
m_rootp = makeNetlist();
}
void clear();
void shutdown(); // Release allocated resorces
// ACCESSORS (general)
AstNetlist* rootp() const { return m_rootp; }
VWidthMinUsage widthMinUsage() const { return m_widthMinUsage; }
@@ -112,7 +128,7 @@ public:
// METHODS
void readFiles();
void checkTree();
void checkTree() const;
static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0,
bool doDump = true);
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
@@ -124,16 +140,19 @@ public:
if (newNumber) m_debugFileNumber = newNumber;
char digits[100];
sprintf(digits, "%03d", m_debugFileNumber);
return opt.makeDir() + "/" + opt.prefix() + "_" + digits + "_" + nameComment;
return opt.hierTopDataDir() + "/" + opt.prefix() + "_" + digits + "_" + nameComment;
}
bool needC11() const { return m_needC11; }
void needC11(bool flag) { m_needC11 = flag; }
bool needHeavy() const { return m_needHeavy; }
void needHeavy(bool flag) { m_needHeavy = flag; }
bool needTraceDumper() const { return m_needTraceDumper; }
void needTraceDumper(bool flag) { m_needTraceDumper = flag; }
bool dpi() const { return m_dpi; }
void dpi(bool flag) { m_dpi = flag; }
V3HierBlockPlan* hierPlanp() const { return m_hierPlanp; }
void hierPlanp(V3HierBlockPlan* plan) {
UASSERT(!m_hierPlanp, "call once");
m_hierPlanp = plan;
}
void useParallelBuild(bool flag) { m_useParallelBuild = flag; }
bool useParallelBuild() const { return m_useParallelBuild; }
const std::string& ptrToId(const void* p);

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