Compare commits

..
428 Commits
Author SHA1 Message Date
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
Wilson Snyder 04c0fc8aa7 Version bump 2020-06-06 07:48:47 -04:00
Wilson Snyder 1d8955fea5 Internal: Update fastcov.py from upstream. 2020-06-06 05:48:36 -04:00
Wilson Snyder 48740a0dba Tests: Add t_param_type 2020-06-05 22:22:44 -04:00
Geza Lore 4a404bd92e Always mask LSB in V3Merge Cond when mergin AstAnd 2020-06-06 00:17:59 +01:00
Wilson Snyder ff41701ddc Fix crash on undeclared packages. 2020-06-05 18:50:06 -04:00
Wilson Snyder 2590c9c4a6 Internal: Update fastcov.py from upstream. 2020-06-05 18:05:49 -04:00
Wilson Snyder c5d61da5d2 Internal coverage: Fix coverage of tests that abort. No functional change intended. 2020-06-05 08:00:22 -04:00
Wilson Snyder 5a622fd9db Tests: Temporary fix for (#2407) 2020-06-05 07:28:51 -04:00
Wilson Snyder c83b1478e1 Internals: Ifdef out V3Combine incomplete dead code. 2020-06-04 21:55:00 -04:00
Wilson Snyder 3243651c63 Internals: Fix misc internal coverage holes. No functional change intended. 2020-06-04 21:40:40 -04:00
Wilson Snyder 8d61cd9029 New fastcov internal coverage scheme 2020-06-04 20:59:52 -04:00
Wilson Snyder 7fe49de420 Tests: Tests to fix misc internal coverage holes. 2020-06-04 20:23:55 -04:00
Wilson Snyder a433096d5a Internals: Fix misc internal coverage holes. No functional change intended. 2020-06-04 19:49:39 -04:00
Geza Lore b88e1e6970 Travis: Fix cron (always build focal) 2020-06-04 17:36:53 +01:00
Wilson Snyder 79f228b04f Remove dead code (bisonreader) 2020-06-03 20:11:09 -04:00
Wilson Snyder d7cc1e6844 Tests: Use lint in many negative tests to avoid running under both vlt and vltmt 2020-06-03 20:05:13 -04:00
Wilson Snyder 42312101b5 Tests: Add array OOB tests as unsupported (#792) 2020-06-03 19:36:50 -04:00
Wilson Snyder 329f5b712a Tests: Add alias tests as unsupported (#697) 2020-06-03 19:27:22 -04:00
Geza Lore 6ddd92c0a1 Travis: Use workspaces and per job persistent ccache (#2399)
Change the Travis builds to use workspaces and persistent ccache

We proceed in 2 stages (as before, but using workspaces for
persistence):
1. In the 'build' stage, we clone the repo, build it and
   save the whole checkout ($TRAVIS_BUILD_DIR) as a workspace
2. In the 'test' stage, rather than cloning the repo, multiple jobs
   pull down the same workspace we built to run the tests from

This enables:
- Reuse of the build in multiple test jobs (this is what we used the Travis
  cache for before)
- Each job having a separate persistent Travis cache, which now only
  contains the ccache. This means all jobs, including 'build' and 'test'
  jobs can make maximum use of ccache across runs. This drastically cuts
  down build times when the ccache hits, which is very often the case for
  'test' jobs. Also, the separate caches only store the objects build by
  the particular job that owns the cache, so we can keep the per job
  ccache small.

If the commit message contains '[travis ccache clear]', the ccache will
be cleared at the beginning of the build. This can be used to test build
complete within the 50 minute timeout imposed by Travis, even without a
persistent ccache.
2020-06-03 21:10:13 +01:00
Tomasz Gorochowik 277dee109c Fix Ariane issues with PostAdd nodes (#2400) 2020-06-03 12:50:24 -04:00
Wilson Snyder ef71576825 Fix coredump from increment patch (#2391) 2020-06-03 08:30:49 -04:00
Wilson Snyder c3271aa891 Fix duplicate VLCOVGEN short code 2020-06-02 21:42:24 -04:00
Geza Lore 1cf17b5e78 Fix unused variable. 2020-06-02 22:45:55 +01:00
Ludwig Rogiers 2b6353b36e Support vpi_handle type vpiLeftRange and vpiRightRange for vpiRange objects (#2395)
* Implement vpi_handle type vpiLeftRange and vpiRightRange for vpiRange objects

* Change VerilatedVpioConst type to vpiConstant
2020-06-02 08:04:22 -04:00
Wilson Snyder 8b647f0977 Fix error on UNPACKED in parser. (#1541) 2020-06-02 08:00:37 -04:00
Wilson Snyder 4c31c5fab5 Fix unused variable. 2020-06-02 07:52:27 -04:00
Wilson Snyder 6ce878cb0d Fix some clang-tidy warnings 2020-06-01 23:16:17 -04:00
Geza Lore a67ba04c37 Remove dead code and some unused parameters
Found with CLion inspections
2020-06-01 17:49:42 +01:00
Wilson Snyder ae448e5ef9 Fix older GCC compiler error. 2020-06-01 09:08:50 -04:00
Wilson Snyder a57826b125 Line Coverage now tracks all statement lines, not just branch lines. 2020-05-31 15:52:17 -04:00
Geza Lore 656c460605 Add --dump-tree-addrids developer option 2020-05-31 20:21:55 +01:00
Geza Lore 95534fa5c5 Remove unused headers (#2389) 2020-05-31 20:21:07 +01:00
Wilson Snyder 611e8b10c6 Fix Verilog coverage to pass real column information 2020-05-31 09:05:10 -04:00
Michael Killough 047852eb08 Fix OpenBSD make in tests. (#2388) 2020-05-31 09:03:51 -04:00
Geza Lore 6318a08056 Fix --dump-tree with sparse dumps.
"No changes since last dump!" is now only printed if the "last" dump was
actually performed and not skipped due to V3Option::dumpTreeLevel
settings.
2020-05-31 13:48:30 +01:00
Wilson Snyder b60a92eed3 Fix pre-C11 compiler warning. 2020-05-30 21:11:37 -04:00
Geza Lore fe306a36b8 Add MergeCond pass to combine assignments with ?: on rhs (#2376)
This provides minor simulation performance benefit, but can provide
large C++ compilation time improvement, notably with Clang (4x).

This patch implements #2366 .
2020-05-30 21:09:05 +01:00
Geza Lore 18870f8b62 Remove remnants of long removed --trace-dups option
See #2385
2020-05-30 20:16:40 +01:00
Geza Lore 9712ceedd7 Internals: Remove empty statements. No functional change intended.
Remove stray semicolons, mostly by capturing them in macros accurately.
This removes a ton on lint warnings from CLion.
2020-05-30 19:13:18 +01:00
Wilson Snyder 2e32387e5c Fix GCC false warning on array bounds. (#2386) 2020-05-30 13:47:53 -04:00
Wilson Snyder b66877c9df Internals: Refactor V3Expand newWordSel. No functional change intended. 2020-05-30 13:47:53 -04:00
Geza Lore 74a6f94e2b Internals: Remove dead code 2020-05-30 17:20:23 +01:00
Wilson Snyder 35fc8b7259 Debug: Show column numbers in .tree files 2020-05-30 10:08:30 -04:00
Wilson Snyder e591afd101 Disable over-sensitive debug dump. 2020-05-30 09:35:48 -04:00
Wilson Snyder a41cdf4cfb Tests: Add driver_verilator_flags (for verilator_ext_tests) 2020-05-30 08:19:44 -04:00
Wilson Snyder ef72c42aa7 Commentary 2020-05-29 19:58:59 -04:00
Wilson Snyder fbc814b54a Internal code coverage fixes 2020-05-29 19:35:54 -04:00
Wilson Snyder 4cfa3f879a Internals: Allow VL_DANGLING on pointer const. 2020-05-29 18:31:53 -04:00
Wilson Snyder 4a8c7e869f Fix coverage issue 2020-05-29 17:59:35 -04:00
Tomasz Gorochowik a4a1c7a384 Fix swerv issues with Increment nodes (#2380) 2020-05-29 13:03:04 -04:00
Ludwig Rogiers 460315128b Fix vpi_get_value() error message when passing unsupported vpiHandle. (#2378) 2020-05-29 08:10:22 -04:00
Wilson Snyder 8ddafb4d9f Update contributors (from email) 2020-05-28 21:35:38 -04:00
Wilson Snyder ebda8f866c Cleanup codacity and missing consts. 2020-05-28 21:04:36 -04:00
Wilson Snyder 5ee4595aa8 Remove dead code (git_untabify), instead use make clang-format 2020-05-28 21:04:17 -04:00
Wilson Snyder 5089ac6119 Remove VL_ULL as ULL now in MSVC & C++11 2020-05-28 20:32:07 -04:00
Wilson Snyder 3f66f846cd Travis enable SystemC test (#1601) 2020-05-28 18:52:03 -04:00
Wilson Snyder 279f21bb5b Configure now enables SystemC if it is installed as a system headers. 2020-05-28 18:51:46 -04:00
Wilson Snyder 773ed97504 Internals Most VerilatedLockGuard can be const. No functional change intended. 2020-05-28 18:23:46 -04:00
Wilson Snyder b6d4899d3f Commentary 2020-05-28 18:09:31 -04:00
Maciej Sobkowski 9d48ff7745 Support pre/postifx incrementation/decrementation in array index (#2223) 2020-05-28 18:08:15 -04:00
Stephen Henry c4aab57c62 Internals: Refactor to introduce VerilatedFdList. (#2363) 2020-05-28 17:59:18 -04:00
Maarten De Braekeleer e8f27be200 Fix Visual Studio compiler issues (#2375)
* Make sure compiler creates same object file as target of rule
* MSVC requires a string return
* Case ranges are a gnu extension which MSVC does not understand
* _dupenv_s also returns 0 if the var could not be found
See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/dupenv-s-wdupenv-s?view=vs-2019
2020-05-28 17:39:20 -04:00
Wilson Snyder 15f0f967b3 Fix uninit variable warning 2020-05-28 17:33:44 -04:00
Wilson Snyder cbafff8a71 Commentary 2020-05-27 21:52:55 -04:00
Wilson Snyder 41e362b580 Tests: Remove some old conditional-fail checks. 2020-05-27 21:44:28 -04:00
Geza Lore 622f59ad65 Set OPT_FAST=-Os as default (#2374) 2020-05-28 00:57:49 +01:00
Wilson Snyder c5da38206e Fix configure over-disabling warnings. 2020-05-27 08:45:11 -04:00
Geza Lore d737266f64 Add OPT_GLOBAL to use for run-time library (#2373)
This allows compiling the run-time library with optimization even when OPT_FAST is not used in order to imporove model build speed, possibly during debug cycles.
2020-05-27 01:52:08 +01:00
Wilson Snyder 978c35995a Support const cast (ignored since not linting const yet) 2020-05-26 20:44:20 -04:00
Wilson Snyder 2af7f2fa18 Internals: Parser cleanup of cast. 2020-05-26 20:29:54 -04:00
Wilson Snyder 373c9090d3 Update contributors (from email) 2020-05-26 19:12:19 -04:00
Stefan Wallentowitz 723d407a87 [docker] Unify docker files (#2371)
Unify the actions in the Dockerfiles between the runtime environment
and the run containers.

Fixes #2345

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-26 20:38:43 +02:00
Stefan Wallentowitz dc90e6c3c3 Generate file with waivers (#2354)
This adds the flag --generate-waivefile <filename>. This will generate
a verilator config file with the proper lint_off statemens to turn off
warnings emitted during this particular run.

This feature can be used to start with using Verilator as linter and
systematically capture all known lint warning for further
elimination. It hopefully helps people turning of -Wno-fatal or
-Wno-lint and gradually improve their code base.

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-26 20:38:14 +02:00
Stefan Wallentowitz 68a2ed6776 Fix output of loops on waiving (#2355)
When an unopt loop is waived, we also don't want the loop's example
path being plot.

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-26 08:45:57 +02:00
Wilson Snyder 7f32d4dc45 Internals: Parser cleanup of expressions. 2020-05-25 21:51:05 -04:00
Geza Lore 7b683fe258 Use sane --output-split values by default to help large builds
--output-split is now on by default with value 20000.
--output-split-cfuncs and --output-split-ctrace now defaults to the
value of --output-split unless explicitly specified.
2020-05-26 01:22:10 +01:00
Geza Lore 72858175a2 Only emit VM_PARALLEL_BUILDS=1 iff --output-split caused a split.
Previously we set VM_PARALLEL_BUILDS=1 if the --output-split option was
provided. Now we only do it iff it actually causes a split.
2020-05-26 01:22:10 +01:00
Geza Lore 9d7086067c Rework serial/parallel build mode
Instead of __ALLfast.cpp and __ALLslow.cpp, we now create only a single
__ALL.cpp and compile it with OPT_FAST, this speeds up small builds
where the C compiler does not dominate. A separate patch will follow
turning VM_PARALLEL_BUILDS on by default at a certain size.

Given this change to the build there is now no point in emitting both
fast and slow routines into the same .cpp file when --output-split is
not set as they will be just included in the same __ALL.cpp file. To
keep things simpler and the output easier to comprehend, V3EmitC has
also been changed to always emit the fast and slow files separately.

Also change verilated.mk to apply OPT_SLOW to all slow files, not just
ones called *__Slow.cpp. This change in particular ensures __Syms.cpp
is build as slow.

Part of #2360.
2020-05-26 01:22:10 +01:00
Wilson Snyder 5bb1da88ed Internals: Comment grammar continuations. No functional change. 2020-05-25 19:40:20 -04:00
Wilson Snyder 9969a60b34 Commentary 2020-05-25 18:51:12 -04:00
Wilson Snyder 72402fa91e Internals: Parser cleanup of parameters, second part. 2020-05-25 18:49:29 -04:00
Wilson Snyder 8255f3f9fe Internals: Parser cleanup of parameters, first part. 2020-05-25 18:41:47 -04:00
Wilson Snyder 8957f77793 Internals: Refector needHeavy into methods. No functional change intended. 2020-05-25 15:34:24 -04:00
Wilson Snyder 7187b82d1d Update contributors (from email). 2020-05-25 13:36:24 -04:00
Ahmed El-Mahmoudy 1a92a58720 Fix spelling mistakes (#2364) 2020-05-25 12:43:32 -04:00
Wilson Snyder 2351f9b9ad Update contributors (from email). 2020-05-25 10:54:22 -04:00
Wilson Snyder abc3c216f8 Internal code coverage: Better support fastcov [still not default]. 2020-05-25 10:50:46 -04:00
Wilson Snyder f1afa667d7 Update contributors. 2020-05-25 09:16:40 -04:00
Wilson Snyder 76d0671952 Travis: Fix cron. 2020-05-25 08:46:46 -04:00
Jan Van Winkel 424769c32b Fix warning for unused param in VL_RTOIROUND_Q_D (#2356) 2020-05-25 08:13:12 -04:00
Wilson Snyder f7249ad23a Internals: AstRefDType points to AstTypedef instead of sub-dtype, in prep for future commits. 2020-05-24 14:22:06 -04:00
Wilson Snyder 613d76c578 Travis: Fix cron. 2020-05-24 08:30:59 -04:00
Wilson Snyder 50662751fe Fix compiler unsigned warnings 2020-05-23 22:38:17 -04:00
Wilson Snyder c9e59e767a Tests: Add setenv method. 2020-05-23 22:24:26 -04:00
Vassilis Papaefstathiou a7432bdea7 Support wide operands in queues and dynamic arrays (#2352) 2020-05-23 21:59:56 -04:00
Wilson Snyder 9ffad7f0db Internal cleanups. No functional change intended 2020-05-23 21:57:08 -04:00
Wilson Snyder 3097d5e093 Commentary 2020-05-23 21:56:56 -04:00
Yuri Victorovich cff4b5a5ee Fix WIFEXITED error on FreeBSD. (#2351) (#2353) 2020-05-23 16:30:36 -04:00
Wilson Snyder eda46e3949 Internals: Favor exprOrDataType where possible. No functional change intended. 2020-05-23 13:08:56 -04:00
Wilson Snyder 71651718d4 Internals: Track :: in AstDot parsing. No parsing change intended. 2020-05-23 12:44:15 -04:00
Wilson Snyder da0cb44954 Internals: Refactor parsing id's up to parent rules. No functional change intended. 2020-05-23 12:19:43 -04:00
Wilson Snyder 57621a93ad Internals: Move PLI errors into linker, and better test. 2020-05-23 11:55:34 -04:00
Wilson Snyder 6a882f9dc6 Internal code coverage improvements. No functional change intended. 2020-05-23 10:34:58 -04:00
Wilson Snyder c18b0eb122 Internal coverage: Limit parallelism to core count. 2020-05-23 09:50:04 -04:00
Wilson Snyder 3c28a66acf Internal coverage: Fix --hashset option. --stop now default. 2020-05-23 09:17:16 -04:00
Wilson Snyder 5c11de1663 Tests: Check queue typedef. 2020-05-22 22:14:26 -04:00
Wilson Snyder 72ea6bf414 Travis: Fix cron. 2020-05-22 08:39:56 -04:00
Ludwig Rogiers 101314a572 Add VPI error reset to vpi_get_time() (#2347) 2020-05-22 07:09:47 -04:00
Wilson Snyder 01f3e81a36 Internals: Parse extend/implements/etc using generic identifiers. 2020-05-21 21:31:15 -04:00
Wilson Snyder 3cb3b6c400 clang-format verilog.l. No functional change. 2020-05-21 19:46:21 -04:00
Wilson Snyder 8f58b58853 Internals: Parse using idAny where can to better detect id errors. 2020-05-20 23:29:37 -04:00
Wilson Snyder b66826169d Internals: Refactor inherits/extends parse so don't need type vs nontype IDs. 2020-05-20 23:10:45 -04:00
Wilson Snyder d2a7376f14 Fix spacing. No functional change 2020-05-20 22:33:32 -04:00
Wilson Snyder c9e8a1cb4d Commentary 2020-05-20 20:31:57 -04:00
Wilson Snyder 8170f6f03f Travis: Fix cron. 2020-05-20 17:39:32 -04:00
Stefan Wallentowitz 0abf88823f Docker upgrade to Ubuntu 20.04 (#2318)
* [docker] Remove versions from Docker files

There is no dependency on an actual version, it was only there to
silence the linter. Instead the linter is now set to not warn about
it.

Signed-off-by: Stefan Wallentowitz <[email protected]>

* [docker] Update to Ubuntu 20.04

Update to new Ubuntu release:

 - Only GCC 9.3 available. Also add clang (10.0) now.
 - SystemC is now a package 🎉

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-20 06:58:43 -04:00
Todd Strader accf5a9a17 Check if Parallel::Forker is new enough (#2343) 2020-05-19 14:31:13 -04:00
Wilson Snyder c64c81b7a3 Workaround missing guard (partial #2333). 2020-05-19 08:31:52 -04:00
Wilson Snyder 7834028842 Tests: Skip genhtml if too old 2020-05-19 08:24:21 -04:00
Wilson Snyder 1e0d5eb238 Release examples/Makefiles under CC0. 2020-05-18 22:23:19 -04:00
Wilson Snyder b5460bd867 Travis-CI fixes 2020-05-18 18:34:26 -04:00
Geza Lore 53cde90c8f De-constify fields to appease old GCC with broken STL
No functional change intended, fixes #2342
2020-05-18 19:01:08 +01:00
Geza Lore d20a4db773 Fix regression due to early constant folding in +: and -: (#2338) 2020-05-18 18:46:00 +01:00
Wilson Snyder 0f7677480f Commentary 2020-05-18 08:11:56 -04:00
Stephen Henry ba3930777a Support display/scan %u/%z (#2324) (#2332) 2020-05-18 08:10:32 -04:00
Geza Lore 9c054a5774 Optimize trace activity flags a bit more
- Improve flag pruning heuristic
- Set all trace activity flags in slow code. This in turns enables us
to remove checking the slow flag on the fast path.
2020-05-17 19:41:24 +01:00
Stephen Henry cef0105dfc Fix requiring C++11 algorithms. (#2339) (#2340) 2020-05-17 11:44:42 -04:00
Wilson Snyder 4773a1e77c Misc internal coverage improvements. 2020-05-17 11:06:14 -04:00
Wilson Snyder ed4c7038b4 Tracing: Remove dead code. No functional change intended. 2020-05-17 09:53:58 -04:00
Wilson Snyder c4f31d3bb6 Tracing: Remove dead code. No functional change intended. 2020-05-17 09:52:03 -04:00
Geza Lore dc25e9b949 Optimize fine grained trace activity flags (#2336)
Firstly, we always use a byte array for fine grained activity flags
instead of a bit vector (we used to use a byte array only if we had
parallel mtasks). The byte vector can be set more cheaply in eval,
closing about 1/3 of the gap in performance between compiling with
or without --trace on SweRV EH1. The speed of tracing itself is not
measurably different.

Secondly, we prune the activity tracking such that if a set of activity
flag combinations only guard a small number of signals, we will turn
those signals into awayls traced signals. This avoids code which
sometimes tests dozens of activity flags just to subsequently check one
signal and dump it if it's value changed. We can just check the signal
state straight instead, and not bother with the flags. This removes
about 30% of activity flags in SweRV EH1, and makes both single threaded
VCD and FST tracing 8-9% faster.
2020-05-17 13:53:02 +01:00
Wilson Snyder 1f52b01b2c Travis: Fix cron. 2020-05-17 08:48:31 -04:00
Wilson Snyder d5fc0fca41 Travis: Fix cron. 2020-05-17 08:19:42 -04:00
Wilson Snyder 212aa332dd Commentary 2020-05-16 18:53:18 -04:00
Wilson Snyder 17e7da77f0 Misc internal coverage improvements. 2020-05-16 18:02:54 -04:00
Wilson Snyder 201f0d3f5f Codecov badge 2020-05-16 15:02:22 -04:00
Wilson Snyder 7d0b3b300a Travis: Setup cron coverage 2020-05-16 14:59:30 -04:00
Wilson Snyder 0b55e205f7 Internal code_coverage: speedup aggregation. 2020-05-16 14:53:22 -04:00
Wilson Snyder 9c0c6439cc Clean additional objects. 2020-05-16 13:28:03 -04:00
Wilson Snyder d33d0301f8 Support verilator_coverage --write-info for lcov HTML reports. 2020-05-16 09:18:35 -04:00
Wilson Snyder 6fd7f45cef Internals: Remove dead needHInlines code 2020-05-16 07:53:27 -04:00
Wilson Snyder 57a937df03 Misc internal coverage cleanups 2020-05-16 07:43:22 -04:00
Wilson Snyder ffd461dcf8 Tests: Check need -cc message 2020-05-16 07:10:44 -04:00
Wilson Snyder f77058774e Add codecov.yml 2020-05-16 06:15:45 -04:00
Wilson Snyder 1d0a726437 Update internal code coverage framework. 2020-05-16 06:15:25 -04:00
Wilson Snyder 29bcbb0417 Suppress impossible code coverage issues 2020-05-15 22:34:29 -04:00
Wilson Snyder 2d11c2cbb3 Tests: Fix driver called with no tests 2020-05-15 22:33:35 -04:00
Wilson Snyder 2edbcce032 Tests: Need only one run of t_trace_c_api.pl 2020-05-15 22:33:20 -04:00
Wilson Snyder 35a53d9adb Add t_trace_c_api test. 2020-05-15 20:38:08 -04:00
Wilson Snyder 2885c2ce97 Fix coredump on countbits. 2020-05-15 19:29:17 -04:00
Geza Lore 900c023bb5 Refactor trace implementation to allow experimentation
The main goal of this patch is to enable splitting the full and
incremental tracing functions into multiple functions, which can then be
run in parallel at a later stage. It also simplifies further
experimentation as all of the interesting trace code construction now
happens in V3Trace. No functional change is intended by this patch, but
there are some implementation changes in the generated code.

Highlights:
- Pass symbol table directly to trace callbacks for simplicity.
- A new traceRegister function is generated which adds each trace
function as an individual callback, which means we can have multiple
callbacks for each trace function type.
- A new traceCleanup function is generated which clears the activity
flags, as the trace callbacks might be implemented as multiple functions.
- Re-worked sub-function handling so there is no separate sub-function
for each trace activity class. Sub-functions are generate when required
by splitting.
- traceFull/traceChg are now created in V3Trace rather than V3TraceDecl,
this requires carrying the trace value tree in TraceDecl until it
reaches V3Trace where the TraceInc nodes are created (previously a
TraceInc was also created in V3TraceDecl which carries the value).
2020-05-15 18:34:29 +01:00
Geza Lore 12b95f6b93 Clean up V3TraceDecl & V3Trace. No functional change intended.
- Constify variables
- Remove redundancies
- [Hopefully] make some code a bit more readable
2020-05-15 18:34:29 +01:00
Wilson Snyder 85de3048a5 Tests: Avoid poluting non-obj_ files. 2020-05-14 18:50:49 -04:00
Wilson Snyder c1a9fe07e9 Support multi channel descriptor I/O (#2190)
clang-format and Changes update. No functional change.
2020-05-14 18:14:50 -04:00
Stephen Henry 1a0da2e4ec Support multi-channel descriptor (MCD) I/O (#2197) 2020-05-14 18:03:00 -04:00
Wilson Snyder 38d11ecabe Commentary 2020-05-13 21:06:00 -04:00
Wilson Snyder 148762364b Tests: Complicated for loops long ago supported. 2020-05-13 20:53:55 -04:00
Huang Rui 68d7596adf Fix compile error when using bison 3.6.1 (#2320)
Workaround issue: bison 3.6.1 generated unexpected nested-comment
Closes: https://github.com/verilator/verilator/issues/2320
Signed-off-by: Huang Rui <[email protected]>
2020-05-13 19:18:56 -04:00
Wilson Snyder f005b7fd87 Support scan %* format 2020-05-11 22:13:59 -04:00
Wilson Snyder 68ed683681 Travis: Run 20.04 for non-cron, more others for cron. 2020-05-11 20:31:37 -04:00
Wilson Snyder 61e41595a2 Fix clang warning 2020-05-11 20:31:37 -04:00
Stephen Henry 484b574cef Fix crash on self-referential enum type. (#2319) 2020-05-11 18:44:28 -04:00
Wilson Snyder 29695adf70 Fix 10s/100s timeunits. 2020-05-11 08:15:52 -04:00
Wilson Snyder fac43811fd Commentary 2020-05-10 21:26:09 -04:00
Wilson Snyder 15f63d12d5 Fix message for seeded random. 2020-05-10 21:15:48 -04:00
Wilson Snyder ba7b3fd60f Support $display(,,). 2020-05-10 20:48:18 -04:00
Wilson Snyder 897b9ccfe2 Fix display of huge double. 2020-05-10 16:03:46 -04:00
Wilson Snyder b97e1aa9fe Support cast to string 2020-05-10 15:42:16 -04:00
Wilson Snyder d4a631446b Fix crash in unroller on increment-only while loops. 2020-05-10 15:26:41 -04:00
Wilson Snyder a2cc053c6f Tests: Fix t_math_svl.pl 2020-05-10 15:19:38 -04:00
Wilson Snyder 8998ffc4e5 Support reporting some fork syntax errors. 2020-05-10 15:01:43 -04:00
Wilson Snyder ca162716c6 Internals: clang-format 2020-05-10 14:29:15 -04:00
Wilson Snyder 629dd16714 Tests: Rename t_delay_func_bad 2020-05-10 14:28:42 -04:00
Wilson Snyder 12b903caf4 Improve error on using array.unique method. 2020-05-10 14:28:42 -04:00
Yossi Nivin f9a0cf0cff Support $countbits (#2287) 2020-05-10 14:27:22 -04:00
Wilson Snyder 070bcddf5a Support unpacked array .sum and .product. 2020-05-10 12:48:33 -04:00
Wilson Snyder feb1e2bd48 Commentary 2020-05-10 11:01:57 -04:00
Wilson Snyder 6e7ee23644 Internals: Code cleanups. 2020-05-09 15:00:46 -04:00
Wilson Snyder c00cc18d37 Optimize dead code after gotos 2020-05-09 15:00:36 -04:00
Wilson Snyder a7e17a8855 Fix double conversion on half of conditional. 2020-05-08 21:35:45 -04:00
Wilson Snyder 60fa1db731 Tests: Trivial cleanup 2020-05-08 21:35:45 -04:00
Geza Lore ac09ad3ffd Minor improvements to DPI open array handling (#2316)
- Allow arbitrary number of open array dimensions, not just 3. Note
right now this only works with the array querying functions specified
in IEEE 1800-2017 H.12.2
- Issue error when passing dynamic array or queue as DPI open array
(currently unsupported)
- Also tweaked AstVar::vlArgTypeRecurse, which should now error or fail
for unsupported types.
2020-05-08 18:22:44 +01:00
Wilson Snyder 27953e26b6 Backout example change. 2020-05-08 07:35:54 -04:00
Wilson Snyder 9375d9f603 Fix $isunknown with constant Zs. 2020-05-07 21:40:08 -04:00
Wilson Snyder 72bd91c7f1 Support $isunbounded and parameter $. (#2104) 2020-05-07 21:12:58 -04:00
Wilson Snyder 8850ca962e Fix newish error to use standard parens to ref IEEE. 2020-05-07 21:12:58 -04:00
Wilson Snyder 7fd590f855 Commentary 2020-05-07 21:12:58 -04:00
Wilson Snyder 5f7ae1fbce wip 2020-05-07 21:04:26 -04:00
Wilson Snyder b56a25e89c Fix newish error to use standard parens to ref IEEE. 2020-05-07 18:21:11 -04:00
Wilson Snyder 4f32b093e6 Commentary 2020-05-07 18:11:06 -04:00
Geza Lore 6a54fb6f96 Modify std::multimap in V3Combine safely.
We used to iterate the m_callMmap std::multimap by getting limit
iterators from equal_range, but we also modify the same map in the loop
which invalidates those limit iterators. Note this only caused actual
problems if the new AstCCall inserted via 'addCall' in the loop had a
memory address (which is used as the key) which fell into the range
returned by equal_range, so was pretty hard to trigger.
2020-05-07 14:31:43 +01:00
Wilson Snyder 546ccd56c4 Internals: Enable future JumpGo to non-end. No functional change intended. 2020-05-06 21:33:05 -04:00
Wilson Snyder ca77a93214 Add lint check for bad delay locations. 2020-05-06 19:25:13 -04:00
Dan Petrisko ee1b20e1cd Adding missing sstream include (#2312) 2020-05-06 19:16:41 -04:00
Yutetsu TAKATSUKASA aa86e0bbc0 Support 'E', 'p', and 'P' when overriding floating point parameter. (#2310) 2020-05-06 07:45:07 -04:00
Wilson Snyder b6b3482010 Internals: Use typ delay by default 2020-05-05 20:42:19 -04:00
Wilson Snyder 05aecd2c0b Internals: Fix tabs in astgen. No effective functional change. 2020-05-05 20:33:35 -04:00
Wilson Snyder 6ab3d8f3ed Internals: Refactor to add AstNodeProcedure. No functional change intended. 2020-05-05 19:12:36 -04:00
Wilson Snyder 0fcc7f2987 Fix default pkgconfig version to have no spaces (#2308) 2020-05-05 08:46:24 -04:00
Wilson Snyder 7d7e67b49b Show Verilog reference on V3Number asserts. 2020-05-04 19:57:21 -04:00
Wilson Snyder a41ea180fa Fix +: and -: on unpacked arrays. (#2304) 2020-05-04 19:40:50 -04:00
Wilson Snyder 98889b3f4e Tests: Fix permission 2020-05-04 19:35:48 -04:00
Tim Snyder 83fbfa8c71 Fix /usr/bin/env perl in lieu of /usr/bin/perl (#2307)
Enables scripts to work where perl is not installed at /usr/bin/perl
2020-05-04 19:27:30 -04:00
Tim Snyder a57262d6e7 Fix use /usr/bin/env perl in lieu of /usr/bin/perl (#2306)
Enables scripts to work where perl is not installed at /usr/bin/perl
2020-05-04 18:42:15 -04:00
Geza Lore fe708f045a Fix Travis oddity 2020-05-04 00:21:07 +01:00
Geza Lore 8afcd67a1f Fix FST tracing of little endian vectors 2020-05-03 22:39:45 +01:00
Wilson Snyder 16e258eb4c Commentary: reformat changes, relocate announcements 2020-05-03 16:10:02 -04:00
Wilson Snyder d6fbbddac9 devel release 2020-05-03 11:18:53 -04:00
1961 changed files with 39083 additions and 22476 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
@@ -3,3 +3,4 @@ exclude_paths:
- '.github/**'
- 'ci/build_verilator.sh'
- 'include/vltstd/**'
- 'nodist/fastcov.py'
+1
View File
@@ -1,5 +1,6 @@
\#*
.#*
.nfs*
*~
*.tidy
*.old
+122 -160
View File
@@ -8,176 +8,138 @@
version: ~> 1.0
os: linux
language: cpp
cache: ccache
env:
global:
- VERILATOR_CACHE=$HOME/verilator_cache
- VERILATOR_ROOT=$PWD
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
- VERILATOR_AUTHOR_SITE=1
cache:
directories:
- $VERILATOR_CACHE
- $HOME/.ccache
before_install:
# Perl modules needed for testing
# Not listing Bit::Vector as slow to install, and only skips one test
- touch temp.cpp ; g++ -E -dM -c temp.cpp | sort ; rm -rf temp.cpp
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
- sudo apt-get install gdb gtkwave
- sudo apt-get install libgoogle-perftools-dev
before_script:
- bash -x ci/build_vcddiff.sh
- bash -x ci/build_verilator.sh
after_script:
- ccache -s
env:
global:
- VERILATOR_ROOT=$TRAVIS_BUILD_DIR
# The list and order of build stages
stages:
- "Build Verilator"
- test
- build # Build Verilator
- test # Run tests
# Dump info about the environment for debugging
before_install:
# To dump the script that Travis itself is executing, add 'cat $0' here
- cd "$TRAVIS_BUILD_DIR" # Skipping the git clone in later stages requires this
- export CCACHE_MAXSIZE=$(ci/travis-ccache-size.bash) # Set here after the 'cd'
- env | sort
- ls -lA .
- ls -lA bin
- g++ -E -dM -c -x c++ /dev/null | sort
- 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
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" ] && [ "$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
# All jobs run the same script
script: ./ci/travis-script.bash
# Enumerate all the jobs
jobs:
include:
- if: type != cron
stage: "Build Verilator"
name: Build Verilator
compiler: gcc
script: echo "Done building Verilator"
# Non-cron build will just run on whatever linux flavor we get
- if: type != cron
stage: test
name: Dist test
compiler: gcc
script: ci/test.sh dist
- if: type != cron
stage: test
name: Vlt test
compiler: gcc
script: ci/test.sh vlt
- if: type != cron
stage: test
name: Vltmt set 0 test
compiler: gcc
script: ci/test.sh vltmt0
- if: type != cron
stage: test
name: Vltmt set 1 test
compiler: gcc
script: ci/test.sh vltmt1
# Cron builds try different OS/compiler combinations
- if: type = cron
stage: "Build Verilator"
name: Build xenial gcc Verilator
os: linux
dist: xenial
compiler: gcc
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Xenial gcc dist test
os: linux
dist: xenial
compiler: gcc
script: ci/test.sh dist
- if: type = cron
stage: test
name: Xenial gcc vlt test
os: linux
dist: xenial
compiler: gcc
script: ci/test.sh vlt
- if: type = cron
stage: test
name: Xenial gcc vltmt test
os: linux
dist: xenial
compiler: gcc
script: ci/test.sh vltmt
- if: type = cron
stage: "Build Verilator"
name: Build xenial clang Verilator
os: linux
dist: xenial
compiler: clang
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Xenial clang dist test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh dist
- if: type = cron
stage: test
name: Xenial clang vlt test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh vlt
- if: type = cron
stage: test
name: Xenial clang vltmt test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh vltmt
# - if: type = cron
# stage: "Build Verilator"
# name: Build OSX gcc Verilator
# os: osx
# compiler: gcc
# script: echo "Done building Verilator"
# - if: type = cron
# stage: test
# name: OSX gcc dist test
# os: osx
# compiler: gcc
# script: ci/test.sh dist
# - if: type = cron
# stage: test
# name: OSX gcc vlt test
# os: osx
# compiler: gcc
# script: ci/test.sh vlt
# - if: type = cron
# stage: test
# name: OSX gcc vltmt test
# os: osx
# compiler: gcc
# script: ci/test.sh vltmt
- if: type = cron
stage: "Build Verilator"
name: Build trusty gcc Verilator
os: linux
dist: trusty
compiler: gcc
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Trusty gcc dist test
os: linux
dist: trusty
compiler: gcc
script: ci/test.sh dist
- if: type = cron
stage: test
name: Trusty gcc vlt test
os: linux
dist: trusty
compiler: gcc
script: ci/test.sh vlt
- if: type = cron
stage: test
os: linux
dist: trusty
name: Trusty gcc vltmt test
compiler: gcc
script: ci/test.sh vltmt
############################################################################
# Jobs in the 'build' stage
############################################################################
# GCC builds
- {stage: build, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {create: {name: trusty-gcc, paths: .}}}
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {create: {name: xenial-gcc, paths: .}}}
- {stage: build, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {create: {name: bionic-gcc, paths: .}}}
- {stage: build, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc, paths: .}}}
# Clang builds
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {create: {name: xenial-clang, paths: .}}}
- {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
############################################################################
# GCC tests
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
# Clang tests
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
# Coverage tests
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
- {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:
+999 -868
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -45,6 +45,7 @@ src/Makefile$
src/Makefile_obj$
include/verilated.mk$
test_regress/.gdbinit$
codecov.yml
config.cache$
config.status$
verilator\.log
+5 -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. ####
@@ -425,6 +424,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 +437,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 +464,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 +545,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
+9 -6
View File
@@ -5,6 +5,7 @@ ifdef::env-github[]
image:https://img.shields.io/badge/License-LGPL%20v3-blue.svg[license LGPLv3,link=https://www.gnu.org/licenses/lgpl-3.0]
image:https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg[license Artistic-2.0,link=https://opensource.org/licenses/Artistic-2.0]
image:https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f[Code Quality,link=https://www.codacy.com/gh/verilator/verilator]
image:https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg[Coverage,link=https://codecov.io/gh/verilator/verilator]
image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator]
endif::[]
@@ -20,9 +21,9 @@ endif::[]
== Welcome to Verilator
[cols="a,a",indent=0,frame="none"]
[cols="a,a",indent=0,frame="none",grid="rows"]
|===
^.^| *Welcome to Verilator, the fastest Verilog HDL simulator.*
^.^| *Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.*
+++ <br/> +++ &bullet; Accepts synthesizable Verilog or SystemVerilog
+++ <br/> +++ &bullet; Performs lint code-quality checks
+++ <br/> +++ &bullet; Compiles into multithreaded {cpp}, or SystemC
@@ -73,15 +74,15 @@ replacement for NC-Verilog, VCS or another commercial Verilog simulator, or
if you are looking for a behavioral Verilog simulator e.g. for a quick
class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for
this.) However, if you are looking for a path to migrate SystemVerilog to
{cpp} or SystemC, and your team is comfortable writing just a
touch of {cpp} code, Verilator is the tool for you.
{cpp} or SystemC, or your team is comfortable writing just a touch of {cpp}
code, Verilator is the tool for you.
== Performance
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather,
Verilator compiles your code into a much faster optimized and optionally
thread-partitioned model, which is in turn wrapped inside a
{cpp}/SystemC/{cpp}-under-Python module. The results are a compiled
{cpp}/SystemC module. The results are a compiled
Verilog model that executes even on a single-thread over 10x faster than
standalone SystemC, and on a single thread is about 100 times faster than
interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus
@@ -112,9 +113,11 @@ For more information:
* https://verilator.org/verilator_doc.html[Verilator manual (HTML)],
or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
* https://github.com/verilator/verilator-announce[Subscribe to verilator announcements]
* https://verilator.org/forum[Verilator forum]
* https://verilator.org/issues[Verilator Issues]
* https://verilator.org/issues[Verilator issues]
== Support
+760 -600
View File
File diff suppressed because it is too large Load Diff
+17 -3
View File
@@ -156,6 +156,8 @@ verilator_coverage - Verilator coverage analyzer
verilator_coverage -write merged.dat -read <datafiles>...
verilator_coverage -write-info merged.info -read <datafiles>...
Verilator_coverage processes Verilator coverage reports.
With --anotate, it reads the specified data file and generates annotated
@@ -224,8 +226,20 @@ Displays program version and exits.
=item --write I<filename>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename. This is useful in scripts to
combine many sequential runs into one master coverage file.
should be written to the given filename in verilator_coverage data format.
This is useful in scripts to combine many sequential runs into one master
coverage file.
=item --write-info I<filename.info>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in C<lcov> .info format.
This may be used to use C<lcov> to aggregate or generate reports.
The info format loses data compared to the Verilator coverage data format;
the info will all forms of coverage converted to line style coverage, and
if there are multiple coverage points on a single line, the minimum
coverage across those points will be used to report coverage of the line.
=back
@@ -277,7 +291,7 @@ Wilson Snyder <[email protected]>
=head1 SEE ALSO
C<verilator>
C<verilator>, C<lcov>
L<verilator_coverage --help> which is the source for this document.
-19
View File
@@ -1,19 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Build script for vcddiff
#
# Copyright 2019 by Todd Strader. 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
set -e
# NB: it would be better to add this via a PPA
TMP_DIR=$(mktemp -d)
git -C "${TMP_DIR}" clone https://github.com/veripool/vcddiff
VCDDIFF_DIR=${TMP_DIR}/vcddiff
git -C "${VCDDIFF_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${VCDDIFF_DIR}"
sudo cp "${VCDDIFF_DIR}/vcddiff" /usr/local/bin
-65
View File
@@ -1,65 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Travis CI build script
#
# Copyright 2019 by Todd Strader. 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 script builds and caches the Verilator binaries for Travis CI
# (and possibly other CI platforms). The Verilator CI system uses this
# script, but other CI systems that depend on Verilator may also use
# the script.
# see: https://github.com/verilator/verilator_ext_tests/blob/master/.travis.yml
# To use this script, either checkout Verilator as part of the CI build
# process or add Verilator as a Git submodule. Verilator tarballs can
# not be used as the script relies on Git revisions for caching.
set -e
if [ -z "${VERILATOR_NUM_JOBS}" ]; then
VERILATOR_NUM_JOBS=$(nproc)
fi
# Caching would be simpler if we installed without VERILATOR_ROOT, but
# it's needed for driver.pl outside of the repo
if [ -z "${VERILATOR_ROOT}" ]; then
echo "VERILATOR_ROOT not set"
exit -1
fi
if [ -z "${VERILATOR_CACHE}" ]; then
echo "VERILATOR_CACHE not set"
exit -1
fi
VERILATOR_REV=$(cd "${VERILATOR_ROOT}" && git rev-parse HEAD)
echo "Found Verilator rev ${VERILATOR_REV}"
CACHED_REV_FILE=${VERILATOR_CACHE}/.rev.txt
if [[ ! -f "${CACHED_REV_FILE}" || \
$(< "${CACHED_REV_FILE}") != "${VERILATOR_REV}" ]]; then
echo "Building Verilator"
# Unsure why Travis monkies with the capitalization of the stage name, but it does
if [[ -n ${TRAVIS_BUILD_STAGE_NAME} && \
${TRAVIS_BUILD_STAGE_NAME} != "Build verilator" ]]; then
echo "WARNING: Building Verilator in Travis build stage other than \"Build verilator\": ${TRAVIS_BUILD_STAGE_NAME}"
fi
cd "${VERILATOR_ROOT}"
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS} && make -j ${VERILATOR_NUM_JOBS}
# Copy the Verilator build artifacts
mkdir -p "${VERILATOR_CACHE}"
rm -rf ${VERILATOR_CACHE}/*
cp bin/*bin* "${VERILATOR_CACHE}"
# Remember the Git revision
echo "${VERILATOR_REV}" > "${CACHED_REV_FILE}"
else
echo "Using cached Verilator"
cd "${VERILATOR_ROOT}"
# Create include/verilated_config.h and maybe other things
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS}
cp ${VERILATOR_CACHE}/* bin
fi
+27 -29
View File
@@ -6,44 +6,40 @@
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:18.04
FROM ubuntu:20.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends -y \
autoconf=2.69-11 \
bc=1.07.1-2 \
bison=2:3.0.4.dfsg-1build1 \
build-essential=12.4ubuntu1 \
ca-certificates=20180409 \
cmake=3.10.2-1ubuntu2.18.04.1 \
flex=2.6.4-6 \
gdb=8.1-0ubuntu3.2 \
gcc-6=6.5.0-2ubuntu1~18.04 \
gcc-5=5.5.0-12ubuntu1 \
gcc-4.8=4.8.5-4ubuntu8 \
git=1:2.17.1-1ubuntu0.5 \
gtkwave=3.3.86-1 \
g++-6=6.5.0-2ubuntu1~18.04 \
g++-5=5.5.0-12ubuntu1 \
g++-4.8=4.8.5-4ubuntu8 \
libfl2=2.6.4-6 \
libfl-dev=2.6.4-6 \
numactl=2.0.11-2.1ubuntu0.1 \
perl=5.26.1-6ubuntu0.3 \
python3=3.6.7-1~18.04 \
wget=1.19.4-1ubuntu2.2 \
zlibc=0.9k-4.3 \
zlib1g=1:1.2.11.dfsg-0ubuntu2 \
zlib1g-dev=1:1.2.11.dfsg-0ubuntu2 \
autoconf \
bc \
bison \
build-essential \
ca-certificates \
ccache \
clang \
cmake \
flex \
gdb \
git \
gtkwave \
libfl2 \
libfl-dev \
libgoogle-perftools-dev \
libsystemc \
libsystemc-dev \
numactl \
perl \
python3 \
wget \
zlibc \
zlib1g \
zlib1g-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /tmp
COPY build-systemc.sh /tmp/
RUN ./build-systemc.sh
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
RUN git clone https://github.com/veripool/vcddiff.git && \
@@ -55,4 +51,6 @@ COPY build.sh /tmp/build.sh
ENV VERILATOR_AUTHOR_SITE=1
WORKDIR /work
ENTRYPOINT [ "/tmp/build.sh" ]
+3 -3
View File
@@ -5,7 +5,7 @@ build. It uses the following parameters:
* Source repository (default: https://github.com/verilator/verilator)
* Source revision (default: master)
* GCC version (4.8.5, 5.5.0, 6.5.0, 7.4.0, default: 7.4.0)
* Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0)
The container is published as `verilator/verilator-buildenv` on
https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub].
@@ -20,13 +20,13 @@ To also run tests:
To change the compiler:
docker run -ti -e CC=gcc-4.8 -e CXX=g++-4.8 verilator/verilator-buildenv test
docker run -ti -e CC=clang-10 -e CXX=clang++-10 verilator/verilator-buildenv test
The tests that involve gdb are not working due to security restrictions.
To run those too:
....
docker run -ti -v ${PWD}:/tmp/repo -e REPO=/tmp/repo -e REV=`git rev-parse --short HEAD` -e CC=gcc-4.8 -e CXX=g++-4.8 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
docker run -ti -e CC=clang-10 -e CXX=clang++-10 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
....
Rather then building using a remote git repository you may prefer to use a
-30
View File
@@ -1,30 +0,0 @@
#!/bin/bash -e
# DESCRIPTION: Build SystemC in Ubuntu 18.04 with different g++/gcc
#
# Copyright 2020 by Stefan Wallentowitz. 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
build_variant () {
version=$($1 --version | grep gcc | awk '{print $4}')
mkdir "/usr/local/systemc-2.3.3-gcc$version"
mkdir build
cd build
../configure --prefix="/usr/local/systemc-2.3.3-gcc$version" CC="$1" CXX="$2" LD="$2"
make -j
make install
cd ..
rm -r build
}
wget https://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.3.tar.gz
tar -xzf systemc-2.3.3.tar.gz
cd systemc-2.3.3
build_variant gcc g++
build_variant gcc-6 g++-6
build_variant gcc-5 g++-5
build_variant gcc-4.8 g++-4.8
cd ..
rm -r systemc-2.3.3*
-6
View File
@@ -12,12 +12,6 @@
: "${CC:=gcc}"
: "${CXX:=g++}"
GCCVERSION=$(${CC} --version | grep gcc | awk '{print $4}')
export SYSTEMC_INCLUDE="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/include"
export SYSTEMC_LIBDIR="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/lib-linux64"
export LD_LIBRARY_PATH=${SYSTEMC_LIBDIR}
SRCS=$PWD/verilator
git clone "$REPO" "$SRCS"
+9 -8
View File
@@ -6,19 +6,20 @@
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:18.04
FROM ubuntu:20.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
&& apt-get install --no-install-recommends -y \
autoconf=2.69-11 \
bc=1.07.1-2 \
bison=2:3.0.4.dfsg-1build1 \
build-essential=12.4ubuntu1 \
ca-certificates=20180409 \
autoconf \
bc \
bison \
build-essential \
ca-certificates \
ccache \
flex=2.6.4-6 \
flex \
git \
libfl-dev=2.6.4-6 \
libfl-dev \
libgoogle-perftools-dev \
perl \
python3 \
-34
View File
@@ -1,34 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Travis CI test script
#
# Copyright 2019 by Todd Strader. 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
set -e
export DRIVER_FLAGS='-j 0 --quiet --rerun'
case $1 in
dist)
make -C test_regress SCENARIOS=--dist
;;
vlt)
make -C test_regress SCENARIOS=--vlt
;;
vltmt)
make -C test_regress SCENARIOS=--vltmt
;;
vltmt0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
*)
echo "Usage: test.sh (dist|vlt|vltmt)"
exit -1
;;
esac
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI ccache maintenance
#
# Copyright 2020 by Geza Lore. 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 script is run in 'before_script', once ccache has been set up.
################################################################################
set -e
set -x
# Show version
ccache --version
# Flush ccache if requested in commit message
COMMIT="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[travis\s\+ccache\s\+clear\]'; then
echo "Flushing ccache due to commit message"
ccache -C
fi
# Dump stats, then zero stats
ccache -s -z
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI ccache sizer
#
# Copyright 2020 by Geza Lore. 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 script computes the size of the ccache to be used for a job. We want the
# ccache to be just big enough to be able to hold a whole build so a re-build
# of the same does not miss in the cache due to capacity, but we don't want the
# ccache too big as pulling it down from the network takes time, and it is
# unlikely objects from much earlier builds would be useful.
################################################################################
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
if [ "$COVERAGE" == 1 ]; then
echo "1024M"
else
echo "768M"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
if [[ $TESTS == coverage-* ]]; then
echo "1536M"
else
echo "256M"
fi
else
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI dependency install script
#
# Copyright 2020 by Geza Lore. 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 script runs in the 'install' phase of all jobs, in all stages. We try to
# minimize the time spent in this by selectively installing only the components
# required by the particular build stage.
################################################################################
# Note that Travis runs "apt-get update" when "apt-get install" is used in the
# .travis.yml file directly, but since we invoke it via this script, we need to
# run it manually where requried, otherwise some packages cannot be found.
set -e
set -x
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}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
# build Verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
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
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
# run the tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get update
sudo apt-get install gdb gtkwave lcov
if [ "$TRAVIS_DIST" = "focal" ]; then
sudo apt-get install libsystemc-dev
fi
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
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI main job script
#
# Copyright 2020 by Geza Lore. 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 is the main script executed in the 'script' phase by all jobs. We use a
# single script to keep the .travis.yml spec simple. We pass job parameters via
# environment variables using 'env' keys. Having different 'env' keys in jobs
# ensures they use different Travis build caches.
################################################################################
set -e
set -x
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 [ "$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
nodist/code_coverage --stages 1-2
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Run tests
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
##############################################################################
# Unknown build stage
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi
+38
View File
@@ -0,0 +1,38 @@
# DESCRIPTION: codecov.io config
#
# Copyright 2020-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
####################
# Validate:
# curl --data-binary @codecov.yml https://codecov.io/validate
codecov:
require_ci_to_pass: no
coverage:
precision: 2
round: down
range: "70...100"
ignore:
- "ci"
- "docs"
- "examples"
- "include/gtkwave"
- "include/vltstd"
- "test_regress"
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: yes
+60 -43
View File
@@ -7,16 +7,20 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.034 2020-05-03],
AC_INIT([Verilator],[4.100 2020-09-07],
[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)
# Version
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
PACKAGE_VERSION_NUMBER=`AS_ECHO("$PACKAGE_VERSION") | sed 's/ .*//g'`
AC_SUBST(PACKAGE_VERSION_NUMBER)
# Ignore automake flags passed by Ubuntu builds
AC_ARG_ENABLE([dependency-tracking],
@@ -109,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
@@ -150,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
@@ -400,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
@@ -413,24 +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)
])
# 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.
@@ -438,6 +437,24 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
[], [#include <sys/stat.h>])
# HAVE_SYSTEMC
# - If found the default search path has it, so support is always enabled.
# - 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)])
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],[1],[Defined if have SystemC library])],
[_my_result=no])
AC_MSG_RESULT($_my_result)
LIBS="$ACO_SAVE_LIBS"
AC_SUBST(HAVE_SYSTEMC)
# Checks for system services
# Other install directories
+25
View File
@@ -6,27 +6,42 @@ 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
Jan Van Winkel
Jeremy Bennett
John Coiner
John Demme
Josh Redford
Julien Margetts
Kanad Kanhere
Kevin Kiningham
Kuba Ober
Ludwig Rogiers
Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Marshal Qiao
Matthew Ballance
Michael Killough
Mike Popoloski
Nathan Kohagen
Nathan Myers
@@ -35,15 +50,25 @@ Peter Horvath
Peter Monsson
Philipp Wagner
Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Richard Myers
Rupert Swarbrick
Sean Cross
Sebastien Van Cauwenberghe
Sergi Granell
Stefan Wallentowitz
Stephen Henry
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Tymoteusz Blazejczyk
Vassilis Papaefstathiou
Veripool API Bot
Wilson Snyder
Yossi Nivin
Yuri Victorovich
Yutetsu TAKATSUKASA
Yves Mathieu
+15 -18
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,19 +69,18 @@ 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
To build or run Verilator you need these standard packages:
sudo apt-get install perl python3
sudo apt-get install make
sudo apt-get install perl python3 make
sudo apt-get install g++ # Alternatively, clang
sudo apt-get install libgz # Non-Ubuntu (ignore if gives error)
sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
@@ -90,17 +89,16 @@ 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:
sudo apt-get install git
sudo apt-get install autoconf flex bison
sudo apt-get install git autoconf flex bison
Those developing Verilator itself may also want these (see internals.adoc):
sudo apt-get install gdb asciidoctor graphviz cmake clang-format
sudo apt-get install gdb asciidoctor graphviz cmake clang clang-format gprof lcov
cpan install Pod::Perldoc
cpan install Unix::Processors
cpan install Parallel::Forker
@@ -130,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:
@@ -266,10 +264,9 @@ set in your environment; it is built into the executable.
== Announcements
To get notified of new releases, login to
https://www.veripool.org[Veripool], and click the "watch" button near the
top right under https://www.veripool.org/projects/verilator/news[Verilator
News].
To get notified of new releases, go to
https://github.com/verilator/verilator-announce[Verilator announcement
repository] and follow the instructions there.
== Directory Structure
+34 -13
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
@@ -777,19 +775,20 @@ 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
Tree files are dumps of the AST Tree and are produced between every major
algorithmic stage. An example:
NETLIST 0x90fb00 <e1> {a0}
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
NETLIST 0x90fb00 <e1> {a0ah}
1: MODULE 0x912b20 <e8822> {a8ah} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24ah} @dt=this(sw32) integer kwd=integer range=[31:0]
The following summarizes the above example dump, with more detail on each
field in the section below.
@@ -807,8 +806,9 @@ the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
| `<e74>` | means the 74th edit to the netlist was the last modification to
this node.
| `{a22}` | indicates this node is related to line 22 in the source filename
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
| `{a22ah}` | indicates this node is related to the source filename "a",
where "a" is the first file read, "z" the 26th, and "aa" the 27th. Then
line 22 in that file, then column 8 (aa=0, az=25, ba=26, ...).
| `@dt=0x...` | indicates the address of the data type this node contains.
@@ -849,7 +849,10 @@ correspond directly to Verilog entities (for example `MODULE` and
Address of the node::
A hexadecimal address of the node in memory. Useful for examining with the
debugger.
debugger. If the actual address values are not important, then using the
`--dump-tree-addrids` option will convert address values to short identifiers
of the form `([A-Z]*)`, which is hopefully easier for the reader to cross
reference throughout the dump.
Last edit number::
@@ -996,6 +999,24 @@ function in `src/verilator.cpp`.
To get your pass to build you'll need to add its binary filename to the
list in `src/Makefile_obj.in` and reconfigure.
=== "Never" features
Verilator ideally would support all of IEEE, and has the goal to get close
to full support. However the following IEEE sections and features are not
anticipated to be ever implemented for the reasons indicated.
[horizontal]
IEEE 1800-2017 3.3 recursive modules:: Little/no tool support, and arguably not a good practice.
IEEE 1800-2017 6.12 "shortreal":: Little/no tool support, and easily simply promoted to real.
IEEE 1800-2017 11.11 Min, typ, max:: No SDF support so will always use typical.
IEEE 1800-2017 11.12 "let":: Little/no tool support, makes difficult to implement parsers.
IEEE 1800-2017 20.15 Probabilistic functions:: Little industry use.
IEEE 1800-2017 20.16 Stochastic analysis:: Little industry use.
IEEE 1800-2017 20.17 PLA modeling:: Little industry use and outdated technology.
IEEE 1800-2017 31 Timing checks:: No longer relevant with static timing analysis tools.
IEEE 1800-2017 32 SDF annotation:: No longer relevant with static timing analysis tools.
IEEE 1800-2017 33 Config:: Little/no tool support or industry use.
== Distribution
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project
# using cmake and verilator.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to SystemC project
# using CMake and Verilator.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project
# using cmake and verilator.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project
# using cmake and verilator.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to SystemC project
# using CMake and Verilator.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion
+1 -1
View File
@@ -19,7 +19,7 @@ int main(int argc, char** argv, char** env) {
// e.g. examples/c_tracing.
// Prevent unused variable warnings
if (0 && argc && argv && env) {}
if (false && argc && argv && env) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop;
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion
+1 -9
View File
@@ -23,25 +23,17 @@ int sc_main(int argc, char* argv[]) {
// e.g. examples/c_tracing.
// Prevent unused variable warnings
if (0 && argc && argv) {}
if (false && argc && argv) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
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
+4 -6
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefiles. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# Copyright 2019 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion
@@ -70,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 --------------------------------------"
+4 -4
View File
@@ -20,7 +20,7 @@ vluint64_t main_time = 0;
double sc_time_stamp() { return main_time; }
int main(int argc, char** argv, char** env) {
if (0 && argc && argv && env) {}
if (false && argc && argv && env) {}
Verilated::debug(0);
Verilated::randReset(2);
@@ -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);
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion
+3 -5
View File
@@ -5,11 +5,9 @@
#
# This is executed in the object directory, and called by ../Makefile
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
#######################################################################
+2 -2
View File
@@ -22,7 +22,7 @@ int main(int argc, char** argv, char** env) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (0 && argc && argv && env) {}
if (false && argc && argv && env) {}
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs
@@ -99,7 +99,7 @@ int main(int argc, char** argv, char** env) {
// Destroy model
delete top;
top = NULL;
top = nullptr;
// Fin
exit(0);
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion
+5 -7
View File
@@ -5,11 +5,9 @@
#
# This is executed in the object directory, and called by ../Makefile
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
#######################################################################
@@ -39,8 +37,8 @@ endif
# If you build your own rules from scratch, note you need to include
# SystemC as follows (Vtop.mk file includes verilated.mk with these
# already).
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
# See the benchmarking section of bin/verilator.
# Support class optimizations. This includes the tracing and symbol table.
+4 -24
View File
@@ -24,7 +24,7 @@ int sc_main(int argc, char* argv[]) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (0 && argc && argv) {}
if (false && argc && argv) {}
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs
@@ -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;
+3 -5
View File
@@ -2,11 +2,9 @@
#
# DESCRIPTION: Verilator Example: XML tests
#
# 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 ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.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
}
}
+448 -299
View File
File diff suppressed because it is too large Load Diff
+166 -110
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,30 +313,30 @@ 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();
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const Type type) VL_MT_UNSAFE;
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; }
@@ -365,7 +361,7 @@ public: // But internals only - called from VerilatedModule's
class VerilatedHierarchy {
public:
void add(VerilatedScope* fromp, VerilatedScope* top);
static void add(VerilatedScope* fromp, VerilatedScope* top);
};
//===========================================================================
@@ -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
@@ -386,8 +380,8 @@ class Verilated {
bool s_assertOn; ///< Assertions are enabled
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
// Slow path
unsigned s_timeunit : 4; ///< Time unit as 0..15
unsigned s_timeprecision : 4; ///< Time precision as 0..15
vlsint8_t s_timeunit; ///< Time unit as 0..15
vlsint8_t s_timeprecision; ///< Time precision as 0..15
int s_errorCount; ///< Number of errors
int s_errorLimit; ///< Stop on error number
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
@@ -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,15 @@ 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;
/// 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 +560,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 +643,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
@@ -673,13 +682,9 @@ extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP r
/// File I/O
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
extern IData VL_FOPEN_S(const char* filenamep, const char* modep);
extern IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode);
extern IData VL_FOPEN_QI(QData filename, IData mode);
inline IData VL_FOPEN_II(IData filename, IData mode) VL_MT_SAFE {
return VL_FOPEN_QI(filename, mode);
}
extern void VL_FFLUSH_I(IData fdi);
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin);
extern IData VL_FTELL_I(IData fdi);
extern void VL_FCLOSE_I(IData fdi);
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
@@ -711,7 +716,7 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
/// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (VL_ULL(1) << VL_BITBIT_Q(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (1ULL << VL_BITBIT_Q(bit)))
#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit))
@@ -722,22 +727,22 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
/// Create two 32-bit words from quadword
/// WData is always at least 2 words; does not clean upper bits
#define VL_SET_WQ(owp, data) \
{ \
do { \
(owp)[0] = static_cast<IData>(data); \
(owp)[1] = static_cast<IData>((data) >> VL_EDATASIZE); \
}
} while (false)
#define VL_SET_WI(owp, data) \
{ \
do { \
(owp)[0] = static_cast<IData>(data); \
(owp)[1] = 0; \
}
} while (false)
#define VL_SET_QW(lwp) \
((static_cast<QData>((lwp)[0])) \
| (static_cast<QData>((lwp)[1]) << (static_cast<QData>(VL_EDATASIZE))))
#define _VL_SET_QII(ld, rd) ((static_cast<QData>(ld) << VL_ULL(32)) | static_cast<QData>(rd))
#define _VL_SET_QII(ld, rd) ((static_cast<QData>(ld) << 32ULL) | static_cast<QData>(rd))
/// Return FILE* from IData
extern FILE* VL_CVT_I_FP(IData lhs);
extern FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE;
// clang-format off
// Use a union to avoid cast-to-different-size warnings
@@ -768,9 +773,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 {
@@ -780,7 +803,7 @@ static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
// (Requires clean input)
#define VL_SIGN_I(nbits, lhs) ((lhs) >> VL_BITBIT_I((nbits)-VL_UL(1)))
#define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-VL_ULL(1)))
#define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-1ULL))
#define VL_SIGN_E(nbits, lhs) ((lhs) >> VL_BITBIT_E((nbits)-VL_EUL(1)))
#define VL_SIGN_W(nbits, rwp) \
((rwp)[VL_BITWORD_E((nbits)-VL_EUL(1))] >> VL_BITBIT_E((nbits)-VL_EUL(1)))
@@ -792,7 +815,7 @@ static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) VL_PURE {
return (-((lhs) & (VL_UL(1) << (lbits - 1))));
}
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
return (-((lhs) & (VL_ULL(1) << (lbits - 1))));
return (-((lhs) & (1ULL << (lbits - 1))));
}
// Debugging prints
@@ -823,13 +846,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();
@@ -847,7 +865,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);
@@ -930,8 +948,7 @@ static inline void VL_ASSIGNBIT_II(int, int bit, IData& lhsr, IData rhs) VL_PURE
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_ULL(1) << VL_BITBIT_Q(bit)))
| (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)];
@@ -949,7 +966,7 @@ static inline void VL_ASSIGNBIT_IO(int, int bit, IData& lhsr, IData) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
lhsr = (lhsr | (VL_ULL(1) << VL_BITBIT_Q(bit)));
lhsr = (lhsr | (1ULL << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)];
@@ -1217,6 +1234,36 @@ static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE {
return r;
}
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
if (ctrlSum == 3) {
return VL_COUNTONES_I(lhs);
} else if (ctrlSum == 0) {
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
return VL_COUNTONES_I(~lhs & mask);
} else {
return (lbits == 32) ? 32 : lbits;
}
}
static inline IData VL_COUNTBITS_Q(int lbits, QData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
return VL_COUNTBITS_I(32, static_cast<IData>(lhs), ctrl0, ctrl1, ctrl2)
+ VL_COUNTBITS_I(lbits - 32, static_cast<IData>(lhs >> 32), ctrl0, ctrl1, ctrl2);
}
#define VL_COUNTBITS_E VL_COUNTBITS_I
static inline IData VL_COUNTBITS_W(int lbits, int words, WDataInP lwp, IData ctrl0, IData ctrl1,
IData ctrl2) VL_MT_SAFE {
EData r = 0;
IData wordLbits = 32;
for (int i = 0; i < words; ++i) {
if (i == words - 1) { wordLbits = lbits % 32; }
r += VL_COUNTBITS_E(wordLbits, lwp[i], ctrl0, ctrl1, ctrl2);
}
return r;
}
static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
}
@@ -1261,7 +1308,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
if (VL_UNLIKELY(!lhs)) return 0;
lhs--;
int shifts = 0;
for (; lhs != 0; ++shifts) lhs = lhs >> VL_ULL(1);
for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE {
@@ -1428,6 +1475,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) {
@@ -1459,8 +1507,8 @@ static inline WDataOutP VL_ADD_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
QData carry = 0;
for (int i = 0; i < words; ++i) {
carry = carry + static_cast<QData>(lwp[i]) + static_cast<QData>(rwp[i]);
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[i] = (carry & 0xffffffffULL);
carry = (carry >> 32ULL) & 0xffffffffULL;
}
// Last output word is dirty
return owp;
@@ -1472,8 +1520,8 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
carry = (carry + static_cast<QData>(lwp[i])
+ static_cast<QData>(static_cast<IData>(~rwp[i])));
if (i == 0) ++carry; // Negation of rwp
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[i] = (carry & 0xffffffffULL);
carry = (carry >> 32ULL) & 0xffffffffULL;
}
// Last output word is dirty
return owp;
@@ -1486,8 +1534,8 @@ static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
QData mul = static_cast<QData>(lwp[lword]) * static_cast<QData>(rwp[rword]);
for (int qword = lword + rword; qword < words; ++qword) {
mul += static_cast<QData>(owp[qword]);
owp[qword] = (mul & VL_ULL(0xffffffff));
mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[qword] = (mul & 0xffffffffULL);
mul = (mul >> 32ULL) & 0xffffffffULL;
}
}
}
@@ -1535,8 +1583,8 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
for (int i = 0; i < words; ++i) {
carry = carry + static_cast<QData>(static_cast<IData>(~owp[i]));
if (i == 0) ++carry; // Negation of temp2
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[i] = (carry & 0xffffffffULL);
carry = (carry >> 32ULL) & 0xffffffffULL;
}
// Not needed: owp[words-1] |= 1<<VL_BITBIT_E(lbits-1); // Set sign bit
}
@@ -1546,24 +1594,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;
@@ -1627,7 +1681,7 @@ static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) VL_PUR
IData out = 1;
for (int i = 0; i < rbits; ++i) {
if (i > 0) power = power * power;
if (rhs & (VL_ULL(1) << i)) out *= power;
if (rhs & (1ULL << i)) out *= power;
}
return out;
}
@@ -1635,10 +1689,10 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) VL_PUR
if (VL_UNLIKELY(rhs == 0)) return 1;
if (VL_UNLIKELY(lhs == 0)) return 0;
QData power = lhs;
QData out = VL_ULL(1);
QData out = 1ULL;
for (int i = 0; i < rbits; ++i) {
if (i > 0) power = power * power;
if (rhs & (VL_ULL(1) << i)) out *= power;
if (rhs & (1ULL << i)) out *= power;
}
return out;
}
@@ -1884,7 +1938,8 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_
case 1: ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU
case 2: ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU
case 3: ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU
case 4: ret = ((ret >> 16) | (ret << 16));
case 4: ret = ((ret >> 16) | (ret << 16)); // FALLTHRU
default:;
}
return ret >> (VL_IDATASIZE - lbits);
}
@@ -1896,25 +1951,26 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
vluint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2);
vluint32_t lbitsRem = lbits - lbitsFloor;
QData msbMask = VL_MASK_Q(lbitsRem) << lbitsFloor;
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_ULL(1) << rd_log2) - lbitsRem));
ret = (ret & ~msbMask) | ((ret & msbMask) << ((1ULL << rd_log2) - lbitsRem));
}
switch (rd_log2) {
case 0:
ret = (((ret >> 1) & VL_ULL(0x5555555555555555))
| ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU
ret = (((ret >> 1) & 0x5555555555555555ULL)
| ((ret & 0x5555555555555555ULL) << 1)); // FALLTHRU
case 1:
ret = (((ret >> 2) & VL_ULL(0x3333333333333333))
| ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU
ret = (((ret >> 2) & 0x3333333333333333ULL)
| ((ret & 0x3333333333333333ULL) << 2)); // FALLTHRU
case 2:
ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f))
| ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU
ret = (((ret >> 4) & 0x0f0f0f0f0f0f0f0fULL)
| ((ret & 0x0f0f0f0f0f0f0f0fULL) << 4)); // FALLTHRU
case 3:
ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff))
| ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU
ret = (((ret >> 8) & 0x00ff00ff00ff00ffULL)
| ((ret & 0x00ff00ff00ff00ffULL) << 8)); // FALLTHRU
case 4:
ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff))
| ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU
case 5: ret = ((ret >> 32) | (ret << 32));
ret = (((ret >> 16) & 0x0000ffff0000ffffULL)
| ((ret & 0x0000ffff0000ffffULL) << 16)); // FALLTHRU
case 5: ret = ((ret >> 32) | (ret << 32)); // FALLTHRU
default:;
}
return ret >> (VL_QUADSIZE - lbits);
}
@@ -2358,14 +2414,14 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP ow
/// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
static inline QData VL_RTOIROUND_Q_D(int bits, double lhs) VL_PURE {
static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
// This does not need to support subnormals as they are sub-integral
lhs = VL_ROUND(lhs);
if (lhs == 0.0) return 0;
QData q = VL_CVT_Q_D(lhs);
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52);
int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
vluint64_t out = 0;
if (lsb < 0) {
out = mantissa >> -lsb;
@@ -2385,8 +2441,8 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
VL_ZERO_W(obits, owp);
if (lhs == 0.0) return owp;
QData q = VL_CVT_Q_D(lhs);
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52);
int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
if (lsb < 0) {
VL_SET_WQ(owp, mantissa >> -lsb);
} else if (lsb < obits) {
@@ -2505,25 +2561,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,
@@ -2531,7 +2587,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,
@@ -2539,7 +2595,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,
@@ -2547,7 +2603,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,
@@ -2555,7 +2611,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
+65 -42
View File
@@ -84,27 +84,29 @@ CPPFLAGS += $(VM_USER_CFLAGS)
LDFLAGS += $(VM_USER_LDFLAGS)
LDLIBS += $(VM_USER_LDLIBS)
# See the benchmarking section of bin/verilator.
# Support class optimizations. This includes the tracing and symbol table.
# SystemC takes minutes to optimize, thus it is off by default.
#OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
#OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
######################################################################
# Optimization control.
#######################################################################
##### Aggregates
# See also the BENCHMARKING & OPTIMIZATION section of the manual.
VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW)
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW)
# Optimization flags for non performance-critical/rarely executed code.
# No optimization by default, which improves compilation speed.
OPT_SLOW =
# Optimization for performance critical/hot code. Most time is spent in these
# routines. Optimizing by default for improved execution speed.
OPT_FAST = -Os
# Optimization applied to the common run-time library used by verilated models.
# For compatibility this is called OPT_GLOBAL even though it only applies to
# files in the run-time library. Normally there should be no need for the user
# to change this as the library is small, but can have significant speed impact.
OPT_GLOBAL = -Os
#######################################################################
##### SystemC builds
ifeq ($(VM_SC),1)
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
SC_LIBS = -lsystemc
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
# Systemc 1.2.1beta
@@ -163,58 +165,79 @@ ifneq ($(VK_LIBS_THREADED),0)
endif
#######################################################################
##### Stub
### Aggregates
preproc:
VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
#######################################################################
# Overall Objects Linking
### Overall Objects Linking
VK_CLASSES_FAST_CPP = $(addsuffix .cpp, $(VM_CLASSES_FAST))
VK_CLASSES_SLOW_CPP = $(addsuffix .cpp, $(VM_CLASSES_SLOW))
VK_SUPPORT_FAST_CPP = $(addsuffix .cpp, $(VM_SUPPORT_FAST))
VK_SUPPORT_SLOW_CPP = $(addsuffix .cpp, $(VM_SUPPORT_SLOW))
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
# Note VM_GLOBAL_FAST and VM_GLOBAL_SLOW holds the files required from the
# run-time library. In practice everything is actually in VM_GLOBAL_FAST,
# but keeping the distinction for compatibility for now.
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
ifneq ($(VM_PARALLEL_BUILDS),1)
# Fast building, all .cpp's in one fell swoop
# This saves about 5 sec per module, but can be slower if only a little changes
VK_OBJS += $(VM_PREFIX)__ALLfast.o $(VM_PREFIX)__ALLslow.o
all_cpp: $(VM_PREFIX)__ALLfast.cpp $(VM_PREFIX)__ALLslow.cpp
$(VM_PREFIX)__ALLfast.cpp: $(VK_CLASSES_FAST_CPP) $(VK_SUPPORT_FAST_CPP)
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
$(VM_PREFIX)__ALLslow.cpp: $(VK_CLASSES_SLOW_CPP) $(VK_SUPPORT_SLOW_CPP)
# Fast build for small designs: All .cpp files in one fell swoop. This
# saves total compute, but can be slower if only a little changes. It is
# also a lot slower for medium to large designs when the speed of the C
# compiler dominates, which in this mode is not parallelizable.
VK_OBJS += $(VM_PREFIX)__ALL.o
$(VM_PREFIX)__ALL.cpp: $(addsuffix .cpp, $(VM_FAST) $(VM_SLOW))
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
all_cpp: $(VM_PREFIX)__ALL.cpp
else
#Slow way of building... Each .cpp file by itself
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
# Parallel build: Each .cpp file by itself. This can be somewhat slower for
# very small designs and examples, but is a lot faster for large designs.
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
ifneq ($(VM_DEFAULT_RULES),0)
$(VM_PREFIX)__ALLfast.o: $(VM_PREFIX)__ALLfast.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
$(VM_PREFIX)__ALLslow.o: $(VM_PREFIX)__ALLslow.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
# VM_GLOBAL_FAST files including verilated.o use this rule
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
# and user files passed on the Verilator command line use this rule.
%.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
%__Slow.o: %__Slow.cpp
$(VK_SLOW_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
$(VK_GLOBAL_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
endif
#Default rule embedded in make:
+49 -62
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 {}
};
//=============================================================================
@@ -94,23 +94,18 @@ private:
typedef std::map<int, std::string> IndexValueMap;
typedef std::deque<VerilatedCovImpItem*> ItemList;
private:
// MEMBERS
VerilatedMutex m_mutex; ///< Protects all members
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
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:
@@ -124,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
@@ -221,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();
@@ -250,16 +241,15 @@ public:
// PUBLIC METHODS
void clear() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
clearGuts();
}
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
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,25 +261,23 @@ public:
}
void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
(*it)->zero();
}
const VerilatedLockGuard lock(m_mutex);
for (const auto& itemp : m_items) itemp->zero();
}
// We assume there's always call to i/f/p in that order
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
}
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0] = "filename";
@@ -332,22 +320,22 @@ public:
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
if (VL_UNCOVERABLE(!legalKey(key))) {
std::string msg
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
+ key);
+ key); // LCOV_EXCL_LINE
VL_FATAL_MT("", 0, "", msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
m_insertp = nullptr;
}
void write(const char* filename) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
#ifndef VM_COVERAGE
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif
@@ -362,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;
@@ -396,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();
@@ -407,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;
}
}
@@ -447,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);
}
@@ -475,11 +462,11 @@ void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8)
}
// Backward compatibility for Verilator
void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
const std::string& val4, A(5), A(6)) VL_MT_SAFE {
const std::string& val4, A(5), A(6), A(7)) VL_MT_SAFE {
std::string val2str = vlCovCvtToStr(val2);
std::string val3str = vlCovCvtToStr(val3);
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
C(6), N(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
C(6), C(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
}
#undef A
+2 -2
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));
@@ -121,7 +121,7 @@ public:
D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29));
// Backward compatibility for Verilator
static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4,
A(5), A(6));
A(5), A(6), A(7));
#undef K
#undef A
+3
View File
@@ -38,6 +38,7 @@ VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr
VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ")
VLCOVGEN_ITEM("name=>'linescov', short=>'S', group=>1, default=>'', descr=>'List of comma-separated lines covered'")
VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ")
@@ -80,6 +81,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
#define VL_CIK_HIER "h"
#define VL_CIK_LIMIT "L"
#define VL_CIK_LINENO "l"
#define VL_CIK_LINESCOV "S"
#define VL_CIK_PER_INSTANCE "P"
#define VL_CIK_ROW0 "r0"
#define VL_CIK_ROW0_NAME "R0"
@@ -121,6 +123,7 @@ public:
if (key == "hier") return VL_CIK_HIER;
if (key == "limit") return VL_CIK_LIMIT;
if (key == "lineno") return VL_CIK_LINENO;
if (key == "linescov") return VL_CIK_LINESCOV;
if (key == "per_instance") return VL_CIK_PER_INSTANCE;
if (key == "row0") return VL_CIK_ROW0;
if (key == "row0_name") return VL_CIK_ROW0_NAME;
+12 -12
View File
@@ -47,7 +47,7 @@
// Function requires a "context" in the import declaration
#define _VL_SVDPI_CONTEXT_WARN() \
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
"'context' keyword.\n");
"'context' keyword.\n")
//======================================================================
//======================================================================
@@ -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;
}
@@ -416,7 +416,7 @@ static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1
case VLVT_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1;
case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
case VLVT_UINT64:
return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & VL_ULL(1);
return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & 1ULL;
case VLVT_WDATA: {
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
return VL_BITRSHIFT_W(wdatap, lsb) & 1;
@@ -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());
+26 -46
View File
@@ -36,17 +36,12 @@
#include "gtkwave/lz4.c"
#include <algorithm>
#include <cerrno>
#include <ctime>
#include <fcntl.h>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
#else
# include <stdint.h>
# include <unistd.h>
#endif
@@ -63,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 {
@@ -87,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);
@@ -96,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();
@@ -111,7 +101,7 @@ void VerilatedFst::close() {
m_assertOne.check();
VerilatedTrace<VerilatedFst>::close();
fstWriterClose(m_fst);
m_fst = NULL;
m_fst = nullptr;
}
void VerilatedFst::flush() {
@@ -132,23 +122,23 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem
m_local2fstdtype[dtypenum] = enumNum;
}
void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, vluint32_t len,
vluint32_t bits) {
void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
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), end;
std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
std::list<std::string> tokens(beg, end); // Split name
std::string symbol_name(tokens.back());
tokens.pop_back(); // Remove symbol name from hierarchy
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;
@@ -163,7 +153,7 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
// 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);
}
@@ -177,40 +167,35 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
fstWriterEmitEnumTableRef(m_fst, enumNum);
}
if (p.second) { // New
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, 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, len, name_str.c_str(), p.first->second);
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
}
}
void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 0, 0);
}
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
}
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
}
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
}
void VerilatedFst::declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
}
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 63, 0);
}
// Note: emit* are only ever called from one place (full* in
@@ -266,11 +251,6 @@ void VerilatedFst::emitWData(vluint32_t code, const WData* newvalp, int bits) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
}
VL_ATTR_ALWINLINE
void VerilatedFst::emitFloat(vluint32_t code, float newval) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
}
VL_ATTR_ALWINLINE
void VerilatedFst::emitDouble(vluint32_t code, double newval) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
+11 -14
View File
@@ -50,24 +50,24 @@ 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);
void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits);
void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
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.
@@ -77,14 +77,13 @@ protected:
inline void emitIData(vluint32_t code, IData newval, int bits);
inline void emitQData(vluint32_t code, QData newval, int bits);
inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
inline void emitFloat(vluint32_t code, float newval);
inline void emitDouble(vluint32_t code, double newval);
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
@@ -94,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
@@ -112,8 +111,6 @@ public:
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
};
@@ -138,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(); }
+21 -27
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) {
@@ -427,7 +420,8 @@ extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld);
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, void* memp, QData start,
QData end) VL_MT_SAFE;
+216 -106
View File
@@ -32,6 +32,7 @@
#include <deque>
#include <set>
#include <vector>
#include <numeric>
#ifdef VL_THREADED
# include <functional>
# include <queue>
@@ -61,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; }
@@ -83,7 +84,7 @@ class VerilatedEvalMsgQueue {
public:
// CONSTRUCTORS
VerilatedEvalMsgQueue()
: m_depth(0) {
: m_depth{0} {
assert(atomic_is_lock_free(&m_depth));
}
~VerilatedEvalMsgQueue() {}
@@ -95,7 +96,7 @@ public:
// METHODS
//// Add message to queue (called by producer)
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
}
@@ -111,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();
@@ -168,13 +169,31 @@ public:
};
#endif // VL_THREADED
// FILE* list constructed from a file-descriptor
class VerilatedFpList {
FILE* m_fp[31];
std::size_t m_sz = 0;
public:
typedef FILE* const* const_iterator;
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; }
std::size_t capacity() const { return 31; }
void push_back(FILE* fd) {
if (VL_LIKELY(size() < capacity())) m_fp[m_sz++] = fd;
}
};
//======================================================================
// 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;
@@ -182,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;
@@ -229,19 +244,41 @@ protected:
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
/// List of free descriptors (SLOW - FOPEN/CLOSE only)
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
std::vector<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
// 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) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
}
VerilatedImp() {}
~VerilatedImp() {}
static void setup();
static void teardown();
private:
VL_UNCOPYABLE(VerilatedImp);
@@ -253,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) {
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);
@@ -285,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 {
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 {
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;
}
@@ -304,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.
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 {
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);
}
}
@@ -330,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
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 {
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
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 {
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
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
@@ -388,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
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 {
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());
@@ -408,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
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 {
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
@@ -435,49 +470,124 @@ 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;
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNew(FILE* fp) VL_MT_SAFE {
static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
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
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
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start * 2);
for (size_t i = start; i < start * 2; ++i) {
s_s.m_fdFree.push_back(static_cast<IData>(i));
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 fdDelete(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
static void fdFlush(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (const auto& i : fdlist) fflush(i);
}
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
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.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.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
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.v.m_fdMutex);
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
IData idx = VL_MASK_I(31) & fdi;
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.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 {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr;
return *fdlist.begin();
}
private:
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.v.m_fdMutex) {
VerilatedFpList fp;
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
const IData idx = fdi & VL_MASK_I(31);
switch (idx) {
case 0: fp.push_back(stdin); break;
case 1: fp.push_back(stdout); break;
case 2: fp.push_back(stderr); break;
default:
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.v.m_fdps[i]);
}
}
return fp;
}
};
+14 -10
View File
@@ -123,13 +123,13 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
if (filenamep[0] == '|') {
assert(0); // Not supported yet.
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else {
// 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;
@@ -146,12 +146,12 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
if (filenamep[0] == '|') {
assert(0); // Not supported yet.
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
assert(0); // LCOV_EXCL_LINE // Not supported yet.
} 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;
@@ -194,13 +194,15 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
ssize_t got = ::write(m_fd, wp, remaining);
if (got > 0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
} else if (VL_UNCOVERABLE(got < 0)) {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
// LCOV_EXCL_STOP
}
}
}
@@ -223,13 +225,15 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
ssize_t got = ::read(m_fd, m_endp, remaining);
if (got > 0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
} else if (VL_UNCOVERABLE(got < 0)) {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
// LCOV_EXCL_STOP
}
} else { // got==0, EOF
// Fill buffer from here to end with NULLs so reader's don't
+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;
+68 -96
View File
@@ -29,6 +29,8 @@
#include "verilatedos.h"
#include <vector>
//===========================================================================
/// Verilator range
/// Thread safety: Assume is constructed only with model, then any number of readers
@@ -42,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;
@@ -78,96 +80,61 @@ class VerilatedVarProps {
const int m_pdims; // Packed dimensions
const int m_udims; // Unpacked dimensions
VerilatedRange m_packed; // Packed array range
VerilatedRange m_unpacked[3]; // Unpacked array range
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
void initUnpacked(const int* ulims) {
for (int i = 0; i < m_udims; ++i) {
const int left = ulims ? ulims[2 * i + 0] : 0;
const int right = ulims ? ulims[2 * i + 1] : 0;
m_unpacked.push_back(VerilatedRange(left, right));
}
}
// CONSTRUCTORS
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) {}
: 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) {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(1) {
m_unpacked[0].init(u0l, u0r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l,
int u1r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(2) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l,
int u1r, int u2l, int u2r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(3) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
m_unpacked[2].init(u2l, u2r);
: 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)) // 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 u0l, int u0r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(1)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r, int u1l, int u1r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(2)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(3)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
m_unpacked[2].init(u2l, u2r);
int udims, const int* ulims)
: 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);
}
public:
@@ -189,27 +156,29 @@ public:
// DPI accessors
int left(int dim) const {
return dim == 0 ? m_packed.left()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].left() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left() : 0;
}
int right(int dim) const {
return dim == 0 ? m_packed.right()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].right() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right() : 0;
}
int low(int dim) const {
return dim == 0 ? m_packed.low()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].low() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low() : 0;
}
int high(int dim) const {
return dim == 0 ? m_packed.high()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].high() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high() : 0;
}
int increment(int dim) const {
return dim == 0 ? m_packed.increment()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].increment() : 0;
return dim == 0
? m_packed.increment()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0;
}
int elements(int dim) const {
return dim == 0 ? m_packed.elements()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].elements() : 0;
return dim == 0
? m_packed.elements()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements() : 0;
}
/// Total size in bytes (note DPI limited to 4GB)
size_t totalSize() const;
@@ -227,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; }
@@ -263,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() {}
@@ -278,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
+22 -26
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() {
@@ -120,21 +118,21 @@ void VlThreadPool::setupProfilingClientThread() {
// try not to malloc while collecting profiling.
t_profilep->reserve(4096);
{
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
m_allProfiles.insert(t_profilep);
}
}
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
VerilatedLockGuard lk(m_mutex);
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
const VerilatedLockGuard lk(m_mutex);
for (const auto& profilep : m_allProfiles) {
// Every thread's profile trace gets a copy of rec.
(*it)->emplace_back(rec);
profilep->emplace_back(rec);
}
}
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
FILE* fp = fopen(filenamep, "w");
@@ -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
}
+13 -20
View File
@@ -119,23 +119,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 +167,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
@@ -234,7 +227,7 @@ public:
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
bool notify;
{
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
m_ready.emplace_back(fnp, evenCycle, sym);
m_ready_size.fetch_add(1, std::memory_order_relaxed);
notify = m_waiting;
+43 -28
View File
@@ -40,7 +40,7 @@
// Threaded tracing
// A simple synchronized first in first out queue
template <class T> class VerilatedThreadQueue {
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
private:
VerilatedMutex m_mutex; // Protects m_queue
std::condition_variable_any m_cv;
@@ -73,7 +73,7 @@ public:
// Non blocking get
bool tryGet(T& result) {
VerilatedLockGuard lockGuard(m_mutex);
const VerilatedLockGuard lockGuard(m_mutex);
if (m_queue.empty()) { return false; }
result = m_queue.front();
m_queue.pop_front();
@@ -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,
@@ -95,7 +95,6 @@ public:
CHG_IDATA = 0x4,
CHG_QDATA = 0x5,
CHG_WDATA = 0x6,
CHG_FLOAT = 0x7,
CHG_DOUBLE = 0x8,
// TODO: full..
TIME_CHANGE = 0xd,
@@ -105,8 +104,6 @@ public:
};
#endif
class VerilatedTraceCallInfo;
//=============================================================================
// VerilatedTrace
@@ -114,13 +111,38 @@ class VerilatedTraceCallInfo;
// implementations in the format specific derived class, which must be passed
// as the type parameter T_Derived
template <class T_Derived> class VerilatedTrace {
private:
public:
//=========================================================================
// Generic tracing internals
typedef void (*initCb_t)(void*, T_Derived*, uint32_t); // Type of init callbacks
typedef void (*dumpCb_t)(void*, T_Derived*); // Type of all but init callbacks
private:
struct CallbackRecord {
// Note: would make these fields const, but some old STL implementations
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
// assignment operator on inserting into collections, so they don't work
// with const fields...
union {
initCb_t m_initCb; // The callback function
dumpCb_t m_dumpCb; // The callback function
};
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} {}
CallbackRecord(dumpCb_t cb, void* userp)
: m_dumpCb{cb}
, m_userp{userp} {}
};
vluint32_t* m_sigs_oldvalp; ///< Old value store
vluint64_t m_timeLastDump; ///< Last time we did a dump
std::vector<VerilatedTraceCallInfo*> m_callbacks; ///< Routines to perform dumping
std::vector<CallbackRecord> m_initCbs; ///< Routines to initialize traciong
std::vector<CallbackRecord> m_fullCbs; ///< Routines to perform full dump
std::vector<CallbackRecord> m_chgCbs; ///< Routines to perform incremental dump
std::vector<CallbackRecord> m_cleanupCbs; ///< Routines to call at the end of dump
bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump'
vluint32_t m_nextCode; ///< Next code number to assign
vluint32_t m_numSignals; ///< Number of distinct signals
@@ -130,10 +152,17 @@ private:
double m_timeRes; ///< Time resolution (ns/ms etc)
double m_timeUnit; ///< Time units (ns/ms etc)
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec);
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
// 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;
@@ -209,8 +238,8 @@ protected:
// These hooks are called before a full or change based dump is produced.
// The return value indicates whether to proceed with the dump.
virtual bool preFullDump() { return true; }
virtual bool preChangeDump() { return true; }
virtual bool preFullDump() = 0;
virtual bool preChangeDump() = 0;
public:
//=========================================================================
@@ -232,13 +261,13 @@ public:
//=========================================================================
// Non-hot path internal interface to Verilator generated code
typedef void (*callback_t)(T_Derived* tracep, void* userthis, vluint32_t code);
void addInitCb(initCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addFullCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addChgCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void changeThread() { m_assertOne.changeThread(); }
void addCallback(callback_t initcb, callback_t fullcb, callback_t changecb,
void* userthis) VL_MT_UNSAFE_ONE;
void module(const std::string& name) VL_MT_UNSAFE_ONE {
m_assertOne.check();
m_moduleName = name;
@@ -261,7 +290,6 @@ public:
// duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0;
// duck-typed void emitQData(vluint32_t code, QData newval, int bits) = 0;
// duck-typed void emitWData(vluint32_t code, const WData* newvalp, int bits) = 0;
// duck-typed void emitFloat(vluint32_t code, float newval) = 0;
// duck-typed void emitDouble(vluint32_t code, double newval) = 0;
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
@@ -273,7 +301,6 @@ public:
void fullIData(vluint32_t* oldp, IData newval, int bits);
void fullQData(vluint32_t* oldp, QData newval, int bits);
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits);
void fullFloat(vluint32_t* oldp, float newval);
void fullDouble(vluint32_t* oldp, double newval);
#ifdef VL_TRACE_THREADED
@@ -319,14 +346,6 @@ public:
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
}
inline void chgFloat(vluint32_t code, float newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_FLOAT;
m_traceBufferWritep[1] = code;
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<float*>(m_traceBufferWritep + 2) = newval;
m_traceBufferWritep += 3;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
}
inline void chgDouble(vluint32_t code, double newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
m_traceBufferWritep[1] = code;
@@ -374,10 +393,6 @@ public:
}
}
}
inline void CHG(Float)(vluint32_t* oldp, float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<float*>(oldp) != newval)) fullFloat(oldp, newval);
}
inline void CHG(Double)(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
+78 -75
View File
@@ -39,7 +39,7 @@
// Static utility functions
static double timescaleToDouble(const char* unitp) {
char* endp;
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;
@@ -73,31 +73,6 @@ static std::string doubleToTimescale(double value) {
return valuestr; // Gets converted to string, so no ref to stack
}
//=============================================================================
// Internal callback routines for each module being traced.
// Each module that wishes to be traced registers a set of callbacks stored in
// this class. When the trace file is being constructed, this class provides
// the callback routines to be executed.
class VerilatedTraceCallInfo {
public: // This is in .cpp file so is not widely visible
typedef VerilatedTrace<VL_DERIVED_T>::callback_t callback_t;
callback_t m_initcb; ///< Initialization Callback function
callback_t m_fullcb; ///< Full Dumping Callback function
callback_t m_changecb; ///< Incremental Dumping Callback function
void* m_userthis; ///< User data pointer for callback
vluint32_t m_code; ///< Starting code number (set later by traceInit)
// CONSTRUCTORS
VerilatedTraceCallInfo(callback_t icb, callback_t fcb, callback_t changecb, void* ut)
: m_initcb(icb)
, m_fullcb(fcb)
, m_changecb(changecb)
, m_userthis(ut)
, m_code(1) {}
~VerilatedTraceCallInfo() {}
};
#ifdef VL_TRACE_THREADED
//=========================================================================
// Buffer management
@@ -196,11 +171,6 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
chgWDataImpl(oldp, readp, top);
readp += VL_WORDS_I(top);
continue;
case VerilatedTraceCommand::CHG_FLOAT:
VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT " << top);
chgFloatImpl(oldp, *reinterpret_cast<const float*>(readp));
readp += 1;
continue;
case VerilatedTraceCommand::CHG_DOUBLE:
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
@@ -224,13 +194,14 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
shutdown = true;
break;
//===
// Unknown command
default:
//===
// Unknown command
default: { // LCOV_EXCL_START
VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
break;
} // LCOV_EXCL_STOP
}
// The above switch will execute 'continue' when necessary,
@@ -287,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());
@@ -310,11 +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);
while (!m_callbacks.empty()) {
delete m_callbacks.back();
m_callbacks.pop_back();
}
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
@@ -334,11 +318,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
m_numSignals = 0;
m_maxBits = 0;
// Call all initialize callbacks, which will call decl* for each signal.
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedTraceCallInfo* cip = m_callbacks[ent];
cip->m_code = nextCode();
(cip->m_initcb)(self(), cip->m_userthis, cip->m_code);
// Call all initialize callbacks, which will:
// - Call decl* for each signal
// - Store the base code
for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
const CallbackRecord& cbr = m_initCbs[i];
cbr.m_initCb(cbr.m_userp, self(), nextCode());
}
if (expectedCodes && nextCode() != expectedCodes) {
@@ -350,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
@@ -409,12 +398,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const std::st
template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
m_assertOne.check();
if (VL_UNLIKELY(m_timeLastDump && timeui <= m_timeLastDump)) {
if (VL_UNCOVERABLE(m_timeLastDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64
"u, dump call ignored\n",
m_timeLastDump, timeui);
return;
}
} // LCOV_EXCL_STOP
m_timeLastDump = timeui;
Verilated::quiesce();
@@ -452,17 +441,22 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
// Run the callbacks
if (VL_UNLIKELY(m_fullDump)) {
m_fullDump = false; // No more need for next dump to be full
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedTraceCallInfo* cip = m_callbacks[ent];
(cip->m_fullcb)(self(), cip->m_userthis, cip->m_code);
for (vluint32_t i = 0; i < m_fullCbs.size(); ++i) {
const CallbackRecord& cbr = m_fullCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
} else {
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedTraceCallInfo* cip = m_callbacks[ent];
(cip->m_changecb)(self(), cip->m_userthis, cip->m_code);
for (vluint32_t i = 0; i < m_chgCbs.size(); ++i) {
const CallbackRecord& cbr = m_chgCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
}
for (vluint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
const CallbackRecord& cbr = m_cleanupCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
#ifdef VL_TRACE_THREADED
if (VL_LIKELY(bufferp)) {
// Mark end of the trace buffer we just filled
@@ -481,17 +475,32 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
// Non-hot path internal interface to Verilator generated code
template <>
void VerilatedTrace<VL_DERIVED_T>::addCallback(callback_t initcb, callback_t fullcb,
callback_t changecb,
void* userthis) VL_MT_UNSAFE_ONE {
void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
CallbackRecord& cbRec) {
m_assertOne.check();
if (VL_UNLIKELY(timeLastDump() != 0)) {
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ " called with already open file");
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
VerilatedTraceCallInfo* cip = new VerilatedTraceCallInfo(initcb, fullcb, changecb, userthis);
m_callbacks.push_back(cip);
} // LCOV_EXCL_STOP
cbVec.push_back(cbRec);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addInitCb(initCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_initCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addFullCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_fullCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addChgCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_chgCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addCleanupCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_cleanupCbs, cbr);
}
//=========================================================================
@@ -537,12 +546,6 @@ void VerilatedTrace<VL_DERIVED_T>::fullWData(vluint32_t* oldp, const WData* newv
self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits);
}
template <> void VerilatedTrace<VL_DERIVED_T>::fullFloat(vluint32_t* oldp, float newval) {
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<float*>(oldp) = newval;
self()->emitFloat(oldp - m_sigs_oldvalp, newval);
}
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<double*>(oldp) = newval;
-497
View File
@@ -1,497 +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 _V3_UNORDERED_SET_MAP_H_
#define _V3_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<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(VL_ULL(0xFFFFFFFFFFFFFFFF), 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) ? VL_ULL(11400714819323198485) : 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 (VL_ULL(1) << 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 = VL_ULL(1) << 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
+80 -166
View File
@@ -27,7 +27,6 @@
#include <cerrno>
#include <ctime>
#include <fcntl.h>
#include <sys/stat.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
@@ -35,8 +34,6 @@
# include <unistd.h>
#endif
#include "verilated_intrinsics.h"
// SPDIFF_ON
#ifndef O_LARGEFILE // For example on WIN32
@@ -54,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
@@ -69,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) {
VerilatedLockGuard lock(singleton().s_vcdMutex);
singleton().s_vcdVecp.push_back(vcdp);
}
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
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
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();
}
}
};
//=============================================================================
//=============================================================================
//=============================================================================
@@ -132,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) {
@@ -155,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;
@@ -203,8 +148,8 @@ void VerilatedVcd::openNext(bool incFilename) {
}
m_filename = name;
}
if (m_filename[0] == '|') {
assert(0); // Not supported yet.
if (VL_UNCOVERABLE(m_filename[0] == '|')) {
assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
if (!m_filep->open(m_filename)) {
@@ -241,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;
@@ -261,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() {
@@ -337,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);
}
}
@@ -358,13 +302,15 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
if (got > 0) {
wp += got;
m_wroteBytes += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
} else if (VL_UNCOVERABLE(got < 0)) {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
closeErr();
break;
// LCOV_EXCL_STOP
}
}
}
@@ -399,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");
@@ -422,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();
@@ -583,9 +529,6 @@ void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int
int lsb) {
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
}
void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 31, 0);
}
void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 63, 0);
}
@@ -699,15 +642,6 @@ void VerilatedVcd::emitWData(vluint32_t code, const WData* newvalp, int bits) {
finishLine(code, wp);
}
VL_ATTR_ALWINLINE
void VerilatedVcd::emitFloat(vluint32_t code, float newval) {
char* wp = m_writep;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(wp, "r%.16g", static_cast<double>(newval));
wp += strlen(wp);
finishLine(code, wp);
}
VL_ATTR_ALWINLINE
void VerilatedVcd::emitDouble(vluint32_t code, double newval) {
char* wp = m_writep;
@@ -742,7 +676,7 @@ void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits)
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0');
*m_writep++ = ((newval & (1ULL << bit)) ? '1' : '0');
}
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
@@ -764,7 +698,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; }
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0');
*m_writep++ = ((newval[(bit / 64)] & (1ULL << (bit & 0x3f))) ? '1' : '0');
}
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
@@ -792,14 +726,13 @@ void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vl
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri,
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
int bits) {
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
(*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri;
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++
= "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
*m_writep++ = "01zz"[((newval >> bit) & 1ULL) | (((newtri >> bit) & 1ULL) << 1ULL)];
}
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
@@ -834,46 +767,12 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
(*(reinterpret_cast<float*>(oldp(code)))) = newval;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", static_cast<double>(newval));
m_writep += strlen(m_writep);
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullBitX(vluint32_t code) {
*m_writep++ = 'x';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullBusX(vluint32_t code, int bits) {
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) *m_writep++ = 'x';
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); }
void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); }
#endif // VL_TRACE_VCD_OLD_API
//======================================================================
// Static members
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); }
//======================================================================
//======================================================================
//======================================================================
// clang-format off
#ifdef VERILATED_VCD_TEST
#include <iostream>
@@ -882,34 +781,39 @@ vluint32_t v1, v2, s1, s2[3];
vluint32_t tri96[3];
vluint32_t tri96__tri[3];
vluint64_t quad96[2];
vluint64_t tquad;
vluint64_t tquad__tri;
vluint8_t ch;
vluint64_t timestamp = 1;
double doub = 0;
double doub = 0.0;
float flo = 0.0f;
void vcdInit(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) {
vcdp->scopeEscape('.');
vcdp->module("top");
vcdp->declBus(0x2, "v1",-1,5,1);
vcdp->declBus(0x3, "v2",-1,6,0);
vcdp->module("top.sub1");
vcdp->declBit(0x4, "s1",-1);
vcdp->declBit(0x5, "ch",-1);
vcdp->module("top.sub2");
vcdp->declArray(0x6, "s2",-1, 40,3);
/**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1);
/**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1);
/**/ vcdp->module("top.sub1");
/***/ vcdp->declBit(0x4, "s1", -1, 0);
/***/ vcdp->declBit(0x5, "ch", -1, 0);
/**/ vcdp->module("top.sub2");
/***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3);
// Note need to add 3 for next code.
vcdp->module("top2");
vcdp->declBus(0x2, "t2v1",-1,4,1);
vcdp->declTriBit(0x10, "io1",-1);
vcdp->declTriBus(0x12, "io5",-1,4,0);
vcdp->declTriArray(0x16, "io96",-1,95,0);
// Note need to add 6 for next code.
vcdp->declDouble(0x1c, "doub",-1);
// Note need to add 2 for next code.
vcdp->declArray(0x1e, "q2",-1,95,0);
// Note need to add 4 for next code.
/**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1);
/**/ vcdp->declTriBit(0x10, "io1", -1, 0);
/**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0);
/**/ vcdp->declTriArray(0x16, "io96", -1, 0, 95, 0);
/**/ // Note need to add 6 for next code.
/**/ vcdp->declDouble(0x1c, "doub", -1, 0);
/**/ // Note need to add 2 for next code.
/**/ vcdp->declArray(0x20, "q2", -1, 0, 95, 0);
/**/ // Note need to add 4 for next code.
/**/ vcdp->declTriQuad(0x24, "tq", -1, 0, 63, 0);
/**/ // Note need to add 4 for next code.
}
void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
void vcdFull(void*, VerilatedVcd* vcdp) {
vcdp->fullBus(0x2, v1, 5);
vcdp->fullBus(0x3, v2, 7);
vcdp->fullBit(0x4, s1);
@@ -919,10 +823,11 @@ void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
vcdp->fullTriArray(0x16, tri96, tri96__tri, 96);
vcdp->fullDouble(0x1c, doub);
vcdp->fullArray(0x1e, &quad96[0], 96);
vcdp->fullArray(0x20, &quad96[0], 96);
vcdp->fullTriQuad(0x24, tquad, tquad__tri, 64);
}
void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
void vcdChange(void*, VerilatedVcd* vcdp) {
vcdp->chgBus(0x2, v1, 5);
vcdp->chgBus(0x3, v2, 7);
vcdp->chgBit(0x4, s1);
@@ -932,12 +837,12 @@ void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
vcdp->chgTriArray(0x16, tri96, tri96__tri, 96);
vcdp->chgDouble(0x1c, doub);
vcdp->chgArray(0x1e, &quad96[0], 96);
vcdp->chgArray(0x20, &quad96[0], 96);
vcdp->chgTriQuad(0x24, tquad, tquad__tri, 64);
}
main() {
std::cout << "test: O_LARGEFILE=" << O_LARGEFILE << std::endl;
// clang-format off
void vcdTestMain(const char* filenamep) {
v1 = v2 = s1 = 0;
s2[0] = s2[1] = s2[2] = 0;
tri96[2] = tri96[1] = tri96[0] = 0;
@@ -945,43 +850,52 @@ main() {
quad96[1] = quad96[0] = 0;
ch = 0;
doub = 0;
tquad = tquad__tri = 0;
{
VerilatedVcdC* vcdp = new VerilatedVcdC;
vcdp->spTrace()->addCallback(&vcdInit, &vcdFull, &vcdChange, 0);
vcdp->open("test.vcd");
vcdp->evcd(true);
vcdp->spTrace()->addInitCb(&vcdInit, 0);
vcdp->spTrace()->addFullCb(&vcdFull, 0);
vcdp->spTrace()->addChgCb(&vcdChange, 0);
vcdp->open(filenamep);
// Dumping
vcdp->dump(timestamp++);
vcdp->dump(++timestamp);
v1 = 0xfff;
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
quad96[1] = 0xffffffff; quad96[0] = 0;
doub = 1.5;
vcdp->dump(timestamp++);
flo = 1.4f;
vcdp->dump(++timestamp);
v2 = 0x1;
s2[1] = 2;
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
quad96[1] = 0; quad96[0] = ~0;
doub = -1.66e13;
vcdp->dump(timestamp++);
flo = 0.123f;
tquad = 0x00ff00ff00ff00ffULL;
tquad__tri = 0x0000fffff0000ffffULL;
vcdp->dump(++timestamp);
ch = 2;
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
doub = -3.33e-13;
vcdp->dump(timestamp++);
vcdp->dump(timestamp++);
vcdp->dump(++timestamp);
vcdp->dump(++timestamp);
# ifdef VERILATED_VCD_TEST_64BIT
vluint64_t bytesPerDump = VL_ULL(15);
for (vluint64_t i = 0; i < ((VL_ULL(1) << 32) / bytesPerDump); i++) {
vluint64_t bytesPerDump = 15ULL;
for (vluint64_t i = 0; i < ((1ULL << 32) / bytesPerDump); i++) {
v1 = i;
vcdp->dump(timestamp++);
vcdp->dump(++timestamp);
}
# endif
vcdp->close();
}
}
#endif
// clang-format on
//********************************************************************
// ;compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// ;compile-command: "v4make test_regress/t/t_trace_c_api.pl"
//
// Local Variables:
// End:
+29 -46
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.
@@ -130,14 +126,13 @@ protected:
inline void emitIData(vluint32_t code, IData newval, int bits);
inline void emitQData(vluint32_t code, QData newval, int bits);
inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
inline void emitFloat(vluint32_t code, float newval);
inline void emitDouble(vluint32_t code, double newval);
public:
//=========================================================================
// External interface to client code
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
explicit VerilatedVcd(VerilatedVcdFile* filep = nullptr);
~VerilatedVcd();
// ACCESSORS
@@ -163,7 +158,6 @@ public:
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declFloat(vluint32_t code, const char* name, bool array, int arraynum);
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
#ifdef VL_TRACE_VCD_OLD_API
@@ -195,7 +189,6 @@ public:
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
fullArray(oldp - this->oldp(0), newvalp, bits);
}
void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - this->oldp(0), newval); }
void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }
inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
@@ -214,9 +207,6 @@ public:
inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
chgArray(oldp - this->oldp(0), newvalp, bits);
}
inline void chgFloat(vluint32_t* oldp, float newval) {
chgFloat(oldp - this->oldp(0), newval);
}
inline void chgDouble(vluint32_t* oldp, double newval) {
chgDouble(oldp - this->oldp(0), newval);
}
@@ -230,20 +220,10 @@ public:
void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
int bits);
void fullDouble(vluint32_t code, const double newval);
void fullFloat(vluint32_t code, const float newval);
/// Inside dumping routines, dump one signal as unknowns
/// Presently this code doesn't change the oldval vector.
/// Thus this is for special standalone applications that after calling
/// fullBitX, must when then value goes non-X call fullBit.
void fullBitX(vluint32_t code);
void fullBusX(vluint32_t code, int bits);
void fullQuadX(vluint32_t code, int bits);
void fullArrayX(vluint32_t code, int bits);
/// Inside dumping routines, dump one signal if it has changed.
/// We do want to inline these to avoid calls when the value did not change.
@@ -262,7 +242,7 @@ public:
inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
if (VL_UNLIKELY(diff)) {
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) {
if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
fullQuad(code, newval, bits);
}
}
@@ -303,12 +283,12 @@ public:
}
}
}
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri,
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
int bits) {
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
| ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
if (VL_UNLIKELY(diff)) {
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) {
if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
fullTriQuad(code, newval, newtri, bits);
}
}
@@ -329,15 +309,9 @@ public:
fullDouble(code, newval);
}
}
inline void chgFloat(vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY((*(reinterpret_cast<float*>(oldp(code)))) != newval)) {
fullFloat(code, newval);
}
}
protected:
// METHODS
// Old/standalone API only
void evcd(bool flag) { m_evcd = flag; }
#endif // VL_TRACE_VCD_OLD_API
};
@@ -362,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(); }
@@ -405,6 +379,15 @@ public:
/// Internal class access
inline VerilatedVcd* spTrace() { return &m_sptrace; }
#ifdef VL_TRACE_VCD_OLD_API
//=========================================================================
// Note: These are only for testing for backward compatibility with foreign
// code and is not used by Verilator. Do not use these as there is no
// guarantee of functionality.
/// Use evcd format
void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); }
#endif
};
#endif // guard
+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
+9 -109
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) {}
#endif
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
//--------------------------------------------------
#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
};
+608 -645
View File
File diff suppressed because it is too large Load Diff
+40 -37
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
@@ -144,30 +144,23 @@
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
///< protected to make sure single-caller
#ifdef _MSC_VER
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
// Was "(c##ui64)". C++11 has standardized on ULL, and MSVC now supports this.
// We propose to no longer require using this macro no sooner than June 2020.
// File an issue ASAP if this breaks anything.
#else
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
#endif
#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
// This is not necessarily the same as #UL, depending on what the IData typedef is.
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
#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 { \
(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.
///< Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
/// 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 { \
do { \
@@ -176,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 { \
@@ -191,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
//=========================================================================
@@ -224,6 +205,20 @@
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
#endif
//=========================================================================
// Internal coverage
#ifdef VL_GCOV
extern "C" {
void __gcov_flush(); // gcc sources gcc/gcov-io.h has the prototype
}
/// Flush internal code coverage data before e.g. abort()
# define VL_GCOV_FLUSH() \
__gcov_flush()
#else
# define VL_GCOV_FLUSH()
#endif
//=========================================================================
// Warning disabled
@@ -381,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
@@ -401,7 +396,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
/// Mask for quads with 1's where relevant bits are (0=all bits)
#define VL_MASK_Q(nbits) \
(((nbits) & VL_SIZEBITS_Q) ? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q)) - VL_ULL(1)) : VL_ULL(~0))
(((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL)
/// Mask for EData with 1's where relevant bits are (0=all bits)
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
#define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized
@@ -428,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) \
{ \
@@ -493,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
-58
View File
@@ -1,58 +0,0 @@
#!/usr/bin/env perl
######################################################################
#
# Copyright 2007-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
#
######################################################################
# DESCRIPTION: Debugging of bison output
use warnings;
use strict;
my $Debug;
my %declared;
my %used;
my $body = 0;
my $rule = "";
my $lineno = 0;
foreach my $line (<STDIN>) {
$lineno++;
chomp $line;
$line =~ s!//.*$!!g;
$line =~ s!\s+! !g;
next if $line eq '';
if ($line =~ m!^\%\%!) {
$body++;
} elsif ($body == 1) {
$rule .= $line;
if ($line =~ m!^\s*;\s*$!) {
#print "Rule: $rule\n";
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
my $rulename = $1; my $preaction = $3;
$declared{$rulename} = $lineno;
$preaction =~ s/\{[^\}]*\}/ /g;
#print "RULEN $rulename PA $preaction\n" if $Debug;
$rule = '';
foreach my $ref (split /\s+/, $preaction) {
next if $ref !~ /^[a-zA-Z]/;
next if $ref eq $rulename;
if (!$used{$ref} && $declared{$ref}) {
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
}
$used{$ref} = $lineno;
print " ref $ref\n" if $Debug;
}
}
}
}
# Local Variables:
# compile-command: "./bisonreader < ../src/verilog.y"
# End:
+302 -57
View File
@@ -6,30 +6,71 @@ use warnings;
use Cwd;
use File::Copy qw(cp);
use File::Path qw(mkpath);
use File::Spec;
use FindBin qw($RealBin);
use Getopt::Long;
use Parallel::Forker;
use Unix::Processors;
use IO::File;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $Opt_Stop = 1;
our $Opt_Fastcov = 1;
our $Exclude_Branch_Regexp;
our $Exclude_Line_Regexp;
our $Remove_Gcda_Regexp;
our @Remove_Sources;
our @Source_Globs;
our $Fork = new Parallel::Forker(use_sig_child => 1, poll_interval => 10*1000);
$Fork->max_proc(Unix::Processors->new->max_online * 1.5);
$SIG{CHLD} = sub { Parallel::Forker::sig_child($Fork); };
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork && $Fork->in_parent; die "Quitting...\n"; };
#======================================================================
# main
our $Opt_Stage = 0;
our $Opt_Hashset;
our $opt_stages = '';
our $Opt_Scenarios;
our %Opt_Stages;
our @Opt_Tests;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"debug" => sub { $Debug = 1; },
"hashset=s" => \$Opt_Hashset, # driver.pl hashset
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
"fastcov!" => \$Opt_Fastcov, # use fastcov, not documented, for debug
"scenarios=s" => \$Opt_Scenarios, # driver.pl scenarios
"stage=s" => \$opt_stages, # starting stage number
"stages=s" => \$opt_stages, # starting stage number
"stop!" => \$Opt_Stop, # stop/do not stop on error in tests
"test=s@" => \@Opt_Tests, # test name
)) {
die "%Error: Bad usage, try 'install_test --help'\n";
die "%Error: Bad usage, try 'code_coverage --help'\n";
}
{
my $start = 0;
my $end = 99;
if ($opt_stages && $opt_stages =~ /^(\d+)$/) {
$start = $end = $1;
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-(\d+$)$/) {
$start = $1; $end = $2;
} elsif ($opt_stages && $opt_stages =~ /^-(\d+$)$/) {
$end = $1;
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-$/) {
$start = $1;
} elsif ($opt_stages) {
die "%Error: --stages not understood: $opt_stages,";
}
for (my $n = $start; $n <= $end; ++$n) { $Opt_Stages{$n} = 1; }
}
test();
@@ -41,97 +82,238 @@ sub test {
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
require "./nodist/code_coverage.dat";
if ($Opt_Stage <= 0) {
print "Stage 0: configure (coverage on)\n";
run("make distclean");
run("./configure --enable-longtests CXX='g++ --coverage'");
run("make -k");
if ($Opt_Stages{1}) {
travis_fold_start("configure");
print "Stage 1: configure (coverage on)\n";
run("make distclean || true");
run("autoconf");
# Exceptions can pollute the branch coverage data
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'");
travis_fold_end();
}
if ($Opt_Stages{2}) {
travis_fold_start("build");
print "Stage 2: build\n";
my $nproc = Unix::Processors->new->max_online;
run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1");
# The optimized versions will not collect good coverage, overwrite them
run("cp bin/verilator_bin_dbg bin/verilator_bin");
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
travis_fold_end();
}
if ($Opt_Stage <= 1) {
print "Stage 1: make examples (with coverage on)\n";
run("make examples");
run("make test_regress");
if ($Opt_Stages{3}) {
travis_fold_start("test");
print "Stage 3: make tests (with coverage on)\n";
if ($#Opt_Tests < 0) {
run("make examples VERILATOR_NO_OPT_BUILD=1")
if !$Opt_Scenarios || $Opt_Scenarios =~ /dist/i;
run("make test_regress VERILATOR_NO_OPT_BUILD=1"
. ($Opt_Scenarios ? " SCENARIOS='".$Opt_Scenarios."'" : "")
. ($Opt_Hashset ? " DRIVER_HASHSET='--hashset=".$Opt_Hashset."'" : "")
. ($Opt_Stop ? '' : ' || true'));
} else {
foreach my $test (@Opt_Tests) {
if (! -f $test && -f "test_regress/t/${test}") {
$test = "test_regress/t/${test}";
}
run($test);
}
}
travis_fold_end();
}
my $cc_dir = "nodist/obj_dir/coverage";
if ($Opt_Stage <= 2) {
print "Stage 2: Create info files under $cc_dir\n";
if ($Opt_Stages{4}) {
travis_fold_start("gcno");
print "Stage 4: Create gcno files under $cc_dir\n";
mkpath($cc_dir);
mkpath("$cc_dir/info");
my $dats = `find . -print | grep .gcda`;
my %dats;
foreach my $dat (split '\n', $dats) {
$dats{$dat} = 1;
}
foreach my $dat (sort keys %dats) {
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
if ($dat =~ /$Remove_Gcda_Regexp/) {
# Remove .gcda/.gcno for files we don't care about before we slowly
# read them
unlink $dat;
unlink $gcno;
delete $dats{$dat};
next;
}
}
$dats = `find . -print | grep .gcno`;
my %gcnos;
foreach my $gcno (split '\n', $dats) {
(my $gbase = $gcno) =~ s!.*/!!;
$gcnos{$gbase} = File::Spec->rel2abs($gcno);
}
# We need a matching .gcno for every .gcda, try to find a matching file elsewhere
foreach my $dat (sort keys %dats) {
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
(my $gbase = $gcno) =~ s!.*/!!;
if (!-r $gcno) {
if ($gcnos{$gbase}) {
symlink($gcnos{$gbase}, $gcno)
or die "%Error: can't ln -s $gcnos{$gbase} $gcno,";
} else {
warn "MISSING .gcno for a .gcda: $gcno\n";
}
}
}
travis_fold_end();
}
if ($Opt_Stages{5} && $Opt_Fastcov) {
travis_fold_start("fastcov");
# Must run in root directory to find all files
mkpath($cc_dir);
#run("${RealBin}/fastcov.py -b -c src/obj_dbg -X".
# " --exclude /usr --exclude test_regress"
# ." -o ${cc_dir}/app_total.json");
run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov".
" --exclude /usr --exclude test_regress"
." -o ${cc_dir}/app_total.info");
travis_fold_end();
}
if ($Opt_Stages{5} && !$Opt_Fastcov) {
travis_fold_start("infos");
print "Stage 5: make infos\n";
my $dats = `find . -print | grep .gcda`;
my %dirs;
foreach my $dat (split '\n', $dats) {
$dat =~ s!/[^/]+$!!;
$dirs{$dat} = 1;
(my $dir = $dat) =~ s!/[^/]+$!!;
$dirs{$dir} = 1;
}
foreach my $dir (sort keys %dirs) {
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info");
$Fork->schedule(run_on_start => sub {
# .info may be empty, so ignore errors (unfortunately)
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir --exclude /usr -o app_test_${outname}.info || true");
})->run;
}
$Fork->wait_all;
travis_fold_end();
}
if ($Opt_Stage <= 3) {
# lcov doesn't have a control file to override single lines, so replicate the sources
print "Stage 3: Clone sources under $cc_dir\n";
if ($Opt_Stages{6}) {
travis_fold_start("clone");
# No control file to override single lines, so replicate the sources
# Also lets us see the insertion markers in the HTML source res
print "Stage 6: Clone sources under $cc_dir\n";
clone_sources($cc_dir);
travis_fold_end();
}
if ($Opt_Stage <= 4) {
print "Stage 4: Copy .gcno files\n";
if ($Opt_Stages{8} && !$Opt_Fastcov) {
travis_fold_start("copy");
print "Stage 8: Copy .gcno files\n";
my $dats = `find . -print | grep .gcno`;
foreach my $dat (split '\n', $dats) {
foreach my $dat (sort (split '\n', $dats)) {
next if $dat =~ /$cc_dir/;
my $outdat = $cc_dir."/".$dat;
#print "cp $dat, $outdat);\n";
cp($dat, $outdat);
}
travis_fold_end();
}
if ($Opt_Stage <= 5) {
print "Stage 5: Combine data files\n";
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my $infos = `cd $cc_dir ; find info -print | grep .info`;
my $comb = "";
my @infos = (split /\n/, $infos);
foreach my $info (@infos) {
$comb .= " -a $info";
# Need to batch them to avoid overrunning shell command length limit
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
$comb = "";
if ($Opt_Stages{10} && !$Opt_Fastcov) {
travis_fold_start("combine");
print "Stage 10: Combine data files\n";
{
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my $infos = `cd $cc_dir ; find info -print | grep .info`;
my $comb = "";
my @infos = (sort (split /\n/, $infos));
foreach my $info (@infos) {
$comb .= " -a $info";
# Need to batch them to avoid overrunning shell command length limit
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
# .info may be empty, so ignore errors (unfortunately)
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info || true");
$comb = "";
}
}
}
travis_fold_end();
}
if ($Opt_Stage <= 6) {
print "Stage 6: Filter processed source files\n";
my $cmd = '';
foreach my $glob (@Remove_Sources) {
$cmd .= " '$glob'";
if ($Opt_Stages{11}) {
travis_fold_start("dirs");
print "Stage 11: Cleanup paths\n";
if ($Opt_Fastcov) {
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
#cleanup_abs_paths_json($cc_dir, "$cc_dir/app_total.json", "$cc_dir/app_total.json");
} else {
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
}
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info");
travis_fold_end();
}
if ($Opt_Stage <= 7) {
print "Stage 7: Create HTML\n";
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
if ($Opt_Stages{12}) {
travis_fold_start("filter");
print "Stage 12: Filter processed source files\n";
my $inc = '';
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$inc .= " '$infile'";
}
}
my $exc = '';
foreach my $glob (@Remove_Sources) {
# Fastcov does exact match not globbing at present
# Lcov requires whole path match so needs the glob
$glob =~ s!^\*!! if $Opt_Fastcov;
$glob =~ s!\*$!! if $Opt_Fastcov;
$exc .= " '$glob'";
}
if ($Opt_Fastcov) {
$inc = "--include ".$inc if $inc ne '';
$exc = "--exclude ".$exc if $exc ne '';
run("cd $cc_dir ; ${RealBin}/fastcov.py -C app_total.info ${inc} ${exc} -x --lcov -o app_total_f.info");
} else {
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
}
travis_fold_end();
}
if ($Opt_Stages{17}) {
travis_fold_start("report");
print "Stage 17: Create HTML\n";
run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp"
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
travis_fold_end();
}
if ($Opt_Stage <= 9) {
if ($Opt_Stages{18}) {
travis_fold_start("upload");
print "Stage 18: Upload\n";
my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info";
print "print: Not running: export CODECOV_TOKEN=<hidden>\n";
print "print: Not running: $cmd\n";
travis_fold_end();
}
if ($Opt_Stages{19}) {
print "*-* All Finished *-*\n";
print "\n";
print "* See report in ${cc_dir}/html/index.html\n";
print "* Remember to make distclean && ./configure before working on non-coverage\n";
}
}
sub clone_sources {
my $cc_dir = shift;
my $excluded_lines = 0;
my $excluded_br_lines = 0;
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$infile !~ m!^/!
@@ -145,21 +327,35 @@ sub clone_sources {
while (defined(my $line = $fh->getline)) {
$lineno++;
chomp $line;
if ($line !~ m!// LCOV_EXCL_LINE!
&& $line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE";
if ($line =~ /LCOV_EXCL_LINE/) {
$line .= " LCOV_EXCL_BR_LINE";
}
elsif ($line =~ /LCOV_EXCL_START/) {
$line .= " LCOV_EXCL_BR_START";
}
elsif ($line =~ /LCOV_EXCL_STOP/) {
$line .= " LCOV_EXCL_BR_STOP";
}
elsif ($line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE LCOV_EXCL_BR_LINE";
$excluded_lines++;
$excluded_br_lines++;
#print "$infile:$lineno: $line";
}
elsif ($line =~ /$Exclude_Branch_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_BR_LINE";
$excluded_br_lines++;
#print "$infile:$lineno: $line";
} else {
}
$ofh->print("$line\n");
}
}
}
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
print "Number of source lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
print "Number of source lines automatically LCOV_EXCL_BR_LINE'ed: $excluded_br_lines\n";
}
sub cleanup_abs_paths {
sub cleanup_abs_paths_info {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
@@ -178,18 +374,41 @@ sub cleanup_abs_paths {
$ofh->print(@lines);
}
sub cleanup_abs_paths_json {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
# Handcrafted cleanup, alternative would be to deserialize/serialize JSON
# But JSON::Parse not installed by default
# JSON::PP more likely to be installed, but slower
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my @lines;
while (defined(my $line = $fh->getline)) {
$line =~ s!"$ENV{VERILATOR_ROOT}/!"!g;
$line =~ s!"$cc_dir/!"!g;
$line =~ s!obj_dbg/verilog.y$!verilog.y!g;
push @lines, $line;
}
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
$ofh->print(@lines);
}
#######################################################################
# .dat file callbacks
sub exclude_branch_regexp {
$Exclude_Branch_Regexp = shift;
}
sub exclude_line_regexp {
$Exclude_Line_Regexp = shift;
}
sub remove_gcda_regexp {
$Remove_Gcda_Regexp = shift;
}
sub remove_source {
my @srcs = @_;
push @Remove_Sources, @srcs;
}
sub source_globs {
my @dirs = @_;
push @Source_Globs, @dirs;
@@ -206,6 +425,15 @@ sub run {
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
}
our $_Travis_Action;
sub travis_fold_start {
$_Travis_Action = shift;
print "travis_fold:start:$_Travis_Action\n";
}
sub travis_fold_end {
print "travis_fold:end:$_Travis_Action\n";
}
#######################################################################
__END__
@@ -231,13 +459,30 @@ This will rebuild the current object files.
=over 4
=item --hashset I<hashset>
Pass test hashset onto driver.pl test harness.
=item --help
Displays this message and program version and exits.
=item -stage I<stage>
=item --scenarios I<scenarios>
Runs a specific stage (see the script).
Pass test scenarios onto driver.pl test harness.
=item --stages I<stage>
Runs a specific stage or range of stages (see the script).
=item --no-stop
Do not stop collecting data if tests fail.
=item --test I<test_regress_test_name>
Instead of normal regressions, run the specified test. May be specified
multiple times for multiple tests.
=back
+18 -2
View File
@@ -21,7 +21,8 @@ source_globs("src/*.cpp",
"include/*/*.c",
);
remove_source("/usr/include/*");
# Note *'s are removed when using fastcov
remove_source("/usr/*");
remove_source("*/include/sysc/*");
remove_source("*/V3ClkGater.cpp");
remove_source("*/V3ClkGater.h");
@@ -37,7 +38,22 @@ remove_source("*include/gtkwave/*");
remove_source("*test_regress/*");
remove_source("*examples/*");
# Remove collected coverage on each little test main file
# Would just be removed with remove_source in later step
remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/);
# Exclude line entirely, also excludes from function and branch coverage
exclude_line_regexp(qr/(\bv3fatalSrc\b
|\bfatalSrc\b
|\bVL_UNCOVERABLE\b
|\bVL_FATAL
|\bUASSERT
|\bERROR_RSVD_WORD
|\bV3ERROR_NA
|\bUINFO\b)/x);
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\)
|\bSELF_CHECK)/x);
1;
+744
View File
@@ -0,0 +1,744 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# Copyright 2018-present, Bryan Gillespie
"""
Author: Bryan Gillespie
https://github.com/RPGillespie6/fastcov
A massively parallel gcov wrapper for generating intermediate coverage formats fast
The goal of fastcov is to generate code coverage intermediate formats as fast as possible,
even for large projects with hundreds of gcda objects. The intermediate formats may then be
consumed by a report generator such as lcov's genhtml, or a dedicated frontend such as coveralls.
Sample Usage:
$ cd build_dir
$ ./fastcov.py --zerocounters
$ <run unit tests>
$ ./fastcov.py --exclude /usr/include test/ --lcov -o report.info
$ genhtml -o code_coverage report.info
"""
import re
import os
import sys
import glob
import json
import time
import logging
import argparse
import threading
import subprocess
import multiprocessing
FASTCOV_VERSION = (1,7)
MINIMUM_PYTHON = (3,5)
MINIMUM_GCOV = (9,0,0)
# Interesting metrics
START_TIME = time.monotonic()
GCOVS_TOTAL = 0
GCOVS_SKIPPED = 0
# For when things go wrong...
# Start error codes at 3 because 1-2 are special
# See https://stackoverflow.com/a/1535733/2516916
EXIT_CODE = 0
EXIT_CODES = {
"gcov_version": 3,
"python_version": 4,
"unsupported_coverage_format": 5,
"excl_not_found": 6,
}
# Disable all logging in case developers are using this as a module
logging.disable(level=logging.CRITICAL)
class FastcovFormatter(logging.Formatter):
def format(self, record):
record.levelname = record.levelname.lower()
log_message = super(FastcovFormatter, self).format(record)
return "[{:.3f}s] {}".format(stopwatch(), log_message)
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
def setExitCode(key):
global EXIT_CODE
EXIT_CODE = EXIT_CODES[key]
def incrementCounters(total, skipped):
global GCOVS_TOTAL
global GCOVS_SKIPPED
GCOVS_TOTAL += total
GCOVS_SKIPPED += skipped
def stopwatch():
"""Return number of seconds since last time this was called."""
global START_TIME
end_time = time.monotonic()
delta = end_time - START_TIME
START_TIME = end_time
return delta
def parseVersionFromLine(version_str):
"""Given a string containing a dotted integer version, parse out integers and return as tuple."""
version = re.search(r'(\d+\.\d+\.\d+)', version_str)
if not version:
return (0,0,0)
return tuple(map(int, version.group(1).split(".")))
def getGcovVersion(gcov):
p = subprocess.Popen([gcov, "-v"], stdout=subprocess.PIPE)
output = p.communicate()[0].decode('UTF-8')
p.wait()
return parseVersionFromLine(output.split("\n")[0])
def removeFiles(files):
for file in files:
os.remove(file)
def getFilteredCoverageFiles(coverage_files, exclude):
def excludeGcda(gcda):
for ex in exclude:
if ex in gcda:
logging.debug("Omitting %s due to '--exclude-gcda %s'", gcda, ex)
return False
return True
return list(filter(excludeGcda, coverage_files))
def findCoverageFiles(cwd, coverage_files, use_gcno):
coverage_type = "user provided"
if not coverage_files:
coverage_type = "gcno" if use_gcno else "gcda"
coverage_files = glob.glob(os.path.join(os.path.abspath(cwd), "**/*." + coverage_type), recursive=True)
logging.info("Found {} coverage files ({})".format(len(coverage_files), coverage_type))
logging.debug("Coverage files found:\n %s", "\n ".join(coverage_files))
return coverage_files
def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
base_report = {"sources": {}}
gcovs_total = 0
gcovs_skipped = 0
gcov_args = "-it"
if args.branchcoverage or args.xbranchcoverage:
gcov_args += "b"
p = subprocess.Popen([args.gcov, gcov_args] + chunk, cwd=args.cdirectory, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
for line in iter(p.stdout.readline, b''):
intermediate_json = json.loads(line.decode(sys.stdout.encoding))
intermediate_json_files = processGcovs(args.cdirectory, intermediate_json["files"], gcov_filter_options)
for f in intermediate_json_files:
distillSource(f, base_report["sources"], args.test_name, args.xbranchcoverage)
gcovs_total += len(intermediate_json["files"])
gcovs_skipped += len(intermediate_json["files"]) - len(intermediate_json_files)
p.wait()
data_q.put(base_report)
metrics_q.put((gcovs_total, gcovs_skipped))
def processGcdas(args, coverage_files, gcov_filter_options):
chunk_size = max(args.minimum_chunk, int(len(coverage_files) / args.jobs) + 1)
processes = []
data_q = multiprocessing.Queue()
metrics_q = multiprocessing.Queue()
for chunk in chunks(coverage_files, chunk_size):
p = multiprocessing.Process(target=gcovWorker, args=(data_q, metrics_q, args, chunk, gcov_filter_options))
processes.append(p)
p.start()
logging.info("Spawned {} gcov processes, each processing at most {} coverage files".format(len(processes), chunk_size))
fastcov_jsons = []
for p in processes:
fastcov_jsons.append(data_q.get())
incrementCounters(*metrics_q.get())
for p in processes:
p.join()
base_fastcov = fastcov_jsons.pop()
for fj in fastcov_jsons:
combineReports(base_fastcov, fj)
return base_fastcov
def shouldFilterSource(source, gcov_filter_options):
"""Returns true if the provided source file should be filtered due to CLI options, otherwise returns false."""
# If explicit sources were passed, check for match
if gcov_filter_options["sources"]:
if source not in gcov_filter_options["sources"]:
logging.debug("Filtering coverage for '%s' due to option '--source-files'", source)
return True
# Check exclude filter
for ex in gcov_filter_options["exclude"]:
if ex in source:
logging.debug("Filtering coverage for '%s' due to option '--exclude %s'", source, ex)
return True
# Check include filter
if gcov_filter_options["include"]:
included = False
for inc in gcov_filter_options["include"]:
if inc in source:
included = True
break
if not included:
logging.debug("Filtering coverage for '%s' due to option '--include %s'", source, " ".join(gcov_filter_options["include"]))
return True
return False
def filterFastcov(fastcov_json, args):
logging.info("Performing filtering operations (if applicable)")
gcov_filter_options = getGcovFilterOptions(args)
for source in list(fastcov_json["sources"].keys()):
if shouldFilterSource(source, gcov_filter_options):
del fastcov_json["sources"][source]
def processGcov(cwd, gcov, files, gcov_filter_options):
# Add absolute path
gcov["file_abs"] = os.path.abspath(os.path.join(cwd, gcov["file"]))
if shouldFilterSource(gcov["file_abs"], gcov_filter_options):
return
files.append(gcov)
logging.debug("Accepted coverage for '%s'", gcov["file_abs"])
def processGcovs(cwd, gcov_files, gcov_filter_options):
files = []
for gcov in gcov_files:
processGcov(cwd, gcov, files, gcov_filter_options)
return files
def dumpBranchCoverageToLcovInfo(f, branches):
branch_miss = 0
branch_found = 0
brda = []
for line_num, branch_counts in branches.items():
for i, count in enumerate(branch_counts):
# Branch (<line number>, <block number>, <branch number>, <taken>)
brda.append((line_num, int(i/2), i, count))
branch_miss += int(count == 0)
branch_found += 1
for v in sorted(brda):
f.write("BRDA:{},{},{},{}\n".format(*v))
f.write("BRF:{}\n".format(branch_found)) # Branches Found
f.write("BRH:{}\n".format(branch_found - branch_miss)) # Branches Hit
def dumpToLcovInfo(fastcov_json, output):
with open(output, "w") as f:
sources = fastcov_json["sources"]
for sf in sorted(sources.keys()):
for tn in sorted(sources[sf].keys()):
data = sources[sf][tn]
f.write("TN:{}\n".format(tn)) #Test Name - used mainly in conjuction with genhtml --show-details
f.write("SF:{}\n".format(sf)) #Source File
fn_miss = 0
fn = []
fnda = []
for function, fdata in data["functions"].items():
fn.append((fdata["start_line"], function)) # Function Start Line
fnda.append((fdata["execution_count"], function)) # Function Hits
fn_miss += int(fdata["execution_count"] == 0)
# NOTE: lcov sorts FN, but not FNDA.
for v in sorted(fn):
f.write("FN:{},{}\n".format(*v))
for v in sorted(fnda):
f.write("FNDA:{},{}\n".format(*v))
f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found
f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit
if data["branches"]:
dumpBranchCoverageToLcovInfo(f, data["branches"])
line_miss = 0
da = []
for line_num, count in data["lines"].items():
da.append((line_num, count))
line_miss += int(count == 0)
for v in sorted(da):
f.write("DA:{},{}\n".format(*v)) # Line
f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found
f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit
f.write("end_of_record\n")
def getSourceLines(source, fallback_encodings=[]):
"""Return a list of lines from the provided source, trying to decode with fallback encodings if the default fails."""
default_encoding = sys.getdefaultencoding()
for encoding in [default_encoding] + fallback_encodings:
try:
with open(source, encoding=encoding) as f:
return f.readlines()
except UnicodeDecodeError:
pass
logging.warning("Could not decode '{}' with {} or fallback encodings ({}); ignoring errors".format(source, default_encoding, ",".join(fallback_encodings)))
with open(source, errors="ignore") as f:
return f.readlines()
def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings):
start_line = 0
end_line = 0
# Start enumeration at line 1 because the first line of the file is line 1 not 0
for i, line in enumerate(getSourceLines(source, fallback_encodings), 1):
# Cycle through test names (likely only 1)
for test_name in fastcov_sources[source]:
fastcov_data = fastcov_sources[source][test_name]
# Build line to function dict so can quickly delete by line number
line_to_func = {}
for f in fastcov_data["functions"].keys():
l = fastcov_data["functions"][f]["start_line"]
if l not in line_to_func:
line_to_func[l] = set()
line_to_func[l].add(f)
if i in fastcov_data["branches"]:
del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw)
del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw)
if del_exclude_br or del_include_br:
del fastcov_data["branches"][i]
if "LCOV_EXCL" not in line:
continue
if "LCOV_EXCL_LINE" in line:
for key in ["lines", "branches"]:
if i in fastcov_data[key]:
del fastcov_data[key][i]
if i in line_to_func:
for key in line_to_func[i]:
if key in fastcov_data["functions"]:
del fastcov_data["functions"][key]
elif "LCOV_EXCL_START" in line:
start_line = i
elif "LCOV_EXCL_STOP" in line:
end_line = i
if not start_line:
end_line = 0
continue
for key in ["lines", "branches"]:
for line_num in list(fastcov_data[key].keys()):
if start_line <= line_num <= end_line:
del fastcov_data[key][line_num]
for line_num in range(start_line, end_line):
if line_num in line_to_func:
for key in line_to_func[line_num]:
if key in fastcov_data["functions"]:
del fastcov_data["functions"][key]
start_line = end_line = 0
elif "LCOV_EXCL_BR_LINE" in line:
if i in fastcov_data["branches"]:
del fastcov_data["branches"][i]
def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, fallback_encodings):
for source in chunk:
try:
exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings)
except FileNotFoundError:
logging.error("Could not find '%s' to scan for exclusion markers...", source)
setExitCode("excl_not_found") # Set exit code because of error
def scanExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, min_chunk_size, fallback_encodings):
chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1)
threads = []
for chunk in chunks(list(fastcov_json["sources"].keys()), chunk_size):
t = threading.Thread(target=exclMarkerWorker, args=(fastcov_json["sources"], chunk, exclude_branches_sw, include_branches_sw, fallback_encodings))
threads.append(t)
t.start()
logging.info("Spawned {} threads each scanning at most {} source files".format(len(threads), chunk_size))
for t in threads:
t.join()
def distillFunction(function_raw, functions):
function_name = function_raw["name"]
# NOTE: need to explicitly cast all counts coming from gcov to int - this is because gcov's json library
# will pass as scientific notation (i.e. 12+e45)
start_line = int(function_raw["start_line"])
execution_count = int(function_raw["execution_count"])
if function_name not in functions:
functions[function_name] = {
"start_line": start_line,
"execution_count": execution_count
}
else:
functions[function_name]["execution_count"] += execution_count
def emptyBranchSet(branch1, branch2):
return (branch1["count"] == 0 and branch2["count"] == 0)
def matchingBranchSet(branch1, branch2):
return (branch1["count"] == branch2["count"])
def filterExceptionalBranches(branches):
filtered_branches = []
exception_branch = False
for i in range(0, len(branches), 2):
if i+1 >= len(branches):
filtered_branches.append(branches[i])
break
# Filter exceptional branch noise
if branches[i+1]["throw"]:
exception_branch = True
continue
# Filter initializer list noise
if exception_branch and emptyBranchSet(branches[i], branches[i+1]) and len(filtered_branches) >= 2 and matchingBranchSet(filtered_branches[-1], filtered_branches[-2]):
return []
filtered_branches.append(branches[i])
filtered_branches.append(branches[i+1])
return filtered_branches
def distillLine(line_raw, lines, branches, include_exceptional_branches):
line_number = int(line_raw["line_number"])
count = int(line_raw["count"])
if line_number not in lines:
lines[line_number] = count
else:
lines[line_number] += count
# Filter out exceptional branches by default unless requested otherwise
if not include_exceptional_branches:
line_raw["branches"] = filterExceptionalBranches(line_raw["branches"])
# Increment all branch counts
for i, branch in enumerate(line_raw["branches"]):
if line_number not in branches:
branches[line_number] = []
blen = len(branches[line_number])
glen = len(line_raw["branches"])
if blen < glen:
branches[line_number] += [0] * (glen - blen)
branches[line_number][i] += int(branch["count"])
def distillSource(source_raw, sources, test_name, include_exceptional_branches):
source_name = source_raw["file_abs"]
if source_name not in sources:
sources[source_name] = {
test_name: {
"functions": {},
"branches": {},
"lines": {}
}
}
for function in source_raw["functions"]:
distillFunction(function, sources[source_name][test_name]["functions"])
for line in source_raw["lines"]:
distillLine(line, sources[source_name][test_name]["lines"], sources[source_name][test_name]["branches"], include_exceptional_branches)
def dumpToJson(intermediate, output):
with open(output, "w") as f:
json.dump(intermediate, f)
def getGcovFilterOptions(args):
return {
"sources": set([os.path.abspath(s) for s in args.sources]), #Make paths absolute, use set for fast lookups
"include": args.includepost,
"exclude": args.excludepost,
}
def addDicts(dict1, dict2):
"""Add dicts together by value. i.e. addDicts({"a":1,"b":0}, {"a":2}) == {"a":3,"b":0}."""
result = {k:v for k,v in dict1.items()}
for k,v in dict2.items():
if k in result:
result[k] += v
else:
result[k] = v
return result
def addLists(list1, list2):
"""Add lists together by value. i.e. addLists([1,1], [2,2]) == [3,3]."""
# Find big list and small list
blist, slist = list(list2), list(list1)
if len(list1) > len(list2):
blist, slist = slist, blist
# Overlay small list onto big list
for i, b in enumerate(slist):
blist[i] += b
return blist
def combineReports(base, overlay):
for source, scov in overlay["sources"].items():
# Combine Source Coverage
if source not in base["sources"]:
base["sources"][source] = scov
continue
for test_name, tcov in scov.items():
# Combine Source Test Name Coverage
if test_name not in base["sources"][source]:
base["sources"][source][test_name] = tcov
continue
# Drill down and create convenience variable
base_data = base["sources"][source][test_name]
# Combine Line Coverage
base_data["lines"] = addDicts(base_data["lines"], tcov["lines"])
# Combine Branch Coverage
for branch, cov in tcov["branches"].items():
if branch not in base_data["branches"]:
base_data["branches"][branch] = cov
else:
base_data["branches"][branch] = addLists(base_data["branches"][branch], cov)
# Combine Function Coverage
for function, cov in tcov["functions"].items():
if function not in base_data["functions"]:
base_data["functions"][function] = cov
else:
base_data["functions"][function]["execution_count"] += cov["execution_count"]
def parseInfo(path):
"""Parse an lcov .info file into fastcov json."""
fastcov_json = {
"sources": {}
}
with open(path) as f:
for line in f:
if line.startswith("TN:"):
current_test_name = line[3:].strip()
elif line.startswith("SF:"):
current_sf = line[3:].strip()
fastcov_json["sources"][current_sf] = {
current_test_name: {
"functions": {},
"branches": {},
"lines": {},
}
}
current_data = fastcov_json["sources"][current_sf][current_test_name]
elif line.startswith("FN:"):
line_num, function_name = line[3:].strip().split(",")
current_data["functions"][function_name] = {}
current_data["functions"][function_name]["start_line"] = int(line_num)
elif line.startswith("FNDA:"):
count, function_name = line[5:].strip().split(",")
current_data["functions"][function_name]["execution_count"] = int(count)
elif line.startswith("DA:"):
line_num, count = line[3:].strip().split(",")
current_data["lines"][line_num] = int(count)
elif line.startswith("BRDA:"):
branch_tokens = line[5:].strip().split(",")
line_num, count = branch_tokens[0], branch_tokens[-1]
if line_num not in current_data["branches"]:
current_data["branches"][line_num] = []
current_data["branches"][line_num].append(int(count))
return fastcov_json
def convertKeysToInt(report):
for source in report["sources"].keys():
for test_name in report["sources"][source].keys():
report_data = report["sources"][source][test_name]
report_data["lines"] = {int(k):v for k,v in report_data["lines"].items()}
report_data["branches"] = {int(k):v for k,v in report_data["branches"].items()}
def parseAndCombine(paths):
base_report = {}
for path in paths:
if path.endswith(".json"):
with open(path) as f:
report = json.load(f)
elif path.endswith(".info"):
report = parseInfo(path)
else:
logging.error("Currently only fastcov .json and lcov .info supported for combine operations, aborting due to %s...\n", path)
sys.exit(EXIT_CODES["unsupported_coverage_format"])
# In order for sorting to work later when we serialize,
# make sure integer keys are int
convertKeysToInt(report)
if not base_report:
base_report = report
logging.info("Setting {} as base report".format(path))
else:
combineReports(base_report, report)
logging.info("Adding {} to base report".format(path))
return base_report
def getCombineCoverage(args):
logging.info("Performing combine operation")
fastcov_json = parseAndCombine(args.combine)
filterFastcov(fastcov_json, args)
return fastcov_json
def getGcovCoverage(args):
# Need at least python 3.5 because of use of recursive glob
checkPythonVersion(sys.version_info[0:2])
# Need at least gcov 9.0.0 because that's when gcov JSON and stdout streaming was introduced
checkGcovVersion(getGcovVersion(args.gcov))
# Get list of gcda files to process
coverage_files = findCoverageFiles(args.directory, args.coverage_files, args.use_gcno)
# If gcda/gcno filtering is enabled, filter them out now
if args.excludepre:
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
# We "zero" the "counters" by simply deleting all gcda files
if args.zerocounters:
removeFiles(coverage_files)
logging.info("Removed {} .gcda files".format(len(coverage_files)))
sys.exit()
# Fire up one gcov per cpu and start processing gcdas
gcov_filter_options = getGcovFilterOptions(args)
fastcov_json = processGcdas(args, coverage_files, gcov_filter_options)
# Summarize processing results
logging.info("Processed {} .gcov files ({} total, {} skipped)".format(GCOVS_TOTAL - GCOVS_SKIPPED, GCOVS_TOTAL, GCOVS_SKIPPED))
logging.debug("Final report will contain coverage for the following %d source files:\n %s", len(fastcov_json["sources"]), "\n ".join(fastcov_json["sources"]))
return fastcov_json
def dumpFile(fastcov_json, args):
if args.lcov:
dumpToLcovInfo(fastcov_json, args.output)
logging.info("Created lcov info file '{}'".format(args.output))
else:
dumpToJson(fastcov_json, args.output)
logging.info("Created fastcov json file '{}'".format(args.output))
def tupleToDotted(tup):
return ".".join(map(str, tup))
def parseArgs():
parser = argparse.ArgumentParser(description='A parallel gcov wrapper for fast coverage report generation')
parser.add_argument('-z', '--zerocounters', dest='zerocounters', action="store_true", help='Recursively delete all gcda files')
# Enable Branch Coverage
parser.add_argument('-b', '--branch-coverage', dest='branchcoverage', action="store_true", help='Include only the most useful branches in the coverage report.')
parser.add_argument('-B', '--exceptional-branch-coverage', dest='xbranchcoverage', action="store_true", help='Include ALL branches in the coverage report (including potentially noisy exceptional branches).')
parser.add_argument('-A', '--exclude-br-lines-starting-with', dest='exclude_branches_sw', nargs="+", metavar='', default=[], help='Exclude branches from lines starting with one of the provided strings (i.e. assert, return, etc.)')
parser.add_argument('-a', '--include-br-lines-starting-with', dest='include_branches_sw', nargs="+", metavar='', default=[], help='Include only branches from lines starting with one of the provided strings (i.e. if, else, while, etc.)')
parser.add_argument('-X', '--skip-exclusion-markers', dest='skip_exclusion_markers', action="store_true", help='Skip reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
parser.add_argument('-x', '--scan-exclusion-markers', dest='scan_exclusion_markers', action="store_true", help='(Combine operations) Force reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
# Capture untested file coverage as well via gcno
parser.add_argument('-n', '--process-gcno', dest='use_gcno', action="store_true", help='Process both gcno and gcda coverage files. This option is useful for capturing untested files in the coverage report.')
# Filtering Options
parser.add_argument('-s', '--source-files', dest='sources', nargs="+", metavar='', default=[], help='Filter: Specify exactly which source files should be included in the final report. Paths must be either absolute or relative to current directory.')
parser.add_argument('-e', '--exclude', dest='excludepost', nargs="+", metavar='', default=[], help='Filter: Exclude source files from final report if they contain one of the provided substrings (i.e. /usr/include test/, etc.)')
parser.add_argument('-i', '--include', dest='includepost', nargs="+", metavar='', default=[], help='Filter: Only include source files in final report that contain one of the provided substrings (i.e. src/ etc.)')
parser.add_argument('-f', '--gcda-files', dest='coverage_files', nargs="+", metavar='', default=[], help='Filter: Specify exactly which gcda or gcno files should be processed. Note that specifying gcno causes both gcno and gcda to be processed.')
parser.add_argument('-E', '--exclude-gcda', dest='excludepre', nargs="+", metavar='', default=[], help='Filter: Exclude gcda or gcno files from being processed via simple find matching (not regex)')
parser.add_argument('-g', '--gcov', dest='gcov', default='gcov', help='Which gcov binary to use')
parser.add_argument('-d', '--search-directory', dest='directory', default=".", help='Base directory to recursively search for gcda files (default: .)')
parser.add_argument('-c', '--compiler-directory', dest='cdirectory', default=".", help='Base directory compiler was invoked from (default: .) \
This needs to be set if invoking fastcov from somewhere other than the base compiler directory.')
parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=multiprocessing.cpu_count(), help='Number of parallel gcov to spawn (default: {}).'.format(multiprocessing.cpu_count()))
parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \
If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.')
parser.add_argument('-F', '--fallback-encodings', dest='fallback_encodings', nargs="+", metavar='', default=[], help='List of encodings to try if opening a source file with the default fails (i.e. latin1, etc.). This option is not usually needed.')
parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json')
parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)')
parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout')
parser.add_argument('-t', '--test-name', dest='test_name', default="", help='Specify a test name for the coverage. Equivalent to lcov\'s `-t`.')
parser.add_argument('-C', '--add-tracefile', dest='combine', nargs="+", help='Combine multiple coverage files into one. If this flag is specified, fastcov will do a combine operation instead invoking gcov. Equivalent to lcov\'s `-a`.')
parser.add_argument('-V', '--verbose', dest="verbose", action="store_true", help="Print more detailed information about what fastcov is doing")
parser.add_argument('-v', '--version', action="version", version='%(prog)s {version}'.format(version=__version__), help="Show program's version number and exit")
args = parser.parse_args()
return args
def checkPythonVersion(version):
"""Exit if the provided python version is less than the supported version."""
if version < MINIMUM_PYTHON:
sys.stderr.write("Minimum python version {} required, found {}\n".format(tupleToDotted(MINIMUM_PYTHON), tupleToDotted(version)))
sys.exit(EXIT_CODES["python_version"])
def checkGcovVersion(version):
"""Exit if the provided gcov version is less than the supported version."""
if version < MINIMUM_GCOV:
sys.stderr.write("Minimum gcov version {} required, found {}\n".format(tupleToDotted(MINIMUM_GCOV), tupleToDotted(version)))
sys.exit(EXIT_CODES["gcov_version"])
def setupLogging(quiet, verbose):
handler = logging.StreamHandler()
handler.setFormatter(FastcovFormatter("[%(levelname)s]: %(message)s"))
root = logging.getLogger()
root.setLevel(logging.INFO)
root.addHandler(handler)
if not quiet:
logging.disable(level=logging.NOTSET) # Re-enable logging
if verbose:
root.setLevel(logging.DEBUG)
def main():
args = parseArgs()
# Setup logging
setupLogging(args.quiet, args.verbose)
# Get report from appropriate source
if args.combine:
fastcov_json = getCombineCoverage(args)
skip_exclusion_markers = not args.scan_exclusion_markers
else:
fastcov_json = getGcovCoverage(args)
skip_exclusion_markers = args.skip_exclusion_markers
# Scan for exclusion markers
if not skip_exclusion_markers:
scanExclusionMarkers(fastcov_json, args.jobs, args.exclude_branches_sw, args.include_branches_sw, args.minimum_chunk, args.fallback_encodings)
logging.info("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"])))
# Dump to desired file format
dumpFile(fastcov_json, args)
# If there was an error along the way, but we still completed the pipeline...
if EXIT_CODE:
sys.exit(EXIT_CODE)
# Set package version... it's way down here so that we can call tupleToDotted
__version__ = tupleToDotted(FASTCOV_VERSION)
if __name__ == '__main__':
main()
-257
View File
@@ -1,257 +0,0 @@
#!/usr/bin/env perl
# See copyright, etc in below POD section.
######################################################################
use warnings;
use Getopt::Long;
#use Data::Dumper; $Data::Dumper::Indent=1; $Data::Dumper::Sortkeys=1; #Debug
use IO::File;
use IO::Dir;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $VERSION = '0.001';
our $Opt_Widen = 1;
#======================================================================
# main
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"help" => sub { print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval => 0,
output=>\*STDOUT, -noperldoc=>1); },
"narrow!" => sub { $Opt_Widen = 0; },
"version" => sub { print "Version $VERSION\n"; exit(0); },
"widen!" => sub { $Opt_Widen = 1; }, # Default, undocumented
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
)) {
die "%Error: Bad usage, try 'git_untabify --help'\n";
}
read_patch();
#######################################################################
sub read_patch {
my $filename = undef;
my $lineno = 0;
my $hunk = 0;
my $editlines = {};
while (defined(my $line = <STDIN>)) {
chomp $line;
if ($line =~ m!^\+\+\+ b/(.*)!) {
find_edits($editlines);
edit_file($filename, $editlines);
$filename = $1;
$lineno = 0;
$editlines = {};
print "FILE $filename\n" if $Debug;
}
elsif ($line =~ m!^@@ -?[0-9]+,?[0-9]* \+?([0-9]+)!) {
$lineno = $1 - 1;
++$hunk;
print " LINE $1 $line" if $Debug;
}
elsif ($line =~ m!^ !) {
++$lineno;
$editlines->{$lineno} = {line => $line,
hunk => $hunk,
user_edit => 0, };
}
elsif ($line =~ m!^\+!) {
++$lineno;
print " $lineno: $line" if $Debug;
$editlines->{$lineno} = {line => $line,
hunk => $hunk,
user_edit => 1, };
}
}
find_edits($editlines);
edit_file($filename, $editlines);
}
sub find_edits {
my $editlines = shift;
# Expand edit regions so if have edited line, non-edited line, edited
# line, we will tab expand the middle ones.
my %hunk_firstlines;
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_firstlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
my %hunk_lastlines;
foreach my $lineno (sort {$b <=> $a} keys %$editlines) {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_lastlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
if ($Opt_Widen) {
# Expand to include }'s that finish basic block
foreach my $hunk (keys %hunk_lastlines) {
while (my $lineno = $hunk_lastlines{$hunk}) {
++$lineno;
if (($editlines->{$lineno}{line} || "")
=~ /^[+ ]\s+}[ \t};]*$/) {
$hunk_lastlines{$hunk} = $lineno;
} else {
last;
}
}
}
# Expand to always untabify at least 3 lines (so that future diff will
# have non-tabs within a edit hunk distance
foreach my $hunk (keys %hunk_firstlines) {
if ($hunk_firstlines{$hunk} == $hunk_lastlines{$hunk}) {
--$hunk_firstlines{$hunk};
++$hunk_lastlines{$hunk};
}
elsif ($hunk_firstlines{$hunk}+1 == $hunk_lastlines{$hunk}) {
++$hunk_lastlines{$hunk};
}
}
}
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
if (($editlines->{$lineno}{line}||"") =~ /\t/) {
my $hunk = $editlines->{$lineno}{hunk};
if ($hunk_firstlines{$hunk} <= $lineno && $hunk_lastlines{$hunk} >= $lineno) {
$editlines->{$lineno}{editit} = 1;
}
}
}
}
sub edit_file {
my $filename = shift;
my $editlines = shift;
my @editits;
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
push @editits, $lineno if $editlines->{$lineno}{editit};
}
return if $#editits < 0;
if (ignore($filename)) {
print "%Warning: Ignoring $filename\n";
return;
}
print "Edit $filename ",join(",",@editits),"\n";
my $lineno = 0;
my @out;
{
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
while (defined(my $line = $fh->getline)) {
++$lineno;
if ($editlines->{$lineno}{editit}) {
print $line;
push @out, untabify($line);
} else {
push @out, $line;
}
}
$fh->close;
}
{
my $fh = IO::File->new(">${filename}.untab") or die "%Error: $! ${filename}.untab,";
$fh->print(join('',@out));
$fh->close;
my ($dev,$ino,$mode) = stat($filename);
chmod $mode, "${filename}.untab";
}
rename("${filename}.untab", $filename) or die "%Error: $! ${filename}.untab,";
}
sub ignore {
my $filename = shift;
return 1 if ($filename =~ /(Makefile|\.mk)/);
return 1 if ($filename =~ /\.(y|l|out|vcd)$/);
return 1 if ($filename =~ /gtkwave/);
#
return 0 if ($filename =~ /\.(sv|v|vh|svh|h|vc|cpp|pl)$/);
return 0;
}
sub untabify {
my $line = shift;
my $out = "";
my $col = 0;
foreach my $c (split //, $line) {
if ($c eq "\t") {
my $destcol = int(($col+8)/8)*8;
while ($col < $destcol) { ++$col; $out .= " "; }
} else {
$out .= $c;
$col++;
}
}
return $out;
}
#######################################################################
__END__
=pod
=head1 NAME
git_untabify - Pipe a git diff report and untabify differences
=head1 SYNOPSIS
git diff a..b | git_untabify
=head1 DESCRIPTION
Take a patch file, and edit the files in the destination patch list to
untabify the related patch lines.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=item --narrow
Only edit lines which the user edited.
If not provided, also edit other lines within at least a 3 line area around
the edit, and between any edits within the same hunk.
=item --version
Displays program version and exits.
=back
=head1 DISTRIBUTION
Copyright 2005-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
=head1 AUTHORS
Wilson Snyder <[email protected]>
=head1 SEE ALSO
=cut
######################################################################
### Local Variables:
### compile-command: "./git_untabify "
### End:
+8 -7
View File
@@ -69,22 +69,23 @@ 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
maintainer-copy::
clean mostlyclean distclean maintainer-clean::
-rm -rf obj_* *.log *.dmp *.vpd core
-rm -f *.o *.d perlxsi.c *_gen_*
-rm -f *__gen*
-rm -f *__gen* obj_*
-rm -f .objcache*
distclean maintainer-clean::
+10 -7
View File
@@ -203,6 +203,7 @@ RAW_OBJS = \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hashed.o \
V3HierBlock.o \
V3Inline.o \
V3Inst.o \
V3InstrCount.o \
@@ -211,11 +212,13 @@ RAW_OBJS = \
V3LinkCells.o \
V3LinkDot.o \
V3LinkJump.o \
V3LinkInc.o \
V3LinkLValue.o \
V3LinkLevel.o \
V3LinkParse.o \
V3LinkResolve.o \
V3Localize.o \
V3MergeCond.o \
V3Name.o \
V3Number.o \
V3Options.o \
@@ -246,6 +249,7 @@ RAW_OBJS = \
V3Undriven.o \
V3Unknown.o \
V3Unroll.o \
V3Waiver.o \
V3Width.o \
V3WidthSel.o \
@@ -275,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
@@ -287,21 +290,21 @@ V3Number_test: V3Number_test.o
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
%.o: %.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
%.o: %.c
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $<
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
#### Generated files
+51 -72
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
@@ -50,38 +50,37 @@ protected:
class ActiveNamer : public ActiveBaseVisitor {
private:
typedef std::map<string, AstActive*> ActiveNameMap;
// 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
@@ -107,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;
}
@@ -130,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); }
};
@@ -146,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);
@@ -175,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;
@@ -183,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()) {
@@ -202,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 {}
};
//######################################################################
@@ -226,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);
@@ -250,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.
@@ -317,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());
@@ -361,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: ");
@@ -373,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()) {
@@ -406,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);
@@ -415,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 {}
};
//######################################################################
+17 -26
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.
@@ -89,7 +89,7 @@ private:
}
// Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp);
AstSenTree* wantp = m_finder.getSenTree(sensesp);
UINFO(4, " lookdone\n");
if (wantp != sensesp) {
// Move the active's contents to the other active
@@ -108,36 +108,27 @@ private:
// No need to do statements under it, they're already moved.
// iterateChildren(nodep);
}
virtual void visit(AstInitial* 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(AstAlways* 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(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been deleted");
}
//--------------------
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 {}
};
//######################################################################
+34 -45
View File
@@ -23,9 +23,6 @@
#include "V3GraphDfa.h"
#include "V3Stats.h"
#include <cstdarg>
#include <iomanip>
//######################################################################
// Assert class functions
@@ -37,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
@@ -77,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));
@@ -115,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()) {
@@ -132,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()) {
@@ -144,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);
@@ -172,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
@@ -229,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;
@@ -242,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")));
}
}
@@ -253,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()) {
@@ -290,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);
}
@@ -299,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()) {
@@ -309,10 +306,11 @@ 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,
@@ -328,13 +326,13 @@ private:
}
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) {
@@ -347,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);
+64 -25
View File
@@ -23,9 +23,6 @@
#include "V3Global.h"
#include "V3AssertPre.h"
#include <cstdarg>
#include <iomanip>
//######################################################################
// Assert class functions
@@ -37,35 +34,35 @@ 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
// 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; }
// 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();
@@ -77,14 +74,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
@@ -92,15 +89,59 @@ 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)); // new AstVarRef(fl, exprp, true)
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()) {
@@ -119,23 +160,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 {}
};
//######################################################################
+57 -63
View File
@@ -23,7 +23,6 @@
#include "V3Broken.h"
#include "V3String.h"
#include <cstdarg>
#include <iomanip>
#include <memory>
@@ -61,17 +60,17 @@ std::ostream& operator<<(std::ostream& os, AstType rhs);
void AstNode::init() {
editCountInc();
m_fileline = NULL;
m_nextp = NULL;
m_backp = NULL;
m_fileline = nullptr;
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;
@@ -276,8 +275,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();
@@ -322,17 +321,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
}
@@ -471,7 +470,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
@@ -487,21 +486,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;
}
@@ -562,10 +561,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;
}
@@ -599,7 +598,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
@@ -611,7 +610,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);
}
@@ -634,8 +633,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
}
@@ -669,7 +668,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;
@@ -677,12 +676,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;
@@ -701,10 +700,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;
@@ -727,7 +726,7 @@ void AstNode::deleteNode() {
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
if (
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
1
true
#else
!v3Global.opt.debugLeak()
#endif
@@ -740,7 +739,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!
@@ -748,8 +747,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();
}
}
@@ -832,11 +831,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
@@ -854,7 +853,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.
}
}
@@ -901,7 +900,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) {
@@ -975,9 +974,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);
}
@@ -1000,7 +997,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()) {
@@ -1053,7 +1050,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");
}
}
@@ -1109,7 +1106,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);
}
@@ -1120,7 +1117,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;
@@ -1129,6 +1126,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
*logsp << "No changes since last dump!\n";
} else {
dumpTree(*logsp);
editCountSetLast(); // Next dump can indicate start from here
}
}
}
@@ -1139,13 +1137,11 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
// set by other steps if it is called in the middle of other operations
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
}
// Next dump can indicate start from here
editCountSetLast();
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str);
assert(0);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE
}
@@ -1154,10 +1150,10 @@ string AstNode::locationStr() const {
const AstNode* backp = this;
int itmax = 10000; // Max iterations before giving up on location search
while (backp) {
if (--itmax < 0) {
if (VL_UNCOVERABLE(--itmax < 0)) {
// Likely some circular back link, and V3Ast is trying to report a low-level error
UINFO(1, "Ran out of iterations finding locationStr on " << backp << endl);
return "";
return ""; // LCOV_EXCL_LINE
}
const AstScope* scopep;
if ((scopep = VN_CAST_CONST(backp, Scope))) {
@@ -1269,8 +1265,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();
}
+453 -395
View File
File diff suppressed because it is too large Load Diff
+219 -168
View File
@@ -22,9 +22,9 @@
#include "V3Global.h"
#include "V3Graph.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3String.h"
#include "V3EmitCBase.h"
#include <cstdarg>
#include <iomanip>
#include <vector>
@@ -36,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 {
@@ -46,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() {
@@ -74,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);
}
@@ -84,7 +84,7 @@ const char* AstNodeUOrStructDType::broken() const {
return "member broken";
}
}
return NULL;
return nullptr;
}
void AstNodeCCall::dump(std::ostream& str) const {
@@ -101,7 +101,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 {
@@ -212,7 +212,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); }
@@ -226,6 +226,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) {
@@ -282,16 +312,16 @@ string AstVar::verilogKwd() const {
class AstVar::VlArgTypeRecursed {
public:
string m_oref; // To output, reference part before name, "&"
string m_osuffix; // To output, suffixed after name, "[3]"
string m_oprefix; // To output, prefixed before name, "Foo_t"
void clear() {
m_oref.clear();
m_osuffix.clear();
m_oprefix.clear();
}
string refParen(const string& name) {
return m_oref.empty() ? name : "(" + m_oref + " " + name + ")";
bool m_isRef; // Is it a reference?
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name) const {
string out;
out += m_type;
out += " ";
out += m_isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
@@ -301,126 +331,86 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
string oname;
if (named) {
oname += " ";
if (!namespc.empty()) oname += namespc + "::";
oname += VIdProtect::protectIf(name(), protect());
}
return ostatic + info.m_oprefix + info.refParen(oname) + info.m_osuffix;
return ostatic + info.render(oname);
}
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool arrayed) const {
bool compound) const {
VlArgTypeRecursed info;
info.m_isRef
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
dtypep = dtypep->skipRefp();
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
VlArgTypeRecursed key = vlArgTypeRecurse(forFunc, adtypep->keyDTypep(), true);
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
string out = "VlAssocArray<";
out += key.m_oprefix;
if (!key.m_osuffix.empty() || !key.m_oref.empty()) {
out += " " + key.m_osuffix + key.m_oref;
}
out += ", ";
out += sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
out += "> ";
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
string out = "VlQueue<";
out += sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
out += "> ";
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
VlArgTypeRecursed info;
string out = "VlQueue<" + sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) out += ", " + cvtToStr(adtypep->boundConst() + 1);
out += "> ";
info.m_oprefix = out;
return info;
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
VlArgTypeRecursed info;
info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
return info;
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed);
info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix;
return info;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
string otype;
string oarray;
bool strtype = bdtypep->keyword() == AstBasicDTypeKwd::STRING;
string bitvec;
if (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
bitvec += "/*" + cvtToStr(dtypep->width() - 1) + ":0*/";
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR
|| bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR)
otype += "const ";
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
otype += "char*";
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
otype += "VerilatedScope*";
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
otype += "double";
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
otype += "float";
} else if (strtype) {
otype += "std::string";
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
otype += "CData" + bitvec;
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
otype += "SData" + bitvec;
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
otype += "IData" + bitvec;
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
otype += "QData" + bitvec;
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (arrayed) {
otype += "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
otype += "WData" + bitvec; // []'s added later
oarray += "[" + cvtToStr(dtypep->widthWords()) + "]";
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
string oref;
if (isDpiOpenArray()
|| (forFunc
&& (isWritable() || direction() == VDirection::REF
|| direction() == VDirection::CONSTREF || (strtype && isNonOutput())))) {
oref = "&";
}
VlArgTypeRecursed info;
info.m_oprefix = otype;
info.m_osuffix = oarray;
info.m_oref = oref;
// UINFO(9, "vlArgRec "<<"oprefix="<<info.m_oprefix<<" osuffix="<<info.m_osuffix
// <<" oref="<<info.m_oref<<" "<<dtypep);
return info;
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
return info;
}
string AstVar::vlEnumType() const {
@@ -472,29 +462,52 @@ string AstVar::vlEnumDir() const {
return out;
}
string AstVar::vlPropInit() const {
string AstVar::vlPropDecl(const string& propName) const {
string out;
out = vlEnumType(); // VLVT_UINT32 etc
out += ", " + vlEnumDir(); // VLVD_IN etc
if (AstBasicDType* bdtypep = basicp()) {
out += ", VerilatedVarProps::Packed()";
out += ", " + cvtToStr(bdtypep->left()) + ", " + cvtToStr(bdtypep->right());
}
bool first = true;
for (AstNodeDType* dtp = dtypep(); dtp;) {
std::vector<int> ulims; // Unpacked dimension limits
for (const AstNodeDType* dtp = dtypep(); dtp;) {
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstNodeArrayDType* adtypep = VN_CAST(dtp, NodeArrayDType)) {
if (first) {
out += ", VerilatedVarProps::Unpacked()";
first = false;
}
out += ", " + cvtToStr(adtypep->declRange().left()) + ", "
+ cvtToStr(adtypep->declRange().right());
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
ulims.push_back(adtypep->declRange().left());
ulims.push_back(adtypep->declRange().right());
dtp = adtypep->subDTypep();
} else {
break; // AstBasicDType - nothing below
}
}
if (!ulims.empty()) {
out += "static const int " + propName + "__ulims[";
out += cvtToStr(ulims.size());
out += "] = {";
auto it = ulims.cbegin();
out += cvtToStr(*it);
while (++it != ulims.cend()) {
out += ", ";
out += cvtToStr(*it);
}
out += "};\n";
}
out += "static const VerilatedVarProps ";
out += propName;
out += "(";
out += vlEnumType(); // VLVT_UINT32 etc
out += ", " + vlEnumDir(); // VLVD_IN etc
if (const AstBasicDType* const bdtypep = basicp()) {
out += ", VerilatedVarProps::Packed()";
out += ", " + cvtToStr(bdtypep->left());
out += ", " + cvtToStr(bdtypep->right());
}
if (!ulims.empty()) {
out += ", VerilatedVarProps::Unpacked()";
out += ", " + cvtToStr(ulims.size() / 2);
out += ", " + propName + "__ulims";
}
out += ");\n";
return out;
}
@@ -513,8 +526,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()) + "]";
@@ -591,13 +604,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()) {
@@ -613,15 +626,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();
}
@@ -651,17 +662,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() {
@@ -746,14 +757,21 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) {
return nodep;
}
const char* AstJumpBlock::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return nullptr;
}
void AstJumpBlock::cloneRelink() {
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
}
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
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();
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
@@ -761,7 +779,6 @@ void AstScope::cloneRelink() {
static_cast<AstNode*>(m_modp)->clonep();
}
}
string AstScope::nameDotless() const {
string out = shortName();
string::size_type pos;
@@ -780,7 +797,6 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
return AstNode::prettyName(out);
}
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
@@ -797,28 +813,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;
@@ -828,7 +844,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
@@ -886,8 +902,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) {
@@ -902,7 +919,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);
@@ -977,27 +994,37 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
//======================================================================
// Per-type Debugging
// Render node address for dumps. By default this is just the address
// printed as hex, but with --dump-tree-addrids we map addresses to short
// strings with a bijection to aid human readability. Observe that this might
// not actually be a unique identifier as the address can get reused after a
// node has been freed.
static std::string nodeAddr(const AstNode* nodep) {
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
}
void AstNode::dump(std::ostream& str) const {
str << typeName() << " "
<< cvtToHex(this)
//<<" "<<cvtToHex(this)->m_backp
<< nodeAddr(this)
//<< " " << nodeAddr(m_backp)
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << "}";
if (user1p()) str << " u1=" << cvtToHex(user1p());
if (user2p()) str << " u2=" << cvtToHex(user2p());
if (user3p()) str << " u3=" << cvtToHex(user3p());
if (user4p()) str << " u4=" << cvtToHex(user4p());
if (user5p()) str << " u5=" << cvtToHex(user5p());
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
<< fileline()->firstColumnLetters() << "}";
if (user1p()) str << " u1=" << nodeAddr(user1p());
if (user2p()) str << " u2=" << nodeAddr(user2p());
if (user3p()) str << " u3=" << nodeAddr(user3p());
if (user4p()) str << " u4=" << nodeAddr(user4p());
if (user5p()) str << " u5=" << nodeAddr(user5p());
if (hasDType()) {
// Final @ so less likely to by accident read it as a nodep
if (dtypep() == this) {
str << " @dt=this@";
} else {
str << " @dt=" << cvtToHex(dtypep()) << "@";
str << " @dt=" << nodeAddr(dtypep()) << "@";
}
if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); }
} else { // V3Broken will throw an error
if (dtypep()) str << " %Error-dtype-exp=null,got=" << cvtToHex(dtypep());
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
}
if (name() != "") {
if (VN_IS(this, Const)) {
@@ -1051,10 +1078,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 {
@@ -1066,7 +1095,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");
@@ -1142,6 +1175,15 @@ void AstJumpGo::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstJumpLabel::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> ";
if (blockp()) {
blockp()->dump(str);
} else {
str << "%Error:UNLINKED";
}
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> ";
@@ -1218,12 +1260,16 @@ void AstRange::dump(std::ostream& str) const {
}
void AstRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (defp()) {
if (typedefp() || subDTypep()) {
static bool s_recursing = false;
if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true;
str << " -> ";
defp()->dump(str);
if (typedefp()) {
typedefp()->dump(str);
} else if (subDTypep()) {
subDTypep()->dump(str);
}
s_recursing = false;
}
} else {
@@ -1239,7 +1285,7 @@ void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (generic()) str << " [GENERIC]";
if (AstNodeDType* dtp = virtRefDTypep()) {
str << " refdt=" << cvtToHex(dtp);
str << " refdt=" << nodeAddr(dtp);
dtp->dumpSmall(str);
}
}
@@ -1384,7 +1430,7 @@ void AstVarScope::dump(std::ostream& str) const {
}
void AstVarXRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
str << " [LV] => ";
} else {
@@ -1402,7 +1448,7 @@ void AstVarXRef::dump(std::ostream& str) const {
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
str << " [LV] => ";
} else {
@@ -1452,17 +1498,20 @@ 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=" << cvtToHex(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); }
void AstDot::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (colon()) str << " [::]";
}
void AstActive::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " => ";
@@ -1474,7 +1523,7 @@ void AstActive::dump(std::ostream& str) const {
}
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> ";
if (dotted() != "") { str << ".=" << dotted() << " "; }
if (taskp()) {
@@ -1506,6 +1555,8 @@ void AstBegin::dump(std::ostream& str) const {
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (!page().empty()) str << " page=" << page();
if (!linescov().empty()) str << " lc=" << linescov();
if (this->dataDeclNullp()) {
str << " -> ";
this->dataDeclNullp()->dump(str);
+3186 -2664
View File
File diff suppressed because it is too large Load Diff
+30 -41
View File
@@ -30,12 +30,9 @@
#include "V3Global.h"
#include "V3Begin.h"
#include "V3Inst.h"
#include "V3Ast.h"
#include <algorithm>
#include <cstdarg>
#include <vector>
//######################################################################
@@ -45,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);
@@ -64,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 != "") {
@@ -95,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;
@@ -150,7 +143,7 @@ private:
m_unnamedScope = oldUnnamed;
// Cleanup
AstNode* addsp = NULL;
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
@@ -166,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());
@@ -180,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());
@@ -195,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);
@@ -208,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() == "") {
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
@@ -228,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;
@@ -247,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 {}
};
//######################################################################
@@ -273,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);
@@ -296,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 -12
View File
@@ -30,7 +30,6 @@
#include "V3Branch.h"
#include "V3Ast.h"
#include <cstdarg>
#include <map>
//######################################################################
@@ -66,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();
@@ -89,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);
}
}
@@ -122,7 +118,7 @@ public:
iterateChildren(nodep);
calc_tasks();
}
virtual ~BranchVisitor() {}
virtual ~BranchVisitor() override {}
};
//######################################################################
+37 -22
View File
@@ -32,8 +32,7 @@
#include "V3AstConstOnly.h"
#include <algorithm>
#include <cstdarg>
#include VL_INCLUDE_UNORDERED_MAP
#include <unordered_map>
//######################################################################
@@ -42,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
@@ -50,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");
@@ -68,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()) {
@@ -79,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;
@@ -90,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");
@@ -114,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
@@ -122,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;
@@ -131,10 +131,18 @@ public:
if (!(iter->second & FLAG_LINKABLE)) return false;
return true;
}
static bool okIfAbove(const AstNode* nodep) {
// Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false;
const auto iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if ((iter->second & FLAG_UNDER_NOW)) return false;
return true;
}
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;
@@ -142,19 +150,22 @@ public:
static void prepForTree() {
#ifndef VL_LEAK_CHECKS
s_nodes.clear();
#endif
#else
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
it->second &= ~FLAG_IN_TREE;
it->second &= ~FLAG_LINKABLE;
}
#endif
}
static void doneWithTree() {
for (int backs = 0; backs < 2;
backs++) { // Those with backp() are probably under one leaking without
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs == 1 : backs == 0)) {
// LCOV_EXCL_START
if (VL_UNCOVERABLE((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs == 1 : backs == 0))) {
// Use only AstNode::dump instead of the virtual one, as there
// may be varp() and other cross links that are bad.
if (v3Global.opt.debugCheck()) {
@@ -173,14 +184,14 @@ public:
}
it->second |= FLAG_LEAKED;
}
// LCOV_EXCL_STOP
}
}
}
public:
// CONSTRUCTORS
BrokenTable() {}
virtual ~BrokenTable() {}
virtual ~BrokenTable() override {}
};
BrokenTable::NodeMap BrokenTable::s_nodes;
@@ -193,6 +204,10 @@ bool AstNode::brokeExistsAbove() const {
// Called by node->broken() routines to do table lookup
return BrokenTable::okIfBelow(this);
}
bool AstNode::brokeExistsBelow() const {
// Called by node->broken() routines to do table lookup
return BrokenTable::okIfAbove(this);
}
//######################################################################
@@ -208,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);
}
@@ -216,7 +231,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenMarkVisitor() {}
virtual ~BrokenMarkVisitor() override {}
};
//######################################################################
@@ -224,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");
@@ -256,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()),
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);
}
@@ -271,7 +286,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenCheckVisitor() {}
virtual ~BrokenCheckVisitor() override {}
};
//######################################################################
+8 -12
View File
@@ -32,10 +32,7 @@
#include "V3CCtors.h"
#include <algorithm>
#include <cmath>
#include <cstdarg>
#include <map>
#include <vector>
class V3CCtorsVisitor {
private:
@@ -49,14 +46,13 @@ private:
int m_funcNum; // Function number being built
public:
AstCFunc* builtFuncp() const { return m_tlFuncp; }
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
@@ -82,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
@@ -101,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);
@@ -146,13 +142,11 @@ void V3CCtors::cctorsAll() {
modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn
{
AstCFunc* varResetFuncp;
V3CCtorsVisitor var_reset(
modp, "_ctor_var_reset",
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
(VN_IS(modp, Class) ? "vlSymsp" : ""),
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
varResetFuncp = var_reset.builtFuncp();
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) {
@@ -176,10 +170,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);
}
+18 -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);
@@ -189,7 +188,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,22 +202,22 @@ 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);
};
//######################################################################
// Class class functions
void V3CUse::cUseAll(AstNetlist* nodep) {
void V3CUse::cUseAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
// Call visitor separately for each module, so visitor state is cleared
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
+1 -1
View File
@@ -27,7 +27,7 @@
class V3CUse {
public:
static void cUseAll(AstNetlist* nodep);
static void cUseAll();
};
#endif // Guard
+33 -38
View File
@@ -43,7 +43,6 @@
#include "V3Stats.h"
#include <algorithm>
#include <cstdarg>
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
@@ -53,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)");
}
@@ -82,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)) {
@@ -96,7 +96,7 @@ private:
} else if (VN_IS(m_caseExprp, Case)
&& (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isUnknown()) {
if (nodep->num().isAnyX()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)");
}
@@ -106,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 {}
};
//######################################################################
@@ -132,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];
@@ -162,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;
@@ -219,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();
}
@@ -281,13 +278,13 @@ private:
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
if (debug() >= 9) {
if (debug() >= 9) { // LCOV_EXCL_START
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (AstNode* itemp = m_valueItem[i]) {
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
}
}
}
} // LCOV_EXCL_STOP
// Handle any assertions
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
@@ -325,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
@@ -378,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
@@ -389,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.
@@ -401,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 {
@@ -423,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 {
@@ -460,7 +458,7 @@ private:
// Xs in case or casez are impossible due to two state simulations
if (casep->casex()) {
} else if (casep->casez() || casep->caseInside()) {
if (itemp->num().isUnknown()) return true;
if (itemp->num().isAnyX()) return true;
} else {
if (itemp->num().isFourState()) return true;
}
@@ -468,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: ");
@@ -483,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);
}
+22 -14
View File
@@ -45,7 +45,6 @@
#include "V3Ast.h"
#include <algorithm>
#include <cstdarg>
//######################################################################
// Cast state, as a visitor of each AstNode
@@ -110,30 +109,39 @@ 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(AstCCast* 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());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
}
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) {
@@ -145,7 +153,7 @@ private:
ensureCast(nodep->lhsp());
}
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
virtual void visit(AstVarRef* nodep) override {
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
&& castSize(nodep) != castSize(nodep->varp())) {
@@ -155,7 +163,7 @@ private:
}
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)#).
@@ -163,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 {}
};
//######################################################################

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