Compare commits

...
179 Commits
Author SHA1 Message Date
Wilson Snyder b350b6a0ff Version bump 2020-12-02 20:09:23 -05:00
Wilson Snyder 80564a8f89 Remove vgen test to avoid Bit::Vector for testing. 2020-12-02 20:06:07 -05:00
Yuri Victorovich 016611021d Fix the default GNU Make executable name on FreeBSD (#2553) 2020-12-02 19:27:53 -05:00
Wilson Snyder fa20614277 Fix Ubuntu 16.04 LTS warning 2020-12-02 19:20:03 -05:00
Wilson Snyder 1e69167191 Internals: Move function in V3Width. No functional change. 2020-12-02 18:51:29 -05:00
Wilson Snyder faa5edc068 Add TspStateBase destructor (#2620). 2020-12-02 07:37:34 -05:00
Wilson Snyder e3c32adad4 Rename static/thread misnamed variables. No functional change. 2020-12-01 19:32:01 -05:00
Wilson Snyder b054d937cb Rename static/thread misnamed variables. No functional change. 2020-12-01 19:01:20 -05:00
Wilson Snyder 212e8fb14b Internals: Cleanup some inlines, use constexpr. No functional change intended. 2020-12-01 18:49:03 -05:00
Wilson Snyder 014e43f0ef Reset index counts on clearing verilated_cov (static removal) 2020-12-01 18:30:25 -05:00
Wilson Snyder d21b4e3fc7 Internal cast preparatory cleanups. 2020-11-29 18:26:06 -05:00
Wilson Snyder 0818d88113 Tests: Cast enum test 2020-11-29 16:59:08 -05:00
Wilson Snyder 77ec2dc875 Internals: Rename some CI comments 2020-11-29 15:06:29 -05:00
Wilson Snyder 665e8edaff Support $monitor and $strobe. 2020-11-29 11:31:38 -05:00
Wilson Snyder 67103d346b Fix $fwriteh/$fwriteo 2020-11-29 10:53:44 -05:00
Wilson Snyder aebb54444e Internals: Favor NodeProcedure. No functional change intended. 2020-11-29 09:50:30 -05:00
Wilson Snyder a54ac52a35 Internals: Use 'Bit' where mean 2-state type. No functional change. 2020-11-29 08:23:36 -05:00
Wilson Snyder aa360052a8 Internals: Code movement, no functional change. 2020-11-28 22:01:11 -05:00
Wilson Snyder e09f039a36 Internals: Remove dead code. No functional change. 2020-11-28 21:43:37 -05:00
Wilson Snyder ff262fc4fb Support type(t) static casting 2020-11-28 17:29:21 -05:00
Wilson Snyder 9a9931fb9d Support complex function arguments. 2020-11-28 13:46:14 -05:00
Wilson Snyder 30686d8550 Support passing of objects to functions 2020-11-28 12:43:24 -05:00
Wilson Snyder 05f3fd7c6e Fix class new with math. 2020-11-28 12:26:44 -05:00
Wilson Snyder e14319b401 Internals: Refactor V3Param through code movement only. No functional change intended. 2020-11-28 12:04:29 -05:00
Wilson Snyder 1299b70945 Internals: Pass class parameters through link. 2020-11-27 22:48:42 -05:00
Wilson Snyder cf2810db8b Change -sv option to select 1800-2017 instead of 1800-2005. 2020-11-27 21:49:47 -05:00
Wilson Snyder d77beecc6e Fix $countbits(..., 'z) 2020-11-27 21:34:40 -05:00
Wilson Snyder 0c6bd42da3 Fix $countbits(..., 'x) 2020-11-27 20:51:32 -05:00
Wilson Snyder 5091298fae Internals: Cleanup V3Unknown. No functional change intended. 2020-11-27 20:25:02 -05:00
Wilson Snyder cef7610b14 Fix crash on virtual interfaces. 2020-11-27 20:02:17 -05:00
Wilson Snyder ed268805ce Lint check for pure virtual in non-virtual class. 2020-11-27 19:53:04 -05:00
Wilson Snyder 123d1af29d Fix crash on non-class static function 2020-11-27 14:58:50 -05:00
Wilson Snyder cc307626c0 Tests: Add class name test. 2020-11-27 10:34:31 -05:00
Wilson Snyder 963fd0664d Fix class-in-module issues 2020-11-27 09:42:51 -05:00
Wilson Snyder 4643d6e883 Internals: Refactor V3Param through code movement only. No functional change intended. 2020-11-27 09:17:44 -05:00
Wilson Snyder d89fc05da1 Internals: Refactor V3Param through code movement only. No functional change intended. 2020-11-27 09:04:56 -05:00
Wilson Snyder 84d7380588 Internals: Param immediate delete, in prep for next commit. No functional change intended. 2020-11-27 08:50:29 -05:00
Wilson Snyder 04febb1944 Internals: Move V3Param code. No functional change. 2020-11-26 15:03:55 -05:00
Wilson Snyder d56b923eaa Fix 'randomize() with {}' crash 2020-11-26 11:50:50 -05:00
Wilson Snyder a37866ee92 Support 'super'. 2020-11-26 11:06:59 -05:00
Wilson Snyder 1a92a44c7d Internals: Assert on misexpected 'new'. 2020-11-26 09:38:47 -05:00
Wilson Snyder 60a1d25a96 Fix extern function member references. 2020-11-26 08:55:32 -05:00
Wilson Snyder ad21f2e850 Fix 'this' in extern functions. 2020-11-26 08:28:53 -05:00
Wilson Snyder ffbae97a3d Tests: Make t_lint_syncasyncnet_bad etc tolerate -Oi. 2020-11-25 21:54:50 -05:00
Wilson Snyder 380137a402 Fix internal pointer shown on CLKDATA warnings 2020-11-25 21:34:56 -05:00
Wilson Snyder ac2058c7ec Tests: Fix t_unopt_combo_waive with -Oi 2020-11-25 21:18:13 -05:00
Wilson Snyder de931d6a97 Fix LHS is not a lvalue when using tristate with -Oi. 2020-11-25 21:09:25 -05:00
Wilson Snyder f2d8e45d72 For performance, use unordered_set/map where possible. No functional change intended. 2020-11-25 20:57:30 -05:00
Wilson Snyder 085ef5fc05 Fix extern function var refs getting errors. 2020-11-25 20:05:44 -05:00
Wilson Snyder 6095efd84e Check for proper 'local' and 'protected' (#2228). 2020-11-25 07:03:01 -05:00
Wilson Snyder 114ab1378f Internals: Track class package on membersels 2020-11-24 23:36:09 -05:00
Wilson Snyder 8622c754b7 Fix unstable statistic 2020-11-24 23:35:44 -05:00
Wilson Snyder bf24fa9478 Fix access to non-overridden base class variable (#2654). 2020-11-24 22:46:02 -05:00
Wilson Snyder e1c45440fc Internals: Rename packagep(). No functional change. 2020-11-24 21:56:03 -05:00
Wilson Snyder b0cb43b2f2 Fix not iterating some extended classes depending on declaration order. 2020-11-24 21:41:32 -05:00
Wilson Snyder dc1f44840d Internals: Fix not clearing packagep on some assignments. Should affect assertions only. 2020-11-24 21:34:11 -05:00
Wilson Snyder fd21a41acd Internals: Minor cleanups before class fix (#2654). No functional change intended. 2020-11-24 21:28:26 -05:00
Wilson Snyder cf09a9b6d2 Commentary 2020-11-24 18:45:36 -05:00
Wilson Snyder dc306cf371 Internal debug: avoid segflt with gdb "pnt" 2020-11-24 18:35:12 -05:00
Wilson Snyder 35374f09b4 Add error on class extending itself 2020-11-24 18:15:49 -05:00
Wilson Snyder e85a2e860e Support 'with item.index'. 2020-11-23 23:18:58 -05:00
Wilson Snyder 103ba1fb6d Commentary 2020-11-20 21:48:11 -05:00
Wilson Snyder b684995292 Support $random and $urandom seeds. 2020-11-19 21:32:33 -05:00
Wilson Snyder c371a63d41 Internals: Fix missing final. No functional change. 2020-11-19 08:23:15 -05:00
Yutetsu TAKATSUKASA 0102efd4ea Support unpacked array in DPI-C (#2648)
* Add tests for unpacked array in DPI-C

* Add more generic parameter generator to AstNodes

* Supports multi dimensional array in DPI ( DPI argmuments <=> Verilator internal type conversion)

consider typedef in V3Task

fix export test

fix inout for scalar

support export func of time

* V3Premit does not show an error for wide words nor ArraySel

* Unnecessary pack func for unapcked array does not appear anymore

* Support unpacked array in runtime header

- Add an overload for lvalue VL_CVT_PACK_STR_NN
- Allow conversion from void *

* touch up tests for codacy advices

* resolve free functions. no functional change intended.
2020-11-19 22:02:58 +09:00
Wilson Snyder abfee1270f Improve internal code coverage 2020-11-18 22:21:48 -05:00
Wilson Snyder 5992d678be Fix clang error, broke last commit. 2020-11-18 22:18:29 -05:00
Wilson Snyder b6ded59c2b Internals: Use and enforce class final for ~5% performance boost. 2020-11-18 21:32:16 -05:00
Wilson Snyder c0888c1b0f Internals: Use newline instead of endl to avoid unneeded flush. 2020-11-18 21:03:23 -05:00
Wilson Snyder fa77141519 Fix unpacked array parameters near functions (#2639). 2020-11-18 20:12:14 -05:00
Wilson Snyder b3760911e7 Internals: Param minor cleanups. No functional change intended. 2020-11-18 19:50:47 -05:00
Yutetsu TAKATSUKASA b500e57991 Add an overload of VL_CVT_PACK_STR_NN for lvalue (#2651) 2020-11-19 06:52:03 +09:00
Yutetsu TAKATSUKASA 19e4013ab5 Allow conversion from const void * to QData (#2650) 2020-11-18 23:44:45 +09:00
Wilson Snyder 82b2af3b83 Commentary 2020-11-17 22:48:37 -05:00
Wilson Snyder e6f7510895 Add check for rand_mode/constraint_mode. 2020-11-17 22:14:18 -05:00
Wilson Snyder 2f718b9ea0 Show IEEE reference in array port message, plus internal cleanups. 2020-11-17 21:10:50 -05:00
Marlon James 899e7bacb2 Fix VPI callback list iteration (#2644)
The end iterator always points to an element past the end of the list.
When new elements are added to the back of the list, they are inserted
before the end iterator.
Instead, track the last element in the list at the start of processing
and stop after it's been processed.
2020-11-17 17:19:51 -05:00
Tomasz Gorochowik 5b3717b369 Tests: Memory clean up in tests (#2645)
This patch normalizes what the tests do before exiting. After this
change each test should call final on the top module and explicitly
free the top module object before exiting.
2020-11-17 06:37:55 -05:00
Wilson Snyder 1e7c61b23e Internals: Refactor huge func in V3Param. No functional change intended. 2020-11-16 22:35:51 -05:00
Marlon James 0e1e380a55 Fix test for callCbs() so it can fail (#2613) 2020-11-16 21:00:09 -05:00
Wilson Snyder 1b0a48ea02 Internals: Use C++11 = default where obvious. No functional change intended. 2020-11-16 19:56:16 -05:00
Wilson Snyder 70b3a599ce Fix trace signal names getting hashed (#2643). 2020-11-16 18:11:27 -05:00
Wilson Snyder 26c0e6ba00 Fix missing array include. 2020-11-16 07:31:12 -05:00
Wilson Snyder efc6fb7fc3 Internals: Better pack AstNode. No functional change. 2020-11-15 22:03:06 -05:00
Wilson Snyder b68038a73f clang-tidy fix. No functional change. 2020-11-15 17:23:02 -05:00
Wilson Snyder f4ef4ad9f3 Internals: Favor std::array where easy. No functional change intended. 2020-11-15 16:21:26 -05:00
Wilson Snyder f6f7684ccd Internal member initialization. No functional change intended. 2020-11-15 15:40:35 -05:00
Wilson Snyder e74cc32f2d Add internal assertion that VarScopes properly formed. 2020-11-14 16:13:06 -05:00
Wilson Snyder c64cc989f0 verilator_gantt: Show CPU physical info. 2020-11-14 12:22:15 -05:00
Wilson Snyder f94fcaa8e4 Move YYDEBUG into header. No functional change intended. 2020-11-14 10:20:27 -05:00
Wilson Snyder 297b297bc7 devel release 2020-11-14 10:00:01 -05:00
Wilson Snyder 02cb3d17a2 Version bump 2020-11-14 09:50:30 -05:00
Wilson Snyder c3cfaf55ed Commentary 2020-11-14 09:26:38 -05:00
Wilson Snyder 3e7013af31 Internal scope cleanup. No functional change. 2020-11-13 21:12:18 -05:00
Wilson Snyder f7a5883205 Internals: assert not double adding. No functional change intended. 2020-11-13 21:12:03 -05:00
Wilson Snyder 5d3482734a Fix precision in verilator_gantt. 2020-11-13 18:51:45 -05:00
Yutetsu TAKATSUKASA e8c03650ae Fix internal error if always block without begin-end has concat (#2640) (#2641) 2020-11-13 09:50:09 -05:00
Wilson Snyder 7eac788306 Add error on using :: with module 2020-11-12 19:45:26 -05:00
Wilson Snyder 6a58e67699 Commentary 2020-11-12 19:31:53 -05:00
Wilson Snyder b49be06a5a Tests: Standard wording. 2020-11-12 18:50:05 -05:00
Wilson Snyder 87b2adb6a1 With --debug, turn off address space layout randomization. 2020-11-12 18:49:49 -05:00
Wilson Snyder 5634a18f78 Tests: Smaller t_vpi_var test 2020-11-11 20:57:24 -05:00
Wilson Snyder b84c9bb4c0 Internals: Show scope debug information. 2020-11-11 19:00:10 -05:00
Wilson Snyder 6dfce882a1 Support $exit as alias of $finish 2020-11-10 22:49:48 -05:00
Wilson Snyder 79d33bf1ee Use C++11 for loops, from clang-migrate. No functional change intended 2020-11-10 22:10:38 -05:00
Wilson Snyder 44eb362a18 clang-tidy cleanups. No functional change intended. 2020-11-10 21:40:14 -05:00
Wilson Snyder 8664aac225 Fix missing newlines in emit. 2020-11-09 18:29:09 -05:00
Wilson Snyder 6965e138aa Add clearer unsupported message for inside on array (#2566) 2020-11-08 23:26:58 -05:00
Wilson Snyder fc52fb9093 Fix arrays of modport interfaces (#2614). 2020-11-08 22:43:32 -05:00
Wilson Snyder cef7708f38 Internals: Fix missed access change. No functional change intended. 2020-11-08 22:02:35 -05:00
Dan Petrisko 438fb01665 Fix exited typo (#2634) 2020-11-08 21:55:33 -05:00
Wilson Snyder 67d5b1a11a Internals: Preserve arrays of modports. Part of #2614. 2020-11-08 19:15:53 -05:00
Wilson Snyder d78941885b Fix cast width propagation (#2597). 2020-11-08 19:07:33 -05:00
Wilson Snyder 6e7b07c794 Internals: Prep for #2597. No functional change intended 2020-11-08 18:58:31 -05:00
Wilson Snyder 9655e287ab Tests: Travis regression fix 2020-11-08 17:06:03 -05:00
Wilson Snyder 917ca2bad7 Tests: Add t_const_opt_red (#2632) (#2633) 2020-11-08 16:39:28 -05:00
Wilson Snyder c3f5dd7414 Tests: Try to stabilize cron test. 2020-11-08 11:17:42 -05:00
Wilson Snyder 04c7fd1696 Tests: Add wire-or mux test for future optimization. 2020-11-07 21:57:31 -05:00
Wilson Snyder 152689776d Report error on typedef referencing self (#2539). 2020-11-07 15:41:37 -05:00
Wilson Snyder 778f133118 Fix dynamic new with init argument (#2325). 2020-11-07 14:28:05 -05:00
Wilson Snyder ff5465308b Internals: Tree dump DEFAULT pattern. No functional change. 2020-11-07 11:56:24 -05:00
Wilson Snyder 602750b1ee Commentary 2020-11-07 10:49:54 -05:00
Wilson Snyder 2a24bb4759 Fix queue poping wrong value when otherwise unused (#2512). 2020-11-07 10:37:55 -05:00
Krzysztof Bieganski 7c4259bc0a Support static methods and typedefs in classes (#2615) 2020-11-06 19:51:21 -05:00
Kaleb Barrett 1c2384cb3d Fix iteration over mutating list bug in VPI impl (#2588)
Previously, in any given VPI callback, if the callback body registered
the same callback, that registering would be processed in the currently
executing call to the call*Cbs function. In the worse case, this could
lead to an infinite loop.
2020-11-06 17:56:15 -05:00
Yutetsu TAKATSUKASAandWilson Snyder 75881754a9 Fix dangling reference (Issue #2622) (#2623)
* collect multiple string literals of "__Vcvt". No functional change is intended.

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

* Update src/V3EmitC.cpp

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

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

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

* share the implementation of $fgets

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

* add checks for scanf with string

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

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

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

* Add test for callCbs() and callValueCbs()
2020-10-26 21:55:27 -04:00
Wilson Snyder 95d1272269 Support associative array pattern assignments and defaults. 2020-10-25 21:05:22 -04:00
Wilson Snyder 046c0a7aa1 Fix queue assignment with different limits, negative indicies 2020-10-24 22:08:11 -04:00
Wilson Snyder 835905bdae Convert cast tasks to assertions 2020-10-24 20:30:52 -04:00
Wilson Snyder 51d1235cda Shorter stringify of empty queues, and better queue tests 2020-10-24 18:00:40 -04:00
Wilson Snyder 2f21b3385a Tests: Casting. 2020-10-24 17:46:09 -04:00
Wilson Snyder 9d0a7d5e70 Commentary (#2606). 2020-10-23 18:30:10 -04:00
Wilson Snyder 4cec3ff2a0 Fix WIDTH warnings on comparisons with nullptr (#2602). 2020-10-22 17:27:23 -04:00
Wilson Snyder 25593c0ee2 Fix capitalization 2020-10-22 17:13:42 -04:00
Wilson Snyder 5d3dd52f13 Support queue slicing (#2326). 2020-10-18 13:23:39 -04:00
Wilson Snyder ec36d0d772 Internals: When resolving assignments pass dtype to children. 2020-10-18 12:30:33 -04:00
Wilson Snyder 3d2503f9aa Tests: Run execute on non-Verilator when unsupported test. 2020-10-17 21:31:58 -04:00
Wilson Snyder 4576644591 Prep for future queue slicing. 2020-10-17 21:09:10 -04:00
Wilson Snyder d8df216a8d Fix emit indent of VL_TO_STRING 2020-10-17 20:05:21 -04:00
Wilson Snyder 964dcd5b7c Tests: Add additional array method tests and error 2020-10-17 19:23:27 -04:00
Wilson Snyder f62c070d06 Internals: Concat strings only when final; prep for queues. 2020-10-17 18:56:38 -04:00
Wilson Snyder a56e0a6e89 Internals: Prep for type method. No functional change intended. 2020-10-17 16:48:11 -04:00
Wilson Snyder 451e961e03 Internals: Prep for type method. No functional change intended. 2020-10-17 16:04:29 -04:00
Wilson Snyder cb550e5357 Remove old MSVC 6 workarounds 2020-10-17 14:21:27 -04:00
Wilson Snyder 829db3eefa Fix tick style on %p formats. 2020-10-16 19:26:04 -04:00
Wilson Snyder 44f938e507 Use static const for emitted parameter declarations. 2020-10-16 19:05:28 -04:00
Wilson Snyder 4849c0530b Fix class extends with typedef. 2020-10-16 18:25:32 -04:00
Wilson Snyder f4ed367850 Internals: Remove verilator_difftree old cleanups. 2020-10-15 21:36:35 -04:00
Wilson Snyder d4df94d866 Internals: Move static resolution to LinkParse. 2020-10-15 21:08:24 -04:00
Wilson Snyder 5d8019f941 Internals: Only need to applyFTask once. No functional change intended. 2020-10-15 21:02:24 -04:00
Wilson Snyder 48597bebaf Tests: Better static tests 2020-10-15 20:44:51 -04:00
Wilson Snyder 470859f929 devel release 2020-10-15 08:26:36 -04:00
575 changed files with 19080 additions and 7565 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-modernize*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-default-arguments,-fuchsia-overloaded-operator,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance'
Checks: '*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-modernize-use-auto,-modernize-use-trailing-return-type,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance'
WarningsAsErrors: ''
HeaderFilterRegex: ''
FormatStyle: none
+58
View File
@@ -3,6 +3,64 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.106 2020-12-02
** Change -sv option to select 1800-2017 instead of 1800-2005.
*** Check for proper 'local' and 'protected' (#2228).
*** Support $random and $urandom seeds.
*** Support $monitor and $strobe.
*** Support complex function arguments.
*** Support 'super'.
*** Support 'with item.index'.
**** Fix the default GNU Make executable name on FreeBSD (#2553). [Yuri Victorovich]
**** Fix trace signal names getting hashed (#2643). [Barbara Gigerl]
**** Fix unpacked array parameters near functions (#2639). [Anderson Ignacio da Silva]
**** Fix access to non-overridden base class variable (#2654). [Tobias Rosenkranz]
* Verilator 4.104 2020-11-14
*** Support queue and associative array 'with' statements (#2616).
*** Support queue slicing (#2326).
*** Support associative array pattern assignments and defaults.
*** Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski]
**** Report error on typedef referencing self (#2539). [Cody Piersall]
**** With --debug, turn off address space layout randomization.
**** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett]
**** Fix cast width propagation (#2597). [flex-liu]
**** Fix return from callValueCbs (#2589) (#2605). [Marlon James]
**** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick]
**** Fix fault when $fgets, $sscanf, etc used with string (#2604). [Yutetsu TAKATSUKASA]
**** Fix WIFEXITED missing from MinGW/MSYS2 (#2609). [Jean Berniolles]
**** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1]
**** Fix arrays of modport interfaces (#2614). [Thierry Tambe]
**** Fix split_var internal error (#2640) (#2641). [Yutetsu TAKATSUKASA]
* Verilator 4.102 2020-10-15
**** Support const object new() assignments.
+1
View File
@@ -66,4 +66,5 @@ ci/
/csrc/
obj_dir.*
TAGS
gmon.out
.*~
+7 -5
View File
@@ -442,15 +442,16 @@ cppcheck: $(CPPCHECK_DEP)
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
CLANGTIDY = clang-tidy
CLANGTIDY_FLAGS = -config=''
CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables'
CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \
$(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP))
CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_THREADED=1 -DVL_CPPCHECK=1
clangtidy: $(CLANGTIDY_DEP)
clang-tidy: $(CLANGTIDY_DEP)
%.cpp.tidy: %.cpp
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@
%.h.tidy: %.h
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@
analyzer-src:
-rm -rf src/obj_dbg
@@ -462,11 +463,12 @@ analyzer-include:
CLANGFORMAT = clang-format
CLANGFORMAT_FLAGS = -i
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c*
clang-format:
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
ftp: info
+32 -19
View File
@@ -76,7 +76,8 @@ if ($opt_gdbbt && !gdb_works()) {
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
if ($opt_gdb) {
# Generic GDB interactive
run (($ENV{VERILATOR_GDB}||"gdb")
run (aslr_off()
.($ENV{VERILATOR_GDB}||"gdb")
." ".verilator_bin()
# Note, uncomment to set breakpoints before running:
# ." -ex 'break main'"
@@ -91,16 +92,22 @@ if ($opt_gdb) {
." -ex 'bt'");
} elsif ($opt_rr) {
# Record with rr
run ("rr record ".verilator_bin()
run (aslr_off()
."rr record ".verilator_bin()
." ".join(' ', @quoted_sw));
} elsif ($opt_gdbbt && $Debug) {
# Run under GDB to get gdbbt
run ("gdb"
run (aslr_off()
."gdb"
." ".verilator_bin()
." --batch --quiet --return-child-result"
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt' -ex 'quit'");
} elsif ($Debug) {
# Debug
run(aslr_off()
.verilator_bin()." ".join(' ',@quoted_sw));
} else {
# Normal, non gdb
run(verilator_bin()." ".join(' ',@quoted_sw));
@@ -165,6 +172,15 @@ sub gdb_works {
return $status==0;
}
sub aslr_off {
my $ok = `setarch --addr-no-randomize echo ok 2>/dev/null` || "";
if ($ok =~ /ok/) {
return "setarch --addr-no-randomize ";
} else {
return "";
}
}
sub run {
# Run command, check errors
my $command = shift;
@@ -1445,7 +1461,7 @@ future version of Verilator no longer always packs unpacked structures.
=item -sv
Specifies SystemVerilog language features should be enabled; equivalent to
"--language 1800-2005". This option is selected by default, it exists for
"--language 1800-2017". This option is selected by default, it exists for
compatibility with other simulators.
=item +systemverilogext+I<ext>
@@ -1980,14 +1996,15 @@ section below for descriptions of some of the files that were created.
(Verilator included a default compile rule and link rule, since we used
--exe and passed a .cpp file on the Verilator command line. Verilator also
then used C<make> to build a final executable. You can also write your own
compile rules, and run make yourself as we'll show in the SYSTEMC section.)
then used C<make> to build a final executable, since we used --build. You
can also write your own compile rules, and run make yourself as we'll show
in the SYSTEMC section.
And now we run it
And now we run it:
obj_dir/Vour
And we get as output
And we get as output:
Hello World
- our.v:2: Verilog $finish
@@ -4075,9 +4092,10 @@ is ignored, only a single trace file may be active at once.
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
$dumplimit/$dumpportlimit are currently ignored.
=item $finish, $stop
=item $exit, $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored.
The rarely used optional parameter to $finish and $stop is ignored. $exit
is aliased to $finish.
=item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets,
$fscanf, $fwrite, $fscanf, $sscanf
@@ -4089,17 +4107,12 @@ $setup, $setuphold, $skew, $timeskew, $width
All specify blocks and timing checks are ignored.
=item $monitor, $strobe
Monitor and strobe are not supported, convert to always_comb $display or
similar.
=item $random, $urandom, $urandom_range
$random and $urandom do not support the optional argument to set the seed.
Use +verilator+seed argument to set the seed. There is one random seed per
C thread, not per module for $random, nor per object for random stability
of $urandom/$urandom_range.
Use +verilator+seed argument to set the seed if there is no $random or
$urandom optional argument to set the seed. There is one random seed per C
thread, not per module for $random, nor per object for random stability of
$urandom/$urandom_range.
=item $readmemb, $readmemh
-25
View File
@@ -9,22 +9,6 @@ use Pod::Usage;
use strict;
use vars qw($Debug);
#======================================================================
# Old version 1 dump nodes with no dtypep's
our %Ver1_Non_Dtyped = map {$_ => 1} qw(
ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM
CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE
COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT
DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF
IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST
NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE
PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR
SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS
SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT
TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE
UDPTABLELINE UNTILSTABLE VASSERT WHILE );
#======================================================================
# main
@@ -133,8 +117,6 @@ sub filter {
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
if ($verCvt) {
next if $line =~ /^ NETLIST/;
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
# # Below Ver1_Non_Dtyped may replace above further
if ($line =~ /: ([A-Z]+) /) {
my $type = $1;
next if $type =~ 'DTYPE';
@@ -147,14 +129,7 @@ sub filter {
}
next;
}
if ($Ver1_Non_Dtyped{$type}) {
$line =~ s! w[0-9]+!!g;
}
}
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
}
print $f2 $line;
}
+81 -9
View File
@@ -60,6 +60,7 @@ sub process {
my $filename = shift;
read_data($filename);
read_cpuinfo();
report();
}
@@ -70,7 +71,7 @@ sub read_data {
%Global = (rdtsc_cycle_time => 0);
my $fh = IO::File->new ($filename) or die "%Error: $! $filename,";
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
while (my $line = $fh->getline) {
if ($line =~ m/VLPROF mtask\s(\d+)\sstart\s(\d+)\send\s(\d+)\selapsed\s(\d+)\spredict_time\s(\d+)\scpu\s(\d+)\son thread (\d+)/) {
my $mtask = $1;
@@ -113,6 +114,27 @@ sub read_data {
}
}
sub read_cpuinfo {
my $filename = "/proc/cpuinfo";
my $fh = IO::File->new("<$filename") or return;
my $cpu;
while (my $line = $fh->getline) {
chomp $line;
if ($line =~ m/^processor\s*:\s*(\d+)\s*$/) {
$cpu = $1;
}
if ($cpu && $line =~ m/^([a-z_ ]+)\s*:\s*(.*)$/) {
my ($term, $value) = ($1, $2);
$term =~ s/\s+$//;
$term =~ s/\s+/_/;
$value =~ s/\s+$//;
$Global{cpuinfo}{$cpu}{$term} = $value;
}
}
}
#######################################################################
sub report {
print "Verilator Gantt report\n";
@@ -162,9 +184,9 @@ sub report {
printf " Total eval time = %d rdtsc ticks\n", $Global{last_end};
printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time;
printf " All-thread mtask time = %d rdtsc ticks\n", $mt_mtask_time;
my $long_efficiency = $long_mtask_time/($Global{last_end});
my $long_efficiency = $long_mtask_time/($Global{last_end} || 1);
printf " Longest-thread efficiency = %0.1f%%\n", $long_efficiency*100;
my $mt_efficiency = $mt_mtask_time/($Global{last_end}*$nthreads);
my $mt_efficiency = $mt_mtask_time/($Global{last_end}*$nthreads || 1);
printf " All-thread efficiency = %0.1f%%\n", $mt_efficiency*100;
printf " All-thread speedup = %0.1f\n", $mt_efficiency*$nthreads;
if ($Global{rdtsc_cycle_time} > 0) {
@@ -198,21 +220,70 @@ sub report {
}
print "\nStatistics:\n";
print " min log(p2e) = $min_p2e from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict}, elapsed $Mtasks{$min_mtask}{elapsed})\n";
print " max log(p2e) = $max_p2e from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict}, elapsed $Mtasks{$max_mtask}{elapsed})\n";
printf " min log(p2e) = %0.3f", $min_p2e;
print " from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict},";
print " elapsed $Mtasks{$min_mtask}{elapsed})\n";
printf " max log(p2e) = %0.3f", $max_p2e;
print " from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict},";
print " elapsed $Mtasks{$max_mtask}{elapsed})\n";
my $stddev = stddev(\@p2e_ratios);
my $mean = mean(\@p2e_ratios);
print " mean = " . ($mean) . "\n";
print " stddev = " . ($stddev) . "\n";
print " e ^ stddev = " . exp($stddev). "\n";
print "\n";
printf " mean = %0.3f\n", $mean;
printf " stddev = %0.3f\n", $stddev;
printf " e ^ stddev = %0.3f\n", exp($stddev);
report_cpus();
if ($nthreads > $ncpus) {
print "\n";
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
print " : See docs on use of numactl.\n";
} else {
if ($Global{cpu_socket_cores_warning}) {
print "\n";
print "%Warning: Multiple threads scheduled on same hyperthreaded core.\n";
print " : See docs on use of numactl.\n";
}
if ($Global{cpu_sockets_warning}) {
print "\n";
print "%Warning: Threads scheduled on multiple sockets.\n";
print " : See docs on use of numactl.\n";
}
}
print "\n";
}
sub report_cpus {
print "\nCPUs:\n";
# Test - show all cores
# for (my $i=0; $i<73; ++$i) { $Global{cpus}{$i} ||= {cpu_time => 0}; }
$Global{cpu_sockets} ||= {};
$Global{cpu_socket_cores} ||= {};
foreach my $cpu (sort {$a <=> $b} keys %{$Global{cpus}}) {
printf " cpu %d: ", $cpu;
printf "cpu_time=%d", $Global{cpus}{$cpu}{cpu_time};
my $socket = $Global{cpuinfo}{$cpu}{physical_id};
$Global{cpu_sockets}{$socket}++ if defined $socket;
printf " socket=%d", $socket if defined $socket;
my $core = $Global{cpuinfo}{$cpu}{core_id};
$Global{cpu_socket_cores}{$socket."__".$core}++ if defined $socket && defined $core;
printf " core=%d", $core if defined $core;
my $model = $Global{cpuinfo}{$cpu}{model_name};
printf " %s", $model if defined $model;
print "\n";
}
$Global{cpu_sockets_warning} = 1
if (scalar keys %{$Global{cpu_sockets}} > 1);
foreach my $scn (values %{$Global{cpu_socket_cores}}) {
$Global{cpu_socket_cores_warning} = 1 if $scn > 1;
}
}
sub report_graph {
@@ -226,6 +297,7 @@ sub report_graph {
}
# One more step so we can fit more labels
$time_per = int($time_per/2);
$time_per ||= 1;
}
my ($graph, $conflicts) = _make_graph($time_per);
+1 -1
View File
@@ -40,7 +40,7 @@ RUN apt-get update \
WORKDIR /tmp
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
RUN cpan install -fi Unix::Processors Parallel::Forker
RUN git clone https://github.com/veripool/vcddiff.git && \
make -C vcddiff && \
-1
View File
@@ -94,7 +94,6 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
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
+1 -1
View File
@@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.102 2020-10-15],
AC_INIT([Verilator],[4.106 2020-12-02],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
+4
View File
@@ -27,13 +27,16 @@ James Hutchinson
Jamey Hicks
James Pallister
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
John Coiner
John Demme
Josh Redford
Julien Margetts
Kaleb Barrett
Kanad Kanhere
Kevin Kiningham
Krzysztof Bieganski
Kuba Ober
Ludwig Rogiers
Lukasz Dalek
@@ -41,6 +44,7 @@ Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Markus Krause
Marlon James
Marshal Qiao
Matthew Ballance
Michael Killough
-1
View File
@@ -102,7 +102,6 @@ Those developing Verilator itself may also want these (see internals.adoc):
cpan install Pod::Perldoc
cpan install Unix::Processors
cpan install Parallel::Forker
cpan install Bit::Vector
==== Install SystemC
+2 -4
View File
@@ -628,8 +628,6 @@ https://github.com/veripool/vcddiff
* Cmake for build paths that use it.
* Bit::Vector to test vgen.pl
=== Controlling the Test Driver
Test drivers are written in PERL. All invoke the main test driver script,
@@ -959,9 +957,9 @@ Then, when the watch fires, to break at every following change to that node:
To print a node:
pn nodep
# or: call nodep->dumpGdb() # aliased to "pn" in src/.gdbinit
# or: call dumpGdb(nodep) # aliased to "pn" in src/.gdbinit
pnt nodep
# or: call nodep->dumpTreeGdb() # aliased to "pnt" in src/.gdbinit
# or: call dumpTreeGdb(nodep) # aliased to "pnt" in src/.gdbinit
When GDB halts, it is useful to understand that the backtrace will commonly
show the iterator functions between each invocation of `visit` in the
+211 -179
View File
@@ -61,7 +61,7 @@ typedef union {
// Global variables
// Slow path variables
VerilatedMutex Verilated::m_mutex;
VerilatedMutex Verilated::s_mutex;
// Keep below together in one cache line
Verilated::Serialized Verilated::s_s;
@@ -75,7 +75,7 @@ VerilatedImp::VerilatedImpU VerilatedImp::s_s;
struct VerilatedImpInitializer {
VerilatedImpInitializer() { VerilatedImp::setup(); }
~VerilatedImpInitializer() { VerilatedImp::teardown(); }
} g_VerilatedImpInitializer;
} s_VerilatedImpInitializer;
//===========================================================================
// User definable functions
@@ -256,6 +256,7 @@ Verilated::Serialized::Serialized() {
s_errorLimit = 1;
s_randReset = 0;
s_randSeed = 0;
s_randSeedEpoch = 1;
s_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure
s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure
}
@@ -279,6 +280,8 @@ void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.v.m_s
static vluint32_t vl_sys_rand32() VL_MT_UNSAFE {
// Return random 32-bits using system library.
// Used only to construct seed for Verilator's PNRG.
static VerilatedMutex s_mutex;
const VerilatedLockGuard lock(s_mutex); // Otherwise rand is unsafe
#if defined(_WIN32) && !defined(__CYGWIN__)
// Windows doesn't have lrand48(), although Cygwin does.
return (rand() << 16) ^ rand();
@@ -288,29 +291,18 @@ static vluint32_t vl_sys_rand32() VL_MT_UNSAFE {
}
vluint64_t vl_rand64() VL_MT_SAFE {
static VerilatedMutex s_mutex;
static VL_THREAD_LOCAL bool t_seeded = false;
static VL_THREAD_LOCAL vluint32_t t_seedEpoch = 0;
static VL_THREAD_LOCAL vluint64_t t_state[2];
if (VL_UNLIKELY(!t_seeded)) {
t_seeded = true;
{
const VerilatedLockGuard lock(s_mutex);
if (Verilated::randSeed() != 0) {
t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
t_state[1] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
} else {
t_state[0] = ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
^ (static_cast<vluint64_t>(vl_sys_rand32())));
t_state[1] = ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
^ (static_cast<vluint64_t>(vl_sys_rand32())));
}
// Fix state as algorithm is slow to randomize if many zeros
// This causes a loss of ~ 1 bit of seed entropy, no big deal
if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0];
if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1];
}
// For speed, we use a thread-local epoch number to know when to reseed
if (VL_UNLIKELY(t_seedEpoch != Verilated::randSeedEpoch())) {
// Set epoch before state, in case races with new seeding
t_seedEpoch = Verilated::randSeedEpoch();
t_state[0] = Verilated::randSeedDefault64();
t_state[1] = t_state[0];
// Fix state as algorithm is slow to randomize if many zeros
// This causes a loss of ~ 1 bit of seed entropy, no big deal
if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0];
if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1];
}
// Xoroshiro128+ algorithm
vluint64_t result = t_state[0] + t_state[1];
@@ -334,6 +326,11 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
}
// LCOV_EXCL_STOP
IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE {
Verilated::randSeed(static_cast<int>(seed));
return VL_RANDOM_I(obits);
}
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
if (Verilated::randReset() == 0) return 0;
IData data = ~0;
@@ -556,7 +553,7 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W
return owp;
}
}
return 0;
return owp;
}
return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp);
}
@@ -688,7 +685,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
// Note uses a single buffer internally; presumes only one usage per printf
// Note also assumes variables < 64 are not wide, this assumption is
// sometimes not true in low-level routines written here in verilated.cpp
static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH];
static VL_THREAD_LOCAL char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
const char* pctp = nullptr; // Most recent %##.##g format
bool inPct = false;
bool widthSet = false;
@@ -766,11 +763,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
if (lbits) {} // UNUSED - always 64
if (fmt == '^') { // Realtime
if (!widthSet) width = VerilatedImp::timeFormatWidth();
output += _vl_vsformat_time(tmp, d, left, width);
output += _vl_vsformat_time(t_tmp, d, left, width);
} else {
std::string fmts(pctp, pos - pctp + 1);
sprintf(tmp, fmts.c_str(), d);
output += tmp;
sprintf(t_tmp, fmts.c_str(), d);
output += t_tmp;
}
break;
}
@@ -814,9 +811,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
int digits = 0;
std::string append;
if (lbits <= VL_QUADSIZE) {
digits = sprintf(tmp, "%" VL_PRI64 "d",
digits = sprintf(t_tmp, "%" VL_PRI64 "d",
static_cast<vlsint64_t>(VL_EXTENDS_QQ(lbits, lbits, ld)));
append = tmp;
append = t_tmp;
} else {
if (VL_SIGN_E(lbits, lwp[VL_WORDS_I(lbits) - 1])) {
WData neg[VL_VALUE_STRING_MAX_WIDTH / 4 + 2];
@@ -843,8 +840,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
int digits = 0;
std::string append;
if (lbits <= VL_QUADSIZE) {
digits = sprintf(tmp, "%" VL_PRI64 "u", ld);
append = tmp;
digits = sprintf(t_tmp, "%" VL_PRI64 "u", ld);
append = t_tmp;
} else {
append = VL_DECIMAL_NW(lbits, lwp);
digits = append.length();
@@ -863,7 +860,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
case 't': { // Time
if (!widthSet) width = VerilatedImp::timeFormatWidth();
output += _vl_vsformat_time(tmp, static_cast<double>(ld), left, width);
output += _vl_vsformat_time(t_tmp, static_cast<double>(ld), left, width);
break;
}
case 'b':
@@ -1037,7 +1034,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
// Read a Verilog $sscanf/$fscanf style format into the output list
// The format must be pre-processed (and lower cased) by Verilator
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH];
static VL_THREAD_LOCAL char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
int floc = fbits - 1;
IData got = 0;
bool inPct = false;
@@ -1045,7 +1042,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
const char* pos = formatp;
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
// fromp, fstr)<<"'"<<endl);
// fromp, fstr)<<"'\n");
if (!inPct && pos[0] == '%') {
inPct = true;
inIgnore = false;
@@ -1079,7 +1076,17 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
WData qowp[VL_WQ_WORDS_E];
VL_SET_WQ(qowp, 0ULL);
WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
if (obits == -1) { // string
owp = nullptr;
if (VL_UNCOVERABLE(fmt != 's')) {
VL_FATAL_MT(
__FILE__, __LINE__, "",
"Internal: format other than %s is passed to string"); // LCOV_EXCL_LINE
}
} else if (obits > VL_QUADSIZE) {
owp = va_arg(ap, WDataOutP);
}
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
switch (fmt) {
case 'c': {
@@ -1091,22 +1098,24 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 's': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, nullptr);
if (!tmp[0]) goto done;
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
for (int i = 0; i < obits && lpos >= 0; --lpos) {
_vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]);
lsb += 8;
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, nullptr);
if (!t_tmp[0]) goto done;
if (owp) {
int lpos = (static_cast<int>(strlen(t_tmp))) - 1;
int lsb = 0;
for (int i = 0; i < obits && lpos >= 0; --lpos) {
_vl_vsss_setbit(owp, obits, lsb, 8, t_tmp[lpos]);
lsb += 8;
}
}
break;
}
case 'd': { // Signed decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "0123456789+-xXzZ?_");
if (!t_tmp[0]) goto done;
vlsint64_t ld = 0;
sscanf(tmp, "%30" VL_PRI64 "d", &ld);
sscanf(t_tmp, "%30" VL_PRI64 "d", &ld);
VL_SET_WQ(owp, ld);
break;
}
@@ -1114,46 +1123,47 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 'e':
case 'g': { // Real number
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
if (!tmp[0]) goto done;
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "+-.0123456789eE");
if (!t_tmp[0]) goto done;
// cppcheck-suppress unusedStructMember // It's used
union {
double r;
vlsint64_t ld;
} u;
u.r = strtod(tmp, nullptr);
u.r = strtod(t_tmp, nullptr);
VL_SET_WQ(owp, u.ld);
break;
}
case 't': // FALLTHRU // Time
case '#': { // Unsigned decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "0123456789+-xXzZ?_");
if (!t_tmp[0]) goto done;
QData ld = 0;
sscanf(tmp, "%30" VL_PRI64 "u", &ld);
sscanf(t_tmp, "%30" VL_PRI64 "u", &ld);
VL_SET_WQ(owp, ld);
break;
}
case 'b': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "01xXzZ?_");
if (!t_tmp[0]) goto done;
_vl_vsss_based(owp, obits, 1, t_tmp, 0, strlen(t_tmp));
break;
}
case 'o': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "01234567xXzZ?_");
if (!t_tmp[0]) goto done;
_vl_vsss_based(owp, obits, 3, t_tmp, 0, strlen(t_tmp));
break;
}
case 'x': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp,
"0123456789abcdefABCDEFxXzZ?_");
if (!t_tmp[0]) goto done;
_vl_vsss_based(owp, obits, 4, t_tmp, 0, strlen(t_tmp));
break;
}
case 'u': {
@@ -1194,6 +1204,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
if (!inIgnore) ++got;
// Reload data if non-wide (if wide, we put it in the right place directly)
if (obits == 0) { // Due to inIgnore
} else if (obits == -1) { // string
std::string* p = va_arg(ap, std::string*);
*p = t_tmp;
} else if (obits <= VL_BYTESIZE) {
CData* p = va_arg(ap, CData*);
*p = owp[0];
@@ -1252,36 +1265,44 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
for (; i < bytes; ++i) { *op++ = 0; }
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
static IData getLine(std::string& str, IData fpi, size_t maxLen) VL_MT_SAFE {
str.clear();
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0;
// The string needs to be padded with 0's in unused spaces in front of
// any read data. This means we can't know in what location the first
// character will finally live, so we need to copy. Yuk.
IData bytes = VL_BYTES_I(obits);
char buffer[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// We don't use fgets, as we must read \0s.
while (str.size() < maxLen) {
const int c = getc(fp); // getc() is threadsafe
if (c == EOF) break;
str.push_back(c);
if (c == '\n') break;
}
return str.size();
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
std::string str;
const IData bytes = VL_BYTES_I(obits);
IData got = getLine(str, fpi, bytes);
if (VL_UNLIKELY(str.empty())) return 0;
// V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe
if (VL_UNCOVERABLE(bytes > VL_TO_STRING_MAX_WORDS * VL_EDATASIZE)) {
if (VL_UNCOVERABLE(bytes < str.size())) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun"); // LCOV_EXCL_LINE
}
// We don't use fgets, as we must read \0s.
IData got = 0;
char* cp = buffer;
while (got < bytes) {
int c = getc(fp); // getc() is threadsafe
if (c == EOF) break;
*cp++ = c;
got++;
if (c == '\n') break;
}
_VL_STRING_TO_VINT(obits, destp, got, buffer);
_VL_STRING_TO_VINT(obits, destp, got, str.data());
return got;
}
// declared in verilated_heavy.h
IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE {
return getLine(dest, fpi, std::numeric_limits<size_t>::max());
}
IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
// We ignore lhs/fpi - IEEE says "most recent error" so probably good enough
IData ret = errno;
@@ -1309,58 +1330,58 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); }
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
_VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str());
_VL_STRING_TO_VINT(obits, destp, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE {
@@ -1373,38 +1394,38 @@ void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, .
}
std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
return output;
return t_output;
}
void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
VL_PRINTF_MT("%s", output.c_str());
VL_PRINTF_MT("%s", t_output.c_str());
}
void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
static VL_THREAD_LOCAL std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
_vl_vsformat(t_output, formatp, ap);
va_end(ap);
VerilatedImp::fdWrite(fpi, output);
VerilatedImp::fdWrite(fpi, t_output);
}
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
@@ -1625,12 +1646,12 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_S
const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE {
const std::string& match = VerilatedImp::argPlusMatch(prefixp);
static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH];
static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
if (match.empty()) return nullptr;
outstr[0] = '\0';
strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+"
t_outstr[0] = '\0';
strncat(t_outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+"
VL_VALUE_STRING_MAX_WIDTH - 1);
return outstr;
return t_outstr;
}
//===========================================================================
@@ -1736,31 +1757,31 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_
static const char* memhFormat(int nBits) {
assert((nBits >= 1) && (nBits <= 32));
static VL_THREAD_LOCAL char buf[32];
static VL_THREAD_LOCAL char t_buf[32];
switch ((nBits - 1) / 4) {
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
case 2: VL_SNPRINTF(buf, 32, "%%03x"); break;
case 3: VL_SNPRINTF(buf, 32, "%%04x"); break;
case 4: VL_SNPRINTF(buf, 32, "%%05x"); break;
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
case 0: VL_SNPRINTF(t_buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(t_buf, 32, "%%02x"); break;
case 2: VL_SNPRINTF(t_buf, 32, "%%03x"); break;
case 3: VL_SNPRINTF(t_buf, 32, "%%04x"); break;
case 4: VL_SNPRINTF(t_buf, 32, "%%05x"); break;
case 5: VL_SNPRINTF(t_buf, 32, "%%06x"); break;
case 6: VL_SNPRINTF(t_buf, 32, "%%07x"); break;
case 7: VL_SNPRINTF(t_buf, 32, "%%08x"); break;
default: assert(false); break; // LCOV_EXCL_LINE
}
return buf;
return t_buf;
}
static const char* formatBinary(int nBits, vluint32_t bits) {
assert((nBits >= 1) && (nBits <= 32));
static VL_THREAD_LOCAL char buf[64];
static VL_THREAD_LOCAL char t_buf[64];
for (int i = 0; i < nBits; i++) {
bool isOne = bits & (1 << (nBits - 1 - i));
buf[i] = (isOne ? '1' : '0');
t_buf[i] = (isOne ? '1' : '0');
}
buf[nBits] = '\0';
return buf;
t_buf[nBits] = '\0';
return t_buf;
}
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
@@ -2179,11 +2200,8 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
//===========================================================================
// Verilated:: Methods
Verilated::ThreadLocal::ThreadLocal() {}
Verilated::ThreadLocal::~ThreadLocal() {}
void Verilated::debug(int level) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_debug = level;
if (level) {
#ifdef VL_DEBUG
@@ -2197,49 +2215,65 @@ void Verilated::debug(int level) VL_MT_SAFE {
}
}
void Verilated::randReset(int val) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_randReset = val;
}
void Verilated::randSeed(int val) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_randSeed = val;
vluint64_t newEpoch = s_s.s_randSeedEpoch + 1;
if (VL_UNLIKELY(newEpoch == 0)) newEpoch = 1;
// Obververs must see new epoch AFTER seed updated
#ifdef VL_THREADED
std::atomic_signal_fence(std::memory_order_release);
#endif
s_s.s_randSeedEpoch = newEpoch;
}
vluint64_t Verilated::randSeedDefault64() VL_MT_SAFE {
if (Verilated::randSeed() != 0) {
return ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
} else {
return ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
^ (static_cast<vluint64_t>(vl_sys_rand32())));
}
}
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_calcUnusedSigs = flag;
}
void Verilated::errorCount(int val) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_errorCount = val;
}
void Verilated::errorCountInc() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
++s_s.s_errorCount;
}
void Verilated::errorLimit(int val) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_errorLimit = val;
}
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_gotFinish = flag;
}
void Verilated::assertOn(bool flag) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_assertOn = flag;
}
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_fatalOnVpiError = flag;
}
void Verilated::timeunit(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_timeunit = value;
}
void Verilated::timeprecision(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_s.s_timeprecision = value;
#ifdef SYSTEMC_VERSION
sc_time sc_res = sc_get_time_resolution();
@@ -2270,15 +2304,15 @@ void Verilated::timeprecision(int value) VL_MT_SAFE {
#endif
}
void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_ns.s_profThreadsStart = flag;
}
void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
s_ns.s_profThreadsWindow = flag;
}
void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(s_mutex);
if (s_ns.s_profThreadsFilenamep) free(const_cast<char*>(s_ns.s_profThreadsFilenamep));
s_ns.s_profThreadsFilenamep = strdup(flagp);
}
@@ -2286,18 +2320,18 @@ void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE {
// Returns new'ed data
// Used by symbol table creation to make module names
static VL_THREAD_LOCAL char* strp = nullptr;
static VL_THREAD_LOCAL size_t len = 0;
static VL_THREAD_LOCAL char* t_strp = nullptr;
static VL_THREAD_LOCAL size_t t_len = 0;
size_t newlen = strlen(n1) + strlen(n2) + strlen(delimiter) + 1;
if (!strp || newlen > len) {
if (strp) delete[] strp;
strp = new char[newlen];
len = newlen;
if (!t_strp || newlen > t_len) {
if (t_strp) delete[] t_strp;
t_strp = new char[newlen];
t_len = newlen;
}
strcpy(strp, n1);
if (*n1) strcat(strp, delimiter);
strcat(strp, n2);
return strp;
strcpy(t_strp, n1);
if (*n1) strcat(t_strp, delimiter);
strcat(t_strp, n2);
return t_strp;
}
//=========================================================================
@@ -2306,8 +2340,8 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
// Keeping these out of class Verilated to avoid having to include <list>
// in verilated.h (for compilation speed)
typedef std::list<std::pair<Verilated::VoidPCb, void*>> VoidPCbList;
static VoidPCbList g_flushCbs;
static VoidPCbList g_exitCbs;
static VoidPCbList s_flushCbs;
static VoidPCbList s_exitCbs;
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
@@ -2323,16 +2357,16 @@ static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE {
}
void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
addCb(cb, datap, g_flushCbs);
const VerilatedLockGuard lock(s_mutex);
addCb(cb, datap, s_flushCbs);
}
void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
removeCb(cb, datap, g_flushCbs);
const VerilatedLockGuard lock(s_mutex);
removeCb(cb, datap, s_flushCbs);
}
void Verilated::runFlushCallbacks() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
runCallbacks(g_flushCbs);
const VerilatedLockGuard lock(s_mutex);
runCallbacks(s_flushCbs);
fflush(stderr);
fflush(stdout);
// When running internal code coverage (gcc --coverage, as opposed to
@@ -2342,16 +2376,16 @@ void Verilated::runFlushCallbacks() VL_MT_SAFE {
}
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
addCb(cb, datap, g_exitCbs);
const VerilatedLockGuard lock(s_mutex);
addCb(cb, datap, s_exitCbs);
}
void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
removeCb(cb, datap, g_exitCbs);
const VerilatedLockGuard lock(s_mutex);
removeCb(cb, datap, s_exitCbs);
}
void Verilated::runExitCallbacks() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
runCallbacks(g_exitCbs);
const VerilatedLockGuard lock(s_mutex);
runCallbacks(s_exitCbs);
}
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
@@ -2366,11 +2400,11 @@ void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
const char* Verilated::commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
const std::string& match = VerilatedImp::argPlusMatch(prefixp);
static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH];
static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
if (match.empty()) return "";
outstr[0] = '\0';
strncat(outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1);
return outstr;
t_outstr[0] = '\0';
strncat(t_outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1);
return t_outstr;
}
void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE {
@@ -2625,8 +2659,6 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
//======================================================================
// VerilatedScope:: Methods
VerilatedScope::VerilatedScope() {}
VerilatedScope::~VerilatedScope() {
// Memory cleanup - not called during normal operation
VerilatedImp::scopeErase(this);
+33 -27
View File
@@ -129,12 +129,12 @@ extern vluint32_t VL_THREAD_ID() VL_MT_SAFE;
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before relaxing
/// Mutex, wrapped to allow -fthread_safety checks
class VL_CAPABILITY("mutex") VerilatedMutex {
class VL_CAPABILITY("mutex") VerilatedMutex final {
private:
std::mutex m_mutex; // Mutex
public:
VerilatedMutex() {}
~VerilatedMutex() {}
VerilatedMutex() = default;
~VerilatedMutex() = default;
const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety
/// Acquire/lock mutex
void lock() VL_ACQUIRE() {
@@ -155,7 +155,7 @@ public:
};
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
class VL_SCOPED_CAPABILITY VerilatedLockGuard {
class VL_SCOPED_CAPABILITY VerilatedLockGuard final {
VL_UNCOPYABLE(VerilatedLockGuard);
private:
@@ -174,19 +174,19 @@ public:
#else // !VL_THREADED
/// Empty non-threaded mutex to avoid #ifdefs in consuming code
class VerilatedMutex {
class VerilatedMutex final {
public:
void lock() {}
void unlock() {}
};
/// Empty non-threaded lock guard to avoid #ifdefs in consuming code
class VerilatedLockGuard {
class VerilatedLockGuard final {
VL_UNCOPYABLE(VerilatedLockGuard);
public:
explicit VerilatedLockGuard(VerilatedMutex&) {}
~VerilatedLockGuard() {}
~VerilatedLockGuard() = default;
void lock() {}
void unlock() {}
};
@@ -194,7 +194,7 @@ public:
#endif // VL_THREADED
/// Remember the calling thread at construction time, and make sure later calls use same thread
class VerilatedAssertOneThread {
class VerilatedAssertOneThread final {
// MEMBERS
#if defined(VL_THREADED) && defined(VL_DEBUG)
vluint32_t m_threadid; /// Thread that is legal
@@ -230,7 +230,7 @@ public:
class VerilatedScope;
class VerilatedModule {
class VerilatedModule VL_NOT_FINAL {
VL_UNCOPYABLE(VerilatedModule);
private:
@@ -269,7 +269,8 @@ public:
#define VL_CELL(instname, type) ///< Declare a cell, ala SP_CELL
/// Declare a module, ala SC_MODULE
#define VL_MODULE(modname) class modname : public VerilatedModule
#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule
// Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical)
/// Constructor, ala SC_CTOR
#define VL_CTOR(modname) modname(const char* __VCname = "")
@@ -298,7 +299,7 @@ public:
//===========================================================================
/// Verilator symbol table base class
class VerilatedSyms {
class VerilatedSyms VL_NOT_FINAL {
public: // But for internal use only
#ifdef VL_THREADED
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
@@ -311,7 +312,7 @@ public: // But for internal use only
/// Verilator global class information class
/// This class is initialized by main thread only. Reading post-init is thread safe.
class VerilatedScope {
class VerilatedScope final {
public:
typedef enum : vluint8_t {
SCOPE_MODULE,
@@ -330,7 +331,7 @@ private:
Type m_type = SCOPE_OTHER; ///< Type of the scope
public: // But internals only - called from VerilatedModule's
VerilatedScope();
VerilatedScope() = default;
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
@@ -359,7 +360,7 @@ public: // But internals only - called from VerilatedModule's
Type type() const { return m_type; }
};
class VerilatedHierarchy {
class VerilatedHierarchy final {
public:
static void add(VerilatedScope* fromp, VerilatedScope* top);
};
@@ -367,10 +368,10 @@ public:
//===========================================================================
/// Verilator global static information class
class Verilated {
class Verilated final {
// MEMBERS
// Slow path variables
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
static VerilatedMutex s_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
static struct Serialized { // All these members serialized/deserialized
// Fast path
@@ -386,8 +387,9 @@ class Verilated {
int s_errorLimit; ///< Stop on error number
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
int s_randSeed; ///< Random seed: 0=random
int s_randSeedEpoch; ///< Number incrementing on each reseed, 0=illegal
Serialized();
~Serialized() {}
~Serialized() = default;
} s_s;
static struct NonSerialized { // Non-serialized information
@@ -407,8 +409,8 @@ class Verilated {
VerilatedMutex m_argMutex; ///< Mutex for s_args members, when VL_THREADED
int argc = 0;
const char** argv = nullptr;
CommandArgValues() {}
~CommandArgValues() {}
CommandArgValues() = default;
~CommandArgValues() = default;
} s_args;
// Not covered by mutex, as per-thread
@@ -422,8 +424,8 @@ class Verilated {
const char* t_dpiFilename = nullptr; ///< DPI context filename
int t_dpiLineno = 0; ///< DPI context line number
ThreadLocal();
~ThreadLocal();
ThreadLocal() = default;
~ThreadLocal() = default;
} t_s;
private:
@@ -442,6 +444,9 @@ public:
static int randReset() VL_MT_SAFE { return s_s.s_randReset; } ///< Return randReset value
static void randSeed(int val) VL_MT_SAFE;
static int randSeed() VL_MT_SAFE { return s_s.s_randSeed; } ///< Return randSeed value
static vluint32_t randSeedEpoch() VL_MT_SAFE { return s_s.s_randSeedEpoch; }
/// Random seed extended to 64 bits, and defaulted if user seed==0
static vluint64_t randSeedDefault64() VL_MT_SAFE;
/// Enable debug of internal verilated code
static void debug(int level) VL_MT_SAFE;
@@ -452,7 +457,7 @@ public:
static inline int debug() VL_MT_SAFE { return s_s.s_debug; }
#else
/// Return constant 0 debug level, so C++'s optimizer rips up
static inline int debug() VL_PURE { return 0; }
static constexpr int debug() VL_PURE { return 0; }
#endif
/// Enable calculation of unused signals
static void calcUnusedSigs(bool flag) VL_MT_SAFE;
@@ -567,8 +572,8 @@ public:
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
static int exportFuncNum(const char* namep) VL_MT_SAFE;
static size_t serialized1Size() VL_PURE { return sizeof(s_s); }
static void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only
static constexpr size_t serialized1Size() VL_PURE { return sizeof(s_s); }
static constexpr void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // For Serialize only
static size_t serialized2Size() VL_PURE;
static void* serialized2Ptr() VL_MT_UNSAFE;
#ifdef VL_THREADED
@@ -648,6 +653,7 @@ 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
extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE;
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
vluint64_t rnd = vl_rand64();
if (VL_LIKELY(hi > lo)) {
@@ -753,9 +759,9 @@ static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE {
u.q = lhs;
return u.fp;
}
/// Return QData from void*
static inline QData VL_CVT_VP_Q(void* fp) VL_PURE {
union { void* fp; QData q; } u;
/// Return QData from const void*
static inline QData VL_CVT_VP_Q(const void* fp) VL_PURE {
union { const void* fp; QData q; } u;
u.q = 0;
u.fp = fp;
return u.q;
+17 -16
View File
@@ -29,7 +29,7 @@
// VerilatedCovImpBase
/// Implementation base class for constants
struct VerilatedCovImpBase {
struct VerilatedCovImpBase VL_NOT_FINAL {
// TYPES
enum { MAX_KEYS = 33 }; /// Maximum user arguments + filename+lineno
enum { KEY_UNDEF = 0 }; /// Magic key # for unspecified values
@@ -39,7 +39,7 @@ struct VerilatedCovImpBase {
// VerilatedCovImpItem
/// Implementation class for a VerilatedCov item
class VerilatedCovImpItem : VerilatedCovImpBase {
class VerilatedCovImpItem VL_NOT_FINAL : VerilatedCovImpBase {
public: // But only local to this file
// MEMBERS
int m_keys[MAX_KEYS]; ///< Key
@@ -52,7 +52,7 @@ public: // But only local to this file
m_vals[i] = 0;
}
}
virtual ~VerilatedCovImpItem() {}
virtual ~VerilatedCovImpItem() = default;
virtual vluint64_t count() const = 0;
virtual void zero() const = 0;
};
@@ -63,7 +63,7 @@ public: // But only local to this file
/// This isn't in the header file for auto-magic conversion because it
/// inlines to too much code and makes compilation too slow.
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
template <class T> class VerilatedCoverItemSpec final : public VerilatedCovImpItem {
private:
// MEMBERS
T* m_countp; ///< Count value
@@ -78,7 +78,7 @@ public:
: m_countp{countp} {
*m_countp = 0;
}
virtual ~VerilatedCoverItemSpec() override {}
virtual ~VerilatedCoverItemSpec() override = default;
};
//=============================================================================
@@ -87,10 +87,10 @@ public:
/// All value and keys are indexed into a unique number. Thus we can greatly reduce
/// the storage requirements for otherwise identical keys.
class VerilatedCovImp : VerilatedCovImpBase {
class VerilatedCovImp final : VerilatedCovImpBase {
private:
// TYPES
typedef std::map<std::string, int> ValueIndexMap;
typedef std::map<const std::string, int> ValueIndexMap;
typedef std::map<int, std::string> IndexValueMap;
typedef std::deque<VerilatedCovImpItem*> ItemList;
@@ -99,13 +99,14 @@ private:
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
int m_nextIndex VL_GUARDED_BY(m_mutex) = (KEY_UNDEF + 1); ///< Next insert value
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() {}
VerilatedCovImp() = default;
VL_UNCOPYABLE(VerilatedCovImp);
public:
@@ -118,14 +119,13 @@ public:
private:
// PRIVATE METHODS
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
static int nextIndex = KEY_UNDEF + 1;
const auto iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++;
assert(nextIndex > 0); // Didn't rollover
m_valueIndexes.insert(std::make_pair(value, nextIndex));
m_indexValues.insert(std::make_pair(nextIndex, value));
return nextIndex;
m_nextIndex++;
assert(m_nextIndex > 0); // Didn't rollover
m_valueIndexes.insert(std::make_pair(value, m_nextIndex));
m_indexValues.insert(std::make_pair(m_nextIndex, value));
return m_nextIndex;
}
static std::string dequote(const std::string& text) VL_PURE {
// Quote any special characters
@@ -235,6 +235,7 @@ private:
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
m_nextIndex = KEY_UNDEF + 1;
}
public:
@@ -350,7 +351,7 @@ public:
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string, std::pair<std::string, vluint64_t>> EventMap;
typedef std::map<const std::string, std::pair<std::string, vluint64_t>> EventMap;
EventMap eventCounts;
for (const auto& itemp : m_items) {
std::string name;
@@ -399,7 +400,7 @@ public:
os << i.first;
if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first);
os << "' " << i.second.second;
os << std::endl;
os << '\n';
}
}
};
+1 -1
View File
@@ -88,7 +88,7 @@ template <class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
/// Global class with methods affecting all coverage data.
/// All public methods in this class are thread safe.
class VerilatedCov {
class VerilatedCov final {
VL_UNCOPYABLE(VerilatedCov);
public:
+1 -1
View File
@@ -102,7 +102,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
/// Verilator coverage global class.
/// This class is thread safe.
class VerilatedCovKey {
class VerilatedCovKey final {
public:
static std::string shortKey(const std::string& key) VL_PURE {
// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
+2 -2
View File
@@ -35,7 +35,7 @@
/// Base class to create a Verilator FST dump
/// This is an internally used class - see VerilatedFstC for what to call from applications
class VerilatedFst : public VerilatedTrace<VerilatedFst> {
class VerilatedFst final : public VerilatedTrace<VerilatedFst> {
private:
// Give the superclass access to private bits (to avoid virtual functions)
friend class VerilatedTrace<VerilatedFst>;
@@ -128,7 +128,7 @@ template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const std::st
/// Also derived for use in SystemC simulations.
/// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE
class VerilatedFstC {
class VerilatedFstC final {
VerilatedFst m_sptrace; ///< Trace file being created
// CONSTRUCTORS
+559 -142
View File
@@ -26,10 +26,13 @@
#include "verilated.h"
#include <algorithm>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
//===================================================================
// String formatters (required by below containers)
@@ -41,10 +44,21 @@ extern std::string VL_TO_STRING(QData lhs);
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
extern std::string VL_TO_STRING_W(int words, WDataInP obj);
//===================================================================
// Shuffle RNG
class VlURNG final {
public:
typedef size_t result_type;
static constexpr size_t min() { return 0; }
static constexpr size_t max() { return 1ULL << 31; }
size_t operator()() { return VL_MASK_I(31) & VL_RANDOM_I(32); }
};
//===================================================================
// Readmem/Writemem operation classes
class VlReadMem {
class VlReadMem final {
bool m_hex; // Hex format
int m_bits; // Bit width of values
const std::string& m_filename; // Filename
@@ -61,7 +75,7 @@ public:
void setData(void* valuep, const std::string& rhs);
};
class VlWriteMem {
class VlWriteMem final {
bool m_hex; // Hex format
int m_bits; // Bit width of values
FILE* m_fp; // File handle for filename
@@ -73,6 +87,363 @@ public:
void print(QData addr, bool addrstamp, const void* valuep);
};
//===================================================================
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue final {
private:
// TYPES
typedef std::deque<T_Value> Deque;
public:
typedef typename Deque::const_iterator const_iterator;
private:
// MEMBERS
Deque m_deque; // State of the assoc array
T_Value m_defaultValue; // Default value
public:
// CONSTRUCTORS
// m_defaultValue isn't defaulted. Caller's constructor must do it.
VlQueue() = default;
~VlQueue() = default;
VlQueue(const VlQueue&) = default;
VlQueue(VlQueue&&) = default;
VlQueue& operator=(const VlQueue&) = default;
VlQueue& operator=(VlQueue&&) = default;
// Standard copy constructor works. Verilog: assoca = assocb
// Also must allow conversion from a different T_MaxSize queue
template <size_t U_MaxSize = 0> VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
m_deque = rhs.privateDeque();
if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1);
return *this;
}
static VlQueue cons(const T_Value& lhs) {
VlQueue out;
out.push_back(lhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
VlQueue out;
out.push_back(rhs);
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
VlQueue out = lhs;
out.push_front(rhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
for (const auto& i : lhs.m_deque) out.push_back(i);
return out;
}
// METHODS
T_Value& atDefault() { return m_defaultValue; }
const T_Value& atDefault() const { return m_defaultValue; }
const Deque& privateDeque() const { return m_deque; }
// Size. Verilog: function int size(), or int num()
int size() const { return m_deque.size(); }
// Clear array. Verilog: function void delete([input index])
void clear() { m_deque.clear(); }
void erase(vlsint32_t index) {
if (VL_LIKELY(index >= 0 && index < m_deque.size()))
m_deque.erase(m_deque.begin() + index);
}
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
}
// function void q.push_back(value)
void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
}
// function value_t q.pop_front();
T_Value pop_front() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.front();
m_deque.pop_front();
return v;
}
// function value_t q.pop_back();
T_Value pop_back() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.back();
m_deque.pop_back();
return v;
}
// Setting. Verilog: assoc[index] = v
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(vlsint32_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(vlsint32_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault();
} else {
return m_deque[index];
}
}
// function void q.insert(index, value);
void insert(vlsint32_t index, const T_Value& value) {
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
m_deque.insert(m_deque.begin() + index, value);
}
// Return slice q[lsb:msb]
VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const {
VlQueue out;
if (VL_UNLIKELY(lsb < 0)) lsb = 0;
if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1;
if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1;
for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
return out;
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
const_iterator end() const { return m_deque.end(); }
// Methods
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
template <typename Func> void sort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) {
// index number is meaninless with sort, as it changes
return with_func(0, a) < with_func(0, b);
});
}
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
template <typename Func> void rsort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) {
// index number is meaninless with sort, as it changes
return with_func(0, a) < with_func(0, b);
});
}
void reverse() { std::reverse(m_deque.begin(), m_deque.end()); }
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); }
VlQueue unique() const {
VlQueue out;
std::unordered_set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(i);
}
}
return out;
}
VlQueue<IData> unique_index() const {
VlQueue<IData> out;
IData index = 0;
std::unordered_set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func> VlQueue find(Func with_func) const {
VlQueue out;
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) out.push_back(i);
++index;
}
return out;
}
template <typename Func> VlQueue<IData> find_index(Func with_func) const {
VlQueue<IData> out;
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) out.push_back(index);
++index;
}
return out;
}
template <typename Func> VlQueue find_first(Func with_func) const {
// Can't use std::find_if as need index number
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue::cons(i);
++index;
}
return VlQueue{};
}
template <typename Func> VlQueue<IData> find_first_index(Func with_func) const {
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
++index;
}
return VlQueue<IData>{};
}
template <typename Func> VlQueue find_last(Func with_func) const {
IData index = m_deque.size() - 1;
for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) {
if (with_func(index, *it)) return VlQueue::cons(*it);
--index;
}
return VlQueue{};
}
template <typename Func> VlQueue<IData> find_last_index(Func with_func) const {
IData index = m_deque.size() - 1;
for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) {
if (with_func(index, *it)) return VlQueue<IData>::cons(index);
--index;
}
return VlQueue<IData>{};
}
// Reduction operators
VlQueue min() const {
if (m_deque.empty()) return VlQueue();
const auto it = std::min_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
VlQueue max() const {
if (m_deque.empty()) return VlQueue();
const auto it = std::max_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out += i;
return out;
}
template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
IData index = 0;
for (const auto& i : m_deque) out += with_func(index++, i);
return out;
}
T_Value r_product() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{*it};
++it;
for (; it != m_deque.end(); ++it) out *= *it;
return out;
}
template <typename Func> T_Value r_product(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
IData index = 0;
T_Value out{with_func(index, *it)};
++it;
++index;
for (; it != m_deque.end(); ++it) out *= with_func(index++, *it);
return out;
}
T_Value r_and() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{*it};
++it;
for (; it != m_deque.end(); ++it) out &= *it;
return out;
}
template <typename Func> T_Value r_and(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
IData index = 0;
T_Value out{with_func(index, *it)};
++it;
++index;
for (; it != m_deque.end(); ++it) out &= with_func(index, *it);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out |= i;
return out;
}
template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
IData index = 0;
for (const auto& i : m_deque) out |= with_func(index++, i);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out ^= i;
return out;
}
template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
IData index = 0;
for (const auto& i : m_deque) out ^= with_func(index++, i);
return out;
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
if (m_deque.empty()) return "'{}"; // No trailing space
std::string out = "'{";
std::string comma;
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
}
};
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog array container
// Similar to std::array<WData, N>, but lighter weight, only methods needed
@@ -81,13 +452,18 @@ public:
// 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).
template <std::size_t T_Words> class VlWide {
template <std::size_t T_Words> class VlWide final {
WData m_storage[T_Words];
public:
// cppcheck-suppress uninitVar
VlWide() {}
~VlWide() {}
VlWide() = default;
~VlWide() = default;
VlWide(const VlWide&) = default;
VlWide(VlWide&&) = default;
VlWide& operator=(const VlWide&) = default;
VlWide& operator=(VlWide&&) = default;
// METHODS
const WData& at(size_t index) const { return m_storage[index]; }
WData& at(size_t index) { return m_storage[index]; }
WData* data() { return &m_storage[0]; }
@@ -112,7 +488,7 @@ template <std::size_t T_Words> std::string VL_TO_STRING(const VlWide<T_Words>& o
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
template <class T_Key, class T_Value> class VlAssocArray {
template <class T_Key, class T_Value> class VlAssocArray final {
private:
// TYPES
typedef std::map<T_Key, T_Value> Map;
@@ -127,14 +503,17 @@ private:
public:
// CONSTRUCTORS
VlAssocArray() {
// m_defaultValue isn't defaulted. Caller's constructor must do it.
}
~VlAssocArray() {}
// Standard copy constructor works. Verilog: assoca = assocb
// m_defaultValue isn't defaulted. Caller's constructor must do it.
VlAssocArray() = default;
~VlAssocArray() = default;
VlAssocArray(const VlAssocArray&) = default;
VlAssocArray(VlAssocArray&&) = default;
VlAssocArray& operator=(const VlAssocArray&) = default;
VlAssocArray& operator=(VlAssocArray&&) = default;
// METHODS
T_Value& atDefault() { return m_defaultValue; }
const T_Value& atDefault() const { return m_defaultValue; }
// Size of array. Verilog: function int size(), or int num()
int size() const { return m_map.size(); }
@@ -196,12 +575,176 @@ public:
return it->second;
}
}
// Setting as a chained operation
VlAssocArray& set(const T_Key& index, const T_Value& value) {
at(index) = value;
return *this;
}
VlAssocArray& setDefault(const T_Value& value) {
atDefault() = value;
return *this;
}
// For save/restore
const_iterator begin() const { return m_map.begin(); }
const_iterator end() const { return m_map.end(); }
// Methods
VlQueue<T_Value> unique() const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_map) {
auto it = saw.find(i.second);
if (it == saw.end()) {
saw.insert(it, i.second);
out.push_back(i.second);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
std::set<T_Key> saw;
for (const auto& i : m_map) {
auto it = saw.find(i.second);
if (it == saw.end()) {
saw.insert(it, i.second);
out.push_back(i.first);
}
}
return out;
}
template <typename Func> VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
for (const auto& i : m_map)
if (with_func(i.first, i.second)) out.push_back(i.second);
return out;
}
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> out;
for (const auto& i : m_map)
if (with_func(i.first, i.second)) out.push_back(i.first);
return out;
}
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
}
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.first, i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.first, i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
}
// Reduction operators
VlQueue<T_Value> min() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element(
m_map.begin(), m_map.end(),
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
m_map.begin(), m_map.end(),
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out += i.second;
return out;
}
template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out += with_func(i.first, i.second);
return out;
}
T_Value r_product() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{it->second};
++it;
for (; it != m_map.end(); ++it) out *= it->second;
return out;
}
template <typename Func> T_Value r_product(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{with_func(it->first, it->second)};
++it;
for (; it != m_map.end(); ++it) out *= with_func(it->first, it->second);
return out;
}
T_Value r_and() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{it->second};
++it;
for (; it != m_map.end(); ++it) out &= it->second;
return out;
}
template <typename Func> T_Value r_and(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{with_func(it->first, it->second)};
++it;
for (; it != m_map.end(); ++it) out &= with_func(it->first, it->second);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out |= i.second;
return out;
}
template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out |= with_func(i.first, i.second);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out ^= i.second;
return out;
}
template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
return out;
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
if (m_map.empty()) return "'{}"; // No trailing space
std::string out = "'{";
std::string comma;
for (const auto& i : m_map) {
@@ -245,133 +788,6 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
}
}
//===================================================================
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
private:
// TYPES
typedef std::deque<T_Value> Deque;
public:
typedef typename Deque::const_iterator const_iterator;
private:
// MEMBERS
Deque m_deque; // State of the assoc array
T_Value m_defaultValue; // Default value
public:
// CONSTRUCTORS
VlQueue() {
// m_defaultValue isn't defaulted. Caller's constructor must do it.
}
~VlQueue() {}
// Standard copy constructor works. Verilog: assoca = assocb
// METHODS
T_Value& atDefault() { return m_defaultValue; }
// Size. Verilog: function int size(), or int num()
int size() const { return m_deque.size(); }
// Clear array. Verilog: function void delete([input index])
void clear() { m_deque.clear(); }
void erase(size_t index) {
if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index);
}
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
}
// function void q.push_back(value)
void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
}
// function value_t q.pop_front();
T_Value pop_front() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.front();
m_deque.pop_front();
return v;
}
// function value_t q.pop_back();
T_Value pop_back() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.back();
m_deque.pop_back();
return v;
}
// Setting. Verilog: assoc[index] = v
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(size_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(size_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
return atDefault();
} else {
return m_deque[index];
}
}
// function void q.insert(index, value);
void insert(size_t index, const T_Value& value) {
if (VL_UNLIKELY(index >= m_deque.size())) return;
m_deque[index] = value;
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
const_iterator end() const { return m_deque.end(); }
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
std::string out = "'{";
std::string comma;
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
}
};
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog class reference container
// There are no multithreaded locks on this; the base variable must
@@ -396,6 +812,7 @@ inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw);
}
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE { return lhs; }
inline std::string& VL_CVT_PACK_STR_NN(std::string& lhs) VL_PURE { return lhs; }
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
WData lw[VL_WQ_WORDS_E];
VL_SET_WI(lw, lhs);
@@ -477,17 +894,17 @@ extern std::string VL_SUBSTR_N(const std::string& lhs, IData rhs, IData ths) VL_
inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool ignoreCase) VL_PURE {
// SystemVerilog does not allow a string variable to contain '\0'.
// So C functions such as strcmp() can correctly compare strings.
int result;
if (ignoreCase) {
result = VL_STRCASECMP(lhs.c_str(), rhs.c_str());
return VL_STRCASECMP(lhs.c_str(), rhs.c_str());
} else {
result = std::strcmp(lhs.c_str(), rhs.c_str());
return std::strcmp(lhs.c_str(), rhs.c_str());
}
return result;
}
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
extern IData VL_FGETS_NI(std::string& dest, IData fpi);
//======================================================================
// Dumping
+18 -14
View File
@@ -46,7 +46,7 @@ class VerilatedScope;
#ifdef VL_THREADED
/// Message, enqueued on an mtask, and consumed on the main eval thread
class VerilatedMsg {
class VerilatedMsg final {
public:
// TYPES
struct Cmp {
@@ -64,7 +64,11 @@ public:
VerilatedMsg(const std::function<void()>& cb)
: m_mtaskId{Verilated::mtaskId()}
, m_cb{cb} {}
~VerilatedMsg() {}
~VerilatedMsg() = default;
VerilatedMsg(const VerilatedMsg&) = default;
VerilatedMsg(VerilatedMsg&&) = default;
VerilatedMsg& operator=(const VerilatedMsg&) = default;
VerilatedMsg& operator=(VerilatedMsg&&) = default;
// METHODS
vluint32_t mtaskId() const { return m_mtaskId; }
/// Execute the lambda function
@@ -74,7 +78,7 @@ public:
/// Each thread has a queue it pushes to
/// This assumes no thread starts pushing the next tick until the previous has drained.
/// If more aggressiveness is needed, a double-buffered scheme might work well.
class VerilatedEvalMsgQueue {
class VerilatedEvalMsgQueue final {
typedef std::multiset<VerilatedMsg, VerilatedMsg::Cmp> VerilatedThreadQueue;
std::atomic<vluint64_t> m_depth; ///< Current depth of queue (see comments below)
@@ -87,7 +91,7 @@ public:
: m_depth{0} {
assert(atomic_is_lock_free(&m_depth));
}
~VerilatedEvalMsgQueue() {}
~VerilatedEvalMsgQueue() = default;
private:
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
@@ -126,7 +130,7 @@ public:
};
/// Each thread has a local queue to build up messages until the end of the eval() call
class VerilatedThreadMsgQueue {
class VerilatedThreadMsgQueue final {
std::queue<VerilatedMsg> m_queue;
public:
@@ -170,7 +174,7 @@ public:
#endif // VL_THREADED
// FILE* list constructed from a file-descriptor
class VerilatedFpList {
class VerilatedFpList final {
FILE* m_fp[31];
std::size_t m_sz = 0;
@@ -189,7 +193,7 @@ public:
//======================================================================
// VerilatedImp
class VerilatedImpData {
class VerilatedImpData final {
// Whole class is internal use only - Global information shared between verilated*.cpp files.
protected:
friend class Verilated;
@@ -207,8 +211,8 @@ protected:
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() {}
~Serialized() {}
Serialized() = default;
~Serialized() = default;
} m_ser;
VerilatedMutex m_sergMutex; ///< Protect m_ser
@@ -260,7 +264,7 @@ protected:
}
};
class VerilatedImp {
class VerilatedImp final {
// Whole class is internal use only - Global information shared between verilated*.cpp files.
protected:
friend class Verilated;
@@ -268,15 +272,15 @@ protected:
// MEMBERS
union VerilatedImpU { ///< Enclose in an union to call ctor/dtor manually
VerilatedImpData v;
VerilatedImpU() {}
~VerilatedImpU() {}
VerilatedImpU() {} // Can't be = default;
~VerilatedImpU() {} // Can't be = default;
};
static VerilatedImpU s_s; ///< Static Singleton; One and only static this
public: // But only for verilated*.cpp
// CONSTRUCTORS
VerilatedImp() {}
~VerilatedImp() {}
VerilatedImp() = default;
~VerilatedImp() = default;
static void setup();
static void teardown();
+10 -10
View File
@@ -28,7 +28,7 @@
// VerilatedSerialize - convert structures to a stream representation
// This class is not thread safe, it must be called by a single thread
class VerilatedSerialize {
class VerilatedSerialize VL_NOT_FINAL {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
@@ -38,8 +38,8 @@ protected:
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
inline static size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16 * 1024; }
static constexpr size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
static constexpr size_t bufferInsertSize() { return 16 * 1024; }
void header() VL_MT_UNSAFE_ONE;
void trailer() VL_MT_UNSAFE_ONE;
@@ -87,7 +87,7 @@ private:
// VerilatedDeserial - load structures from a stream representation
// This class is not thread safe, it must be called by a single thread
class VerilatedDeserialize {
class VerilatedDeserialize VL_NOT_FINAL {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
@@ -98,8 +98,8 @@ protected:
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
inline static size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16 * 1024; }
static constexpr size_t bufferSize() { return 256 * 1024; } // See below for slack calculation
static constexpr size_t bufferInsertSize() { return 16 * 1024; }
virtual void fill() = 0;
void header() VL_MT_UNSAFE_ONE;
@@ -154,13 +154,13 @@ private:
// VerilatedSave - serialize to a file
// This class is not thread safe, it must be called by a single thread
class VerilatedSave : public VerilatedSerialize {
class VerilatedSave final : public VerilatedSerialize {
private:
int m_fd = -1; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
VerilatedSave() {}
VerilatedSave() = default;
virtual ~VerilatedSave() override { close(); }
// METHODS
/// Open the file; call isOpen() to see if errors
@@ -174,13 +174,13 @@ public:
// VerilatedRestore - deserialize from a file
// This class is not thread safe, it must be called by a single thread
class VerilatedRestore : public VerilatedDeserialize {
class VerilatedRestore final : public VerilatedDeserialize {
private:
int m_fd = -1; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
VerilatedRestore() {}
VerilatedRestore() = default;
virtual ~VerilatedRestore() override { close(); }
// METHODS
+1 -1
View File
@@ -34,7 +34,7 @@
// This class is thread safe (though most of SystemC is not).
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
class VlScBvExposer : public sc_bv_base {
class VlScBvExposer final : public sc_bv_base {
public:
static const vluint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE {
return static_cast<const VlScBvExposer*>(&base)->sp_datatp();
+11 -13
View File
@@ -36,16 +36,14 @@
/// Thread safety: Assume is constructed only with model, then any number of readers
// See also V3Ast::VNumRange
class VerilatedRange {
int m_left;
int m_right;
class VerilatedRange final {
int m_left = 0;
int m_right = 0;
protected:
friend class VerilatedVarProps;
friend class VerilatedScope;
VerilatedRange()
: m_left{0}
, m_right{0} {}
VerilatedRange() = default;
VerilatedRange(int left, int right)
: m_left{left}
, m_right{right} {}
@@ -55,7 +53,7 @@ protected:
}
public:
~VerilatedRange() {}
~VerilatedRange() = default;
int left() const { return m_left; }
int right() const { return m_right; }
int low() const { return (m_left < m_right) ? m_left : m_right; }
@@ -70,7 +68,7 @@ public:
/// Verilator variable
/// Thread safety: Assume is constructed only with model, then any number of readers
class VerilatedVarProps {
class VerilatedVarProps VL_NOT_FINAL {
// TYPES
enum { MAGIC = 0xddc4f829 };
// MEMBERS
@@ -138,7 +136,7 @@ public:
}
public:
~VerilatedVarProps() {}
~VerilatedVarProps() = default;
// METHODS
bool magicOk() const { return m_magic == MAGIC; }
VerilatedVarType vltype() const { return m_vltype; }
@@ -189,7 +187,7 @@ public:
//===========================================================================
/// Verilator DPI open array variable
class VerilatedDpiOpenVar {
class VerilatedDpiOpenVar final {
// MEMBERS
const VerilatedVarProps* m_propsp; // Variable properties
void* m_datap; // Location of data (local to thread always, so safe)
@@ -201,7 +199,7 @@ public:
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap)
: m_propsp{propsp}
, m_datap{const_cast<void*>(datap)} {}
~VerilatedDpiOpenVar() {}
~VerilatedDpiOpenVar() = default;
// METHODS
void* datap() const { return m_datap; }
// METHODS - from VerilatedVarProps
@@ -227,7 +225,7 @@ public:
/// Verilator variable
/// Thread safety: Assume is constructed only with model, then any number of readers
class VerilatedVar : public VerilatedVarProps {
class VerilatedVar final : public VerilatedVarProps {
// MEMBERS
void* m_datap; // Location of data
const char* m_namep; // Name - slowpath
@@ -243,7 +241,7 @@ protected:
, m_isParam{isParam} {}
public:
~VerilatedVar() {}
~VerilatedVar() = default;
// ACCESSORS
void* datap() const { return m_datap; }
const VerilatedRange& range() const { return packed(); } // Deprecated
+11 -9
View File
@@ -31,6 +31,7 @@
#include "verilated_sym_props.h"
#include <map>
#include <unordered_map>
#include <vector>
//======================================================================
@@ -42,26 +43,27 @@ struct VerilatedCStrCmp {
};
/// Map of sorted scope names to find associated scope class
class VerilatedScopeNameMap
class VerilatedScopeNameMap final
: public std::map<const char*, const VerilatedScope*, VerilatedCStrCmp> {
public:
VerilatedScopeNameMap() {}
~VerilatedScopeNameMap() {}
VerilatedScopeNameMap() = default;
~VerilatedScopeNameMap() = default;
};
/// Map of sorted variable names to find associated variable class
class VerilatedVarNameMap : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
class VerilatedVarNameMap final : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
public:
VerilatedVarNameMap() {}
~VerilatedVarNameMap() {}
VerilatedVarNameMap() = default;
~VerilatedVarNameMap() = default;
};
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
class VerilatedHierarchyMap : public std::map<const VerilatedScope*, VerilatedScopeVector> {
class VerilatedHierarchyMap final
: public std::unordered_map<const VerilatedScope*, VerilatedScopeVector> {
public:
VerilatedHierarchyMap() {}
~VerilatedHierarchyMap() {}
VerilatedHierarchyMap() = default;
~VerilatedHierarchyMap() = default;
};
#endif // Guard
+2 -4
View File
@@ -98,10 +98,8 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling)
}
VlThreadPool::~VlThreadPool() {
for (int i = 0; i < m_workers.size(); ++i) {
// Each ~WorkerThread will wait for its thread to exit.
delete m_workers[i];
}
// Each ~WorkerThread will wait for its thread to exit.
for (auto& i : m_workers) delete i;
if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread();
}
+6 -6
View File
@@ -52,7 +52,7 @@ typedef void* VlThrSymTab;
typedef void (*VlExecFnp)(bool, VlThrSymTab);
/// Track dependencies for a single MTask.
class VlMTaskVertex {
class VlMTaskVertex final {
// MEMBERS
static std::atomic<vluint64_t> s_yields; // Statistics
@@ -82,7 +82,7 @@ public:
// that must notify this MTaskVertex before it will become ready
// to run.
explicit VlMTaskVertex(vluint32_t upstreamDepCount);
~VlMTaskVertex() {}
~VlMTaskVertex() = default;
static vluint64_t yields() { return s_yields; }
static void yieldThread() {
@@ -124,7 +124,7 @@ public:
};
// Profiling support
class VlProfileRec {
class VlProfileRec final {
protected:
friend class VlThreadPool;
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
@@ -136,7 +136,7 @@ protected:
unsigned m_cpu; // Execution CPU number (at start anyways)
public:
class Barrier {};
VlProfileRec() {}
VlProfileRec() = default;
explicit VlProfileRec(Barrier) { m_cpu = getcpu(); }
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
m_type = VlProfileRec::TYPE_MTASK_RUN;
@@ -168,7 +168,7 @@ public:
class VlThreadPool;
class VlWorkerThread {
class VlWorkerThread final {
private:
// TYPES
struct ExecRec {
@@ -247,7 +247,7 @@ public:
static void startWorker(VlWorkerThread* workerp);
};
class VlThreadPool {
class VlThreadPool final {
// TYPES
typedef std::vector<VlProfileRec> ProfileTrace;
typedef std::set<ProfileTrace*> ProfileSet;
+3 -3
View File
@@ -40,7 +40,7 @@
// Threaded tracing
// A simple synchronized first in first out queue
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
template <class T> class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug
private:
VerilatedMutex m_mutex; // Protects m_queue
std::condition_variable_any m_cv;
@@ -83,7 +83,7 @@ public:
// Commands used by thread tracing. Anonymous enum in class, as we want
// it scoped, but we also want the automatic conversion to integer types.
class VerilatedTraceCommand {
class VerilatedTraceCommand final {
public:
// These must all fit in 4 bit at the moment, as the tracing routines
// pack parameters in the top bits.
@@ -110,7 +110,7 @@ public:
// VerilatedTrace uses F-bounded polymorphism to access duck-typed
// implementations in the format specific derived class, which must be passed
// as the type parameter T_Derived
template <class T_Derived> class VerilatedTrace {
template <class T_Derived> class VerilatedTrace VL_NOT_FINAL {
public:
//=========================================================================
// Generic tracing internals
+7 -4
View File
@@ -19,6 +19,7 @@
// clang-format off
#ifndef VL_CPPCHECK
#ifndef VL_DERIVED_T
# error "This file should be included in trace format implementations"
#endif
@@ -558,7 +559,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, doub
// All of these take a destination pointer where the string will be emitted,
// and a value to convert. There are a couple of variants for efficiency.
inline static void cvtCDataToStr(char* dstp, CData value) {
static inline void cvtCDataToStr(char* dstp, CData value) {
#ifdef VL_HAVE_SSE2
// Similar to cvtSDataToStr but only the bottom 8 byte lanes are used
const __m128i a = _mm_cvtsi32_si128(value);
@@ -580,7 +581,7 @@ inline static void cvtCDataToStr(char* dstp, CData value) {
#endif
}
inline static void cvtSDataToStr(char* dstp, SData value) {
static inline void cvtSDataToStr(char* dstp, SData value) {
#ifdef VL_HAVE_SSE2
// We want each bit in the 16-bit input value to end up in a byte lane
// within the 128-bit XMM register. Note that x86 is little-endian and we
@@ -616,7 +617,7 @@ inline static void cvtSDataToStr(char* dstp, SData value) {
#endif
}
inline static void cvtIDataToStr(char* dstp, IData value) {
static inline void cvtIDataToStr(char* dstp, IData value) {
#ifdef VL_HAVE_AVX2
// Similar to cvtSDataToStr but the bottom 16-bits are processed in the
// top half of the YMM registerss
@@ -635,9 +636,11 @@ inline static void cvtIDataToStr(char* dstp, IData value) {
#endif
}
inline static void cvtQDataToStr(char* dstp, QData value) {
static inline void cvtQDataToStr(char* dstp, QData value) {
cvtIDataToStr(dstp, value >> 32);
cvtIDataToStr(dstp + 32, value);
}
#define cvtEDataToStr cvtIDataToStr
#endif // VL_CPPCHECK
+6 -6
View File
@@ -34,13 +34,13 @@ class VerilatedVcd;
// VerilatedFile
/// File handling routines, which can be overrode for e.g. socket I/O
class VerilatedVcdFile {
class VerilatedVcdFile final {
private:
int m_fd = 0; ///< File descriptor we're writing to
public:
// METHODS
VerilatedVcdFile() {}
virtual ~VerilatedVcdFile() {}
VerilatedVcdFile() = default;
virtual ~VerilatedVcdFile() = default;
virtual bool open(const std::string& name) VL_MT_UNSAFE;
virtual void close() VL_MT_UNSAFE;
virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
@@ -51,7 +51,7 @@ public:
/// Base class to create a Verilator VCD dump
/// This is an internally used class - see VerilatedVcdC for what to call from applications
class VerilatedVcd : public VerilatedTrace<VerilatedVcd> {
class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace<VerilatedVcd> {
private:
// Give the superclass access to private bits (to avoid virtual functions)
friend class VerilatedTrace<VerilatedVcd>;
@@ -76,7 +76,7 @@ private:
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
const char* m_suffixesp; ///< Pointer to first element of above
typedef std::map<std::string, std::string> NameMap;
typedef std::map<const std::string, const std::string> NameMap;
NameMap* m_namemapp = nullptr; ///< List of names for the header
void bufferResize(vluint64_t minsize);
@@ -329,7 +329,7 @@ template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::st
/// Also derived for use in SystemC simulations.
/// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE
class VerilatedVcdC {
class VerilatedVcdC VL_NOT_FINAL {
VerilatedVcd m_sptrace; ///< Trace file being created
// CONSTRUCTORS
+1 -1
View File
@@ -31,7 +31,7 @@
/// This class is passed to the SystemC simulation kernel, just like a
/// documented SystemC trace format.
class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC {
class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedVcdSc);
+166 -157
View File
@@ -55,15 +55,15 @@ constexpr unsigned VL_VPI_LINE_SIZE = 8192;
// Implementation
// Base VPI handled object
class VerilatedVpio {
class VerilatedVpio VL_NOT_FINAL {
// MEM MANGLEMENT
static VL_THREAD_LOCAL vluint8_t* t_freeHead;
public:
// CONSTRUCTORS
VerilatedVpio() {}
virtual ~VerilatedVpio() {}
inline static void* operator new(size_t size) VL_MT_SAFE {
VerilatedVpio() = default;
virtual ~VerilatedVpio() = default;
static void* operator new(size_t size) VL_MT_SAFE {
// We new and delete tons of vpi structures, so keep them around
// To simplify our free list, we use a size large enough for all derived types
// We reserve word zero for the next pointer, as that's safer in case a
@@ -79,13 +79,13 @@ public:
vluint8_t* newp = reinterpret_cast<vluint8_t*>(::operator new(chunk + 8));
return newp + 8;
}
inline static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE {
static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE {
vluint8_t* oldp = (static_cast<vluint8_t*>(obj)) - 8;
*(reinterpret_cast<void**>(oldp)) = t_freeHead;
t_freeHead = oldp;
}
// MEMBERS
static inline VerilatedVpio* castp(vpiHandle h) {
static VerilatedVpio* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h));
}
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
@@ -96,12 +96,12 @@ public:
virtual vluint32_t type() const { return 0; }
virtual vluint32_t size() const { return 0; }
virtual const VerilatedRange* rangep() const { return nullptr; }
virtual vpiHandle dovpi_scan() { return 0; }
virtual vpiHandle dovpi_scan() { return nullptr; }
};
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*);
class VerilatedVpioCb : public VerilatedVpio {
class VerilatedVpioCb final : public VerilatedVpio {
t_cb_data m_cbData;
s_vpi_value m_value;
QData m_time;
@@ -114,8 +114,8 @@ public:
m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal;
m_cbData.value = &m_value;
}
virtual ~VerilatedVpioCb() override {}
static inline VerilatedVpioCb* castp(vpiHandle h) {
virtual ~VerilatedVpioCb() override = default;
static VerilatedVpioCb* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioCb*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiCallback; }
@@ -125,21 +125,21 @@ public:
QData time() const { return m_time; }
};
class VerilatedVpioConst : public VerilatedVpio {
class VerilatedVpioConst final : public VerilatedVpio {
vlsint32_t m_num;
public:
explicit VerilatedVpioConst(vlsint32_t num)
: m_num{num} {}
virtual ~VerilatedVpioConst() override {}
static inline VerilatedVpioConst* castp(vpiHandle h) {
virtual ~VerilatedVpioConst() override = default;
static VerilatedVpioConst* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiConstant; }
vlsint32_t num() const { return m_num; }
};
class VerilatedVpioParam : public VerilatedVpio {
class VerilatedVpioParam final : public VerilatedVpio {
const VerilatedVar* m_varp;
const VerilatedScope* m_scopep;
@@ -148,9 +148,9 @@ public:
: m_varp{varp}
, m_scopep{scopep} {}
virtual ~VerilatedVpioParam() override {}
virtual ~VerilatedVpioParam() override = default;
static inline VerilatedVpioParam* castp(vpiHandle h) {
static VerilatedVpioParam* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioParam*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiParameter; }
@@ -159,21 +159,21 @@ public:
const VerilatedScope* scopep() const { return m_scopep; }
virtual const char* name() const override { return m_varp->name(); }
virtual const char* fullname() const override {
static VL_THREAD_LOCAL std::string out;
out = std::string(m_scopep->name()) + "." + name();
return out.c_str();
static VL_THREAD_LOCAL std::string t_out;
t_out = std::string(m_scopep->name()) + "." + name();
return t_out.c_str();
}
};
class VerilatedVpioRange : public VerilatedVpio {
class VerilatedVpioRange final : public VerilatedVpio {
const VerilatedRange* m_range;
vlsint32_t m_iteration = 0;
public:
explicit VerilatedVpioRange(const VerilatedRange* range)
: m_range{range} {}
virtual ~VerilatedVpioRange() override {}
static inline VerilatedVpioRange* castp(vpiHandle h) {
virtual ~VerilatedVpioRange() override = default;
static VerilatedVpioRange* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioRange*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiRange; }
@@ -187,19 +187,19 @@ public:
nextp->iterationInc();
return ((nextp)->castVpiHandle());
}
return 0; // End of list - only one deep
return nullptr; // End of list - only one deep
}
};
class VerilatedVpioScope : public VerilatedVpio {
class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio {
protected:
const VerilatedScope* m_scopep;
public:
explicit VerilatedVpioScope(const VerilatedScope* scopep)
: m_scopep{scopep} {}
virtual ~VerilatedVpioScope() override {}
static inline VerilatedVpioScope* castp(vpiHandle h) {
virtual ~VerilatedVpioScope() override = default;
static VerilatedVpioScope* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioScope*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiScope; }
@@ -208,10 +208,10 @@ public:
virtual const char* fullname() const override { return m_scopep->name(); }
};
class VerilatedVpioVar : public VerilatedVpio {
class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpio {
const VerilatedVar* m_varp;
const VerilatedScope* m_scopep;
vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange
vluint8_t* m_prevDatap = nullptr; // Previous value of data, for cbValueChange
union {
vluint8_t u8[4];
vluint32_t u32;
@@ -219,7 +219,7 @@ class VerilatedVpioVar : public VerilatedVpio {
vluint32_t m_entSize; // memoized variable size
protected:
void* m_varDatap; // varp()->datap() adjusted for array entries
vlsint32_t m_index;
vlsint32_t m_index = 0;
const VerilatedRange& get_range() const {
// Determine number of dimensions and return outermost
return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed();
@@ -228,9 +228,7 @@ protected:
public:
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
: m_varp{varp}
, m_scopep{scopep}
, m_index{0} {
m_prevDatap = nullptr;
, m_scopep{scopep} {
m_mask.u32 = VL_MASK_I(varp->packed().elements());
m_entSize = varp->entSize();
m_varDatap = varp->datap();
@@ -238,7 +236,7 @@ public:
virtual ~VerilatedVpioVar() override {
if (m_prevDatap) VL_DO_CLEAR(delete[] m_prevDatap, m_prevDatap = nullptr);
}
static inline VerilatedVpioVar* castp(vpiHandle h) {
static VerilatedVpioVar* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioVar*>(reinterpret_cast<VerilatedVpio*>(h));
}
const VerilatedVar* varp() const { return m_varp; }
@@ -254,9 +252,9 @@ public:
virtual const VerilatedRange* rangep() const override { return &get_range(); }
virtual const char* name() const override { return m_varp->name(); }
virtual const char* fullname() const override {
static VL_THREAD_LOCAL std::string out;
out = std::string(m_scopep->name()) + "." + name();
return out.c_str();
static VL_THREAD_LOCAL std::string t_out;
t_out = std::string(m_scopep->name()) + "." + name();
return t_out.c_str();
}
void* prevDatap() const { return m_prevDatap; }
void* varDatap() const { return m_varDatap; }
@@ -268,7 +266,7 @@ public:
}
};
class VerilatedVpioMemoryWord : public VerilatedVpioVar {
class VerilatedVpioMemoryWord final : public VerilatedVpioVar {
public:
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep,
vlsint32_t index, int offset)
@@ -276,23 +274,23 @@ public:
m_index = index;
m_varDatap = (static_cast<vluint8_t*>(varp->datap())) + entSize() * offset;
}
virtual ~VerilatedVpioMemoryWord() override {}
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) {
virtual ~VerilatedVpioMemoryWord() override = default;
static VerilatedVpioMemoryWord* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioMemoryWord*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiMemoryWord; }
virtual vluint32_t size() const override { return varp()->packed().elements(); }
virtual const VerilatedRange* rangep() const override { return &(varp()->packed()); }
virtual const char* fullname() const override {
static VL_THREAD_LOCAL std::string out;
static VL_THREAD_LOCAL std::string t_out;
char num[20];
sprintf(num, "%d", m_index);
out = std::string(scopep()->name()) + "." + name() + "[" + num + "]";
return out.c_str();
t_out = std::string(scopep()->name()) + "." + name() + "[" + num + "]";
return t_out.c_str();
}
};
class VerilatedVpioVarIter : public VerilatedVpio {
class VerilatedVpioVarIter final : public VerilatedVpio {
const VerilatedScope* m_scopep;
VerilatedVarNameMap::const_iterator m_it;
bool m_started = false;
@@ -300,8 +298,8 @@ class VerilatedVpioVarIter : public VerilatedVpio {
public:
explicit VerilatedVpioVarIter(const VerilatedScope* scopep)
: m_scopep{scopep} {}
virtual ~VerilatedVpioVarIter() override {}
static inline VerilatedVpioVarIter* castp(vpiHandle h) {
virtual ~VerilatedVpioVarIter() override = default;
static VerilatedVpioVarIter* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioVarIter*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiIterator; }
@@ -312,18 +310,18 @@ public:
m_it = varsp->begin();
m_started = true;
} else if (VL_UNLIKELY(m_it == varsp->end())) {
return 0;
return nullptr;
} else {
++m_it;
}
if (m_it == varsp->end()) return 0;
if (m_it == varsp->end()) return nullptr;
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle());
}
return 0; // End of list - only one deep
return nullptr; // End of list - only one deep
}
};
class VerilatedVpioMemoryWordIter : public VerilatedVpio {
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
const vpiHandle m_handle;
const VerilatedVar* m_varp;
vlsint32_t m_iteration;
@@ -336,8 +334,8 @@ public:
, m_varp{varp}
, m_iteration{varp->unpacked().right()}
, m_direction{VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) ? 1 : -1} {}
virtual ~VerilatedVpioMemoryWordIter() override {}
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
virtual ~VerilatedVpioMemoryWordIter() override = default;
static VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioMemoryWordIter*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiIterator; }
@@ -346,14 +344,14 @@ public:
}
virtual vpiHandle dovpi_scan() override {
vpiHandle result;
if (m_done) return 0;
if (m_done) return nullptr;
result = vpi_handle_by_index(m_handle, m_iteration);
iterationInc();
return result;
}
};
class VerilatedVpioModule : public VerilatedVpioScope {
class VerilatedVpioModule final : public VerilatedVpioScope {
const char* m_name;
const char* m_fullname;
@@ -364,7 +362,7 @@ public:
if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4;
m_name = m_scopep->identifier();
}
static inline VerilatedVpioModule* castp(vpiHandle h) {
static VerilatedVpioModule* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioModule*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiModule; }
@@ -372,7 +370,7 @@ public:
virtual const char* fullname() const override { return m_fullname; }
};
class VerilatedVpioModuleIter : public VerilatedVpio {
class VerilatedVpioModuleIter final : public VerilatedVpio {
const std::vector<const VerilatedScope*>* m_vec;
std::vector<const VerilatedScope*>::const_iterator m_it;
@@ -381,13 +379,13 @@ public:
: m_vec{&vec} {
m_it = m_vec->begin();
}
virtual ~VerilatedVpioModuleIter() override {}
static inline VerilatedVpioModuleIter* castp(vpiHandle h) {
virtual ~VerilatedVpioModuleIter() override = default;
static VerilatedVpioModuleIter* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioModuleIter*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const override { return vpiIterator; }
virtual vpiHandle dovpi_scan() override {
if (m_it == m_vec->end()) return 0;
if (m_it == m_vec->end()) return nullptr;
const VerilatedScope* modp = *m_it++;
return (new VerilatedVpioModule(modp))->castVpiHandle();
}
@@ -407,15 +405,11 @@ struct VerilatedVpiTimedCbsCmp {
class VerilatedVpiError;
class VerilatedVpiImp {
class VerilatedVpiImp final {
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maxium callback reason
typedef std::list<VerilatedVpioCb*> VpioCbList;
typedef std::set<std::pair<QData, VerilatedVpioCb*>, VerilatedVpiTimedCbsCmp> VpioTimedCbs;
struct product_info {
PLI_BYTE8* product;
};
VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
VpioTimedCbs m_timedCbs; // Time based callbacks
VerilatedVpiError* m_errorInfop = nullptr; // Container for vpi error info
@@ -424,8 +418,8 @@ class VerilatedVpiImp {
static VerilatedVpiImp s_s; // Singleton
public:
VerilatedVpiImp() {}
~VerilatedVpiImp() {}
VerilatedVpiImp() = default;
~VerilatedVpiImp() = default;
static void assertOneCheck() { s_s.m_assertOne.check(); }
static void cbReasonAdd(VerilatedVpioCb* vop) {
if (vop->reason() == cbValueChange) {
@@ -477,26 +471,38 @@ public:
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
bool called = false;
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
if (cbObjList.empty()) return called;
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); true;) {
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
bool was_last = it == last;
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
if (was_last) break;
continue;
}
VerilatedVpioCb* vop = *it++;
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback %d %p\n", reason, vop););
(vop->cb_rtnp())(vop->cb_datap());
called = true;
if (was_last) break;
}
return called;
}
static void callValueCbs() VL_MT_UNSAFE_ONE {
static bool callValueCbs() VL_MT_UNSAFE_ONE {
assertOneCheck();
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
typedef std::set<VerilatedVpioVar*> VpioVarSet;
bool called = false;
typedef std::unordered_set<VerilatedVpioVar*> VpioVarSet;
VpioVarSet update; // set of objects to update after callbacks
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
if (cbObjList.empty()) return called;
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); true;) {
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
bool was_last = it == last;
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
if (was_last) break;
continue;
}
VerilatedVpioCb* vop = *it++;
@@ -512,16 +518,19 @@ public:
update.insert(varop);
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
(vop->cb_rtnp())(vop->cb_datap());
called = true;
}
}
if (was_last) break;
}
for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); }
return called;
}
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
};
class VerilatedVpiError {
class VerilatedVpiError final {
//// Container for vpi error info
t_vpi_error_info m_errorInfo;
@@ -550,7 +559,7 @@ public:
m_buff[0] = '\0';
m_errorInfo.product = const_cast<PLI_BYTE8*>(Verilated::productName());
}
~VerilatedVpiError() {}
~VerilatedVpiError() = default;
static void selfTest() VL_MT_UNSAFE_ONE;
VerilatedVpiError* setMessage(PLI_INT32 level) {
m_flag = true;
@@ -559,14 +568,14 @@ public:
}
void setMessage(const std::string& file, PLI_INT32 line, const char* message, ...) {
// message cannot be a const string& as va_start cannot use a reference
static VL_THREAD_LOCAL std::string filehold;
static VL_THREAD_LOCAL std::string t_filehold;
va_list args;
va_start(args, message);
VL_VSNPRINTF(m_buff, sizeof(m_buff), message, args);
va_end(args);
m_errorInfo.state = vpiPLI;
filehold = file;
setError((PLI_BYTE8*)m_buff, nullptr, const_cast<PLI_BYTE8*>(filehold.c_str()), line);
t_filehold = file;
setError((PLI_BYTE8*)m_buff, nullptr, const_cast<PLI_BYTE8*>(t_filehold.c_str()), line);
}
p_vpi_error_info getError() {
if (m_flag) return &m_errorInfo;
@@ -599,7 +608,7 @@ VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = nullptr;
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); }
void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callValueCbs(); }
bool VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callValueCbs(); }
bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
return VerilatedVpiImp::callCbs(reason);
@@ -1048,10 +1057,10 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
}
}
PLI_INT32 vpi_remove_cb(vpiHandle object) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", object););
PLI_INT32 vpi_remove_cb(vpiHandle cb_obj) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", cb_obj););
VerilatedVpiImp::assertOneCheck();
VerilatedVpioCb* vop = VerilatedVpioCb::castp(object);
VerilatedVpioCb* vop = VerilatedVpioCb::castp(cb_obj);
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!vop)) return 0;
if (vop->cb_datap()->reason == cbAfterDelay) {
@@ -1065,7 +1074,7 @@ PLI_INT32 vpi_remove_cb(vpiHandle object) {
void vpi_get_cb_info(vpiHandle /*object*/, p_cb_data /*cb_data_p*/) { _VL_VPI_UNIMP(); }
vpiHandle vpi_register_systf(p_vpi_systf_data /*systf_data_p*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/) {
_VL_VPI_UNIMP();
@@ -1131,24 +1140,24 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
_VL_VPI_ERROR_RESET();
if (VL_LIKELY(varop)) {
if (varop->varp()->dims() < 2) return 0;
if (varop->varp()->dims() < 2) return nullptr;
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|| indx < varop->varp()->unpacked().right()))
return 0;
return nullptr;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->unpacked().right()))
->castVpiHandle();
}
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|| indx > varop->varp()->unpacked().right()))
return 0;
return nullptr;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->unpacked().left()))
->castVpiHandle();
}
_VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC);
return 0;
return nullptr;
}
// for traversing relationships
@@ -1160,56 +1169,56 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
switch (type) {
case vpiLeftRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
case vpiRightRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
case vpiIndex: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
}
case vpiScope: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
}
case vpiParent: {
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
}
vpiHandle vpi_handle_multi(PLI_INT32 /*type*/, vpiHandle /*refHandle1*/, vpiHandle /*refHandle2*/,
...) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
@@ -1219,8 +1228,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
switch (type) {
case vpiMemoryWord: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
if (vop->varp()->dims() < 2) return nullptr;
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC,
@@ -1231,8 +1240,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
}
case vpiRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
if (vop->varp()->dims() < 2) return nullptr;
// Unsupported is multidim list
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__,
@@ -1244,7 +1253,7 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
}
case vpiReg: {
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle());
}
case vpiModule: {
@@ -1252,13 +1261,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
const VerilatedScope* mod = vop ? vop->scopep() : nullptr;
const auto it = vlstd::as_const(map)->find(const_cast<VerilatedScope*>(mod));
if (it == map->end()) return 0;
if (it == map->end()) return nullptr;
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
return 0;
return nullptr;
}
}
vpiHandle vpi_scan(vpiHandle object) {
@@ -1342,7 +1351,7 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
return 0;
return nullptr;
}
}
@@ -1410,34 +1419,34 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
const char* fullname) {
if (!vl_check_format(varp, valuep, fullname, true)) return;
// Maximum required size is for binary string, one byte per bit plus null termination
static VL_THREAD_LOCAL char outStr[1 + VL_MULS_MAX_WORDS * 32];
static VL_THREAD_LOCAL char t_outStr[1 + VL_MULS_MAX_WORDS * 32];
// cppcheck-suppress variableScope
static VL_THREAD_LOCAL int outStrSz = sizeof(outStr) - 1;
static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
// This may cause backward compatibility issues with older code.
if (valuep->format == vpiVectorVal) {
// Vector pointer must come from our memory pool
// It only needs to persist until the next vpi_get_value
static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS * 2];
valuep->value.vector = out;
static VL_THREAD_LOCAL t_vpi_vecval t_out[VL_MULS_MAX_WORDS * 2];
valuep->value.vector = t_out;
if (varp->vltype() == VLVT_UINT8) {
out[0].aval = *(reinterpret_cast<CData*>(varDatap));
out[0].bval = 0;
t_out[0].aval = *(reinterpret_cast<CData*>(varDatap));
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT16) {
out[0].aval = *(reinterpret_cast<SData*>(varDatap));
out[0].bval = 0;
t_out[0].aval = *(reinterpret_cast<SData*>(varDatap));
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT32) {
out[0].aval = *(reinterpret_cast<IData*>(varDatap));
out[0].bval = 0;
t_out[0].aval = *(reinterpret_cast<IData*>(varDatap));
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT64) {
QData data = *(reinterpret_cast<QData*>(varDatap));
out[1].aval = static_cast<IData>(data >> 32ULL);
out[1].bval = 0;
out[0].aval = static_cast<IData>(data);
out[0].bval = 0;
t_out[1].aval = static_cast<IData>(data >> 32ULL);
t_out[1].bval = 0;
t_out[0].aval = static_cast<IData>(data);
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_WDATA) {
int words = VL_WORDS_I(varp->packed().elements());
@@ -1448,47 +1457,47 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
}
WDataInP datap = (reinterpret_cast<EData*>(varDatap));
for (int i = 0; i < words; ++i) {
out[i].aval = datap[i];
out[i].bval = 0;
t_out[i].aval = datap[i];
t_out[i].bval = 0;
}
return;
}
} else if (valuep->format == vpiBinStrVal) {
valuep->value.str = outStr;
valuep->value.str = t_outStr;
int bits = varp->packed().elements();
CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (bits > outStrSz) {
if (bits > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
bits = outStrSz;
bits = t_outStrSz;
_VL_VPI_WARNING(
__FILE__, __LINE__,
"%s: Truncating string value of %s for %s"
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
VL_MULS_MAX_WORDS, bits);
}
for (i = 0; i < bits; ++i) {
char val = (datap[i >> 3] >> (i & 7)) & 1;
outStr[bits - i - 1] = val ? '1' : '0';
t_outStr[bits - i - 1] = val ? '1' : '0';
}
outStr[i] = '\0';
t_outStr[i] = '\0';
return;
} else if (valuep->format == vpiOctStrVal) {
valuep->value.str = outStr;
valuep->value.str = t_outStr;
int chars = (varp->packed().elements() + 2) / 3;
int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (chars > outStrSz) {
if (chars > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
_VL_VPI_WARNING(
__FILE__, __LINE__,
"%s: Truncating string value of %s for %s"
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
VL_MULS_MAX_WORDS, chars);
chars = outStrSz;
chars = t_outStrSz;
}
for (i = 0; i < chars; ++i) {
div_t idx = div(i * 3, 8);
@@ -1509,44 +1518,44 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
val &= (1 << rem) - 1;
}
}
outStr[chars - i - 1] = '0' + (val & 7);
t_outStr[chars - i - 1] = '0' + (val & 7);
}
outStr[i] = '\0';
t_outStr[i] = '\0';
return;
} else if (valuep->format == vpiDecStrVal) {
valuep->value.str = outStr;
valuep->value.str = t_outStr;
// outStrSz does not include nullptr termination so add one
if (varp->vltype() == VLVT_UINT8) {
VL_SNPRINTF(outStr, outStrSz + 1, "%hhu",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hhu",
static_cast<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
return;
} else if (varp->vltype() == VLVT_UINT16) {
VL_SNPRINTF(outStr, outStrSz + 1, "%hu",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hu",
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
return;
} else if (varp->vltype() == VLVT_UINT32) {
VL_SNPRINTF(outStr, outStrSz + 1, "%u",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%u",
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
return;
} else if (varp->vltype() == VLVT_UINT64) {
VL_SNPRINTF(outStr, outStrSz + 1, "%llu",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%llu",
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
return;
}
} else if (valuep->format == vpiHexStrVal) {
valuep->value.str = outStr;
valuep->value.str = t_outStr;
int chars = (varp->packed().elements() + 3) >> 2;
CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (chars > outStrSz) {
if (chars > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
_VL_VPI_WARNING(
__FILE__, __LINE__,
"%s: Truncating string value of %s for %s"
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
VL_MULS_MAX_WORDS, chars);
chars = outStrSz;
chars = t_outStrSz;
}
for (i = 0; i < chars; ++i) {
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
@@ -1559,35 +1568,35 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
val &= (1 << rem) - 1;
}
}
outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
t_outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
}
outStr[i] = '\0';
t_outStr[i] = '\0';
return;
} else if (valuep->format == vpiStringVal) {
if (varp->vltype() == VLVT_STRING) {
valuep->value.str = reinterpret_cast<char*>(varDatap);
return;
} else {
valuep->value.str = outStr;
valuep->value.str = t_outStr;
int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (bytes > outStrSz) {
if (bytes > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
_VL_VPI_WARNING(
__FILE__, __LINE__,
"%s: Truncating string value of %s for %s"
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz,
VL_MULS_MAX_WORDS, bytes);
bytes = outStrSz;
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname,
t_outStrSz, VL_MULS_MAX_WORDS, bytes);
bytes = t_outStrSz;
}
for (i = 0; i < bytes; ++i) {
char val = datap[bytes - i - 1];
// other simulators replace [leading?] zero chars with spaces, replicate here.
outStr[i] = val ? val : ' ';
t_outStr[i] = val ? val : ' ';
}
outStr[i] = '\0';
t_outStr[i] = '\0';
return;
}
} else if (valuep->format == vpiIntVal) {
@@ -1639,7 +1648,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!valuep)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
return 0;
return nullptr;
}
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
VL_DEBUG_IF_PLI(
@@ -1652,9 +1661,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
"Ignoring vpi_put_value to signal marked read-only,"
" use public_flat_rw instead: %s",
vop->fullname());
return 0;
return nullptr;
}
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return 0;
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr;
if (valuep->format == vpiVectorVal) {
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
if (vop->varp()->vltype() == VLVT_UINT8) {
@@ -1755,7 +1764,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
VL_FUNC, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
return 0;
return nullptr;
}
if (success > 1) {
_VL_VPI_WARNING(__FILE__, __LINE__,
@@ -1844,11 +1853,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s",
VL_FUNC, vop->fullname());
return 0;
return nullptr;
} else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s",
VL_FUNC, vop->fullname());
return 0;
return nullptr;
}
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
return nullptr;
@@ -1910,7 +1919,7 @@ PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) {
@@ -2020,7 +2029,7 @@ PLI_INT32 vpi_put_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*num
}
void* vpi_get_userdata(vpiHandle /*obj*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
PLI_INT32 vpi_put_userdata(vpiHandle /*obj*/, void* /*userdata*/) {
_VL_VPI_UNIMP();
@@ -2051,5 +2060,5 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
PLI_INT32* /*index_array*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
+2 -2
View File
@@ -33,14 +33,14 @@
//======================================================================
class VerilatedVpi {
class VerilatedVpi final {
public:
/// Call timed callbacks
/// Users should call this from their main loops
static void callTimedCbs() VL_MT_UNSAFE_ONE;
/// Call value based callbacks
/// Users should call this from their main loops
static void callValueCbs() VL_MT_UNSAFE_ONE;
static bool callValueCbs() VL_MT_UNSAFE_ONE;
/// Call callbacks of arbitrary types
/// Users can call this from their application code
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE;
+4 -1
View File
@@ -374,7 +374,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//=========================================================================
// Class definition helpers
// Used to declare a class as uncopyable; put after a private:
/// Used to indicate a base class, e.g. cannot label "class final"
#define VL_NOT_FINAL
/// Used to declare a class as uncopyable; put after a private:
#define VL_UNCOPYABLE(Type) \
Type(const Type& other) = delete; \
Type& operator=(const Type&) = delete
+32 -32
View File
@@ -83,28 +83,28 @@ sub test {
require "./nodist/code_coverage.dat";
if ($Opt_Stages{1}) {
travis_fold_start("configure");
ci_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();
ci_fold_end();
}
if ($Opt_Stages{2}) {
travis_fold_start("build");
ci_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();
ci_fold_end();
}
if ($Opt_Stages{3}) {
travis_fold_start("test");
ci_fold_start("test");
print "Stage 3: make tests (with coverage on)\n";
if ($#Opt_Tests < 0) {
run("make examples VERILATOR_NO_OPT_BUILD=1")
@@ -121,12 +121,12 @@ sub test {
run($test);
}
}
travis_fold_end();
ci_fold_end();
}
my $cc_dir = "nodist/obj_dir/coverage";
if ($Opt_Stages{4}) {
travis_fold_start("gcno");
ci_fold_start("gcno");
print "Stage 4: Create gcno files under $cc_dir\n";
mkpath($cc_dir);
mkpath("$cc_dir/info");
@@ -165,11 +165,11 @@ sub test {
}
}
}
travis_fold_end();
ci_fold_end();
}
if ($Opt_Stages{5} && $Opt_Fastcov) {
travis_fold_start("fastcov");
ci_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".
@@ -178,11 +178,11 @@ sub test {
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();
ci_fold_end();
}
if ($Opt_Stages{5} && !$Opt_Fastcov) {
travis_fold_start("infos");
ci_fold_start("infos");
print "Stage 5: make infos\n";
my $dats = `find . -print | grep .gcda`;
my %dirs;
@@ -199,20 +199,20 @@ sub test {
})->run;
}
$Fork->wait_all;
travis_fold_end();
ci_fold_end();
}
if ($Opt_Stages{6}) {
travis_fold_start("clone");
ci_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();
ci_fold_end();
}
if ($Opt_Stages{8} && !$Opt_Fastcov) {
travis_fold_start("copy");
ci_fold_start("copy");
print "Stage 8: Copy .gcno files\n";
my $dats = `find . -print | grep .gcno`;
foreach my $dat (sort (split '\n', $dats)) {
@@ -221,11 +221,11 @@ sub test {
#print "cp $dat, $outdat);\n";
cp($dat, $outdat);
}
travis_fold_end();
ci_fold_end();
}
if ($Opt_Stages{10} && !$Opt_Fastcov) {
travis_fold_start("combine");
ci_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");
@@ -243,11 +243,11 @@ sub test {
}
}
}
travis_fold_end();
ci_fold_end();
}
if ($Opt_Stages{11}) {
travis_fold_start("dirs");
ci_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");
@@ -255,11 +255,11 @@ sub test {
} else {
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
}
travis_fold_end();
ci_fold_end();
}
if ($Opt_Stages{12}) {
travis_fold_start("filter");
ci_fold_start("filter");
print "Stage 12: Filter processed source files\n";
my $inc = '';
foreach my $glob (@Source_Globs) {
@@ -282,24 +282,24 @@ sub test {
} else {
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
}
travis_fold_end();
ci_fold_end();
}
if ($Opt_Stages{17}) {
travis_fold_start("report");
ci_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();
ci_fold_end();
}
if ($Opt_Stages{18}) {
travis_fold_start("upload");
ci_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();
ci_fold_end();
}
if ($Opt_Stages{19}) {
@@ -425,13 +425,13 @@ 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";
our $_Ci_Action;
sub ci_fold_start {
$_Ci_Action = shift;
print "travis_fold:start:$_Ci_Action\n";
}
sub travis_fold_end {
print "travis_fold:end:$_Travis_Action\n";
sub ci_fold_end {
print "travis_fold:end:$_Ci_Action\n";
}
#######################################################################
+1
View File
@@ -57,6 +57,7 @@ exclude_line_regexp(qr/(\bv3fatalSrc\b
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\)
|\bassert\(
|\bBROKEN_RTK\(
|\bSELF_CHECK)/x);
1;
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add axiom-athdl`;
exec('atsim',@ARGV);
exec('atsim', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_atsim - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_atsim {ncv arguments}
invoke_atsim {arguments}
=head1 DESCRIPTION
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add cds-ius`;
exec('iccr',@ARGV);
exec('iccr', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_iccr - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_iccr {ncv arguments}
invoke_iccr {arguments}
=head1 DESCRIPTION
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add cds-ius/latest`;
exec('ncverilog',@ARGV);
exec('ncverilog', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_ncverilog - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_ncverilog {ncv arguments}
invoke_ncverilog {arguments}
=head1 DESCRIPTION
+2 -2
View File
@@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add synopsys-sim/latest`;
exec('vcs',@ARGV);
exec('vcs', @ARGV);
#######################################################################
__END__
@@ -22,7 +22,7 @@ invoke_vcs - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_vcs {ncv arguments}
invoke_vcs {arguments}
=head1 DESCRIPTION
+3 -3
View File
@@ -7,21 +7,21 @@
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
define pn
call $arg0->dumpGdb()
call AstNode::dumpGdb($arg0)
end
document pn
Verilator: Print single AstNode NODEP
end
define pnt
call $arg0->dumpTreeGdb()
call AstNode::dumpTreeGdb($arg0)
end
document pnt
Verilator: Print AstNode NODEP's tree
end
define dtf
call AstNode::dumpTreeFileGdb(0)
call AstNode::dumpTreeFileGdb($arg0, 0)
end
document dtf
Verilator: Dump AstNode tree to file
-1
View File
@@ -94,7 +94,6 @@ LIBS = $(CFG_LIBS) -lm
CPPFLAGS += -MMD
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
CPPFLAGS += -DYYDEBUG # Required to get nice error messages
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
CPPFLAGS += $(COPT)
CPPFLAGS += -MP # Only works on recent GCC versions
+16 -8
View File
@@ -43,12 +43,12 @@
//######################################################################
// Collect existing active names
class ActiveBaseVisitor : public AstNVisitor {
class ActiveBaseVisitor VL_NOT_FINAL : public AstNVisitor {
protected:
VL_DEBUG_FUNC; // Declare debug()
};
class ActiveNamer : public ActiveBaseVisitor {
class ActiveNamer final : public ActiveBaseVisitor {
private:
// STATE
AstScope* m_scopep = nullptr; // Current scope to add statement to
@@ -130,15 +130,15 @@ public:
}
// CONSTRUCTORS
ActiveNamer() {}
virtual ~ActiveNamer() override {}
ActiveNamer() = default;
virtual ~ActiveNamer() override = default;
void main(AstScope* nodep) { iterate(nodep); }
};
//######################################################################
// Active AssignDly replacement functions
class ActiveDlyVisitor : public ActiveBaseVisitor {
class ActiveDlyVisitor final : public ActiveBaseVisitor {
public:
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
@@ -205,13 +205,13 @@ public:
, m_alwaysp{nodep} {
iterate(nodep);
}
virtual ~ActiveDlyVisitor() override {}
virtual ~ActiveDlyVisitor() override = default;
};
//######################################################################
// Active class functions
class ActiveVisitor : public ActiveBaseVisitor {
class ActiveVisitor final : public ActiveBaseVisitor {
private:
// NODE STATE
// Each call to V3Const::constify
@@ -364,6 +364,14 @@ private:
}
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
}
virtual void visit(AstAlwaysPostponed* nodep) override {
UINFO(4, " ALW " << nodep << endl);
if (!nodep->bodysp()) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS);
}
virtual void visit(AstAlwaysPublic* nodep) override {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALWPub " << nodep << endl);
@@ -406,7 +414,7 @@ private:
public:
// CONSTRUCTORS
explicit ActiveVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ActiveVisitor() override {}
virtual ~ActiveVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Active {
class V3Active final {
public:
static void activeAll(AstNetlist* nodep);
};
+2 -2
View File
@@ -35,7 +35,7 @@
//######################################################################
// Active class functions
class ActiveTopVisitor : public AstNVisitor {
class ActiveTopVisitor final : public AstNVisitor {
private:
// NODE STATE
// Entire netlist
@@ -128,7 +128,7 @@ private:
public:
// CONSTRUCTORS
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ActiveTopVisitor() override {}
virtual ~ActiveTopVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3ActiveTop {
class V3ActiveTop final {
public:
static void activeTopAll(AstNetlist* nodep);
};
+76 -6
View File
@@ -26,7 +26,7 @@
//######################################################################
// Assert class functions
class AssertVisitor : public AstNVisitor {
class AssertVisitor final : public AstNVisitor {
private:
// NODE STATE/TYPES
// Cleared on netlist
@@ -36,7 +36,11 @@ private:
// STATE
AstNodeModule* m_modp = nullptr; // Last module
AstBegin* m_beginp = nullptr; // Last begin
unsigned m_monitorNum = 0; // Global $monitor numbering (not per module)
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
unsigned m_modPastNum = 0; // Module past numbering
unsigned m_modStrobeNum = 0; // Module $strobe numbering
VDouble0 m_statCover; // Statistic tracking
VDouble0 m_statAsNotImm; // Statistic tracking
VDouble0 m_statAsImm; // Statistic tracking
@@ -62,7 +66,26 @@ private:
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
}
}
AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) {
if (!m_monitorNumVarp) {
m_monitorNumVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP,
"__VmonitorNum", nodep->findUInt64DType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorNumVarp);
}
const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
return varrefp;
}
AstVarRef* newMonitorOffVarRefp(AstNode* nodep, VAccess access) {
if (!m_monitorOffVarp) {
m_monitorOffVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP,
"__VmonitorOff", nodep->findBitDType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorOffVarp);
}
const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
return varrefp;
}
AstNode* newIfAssertOn(AstNode* nodep) {
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
@@ -73,7 +96,7 @@ private:
// This allows syntax errors and such to be detected normally.
(v3Global.opt.assertOn()
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
: static_cast<AstNode*>(new AstConst(fl, AstConst::BitFalse()))),
nodep, nullptr);
newp->user1(true); // Don't assert/cover this if
return newp;
@@ -207,7 +230,7 @@ private:
bool allow_none = nodep->unique0Pragma();
// Empty case means no property
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
@@ -276,7 +299,7 @@ private:
}
}
// Empty case means no property
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
bool allow_none = has_default || nodep->unique0Pragma();
AstNode* ohot
@@ -342,9 +365,54 @@ private:
} else if (nodep->displayType() == AstDisplayType::DT_ERROR
|| nodep->displayType() == AstDisplayType::DT_FATAL) {
replaceDisplay(nodep, "%%Error");
} else if (nodep->displayType() == AstDisplayType::DT_MONITOR) {
nodep->displayType(AstDisplayType::DT_DISPLAY);
const auto fl = nodep->fileline();
const auto monNum = ++m_monitorNum;
// Where $monitor was we do "__VmonitorNum = N;"
const auto newsetp = new AstAssign{fl, newMonitorNumVarRefp(nodep, VAccess::WRITE),
new AstConst{fl, monNum}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);"
AstNode* stmtsp = nodep;
AstIf* ifp = new AstIf{
fl,
new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)},
new AstEq{fl, new AstConst{fl, monNum},
newMonitorNumVarRefp(nodep, VAccess::READ)}},
stmtsp, nullptr};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
m_modp->addStmtp(newp);
} else if (nodep->displayType() == AstDisplayType::DT_STROBE) {
nodep->displayType(AstDisplayType::DT_DISPLAY);
// Need one-shot
const auto fl = nodep->fileline();
const auto varp
= new AstVar{fl, AstVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++),
nodep->findBitDType()};
m_modp->addStmtp(varp);
// Where $strobe was we do "__Vstrobe = '1;"
const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitTrue{}}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
AstNode* stmtsp = nodep;
AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitFalse{}}});
m_modp->addStmtp(newp);
}
}
virtual void visit(AstMonitorOff* nodep) override {
const auto newp
= new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off()));
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstAssert* nodep) override {
iterateChildren(nodep);
newPslAssertion(nodep, nodep->failsp());
@@ -362,9 +430,11 @@ private:
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
VL_RESTORER(m_modPastNum);
VL_RESTORER(m_modStrobeNum);
{
m_modp = nodep;
m_modPastNum = 0;
m_modStrobeNum = 0;
iterateChildren(nodep);
}
}
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Assert {
class V3Assert final {
public:
static void assertAll(AstNetlist* nodep);
};
+6 -6
View File
@@ -26,7 +26,7 @@
//######################################################################
// Assert class functions
class AssertPreVisitor : public AstNVisitor {
class AssertPreVisitor final : public AstNVisitor {
// Removes clocks and other pre-optimizations
// Eventually inlines calls to sequences, properties, etc.
// We're not parsing the tree, or anything more complicated.
@@ -103,7 +103,7 @@ private:
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
exprp->dtypeSetLogicBool();
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@@ -122,7 +122,7 @@ private:
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
exprp->dtypeSetLogicBool();
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@@ -135,7 +135,7 @@ private:
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstEq(fl, past, exprp->cloneTree(false));
exprp->dtypeSetLogicBool();
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@@ -153,7 +153,7 @@ private:
AstNode* past = new AstPast(fl, lhsp, nullptr);
past->dtypeFrom(lhsp);
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
exprp->dtypeSetLogicBool();
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@@ -197,7 +197,7 @@ public:
// Process
iterate(nodep);
}
virtual ~AssertPreVisitor() override {}
virtual ~AssertPreVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3AssertPre {
class V3AssertPre final {
public:
static void assertPreAll(AstNetlist* nodep);
};
+49 -28
View File
@@ -127,8 +127,9 @@ string AstNode::encodeName(const string& namein) {
}
// Shorten names
// TODO long term use VName in place of "string name"
VName vname(out);
out = vname.hashedName();
// Then we also won't need to save the table of hased values
VName vname{out};
return vname.hashedName();
return out;
}
@@ -161,7 +162,8 @@ string AstNode::dedotName(const string& namein) {
string AstNode::vcdName(const string& namein) {
// VCD tracing expects space to separate hierarchy
// Dots are reserved for dots the user put in the name
string pretty = namein;
// We earlier hashed all symbols, dehash them so user sees real name
string pretty{VName::dehash(namein)};
string::size_type pos;
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " ");
while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " ");
@@ -394,6 +396,7 @@ void AstNode::setOp4p(AstNode* newp) {
void AstNode::addOp1p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp1p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op1p) {
op1p(newp);
} else {
@@ -403,6 +406,7 @@ void AstNode::addOp1p(AstNode* newp) {
void AstNode::addOp2p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp2p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op2p) {
op2p(newp);
} else {
@@ -412,6 +416,7 @@ void AstNode::addOp2p(AstNode* newp) {
void AstNode::addOp3p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp3p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op3p) {
op3p(newp);
} else {
@@ -421,6 +426,7 @@ void AstNode::addOp3p(AstNode* newp) {
void AstNode::addOp4p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp4p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op4p) {
op4p(newp);
} else {
@@ -1023,28 +1029,40 @@ void AstNode::checkTree() {
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
void AstNode::dumpGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_LINE
if (!nodep) {
cout << "<nullptr>" << endl;
return;
}
nodep->dumpGdbHeader();
cout << " ";
dump(cout);
cout << endl; // LCOV_EXCL_LINE
}
nodep->dump(cout);
cout << endl;
} // LCOV_EXCL_STOP
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
dumpPtrs(cout); // LCOV_EXCL_LINE
cout << " Fileline = " << fileline() << endl; // LCOV_EXCL_LINE
}
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_START
dumpPtrs(cout);
cout << " Fileline = " << fileline() << endl;
} // LCOV_EXCL_STOP
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
dumpTree(cout); // LCOV_EXCL_LINE
}
void AstNode::dumpTreeGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_START
if (!nodep) {
cout << "<nullptr>" << endl;
return;
}
nodep->dumpGdbHeader();
nodep->dumpTree(cout);
} // LCOV_EXCL_STOP
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
string filename
= filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
}
void AstNode::dumpTreeFileGdb(const AstNode* nodep, // LCOV_EXCL_START
const char* filenamep) { // For GDB only
if (!nodep) {
cout << "<nullptr>" << endl;
return;
}
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98);
v3Global.rootp()->dumpTreeFile(filename);
} // LCOV_EXCL_STOP
// cppcheck-suppress unusedFunction // Debug only
void AstNode::checkIter() const {
@@ -1082,14 +1100,14 @@ void AstNode::dumpPtrs(std::ostream& os) const {
void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const {
static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9
os << indent << " " << this << endl;
os << indent << " " << this << '\n';
if (debug() > 8) {
os << indent << " ";
dumpPtrs(os);
}
if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); }
if (maxDepth == 1) {
if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; }
if (op1p() || op2p() || op3p() || op4p()) os << indent << "1: ...(maxDepth)\n";
} else {
for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) {
nodep->dumpTree(os, indent + "1:", maxDepth - 1);
@@ -1113,7 +1131,7 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
}
}
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, bool doCheck) {
// Not const function as calls checkTree
if (doDump) {
{ // Write log & close
@@ -1121,9 +1139,9 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
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;
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) {
*logsp << endl;
*logsp << '\n';
*logsp << "No changes since last dump!\n";
} else {
dumpTree(*logsp);
@@ -1131,7 +1149,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
}
}
}
if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) {
if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
@@ -1193,7 +1211,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
std::ostringstream nsstr;
nsstr << str.str();
if (debug()) {
nsstr << endl;
nsstr << '\n';
nsstr << "-node: ";
const_cast<AstNode*>(this)->dump(nsstr);
nsstr << endl;
@@ -1261,6 +1279,9 @@ AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
AstNodeDType* AstNode::findQueueIndexDType() const {
return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline());
}
//######################################################################
// AstNVisitor
+181 -144
View File
@@ -71,7 +71,7 @@ typedef std::set<int> MTaskIdSet; // Set of mtaskIds for Var sorting
//######################################################################
class AstType {
class AstType final {
public:
#include "V3Ast__gen_types.h" // From ./astgen
// Above include has:
@@ -94,7 +94,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return o
//######################################################################
class VLifetime {
class VLifetime final {
public:
enum en : uint8_t { NONE, AUTOMATIC, STATIC };
enum en m_e;
@@ -123,12 +123,24 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
//######################################################################
class VAccess {
class VAccess final {
public:
enum en : uint8_t { READ, WRITE };
enum en : uint8_t {
READ, // Read/Consumed, variable not changed
WRITE, // Written/Updated, variable might be updated, but not consumed
// // so variable might be removable if not consumed elsewhere
READWRITE, // Read/Consumed and written/updated, variable both set and
// // also consumed, cannot remove usage of variable.
// // For non-simple data types only e.g. no tristates/delayed vars.
NOCHANGE // No change to previous state, used only in V3LinkLValue
};
enum en m_e;
const char* ascii() const {
static const char* const names[] = {"RD", "WR"};
static const char* const names[] = {"RD", "WR", "RW", "--"};
return names[m_e];
}
const char* arrow() const {
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
return names[m_e];
}
inline VAccess()
@@ -139,9 +151,13 @@ public:
explicit inline VAccess(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
VAccess invert() const { return (m_e == WRITE) ? VAccess(READ) : VAccess(WRITE); }
bool isRead() const { return m_e == READ; }
bool isWrite() const { return m_e == WRITE; }
VAccess invert() const {
return (m_e == READWRITE) ? VAccess(m_e) : (m_e == WRITE ? VAccess(READ) : VAccess(WRITE));
}
bool isReadOnly() const { return m_e == READ; } // False with READWRITE
bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; }
bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; }
bool isRW() const { return m_e == READWRITE; } // False with READWRITE
};
inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; }
@@ -150,7 +166,7 @@ inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return o
//######################################################################
class VSigning {
class VSigning final {
public:
enum en : uint8_t {
UNSIGNED,
@@ -187,7 +203,7 @@ inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) {
//######################################################################
class AstPragmaType {
class AstPragmaType final {
public:
enum en : uint8_t {
ILLEGAL,
@@ -220,7 +236,7 @@ inline bool operator==(AstPragmaType::en lhs, const AstPragmaType& rhs) { return
//######################################################################
class AstCFuncType {
class AstCFuncType final {
public:
enum en : uint8_t {
FT_NORMAL,
@@ -253,7 +269,7 @@ inline bool operator==(AstCFuncType::en lhs, const AstCFuncType& rhs) { return l
//######################################################################
class VEdgeType {
class VEdgeType final {
public:
// REMEMBER to edit the strings below too
enum en : uint8_t {
@@ -339,7 +355,7 @@ inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs ==
//######################################################################
class AstAttrType {
class AstAttrType final {
public:
// clang-format off
enum en: uint8_t {
@@ -420,7 +436,7 @@ inline bool operator==(AstAttrType::en lhs, const AstAttrType& rhs) { return lhs
//######################################################################
class AstBasicDTypeKwd {
class AstBasicDTypeKwd final {
public:
enum en : uint8_t {
UNKNOWN,
@@ -434,7 +450,6 @@ public:
LONGINT,
DOUBLE,
SHORTINT,
FLOAT,
TIME,
// Closer to a class type, but limited usage
STRING,
@@ -452,18 +467,16 @@ public:
enum en m_e;
const char* ascii() const {
static const char* const names[] = {
"%E-unk", //
"bit", "byte", "chandle", "event", "int", "integer", "logic",
"longint", "real", "shortint", "shortreal", "time", "string", "VerilatedScope*",
"char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"};
"%E-unk", "bit", "byte", "chandle", "event", "int", "integer",
"logic", "longint", "real", "shortint", "time", "string", "VerilatedScope*",
"char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"};
return names[m_e];
}
const char* dpiType() const {
static const char* const names[]
= {"%E-unk", //
"svBit", "char", "void*", "char", "int", "%E-integer",
"svLogic", "long long", "double", "short", "float", "%E-time",
"const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit",
= {"%E-unk", "svBit", "char", "void*", "char", "int",
"%E-integer", "svLogic", "long long", "double", "short", "%E-time",
"const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit",
" MAX"};
return names[m_e];
}
@@ -492,7 +505,6 @@ public:
case LOGIC: return 1; // scalar, can't bit extract unless ranged
case LONGINT: return 64;
case DOUBLE: return 64; // opaque
case FLOAT: return 32; // opaque
case SHORTINT: return 16;
case TIME: return 64;
case STRING: return 64; // opaque // Just the pointer, for today
@@ -505,7 +517,7 @@ public:
}
bool isSigned() const {
return m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER
|| m_e == DOUBLE || m_e == FLOAT;
|| m_e == DOUBLE;
}
bool isUnsigned() const {
return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR
@@ -516,8 +528,7 @@ public:
}
bool isZeroInit() const { // Otherwise initializes to X
return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENTVALUE || m_e == INT
|| m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE
|| m_e == FLOAT);
|| m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE);
}
bool isIntNumeric() const { // Enum increment supported
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
@@ -537,8 +548,7 @@ public:
|| m_e == DOUBLE || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
}
bool isOpaque() const { // IE not a simple number we can bit optimize
return (m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == DOUBLE
|| m_e == FLOAT);
return (m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == DOUBLE);
}
bool isDouble() const { return m_e == DOUBLE; }
bool isEventValue() const { return m_e == EVENTVALUE; }
@@ -556,7 +566,7 @@ inline bool operator==(AstBasicDTypeKwd::en lhs, const AstBasicDTypeKwd& rhs) {
//######################################################################
class VDirection {
class VDirection final {
public:
enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF };
enum en m_e;
@@ -601,7 +611,7 @@ inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) {
//######################################################################
/// Boolean or unknown
class VBoolOrUnknown {
class VBoolOrUnknown final {
public:
enum en : uint8_t { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END };
enum en m_e;
@@ -640,7 +650,7 @@ inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) {
//######################################################################
/// Join type
class VJoinType {
class VJoinType final {
public:
enum en : uint8_t { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 };
enum en m_e;
@@ -673,7 +683,7 @@ inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) {
//######################################################################
class AstVarType {
class AstVarType final {
public:
enum en : uint8_t {
UNKNOWN,
@@ -741,7 +751,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) {
//######################################################################
class VBranchPred {
class VBranchPred final {
public:
enum en : uint8_t { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END };
enum en m_e;
@@ -782,7 +792,7 @@ inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
//######################################################################
class VVarAttrClocker {
class VVarAttrClocker final {
public:
enum en : uint8_t { CLOCKER_UNKNOWN = 0, CLOCKER_YES, CLOCKER_NO, _ENUM_END };
enum en m_e;
@@ -825,7 +835,7 @@ inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) {
//######################################################################
class VAlwaysKwd {
class VAlwaysKwd final {
public:
enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB };
enum en m_e;
@@ -848,7 +858,7 @@ inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs =
//######################################################################
class VCaseType {
class VCaseType final {
public:
enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE };
enum en m_e;
@@ -867,14 +877,23 @@ inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs ==
//######################################################################
class AstDisplayType {
class AstDisplayType final {
public:
enum en : uint8_t { DT_DISPLAY, DT_WRITE, DT_INFO, DT_ERROR, DT_WARNING, DT_FATAL };
enum en : uint8_t {
DT_DISPLAY,
DT_WRITE,
DT_MONITOR,
DT_STROBE,
DT_INFO,
DT_ERROR,
DT_WARNING,
DT_FATAL
};
enum en m_e;
inline AstDisplayType()
AstDisplayType()
: m_e{DT_DISPLAY} {}
// cppcheck-suppress noExplicitConstructor
inline AstDisplayType(en _e)
AstDisplayType(en _e)
: m_e{_e} {}
explicit inline AstDisplayType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
@@ -883,7 +902,7 @@ public:
bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; }
const char* ascii() const {
static const char* const names[]
= {"display", "write", "info", "error", "warning", "fatal"};
= {"display", "write", "monitor", "strobe", "info", "error", "warning", "fatal"};
return names[m_e];
}
};
@@ -899,7 +918,7 @@ inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) {
//######################################################################
class VDumpCtlType {
class VDumpCtlType final {
public:
enum en : uint8_t { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON };
enum en m_e;
@@ -925,7 +944,7 @@ inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return l
//######################################################################
class VParseRefExp {
class VParseRefExp final {
public:
enum en : uint8_t {
PX_NONE, // Used in V3LinkParse only
@@ -959,10 +978,10 @@ inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) {
// VNumRange - Structure containing numeric range information
// See also AstRange, which is a symbolic version of this
class VNumRange {
class VNumRange final {
public:
int m_hi; // HI part, HI always >= LO
int m_lo; // LO
int m_hi = 0; // HI part, HI always >= LO
int m_lo = 0; // LO
union {
int mu_flags;
struct {
@@ -970,10 +989,10 @@ public:
bool m_littleEndian : 1; // Bit vector is little endian
};
};
inline bool operator==(const VNumRange& rhs) const {
bool operator==(const VNumRange& rhs) const {
return m_hi == rhs.m_hi && m_lo == rhs.m_lo && mu_flags == rhs.mu_flags;
}
inline bool operator<(const VNumRange& rhs) const {
bool operator<(const VNumRange& rhs) const {
if ((m_hi < rhs.m_hi)) return true;
if (!(m_hi == rhs.m_hi)) return false; // lhs > rhs
if ((m_lo < rhs.m_lo)) return true;
@@ -985,22 +1004,16 @@ public:
//
class LeftRight {};
VNumRange()
: m_hi{0}
, m_lo{0}
, mu_flags{0} {}
: mu_flags{0} {}
VNumRange(int hi, int lo, bool littleEndian)
: m_hi{0}
, m_lo{0}
, mu_flags{0} {
: mu_flags{0} {
init(hi, lo, littleEndian);
}
VNumRange(LeftRight, int left, int right)
: m_hi{0}
, m_lo{0}
, mu_flags{0} {
: mu_flags{0} {
init((right > left) ? right : left, (right > left) ? left : right, (right > left));
}
~VNumRange() {}
~VNumRange() = default;
// MEMBERS
void init(int hi, int lo, bool littleEndian) {
m_hi = hi;
@@ -1038,7 +1051,7 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) {
//######################################################################
class VUseType {
class VUseType final {
public:
enum en : uint8_t {
IMP_INCLUDE, // Implementation (.cpp) needs an include
@@ -1071,18 +1084,18 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
//######################################################################
class VBasicTypeKey {
class VBasicTypeKey final {
public:
int m_width; // From AstNodeDType: Bit width of operation
int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
VSigning m_numeric; // From AstNodeDType: Node is signed
AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
inline bool operator==(const VBasicTypeKey& rhs) const {
bool operator==(const VBasicTypeKey& rhs) const {
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
}
inline bool operator<(const VBasicTypeKey& rhs) const {
bool operator<(const VBasicTypeKey& rhs) const {
if ((m_width < rhs.m_width)) return true;
if (!(m_width == rhs.m_width)) return false; // lhs > rhs
if ((m_widthMin < rhs.m_widthMin)) return true;
@@ -1102,7 +1115,7 @@ public:
, m_numeric{numeric}
, m_keyword{kwd}
, m_nrange{nrange} {}
~VBasicTypeKey() {}
~VBasicTypeKey() = default;
};
//######################################################################
@@ -1113,7 +1126,7 @@ class WidthVP;
class V3GraphVertex;
class VSymEnt;
class VNUser {
class VNUser final {
union {
void* up;
int ui;
@@ -1128,14 +1141,14 @@ public:
m_u.ui = i;
}
explicit VNUser(void* p) { m_u.up = p; }
~VNUser() {}
~VNUser() = default;
// Casters
WidthVP* c() const { return reinterpret_cast<WidthVP*>(m_u.up); }
VSymEnt* toSymEnt() const { return reinterpret_cast<VSymEnt*>(m_u.up); }
AstNode* toNodep() const { return reinterpret_cast<AstNode*>(m_u.up); }
V3GraphVertex* toGraphVertex() const { return reinterpret_cast<V3GraphVertex*>(m_u.up); }
int toInt() const { return m_u.ui; }
static inline VNUser fromInt(int i) { return VNUser(i); }
static VNUser fromInt(int i) { return VNUser(i); }
};
//######################################################################
@@ -1149,7 +1162,7 @@ public:
// user2. When the member goes out of scope it will be automagically
// freed up.
class AstUserInUseBase {
class AstUserInUseBase VL_NOT_FINAL {
protected:
static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) {
// Perhaps there's still a AstUserInUse in scope for this?
@@ -1180,7 +1193,7 @@ protected:
// We let AstNode peek into here, because when under low optimization even
// an accessor would be way too slow.
// clang-format off
class AstUser1InUse : AstUserInUseBase {
class AstUser1InUse final : AstUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
@@ -1191,7 +1204,7 @@ public:
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser2InUse : AstUserInUseBase {
class AstUser2InUse final : AstUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
@@ -1202,7 +1215,7 @@ public:
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser3InUse : AstUserInUseBase {
class AstUser3InUse final : AstUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
@@ -1213,7 +1226,7 @@ public:
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser4InUse : AstUserInUseBase {
class AstUser4InUse final : AstUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
@@ -1224,7 +1237,7 @@ public:
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser5InUse : AstUserInUseBase {
class AstUser5InUse final : AstUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
@@ -1241,7 +1254,7 @@ public:
// AstNVisitor -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
class AstNVisitor {
class AstNVisitor VL_NOT_FINAL {
private:
// MEMBERS
std::vector<AstNode*> m_deleteps; // Nodes to delete when doDeletes() called
@@ -1254,7 +1267,10 @@ public:
/// along with all children and next(s). This is often better to use
/// than an immediate deleteTree, as any pointers into this node will
/// persist for the lifetime of the visitor
void pushDeletep(AstNode* nodep) { m_deleteps.push_back(nodep); }
void pushDeletep(AstNode* nodep) {
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
m_deleteps.push_back(nodep);
}
/// Call deleteTree on all previously pushDeletep()'ed nodes
void doDeletes();
@@ -1285,7 +1301,7 @@ public:
// AstNRelinker -- Holds the state of a unlink so a new node can be
// added at the same point.
class AstNRelinker {
class AstNRelinker final {
protected:
friend class AstNode;
enum RelinkWhatEn : uint8_t {
@@ -1302,7 +1318,7 @@ protected:
AstNode** m_iterpp = nullptr;
public:
AstNRelinker() {}
AstNRelinker() = default;
void relink(AstNode* newp);
AstNode* oldp() const { return m_oldp; }
void dump(std::ostream& str = std::cout) const;
@@ -1315,7 +1331,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) {
//######################################################################
// V3Hash -- Node hashing for V3Combine
class V3Hash {
class V3Hash final {
// A hash of a tree of nodes, consisting of 8 bits with the number of nodes in the hash
// and 24 bit value hash of relevant information about the node.
// A value of 0 is illegal
@@ -1334,9 +1350,9 @@ public:
uint32_t depth() const { return (m_both >> 24) & 255; }
uint32_t hshval() const { return m_both & M24; }
// OPERATORS
inline bool operator==(const V3Hash& rh) const { return m_both == rh.m_both; }
inline bool operator!=(const V3Hash& rh) const { return m_both != rh.m_both; }
inline bool operator<(const V3Hash& rh) const { return m_both < rh.m_both; }
bool operator==(const V3Hash& rh) const { return m_both == rh.m_both; }
bool operator!=(const V3Hash& rh) const { return m_both != rh.m_both; }
bool operator<(const V3Hash& rh) const { return m_both < rh.m_both; }
// CONSTRUCTORS
class Illegal {}; // for creator type-overload selection
class FullValue {}; // for creator type-overload selection
@@ -1368,7 +1384,7 @@ std::ostream& operator<<(std::ostream& os, const V3Hash& rhs);
//######################################################################
// Callback base class to determine if node matches some formula
class VNodeMatcher {
class VNodeMatcher VL_NOT_FINAL {
public:
virtual bool nodeMatch(const AstNode* nodep) const { return true; }
};
@@ -1382,11 +1398,11 @@ public:
do { \
if (nodep) { \
VL_PREFETCH_RD(&((nodep)->m_nextp)); \
VL_PREFETCH_RD(&((nodep)->m_iterpp)); \
VL_PREFETCH_RD(&((nodep)->m_type)); \
} \
} while (false)
class AstNode {
class AstNode VL_NOT_FINAL {
// v ASTNODE_PREFETCH depends on below ordering of members
AstNode* m_nextp; // Next peer in the parent's list
AstNode* m_backp; // Node that points to this one (via next/op1/op2/...)
@@ -1395,22 +1411,21 @@ class AstNode {
AstNode* m_op3p; // Generic pointer 3
AstNode* m_op4p; // Generic pointer 4
AstNode** m_iterpp; // Pointer to node iterating on, change it if we replace this node.
const AstType m_type; // Node sub-type identifier
// ^ ASTNODE_PREFETCH depends on above ordering of members
// padding - 2 extra bytes here after m_type
int m_cloneCnt; // Mark of when userp was set
AstNodeDType* m_dtypep; // Data type of output or assignment (etc)
AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list
const AstType m_type; // Node sub-type identifier
FileLine* m_fileline; // Where it was declared
vluint64_t m_editCount; // When it was last edited
static vluint64_t s_editCntGbl; // Global edit counter
// Global edit counter, last value for printing * near node #s
static vluint64_t s_editCntLast;
AstNodeDType* m_dtypep; // Data type of output or assignment (etc)
AstNode* m_clonep; // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY)
int m_cloneCnt; // Mark of when userp was set
static int s_cloneCntGbl; // Count of which userp is set
// Attributes
@@ -1526,7 +1541,7 @@ public:
bool brokeExistsBelow() const;
// CONSTRUCTORS
virtual ~AstNode() {}
virtual ~AstNode() = default;
#ifdef VL_LEAK_CHECKS
static void* operator new(size_t size);
static void operator delete(void* obj, size_t size);
@@ -1715,7 +1730,7 @@ public:
void dtypeSetLogicSized(int width, VSigning numeric) {
dtypep(findLogicDType(width, width, numeric)); // Since sized, widthMin is width
}
void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); }
void dtypeSetBit() { dtypep(findBitDType()); }
void dtypeSetDouble() { dtypep(findDoubleDType()); }
void dtypeSetString() { dtypep(findStringDType()); }
void dtypeSetSigned32() { dtypep(findSigned32DType()); }
@@ -1724,13 +1739,14 @@ public:
void dtypeSetVoid() { dtypep(findVoidDType()); }
// Data type locators
AstNodeDType* findLogicBoolDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); }
AstNodeDType* findBitDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); }
AstNodeDType* findDoubleDType() { return findBasicDType(AstBasicDTypeKwd::DOUBLE); }
AstNodeDType* findStringDType() { return findBasicDType(AstBasicDTypeKwd::STRING); }
AstNodeDType* findSigned32DType() { return findBasicDType(AstBasicDTypeKwd::INTEGER); }
AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); }
AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); }
AstNodeDType* findVoidDType() const;
AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
@@ -1748,7 +1764,7 @@ public:
string warnOther() const { return fileline()->warnOther(); }
virtual void dump(std::ostream& str = std::cout) const;
void dumpGdb(); // For GDB only
static void dumpGdb(const AstNode* nodep); // For GDB only
void dumpGdbHeader() const;
// METHODS - Tree modifications
@@ -1798,11 +1814,12 @@ public:
void dumpTree(const string& indent, int maxDepth = 0) const {
dumpTree(cout, indent, maxDepth);
}
void dumpTreeGdb(); // For GDB only
static void dumpTreeGdb(const AstNode* nodep); // For GDB only
void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ",
int maxDepth = 0) const;
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true);
static void dumpTreeFileGdb(const char* filenamep = nullptr);
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
bool doCheck = true);
static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
// METHODS - queries
// Changes control flow, disable some optimizations
@@ -1891,7 +1908,7 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
//=== AstNode* : Derived generic node types
#define ASTNODE_BASE_FUNCS(name) \
virtual ~Ast##name() {} \
virtual ~Ast##name() override = default; \
static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \
return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \
} \
@@ -1900,7 +1917,7 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
} \
Ast##name* clonep() const { return static_cast<Ast##name*>(AstNode::clonep()); }
class AstNodeMath : public AstNode {
class AstNodeMath VL_NOT_FINAL : public AstNode {
// Math -- anything that's part of an expression tree
public:
AstNodeMath(AstType t, FileLine* fl)
@@ -1920,7 +1937,7 @@ public:
bool isOpaque() { return VN_IS(this, CvtPackString); }
};
class AstNodeTermop : public AstNodeMath {
class AstNodeTermop VL_NOT_FINAL : public AstNodeMath {
// Terminal operator -- a operator with no "inputs"
public:
AstNodeTermop(AstType t, FileLine* fl)
@@ -1933,7 +1950,7 @@ public:
virtual void dump(std::ostream& str) const override;
};
class AstNodeUniop : public AstNodeMath {
class AstNodeUniop VL_NOT_FINAL : public AstNodeMath {
// Unary math
public:
AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp)
@@ -1959,7 +1976,7 @@ public:
virtual bool same(const AstNode*) const override { return true; }
};
class AstNodeBiop : public AstNodeMath {
class AstNodeBiop VL_NOT_FINAL : public AstNodeMath {
// Binary math
public:
AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
@@ -1991,7 +2008,7 @@ public:
virtual bool same(const AstNode*) const override { return true; }
};
class AstNodeTriop : public AstNodeMath {
class AstNodeTriop VL_NOT_FINAL : public AstNodeMath {
// Trinary math
public:
AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
@@ -2024,7 +2041,7 @@ public:
virtual bool same(const AstNode*) const override { return true; }
};
class AstNodeQuadop : public AstNodeMath {
class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath {
// Quaternary math
public:
AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs)
@@ -2061,7 +2078,7 @@ public:
virtual bool same(const AstNode*) const override { return true; }
};
class AstNodeBiCom : public AstNodeBiop {
class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop {
// Binary math with commutative properties
public:
AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
@@ -2069,14 +2086,14 @@ public:
ASTNODE_BASE_FUNCS(NodeBiCom)
};
class AstNodeBiComAsv : public AstNodeBiCom {
class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom {
// Binary math with commutative & associative properties
public:
AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiCom{t, fl, lhs, rhs} {}
ASTNODE_BASE_FUNCS(NodeBiComAsv)
};
class AstNodeCond : public AstNodeTriop {
class AstNodeCond VL_NOT_FINAL : public AstNodeTriop {
public:
AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
: AstNodeTriop{t, fl, condp, expr1p, expr2p} {
@@ -2107,7 +2124,7 @@ public:
virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0;
};
class AstNodeBlock : public AstNode {
class AstNodeBlock VL_NOT_FINAL : public AstNode {
// A Begin/fork block
// Parents: statement
// Children: statements
@@ -2131,7 +2148,7 @@ public:
bool unnamed() const { return m_unnamed; }
};
class AstNodePreSel : public AstNode {
class AstNodePreSel VL_NOT_FINAL : public AstNode {
// Something that becomes an AstSel
public:
AstNodePreSel(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
@@ -2155,7 +2172,7 @@ public:
virtual bool same(const AstNode*) const override { return true; }
};
class AstNodeProcedure : public AstNode {
class AstNodeProcedure VL_NOT_FINAL : public AstNode {
// IEEE procedure: initial, final, always
public:
AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp)
@@ -2170,7 +2187,7 @@ public:
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
class AstNodeStmt : public AstNode {
class AstNodeStmt VL_NOT_FINAL : public AstNode {
// Statement -- anything that's directly under a function
bool m_statement; // Really a statement (e.g. not a function with return)
public:
@@ -2188,7 +2205,7 @@ public:
virtual void dump(std::ostream& str = std::cout) const override;
};
class AstNodeAssign : public AstNodeStmt {
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
public:
AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeStmt{t, fl} {
@@ -2213,7 +2230,7 @@ public:
virtual bool brokeLhsMustBeLvalue() const = 0;
};
class AstNodeFor : public AstNodeStmt {
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
public:
AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp,
AstNode* bodysp)
@@ -2234,7 +2251,7 @@ public:
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstNodeIf : public AstNodeStmt {
class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
private:
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
public:
@@ -2260,7 +2277,7 @@ public:
VBranchPred branchPred() const { return m_branchPred; }
};
class AstNodeCase : public AstNodeStmt {
class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
public:
AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp)
: AstNodeStmt{t, fl} {
@@ -2278,15 +2295,16 @@ public:
void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
};
class AstNodeVarRef : public AstNodeMath {
class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath {
// An AstVarRef or AstVarXRef
private:
VAccess m_access; // Left hand side assignment
AstVar* m_varp; // [AfterLink] Pointer to variable itself
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
AstNodeModule* m_packagep = nullptr; // Package hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
string m_name; // Name of variable
string m_hiername; // Scope converted into name-> for emitting
string m_hiernameToProt; // Scope converted into name-> for emitting
string m_hiernameToUnprot; // Scope converted into name-> for emitting
bool m_hierThis = false; // Hiername points to "this" function
public:
@@ -2317,20 +2335,22 @@ public:
void varp(AstVar* varp);
AstVarScope* varScopep() const { return m_varScopep; }
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
string hiername() const { return m_hiername; }
string hiernameToProt() const { return m_hiernameToProt; }
void hiernameToProt(const string& hn) { m_hiernameToProt = hn; }
string hiernameToUnprot() const { return m_hiernameToUnprot; }
void hiernameToUnprot(const string& hn) { m_hiernameToUnprot = hn; }
string hiernameProtect() const;
void hiername(const string& hn) { m_hiername = hn; }
bool hierThis() const { return m_hierThis; }
void hierThis(bool flag) { m_hierThis = flag; }
AstNodeModule* packagep() const { return m_packagep; }
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
// Know no children, and hot function, so skip iterator for speed
// See checkTreeIter also that asserts no children
// cppcheck-suppress functionConst
void iterateChildren(AstNVisitor& v) {}
};
class AstNodeText : public AstNode {
class AstNodeText VL_NOT_FINAL : public AstNode {
private:
string m_text;
@@ -2350,7 +2370,7 @@ public:
const string& text() const { return m_text; }
};
class AstNodeDType : public AstNode {
class AstNodeDType VL_NOT_FINAL : public AstNode {
// Ideally width() would migrate to BasicDType as that's where it makes sense,
// but it's currently so prevalent in the code we leave it here.
// Note the below members are included in AstTypeTable::Key lookups
@@ -2439,13 +2459,18 @@ public:
const char* charIQWN() const {
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
}
string cType(const string& name, bool forFunc, bool isRef) const;
private:
class CTypeRecursed;
CTypeRecursed cTypeRecurse(bool compound) const;
};
class AstNodeUOrStructDType : public AstNodeDType {
class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
// A struct or union; common handling
private:
// TYPES
typedef std::map<string, AstMemberDType*> MemberNameMap;
typedef std::map<const string, AstMemberDType*> MemberNameMap;
// MEMBERS
string m_name; // Name from upper typedef, if any
bool m_packed;
@@ -2505,7 +2530,7 @@ public:
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
};
class AstNodeArrayDType : public AstNodeDType {
class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
@@ -2568,7 +2593,7 @@ public:
VNumRange declRange() const;
};
class AstNodeSel : public AstNodeBiop {
class AstNodeSel VL_NOT_FINAL : public AstNodeBiop {
// Single bit range extraction, perhaps with non-constant selection or array selection
public:
AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp)
@@ -2584,7 +2609,7 @@ public:
virtual bool hasDType() const override { return true; }
};
class AstNodeStream : public AstNodeBiop {
class AstNodeStream VL_NOT_FINAL : public AstNodeBiop {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
public:
AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
@@ -2597,11 +2622,12 @@ public:
//######################################################################
// Tasks/functions common handling
class AstNodeCCall : public AstNodeStmt {
class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt {
// A call of a C++ function, perhaps a AstCFunc or perhaps globally named
// Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
AstCFunc* m_funcp;
string m_hiername;
string m_hiernameToProt;
string m_hiernameToUnprot;
string m_argTypes;
public:
@@ -2615,7 +2641,8 @@ public:
AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp)
: AstNodeStmt{t, oldp->fileline(), true}
, m_funcp{funcp} {
m_hiername = oldp->hiername();
m_hiernameToProt = oldp->hiernameToProt();
m_hiernameToUnprot = oldp->hiernameToUnprot();
m_argTypes = oldp->argTypes();
if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext());
}
@@ -2635,8 +2662,10 @@ public:
virtual bool isPure() const override;
virtual bool isOutputter() const override { return !isPure(); }
AstCFunc* funcp() const { return m_funcp; }
string hiername() const { return m_hiername; }
void hiername(const string& hn) { m_hiername = hn; }
string hiernameToProt() const { return m_hiernameToProt; }
void hiernameToProt(const string& hn) { m_hiernameToProt = hn; }
string hiernameToUnprot() const { return m_hiernameToUnprot; }
void hiernameToUnprot(const string& hn) { m_hiernameToUnprot = hn; }
string hiernameProtect() const;
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
@@ -2645,7 +2674,7 @@ public:
void addArgsp(AstNode* nodep) { addOp2p(nodep); }
};
class AstNodeFTask : public AstNode {
class AstNodeFTask VL_NOT_FINAL : public AstNode {
private:
string m_name; // Name of task
string m_cname; // Name of task if DPI import
@@ -2662,6 +2691,8 @@ private:
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
bool m_dpiTask : 1; // DPI import task (vs. void function)
bool m_isConstructor : 1; // Class constructor
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
bool m_pure : 1; // DPI import pure (vs. virtual pure)
bool m_pureVirtual : 1; // Pure virtual
bool m_virtual : 1; // Virtual method in class
@@ -2682,6 +2713,8 @@ public:
, m_dpiOpenChild{false}
, m_dpiTask{false}
, m_isConstructor{false}
, m_isHideLocal{false}
, m_isHideProtected{false}
, m_pure{false}
, m_pureVirtual{false}
, m_virtual{false} {
@@ -2704,8 +2737,8 @@ public:
void addFvarp(AstNode* nodep) { addNOp1p(nodep); }
bool isFunction() const { return fvarp() != nullptr; }
// op2 = Class/package scope
AstNode* packagep() const { return op2p(); }
void packagep(AstNode* nodep) { setNOp2p(nodep); }
AstNode* classOrPackagep() const { return op2p(); }
void classOrPackagep(AstNode* nodep) { setNOp2p(nodep); }
// op3 = Statements/Ports/Vars
AstNode* stmtsp() const { return op3p(); } // op3 = List of statements
void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
@@ -2740,6 +2773,10 @@ public:
bool dpiTask() const { return m_dpiTask; }
void isConstructor(bool flag) { m_isConstructor = flag; }
bool isConstructor() const { return m_isConstructor; }
bool isHideLocal() const { return m_isHideLocal; }
void isHideLocal(bool flag) { m_isHideLocal = flag; }
bool isHideProtected() const { return m_isHideProtected; }
void isHideProtected(bool flag) { m_isHideProtected = flag; }
void pure(bool flag) { m_pure = flag; }
bool pure() const { return m_pure; }
void pureVirtual(bool flag) { m_pureVirtual = flag; }
@@ -2750,12 +2787,12 @@ public:
VLifetime lifetime() const { return m_lifetime; }
};
class AstNodeFTaskRef : public AstNodeStmt {
class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt {
// A reference to a task (or function)
// Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
private:
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
AstNodeModule* m_packagep = nullptr; // Package hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
string m_name; // Name of variable
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
@@ -2789,8 +2826,8 @@ public:
void taskp(AstNodeFTask* taskp) { m_taskp = taskp; }
virtual void name(const string& name) override { m_name = name; }
void dotted(const string& name) { m_dotted = name; }
AstNodeModule* packagep() const { return m_packagep; }
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
bool pli() const { return m_pli; }
void pli(bool flag) { m_pli = flag; }
// op1 = namep
@@ -2804,7 +2841,7 @@ public:
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
};
class AstNodeModule : public AstNode {
class AstNodeModule VL_NOT_FINAL : public AstNode {
// A module, package, program or interface declaration;
// something that can live directly under the TOP,
// excluding $unit package stuff
@@ -2883,7 +2920,7 @@ public:
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
};
class AstNodeRange : public AstNode {
class AstNodeRange VL_NOT_FINAL : public AstNode {
// A range, sized or unsized
public:
AstNodeRange(AstType t, FileLine* fl)
@@ -2975,7 +3012,7 @@ inline VNumRange AstNodeArrayDType::declRange() const {
inline const char* AstNodeFTaskRef::broken() const {
BROKEN_RTN(m_taskp && !m_taskp->brokeExists());
BROKEN_RTN(m_packagep && !m_packagep->brokeExists());
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
+238 -146
View File
@@ -54,7 +54,7 @@ void AstNodeVarRef::cloneRelink() {
}
string AstNodeVarRef::hiernameProtect() const {
return VIdProtect::protectWordsIf(hiername(), protect());
return hiernameToUnprot() + VIdProtect::protectWordsIf(hiernameToProt(), protect());
}
int AstNodeSel::bitConst() const {
@@ -107,7 +107,7 @@ const char* AstNodeCCall::broken() const {
}
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
string AstNodeCCall::hiernameProtect() const {
return VIdProtect::protectWordsIf(hiername(), protect());
return hiernameToUnprot() + VIdProtect::protectWordsIf(hiernameToProt(), protect());
}
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
@@ -312,107 +312,22 @@ string AstVar::verilogKwd() const {
}
}
class AstVar::VlArgTypeRecursed {
public:
bool m_isRef; // Is it a reference?
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name) const {
string out;
out += m_type;
out += " ";
out += m_isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const {
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
bool isRef = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
string oname;
if (named) {
if (!namespc.empty()) oname += namespc + "::";
oname += VIdProtect::protectIf(name(), protect());
}
return ostatic + info.render(oname);
}
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool compound) const {
VlArgTypeRecursed info;
info.m_isRef
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
dtypep = dtypep->skipRefp();
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
return info;
return ostatic + dtypep()->cType(oname, forFunc, isRef);
}
string AstVar::vlEnumType() const {
@@ -540,38 +455,99 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
return arg;
}
string AstVar::dpiArgType(bool named, bool forReturn) const {
if (forReturn) named = false;
string arg;
if (isDpiOpenArray()) {
arg = "const svOpenArrayHandle";
} else if (!basicp()) {
arg = "UNKNOWN";
} else if (basicp()->isDpiBitVec()) {
if (forReturn) {
arg = "svBitVecVal";
} else if (isReadOnly()) {
arg = "const svBitVecVal*";
} else {
arg = "svBitVecVal*";
}
} else if (basicp()->isDpiLogicVec()) {
if (forReturn) {
arg = "svLogicVecVal";
} else if (isReadOnly()) {
arg = "const svLogicVecVal*";
} else {
arg = "svLogicVecVal*";
}
} else {
arg = basicp()->keyword().dpiType();
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
arg = "unsigned " + arg;
}
if (!forReturn && isWritable()) arg += "*";
class dpiTypesToStringConverter VL_NOT_FINAL {
public:
virtual string openArray(const AstVar*) const { return "const svOpenArrayHandle"; }
virtual string bitLogicVector(const AstVar* varp, bool isBit) const {
return isBit ? "svBitVecVal" : "svLogicVecVal";
}
if (named) arg += " " + name();
return arg;
virtual string primitive(const AstVar* varp) const {
string type;
if (varp->basicp()->keyword().isDpiUnsignable() && !varp->basicp()->isSigned()) {
type = "unsigned ";
}
type += varp->basicp()->keyword().dpiType();
return type;
}
string convert(const AstVar* varp) const {
if (varp->isDpiOpenArray()) {
return openArray(varp);
} else if (!varp->basicp()) {
return "UNKNOWN";
} else if (varp->basicp()->isDpiBitVec() || varp->basicp()->isDpiLogicVec()) {
return bitLogicVector(varp, varp->basicp()->isDpiBitVec());
} else {
return primitive(varp);
}
}
};
string AstVar::dpiArgType(bool named, bool forReturn) const {
if (forReturn) {
return dpiTypesToStringConverter{}.convert(this);
} else {
class converter final : public dpiTypesToStringConverter {
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
return string(varp->isReadOnly() ? "const " : "")
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
}
virtual string primitive(const AstVar* varp) const override {
string type = dpiTypesToStringConverter::primitive(varp);
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
if (!varp->isWritable()
&& varp->basicp()->keyword() != AstBasicDTypeKwd::STRING)
type = "const " + type;
type += "*";
}
return type;
}
};
string arg = converter{}.convert(this);
if (named) arg += " " + name();
return arg;
}
}
string AstVar::dpiTmpVarType(const string& varName) const {
class converter final : public dpiTypesToStringConverter {
string m_name;
string arraySuffix(const AstVar* varp, size_t n) const {
if (AstUnpackArrayDType* unpackp
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
// Convert multi dimensional unpacked array to 1D array
if (n == 0) n = 1;
n *= unpackp->arrayUnpackedElements();
return '[' + cvtToStr(n) + ']';
} else if (n > 0) {
return '[' + cvtToStr(n) + ']';
} else {
return "";
}
}
virtual string openArray(const AstVar* varp) const override {
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
+ arraySuffix(varp, 0);
}
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
return type;
}
virtual string primitive(const AstVar* varp) const override {
string type = dpiTypesToStringConverter::primitive(varp);
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
if (!varp->isWritable() && varp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE)
type = "const " + type;
}
type += ' ' + m_name + arraySuffix(varp, 0);
return type;
}
public:
explicit converter(const string& name)
: m_name(name) {}
};
return converter{varName}.convert(this);
}
string AstVar::scType() const {
@@ -638,6 +614,90 @@ string AstVar::mtasksString() const {
return os.str();
}
class AstNodeDType::CTypeRecursed final {
public:
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name, bool isRef) const {
string out;
out += m_type;
if (name != "") out += " ";
out += isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const {
CTypeRecursed info = cTypeRecurse(false);
return info.render(name, isRef);
}
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
CTypeRecursed info;
const AstNodeDType* dtypep = this->skipRefp();
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
return info;
}
AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
// dimension passed from AstArraySel::dimension
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
@@ -845,9 +905,7 @@ bool AstSenTree::hasCombo() const {
void AstTypeTable::clearCache() {
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
// Just clear out the maps; the search functions will be used to rebuild the map
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
m_basicps[i] = nullptr;
}
for (auto& itr : m_basicps) itr = nullptr;
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
@@ -874,6 +932,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
return m_voidp;
}
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
addTypesp(newp);
m_queueIndexp = newp;
}
return m_queueIndexp;
}
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
//
@@ -1082,6 +1149,7 @@ void AstCell::dump(std::ostream& str) const {
void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << origModName();
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
}
const char* AstClassPackage::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
@@ -1103,6 +1171,13 @@ void AstClass::repairCache() {
clearCache();
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); }
}
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
// TAIL RECURSIVE
if (!refClassp || !baseClassp) return false;
if (refClassp == baseClassp) return true;
if (!refClassp->extendsp()) return false;
return isClassExtendedFrom(refClassp->extendsp()->classp(), baseClassp);
}
void AstClass::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isExtended()) str << " [EXT]";
@@ -1110,6 +1185,9 @@ void AstClass::dump(std::ostream& str) const {
}
AstClass* AstClassExtends::classp() const {
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
refp = VN_CAST(childDTypep(), ClassRefDType);
}
UASSERT_OBJ(refp, this, "class extends non-ref");
return refp->classp();
}
@@ -1166,12 +1244,12 @@ void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str);
int n = 0;
const AstInitArray::KeyItemMap& mapr = map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
for (const auto& itr : mapr) {
if (n++ > 5) {
str << " ...";
break;
}
str << " [" << it->first << "]=" << (void*)it->second;
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
}
}
void AstJumpGo::dump(std::ostream& str) const {
@@ -1338,6 +1416,18 @@ string AstUnpackArrayDType::prettyDTypeName() const {
os << subp->prettyDTypeName() << "$" << ranges;
return os.str();
}
std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
std::vector<AstUnpackArrayDType*> dims;
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
dims.push_back(unpackp);
if (AstNodeDType* subp = unpackp->subDTypep()) {
unpackp = VN_CAST(subp, UnpackArrayDType);
} else {
unpackp = nullptr;
}
}
return dims;
}
void AstNetlist::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << timeunit() << "/" << timeprecision() << "]";
@@ -1363,6 +1453,10 @@ void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstPatMember::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isDefault()) str << " [DEFAULT]";
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str);
@@ -1384,7 +1478,7 @@ void AstTypeTable::dump(std::ostream& str) const {
this->AstNode::dump(str);
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
if (AstBasicDType* subnodep = m_basicps[i]) {
str << endl; // Newline from caller, so newline first
str << '\n'; // Newline from caller, so newline first
str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii();
str << " -> ";
subnodep->dump(str);
@@ -1392,9 +1486,9 @@ void AstTypeTable::dump(std::ostream& str) const {
}
{
const DetailedMap& mapr = m_detailedMap;
for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
AstBasicDType* dtypep = it->second;
str << endl; // Newline from caller, so newline first
for (const auto& itr : mapr) {
AstBasicDType* dtypep = itr.second;
str << '\n'; // Newline from caller, so newline first
str << "\t\tdetailed -> ";
dtypep->dump(str);
}
@@ -1403,7 +1497,7 @@ void AstTypeTable::dump(std::ostream& str) const {
}
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "[assoc-" << (void*)keyDTypep() << "]";
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
}
string AstAssocArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
@@ -1440,15 +1534,13 @@ void AstVarScope::dump(std::ostream& str) const {
str << " ->UNLINKED";
}
}
void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstNodeVarRef::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " " << access().arrow() << " ";
}
void AstVarXRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
}
str << ".=" << dotted() << " ";
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
if (varScopep()) {
@@ -1461,12 +1553,6 @@ void AstVarXRef::dump(std::ostream& str) const {
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
}
if (varScopep()) {
varScopep()->dump(str);
} else if (varp()) {
@@ -1499,6 +1585,12 @@ void AstVar::dump(std::ostream& str) const {
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
}
void AstScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
void AstSenTree::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isMulti()) str << " [MULTI]";
@@ -1536,7 +1628,7 @@ void AstActive::dump(std::ostream& str) const {
}
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " -> ";
if (dotted() != "") { str << ".=" << dotted() << " "; }
if (taskp()) {
+689 -475
View File
File diff suppressed because it is too large Load Diff
+35 -42
View File
@@ -36,7 +36,7 @@
//######################################################################
class BeginState {
class BeginState final {
private:
// NODE STATE
// Entire netlist:
@@ -45,8 +45,8 @@ private:
bool m_anyFuncInBegin = false;
public:
BeginState() {}
~BeginState() {}
BeginState() = default;
~BeginState() = default;
void userMarkChanged(AstNode* nodep) {
nodep->user1(true);
m_anyFuncInBegin = true;
@@ -56,7 +56,7 @@ public:
//######################################################################
class BeginVisitor : public AstNVisitor {
class BeginVisitor final : public AstNVisitor {
private:
// STATE
BeginState* m_statep; // Current global state
@@ -69,6 +69,11 @@ private:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
string dot(const string& a, const string& b) {
if (a == "") return b;
return a + "__DOT__" + b;
}
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
@@ -81,7 +86,7 @@ private:
UINFO(8, " " << nodep << endl);
// Rename it
if (m_unnamedScope != "") {
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
UINFO(8, " rename to " << nodep->name() << endl);
m_statep->userMarkChanged(nodep);
}
@@ -103,8 +108,8 @@ private:
virtual void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep << endl);
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
UINFO(8, "nname " << m_namedScope << endl);
if (nodep->name() != "") { // Else unneeded unnamed block
@@ -114,18 +119,8 @@ private:
while ((pos = dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") {
if (m_namedScope == "") {
m_namedScope = ident;
} else {
m_namedScope = m_namedScope + "__DOT__" + ident;
}
}
if (m_unnamedScope == "") {
m_unnamedScope = ident;
} else {
m_unnamedScope = m_unnamedScope + "__DOT__" + ident;
}
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(
@@ -138,31 +133,29 @@ private:
// Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp());
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
}
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstVar* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
@@ -176,7 +169,7 @@ private:
virtual void visit(AstTypedef* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
@@ -193,7 +186,7 @@ private:
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
// Rename it
nodep->name(m_namedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_namedScope, nodep->name()));
UINFO(8, " rename to " << nodep->name() << endl);
// Move to module
nodep->unlinkFrBack();
@@ -249,12 +242,12 @@ public:
: m_statep{statep} {
iterate(nodep);
}
virtual ~BeginVisitor() override {}
virtual ~BeginVisitor() override = default;
};
//######################################################################
class BeginRelinkVisitor : public AstNVisitor {
class BeginRelinkVisitor final : public AstNVisitor {
// Replace tasks with new pointer
private:
// NODE STATE
@@ -290,7 +283,7 @@ private:
public:
// CONSTRUCTORS
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
virtual ~BeginRelinkVisitor() override {}
virtual ~BeginRelinkVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Begin {
class V3Begin final {
public:
static void debeginAll(AstNetlist* nodep);
};
+2 -2
View File
@@ -35,7 +35,7 @@
//######################################################################
// Branch state, as a visitor of each AstNode
class BranchVisitor : public AstNVisitor {
class BranchVisitor final : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -118,7 +118,7 @@ public:
iterateChildren(nodep);
calc_tasks();
}
virtual ~BranchVisitor() override {}
virtual ~BranchVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Branch {
class V3Branch final {
public:
// CONSTRUCTORS
static void branchAll(AstNetlist* nodep);
+26 -8
View File
@@ -36,7 +36,7 @@
//######################################################################
class BrokenTable : public AstNVisitor {
class BrokenTable VL_NOT_FINAL : public AstNVisitor {
// Table of brokenExists node pointers
private:
// MEMBERS
@@ -190,8 +190,8 @@ public:
}
// CONSTRUCTORS
BrokenTable() {}
virtual ~BrokenTable() override {}
BrokenTable() = default;
virtual ~BrokenTable() override = default;
};
BrokenTable::NodeMap BrokenTable::s_nodes;
@@ -211,7 +211,7 @@ bool AstNode::brokeExistsBelow() const {
//######################################################################
class BrokenMarkVisitor : public AstNVisitor {
class BrokenMarkVisitor final : public AstNVisitor {
// Mark every node in the tree
private:
// NODE STATE
@@ -231,13 +231,15 @@ private:
public:
// CONSTRUCTORS
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenMarkVisitor() override {}
virtual ~BrokenMarkVisitor() override = default;
};
//######################################################################
// Broken state, as a visitor of each AstNode
class BrokenCheckVisitor : public AstNVisitor {
class BrokenCheckVisitor final : public AstNVisitor {
bool m_inScope = false; // Under AstScope
private:
static void checkWidthMin(const AstNode* nodep) {
UASSERT_OBJ(nodep->width() == nodep->widthMin()
@@ -275,9 +277,25 @@ private:
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWrite()),
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstScope* nodep) override {
VL_RESTORER(m_inScope);
{
m_inScope = true;
processAndIterate(nodep);
}
}
virtual void visit(AstNodeVarRef* nodep) override {
processAndIterate(nodep);
// m_inScope because some Vars have initial variable references without scopes
// This might false fire with some debug flags, as not certain we don't have temporary
// clear varScopep's during some an infrequent dump just before we re-LinkDot.
UASSERT_OBJ(
!(v3Global.assertScoped() && m_inScope && nodep->varp() && !nodep->varScopep()), nodep,
"VarRef missing VarScope pointer");
}
virtual void visit(AstNode* nodep) override {
// Process not just iterate
processAndIterate(nodep);
@@ -286,7 +304,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenCheckVisitor() override {}
virtual ~BrokenCheckVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Broken {
class V3Broken final {
public:
static void brokenAll(AstNetlist* nodep);
static void addNewed(AstNode* nodep);
+4 -6
View File
@@ -34,7 +34,7 @@
#include <algorithm>
#include <map>
class V3CCtorsVisitor {
class V3CCtorsVisitor final {
private:
string m_basename;
string m_argsp;
@@ -42,8 +42,8 @@ private:
AstNodeModule* m_modp; // Current module
AstCFunc* m_tlFuncp; // Top level function being built
AstCFunc* m_funcp; // Current function
int m_numStmts; // Number of statements output
int m_funcNum; // Function number being built
int m_numStmts = 0; // Number of statements output
int m_funcNum = 0; // Function number being built
public:
void add(AstNode* nodep) {
@@ -76,8 +76,6 @@ public:
m_argsp = argsp;
m_callargsp = callargsp;
m_modp = nodep;
m_numStmts = 0;
m_funcNum = 0;
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void");
m_tlFuncp->declPrivate(true);
m_tlFuncp->isStatic(false);
@@ -87,7 +85,7 @@ public:
m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp);
}
~V3CCtorsVisitor() {}
~V3CCtorsVisitor() = default;
private:
VL_UNCOPYABLE(V3CCtorsVisitor);
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3CCtors {
class V3CCtors final {
public:
static void cctorsAll();
+27 -25
View File
@@ -36,12 +36,12 @@
//######################################################################
class CUseState {
class CUseState final {
private:
// MEMBERS
AstNodeModule* m_modInsertp; // Current module to insert AstCUse under
typedef std::pair<VUseType, string> UseString;
std::map<UseString, AstCUse*> m_didUse; // What we already used
std::map<const UseString, AstCUse*> m_didUse; // What we already used
// NODE STATE
// Entire netlist:
@@ -68,14 +68,14 @@ public:
// CONSTRUCTORS
explicit CUseState(AstNodeModule* nodep)
: m_modInsertp{nodep} {}
virtual ~CUseState() {}
virtual ~CUseState() = default;
VL_UNCOPYABLE(CUseState);
};
// Visit within a module all nodes and data types they reference, finding
// any classes so we can make sure they are defined when Verilated code
// compiles
class CUseDTypeVisitor : public AstNVisitor {
class CUseDTypeVisitor final : public AstNVisitor {
// MEMBERS
CUseState& m_stater; // State for inserter
bool m_impOnly = false; // In details needed only for implementation
@@ -84,7 +84,7 @@ class CUseDTypeVisitor : public AstNVisitor {
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());
m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->classOrPackagep()->name());
// Need to include extends() when we implement, but no need for pointers to know
VL_RESTORER(m_impOnly);
{
@@ -109,11 +109,11 @@ public:
: m_stater(stater) { // Need () or GCC 4.8 false warning
iterate(nodep);
}
virtual ~CUseDTypeVisitor() override {}
virtual ~CUseDTypeVisitor() override = default;
VL_UNCOPYABLE(CUseDTypeVisitor);
};
class CUseVisitor : public AstNVisitor {
class CUseVisitor final : public AstNVisitor {
// MEMBERS
CUseState m_state; // Inserter state
@@ -148,7 +148,7 @@ class CUseVisitor : public AstNVisitor {
funcp->isStatic(false);
funcp->protect(false);
AstNode* exprp = new AstCMath(nodep->fileline(),
"std::string(\"`{\") + to_string_middle() + \"}\"", 0);
R"(std::string("'{") + to_string_middle() + "}")", 0);
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp));
nodep->addStmtp(funcp);
@@ -162,23 +162,25 @@ class CUseVisitor : public AstNVisitor {
funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n"));
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var)) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + ";
if (itemp->isWide()) {
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
} else {
stmt += "VL_TO_STRING(";
if (auto* varp = VN_CAST(itemp, Var)) {
if (!varp->isParam()) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + ";
if (itemp->isWide()) {
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
} else {
stmt += "VL_TO_STRING(";
}
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
}
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {
@@ -217,7 +219,7 @@ public:
: m_state{nodep} {
iterate(nodep);
}
virtual ~CUseVisitor() override {}
virtual ~CUseVisitor() override = default;
VL_UNCOPYABLE(CUseVisitor);
};
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3CUse {
class V3CUse final {
public:
static void cUseAll();
};
+10 -11
View File
@@ -50,7 +50,7 @@
//######################################################################
class CaseLintVisitor : public AstNVisitor {
class CaseLintVisitor final : public AstNVisitor {
private:
AstNodeCase* m_caseExprp
= nullptr; // Under a CASE value node, if so the relevant case statement
@@ -111,13 +111,13 @@ private:
public:
// CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
virtual ~CaseLintVisitor() override {}
virtual ~CaseLintVisitor() override = default;
};
//######################################################################
// Case state, as a visitor of each AstNode
class CaseVisitor : public AstNVisitor {
class CaseVisitor final : public AstNVisitor {
private:
// NODE STATE
// Cleared each Case
@@ -133,7 +133,7 @@ private:
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];
std::array<AstNode*, 1 << CASE_OVERLAP_WIDTH> m_valueItem;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -318,7 +318,7 @@ private:
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (!itemp->condsp()) {
// Default clause. Just make true, we'll optimize it away later
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue()));
hadDefault = true;
} else {
// Expressioned clause
@@ -336,7 +336,7 @@ private:
VL_DANGLING(iconstp);
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
condp = new AstConst(itemp->fileline(), AstConst::BitFalse());
} else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) {
// Similar logic in V3Width::visit(AstInside)
condp = irangep->newAndFromInside(cexprp, irangep->lhsp()->unlinkFrBack(),
@@ -375,9 +375,8 @@ 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()), nullptr));
nodep->addItemsp(new AstCaseItem(
nodep->fileline(), new AstConst(nodep->fileline(), AstConst::BitTrue()), nullptr));
}
if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: ");
// Now build the IF statement tree
@@ -419,7 +418,7 @@ private:
VL_DANGLING(ifexprp);
if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
itemexprp = new AstConst(itemp->fileline(), AstConst::BitTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
if (itemnextp) {
@@ -486,7 +485,7 @@ private:
public:
// CONSTRUCTORS
explicit CaseVisitor(AstNetlist* nodep) {
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr;
for (auto& itr : m_valueItem) itr = nullptr;
iterate(nodep);
}
virtual ~CaseVisitor() override {
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Case {
class V3Case final {
public:
static void caseAll(AstNetlist* nodep);
static void caseLint(AstNodeCase* nodep);
+4 -4
View File
@@ -49,7 +49,7 @@
//######################################################################
// Cast state, as a visitor of each AstNode
class CastVisitor : public AstNVisitor {
class CastVisitor final : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -73,7 +73,7 @@ private:
ensureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
}
int castSize(AstNode* nodep) {
static int castSize(AstNode* nodep) {
if (nodep->isQuad()) {
return VL_QUADSIZE;
} else if (nodep->width() <= 8) {
@@ -154,7 +154,7 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
if (nodep->access().isRead() && !VN_IS(nodep->backp(), CCast)
if (nodep->access().isReadOnly() && !VN_IS(nodep->backp(), CCast)
&& VN_IS(nodep->backp(), NodeMath) && !VN_IS(nodep->backp(), ArraySel)
&& nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
@@ -193,7 +193,7 @@ private:
public:
// CONSTRUCTORS
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CastVisitor() override {}
virtual ~CastVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Cast {
class V3Cast final {
public:
static void castAll(AstNetlist* nodep);
};
+25 -26
View File
@@ -41,7 +41,7 @@ constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async lo
//######################################################################
class CdcBaseVisitor : public AstNVisitor {
class CdcBaseVisitor VL_NOT_FINAL : public AstNVisitor {
public:
VL_DEBUG_FUNC; // Declare debug()
};
@@ -49,7 +49,7 @@ public:
//######################################################################
// Graph support classes
class CdcEitherVertex : public V3GraphVertex {
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
AstScope* m_scopep;
AstNode* m_nodep;
AstSenTree* m_srcDomainp = nullptr;
@@ -66,7 +66,7 @@ public:
, m_srcDomainSet{false}
, m_dstDomainSet{false}
, m_asyncPath{false} {}
virtual ~CdcEitherVertex() override {}
virtual ~CdcEitherVertex() override = default;
// ACCESSORS
virtual FileLine* fileline() const override { return nodep()->fileline(); }
AstScope* scopep() const { return m_scopep; }
@@ -83,7 +83,7 @@ public:
void asyncPath(bool flag) { m_asyncPath = flag; }
};
class CdcVarVertex : public CdcEitherVertex {
class CdcVarVertex final : public CdcEitherVertex {
AstVarScope* m_varScp;
int m_cntAsyncRst = 0;
bool m_fromFlop = false;
@@ -92,7 +92,7 @@ public:
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: CdcEitherVertex{graphp, scopep, varScp}
, m_varScp{varScp} {}
virtual ~CdcVarVertex() override {}
virtual ~CdcVarVertex() override = default;
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
@@ -105,7 +105,7 @@ public:
void fromFlop(bool flag) { m_fromFlop = flag; }
};
class CdcLogicVertex : public CdcEitherVertex {
class CdcLogicVertex final : public CdcEitherVertex {
bool m_hazard : 1;
bool m_isFlop : 1;
@@ -117,7 +117,7 @@ public:
srcDomainp(sensenodep);
dstDomainp(sensenodep);
}
virtual ~CdcLogicVertex() override {}
virtual ~CdcLogicVertex() override = default;
// ACCESSORS
virtual string name() const override {
return (cvtToHex(nodep()) + "@" + scopep()->prettyName());
@@ -135,7 +135,7 @@ public:
//######################################################################
class CdcDumpVisitor : public CdcBaseVisitor {
class CdcDumpVisitor final : public CdcBaseVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -150,7 +150,7 @@ private:
} else {
*m_ofp << " ";
}
*m_ofp << nodep->prettyTypeName() << " " << endl;
*m_ofp << nodep->prettyTypeName() << "\n";
string lastPrefix = m_prefix;
m_prefix = lastPrefix + "1:";
iterateAndNextNull(nodep->op1p());
@@ -170,12 +170,12 @@ public:
, m_prefix{prefix} {
iterate(nodep);
}
virtual ~CdcDumpVisitor() override {}
virtual ~CdcDumpVisitor() override = default;
};
//######################################################################
class CdcWidthVisitor : public CdcBaseVisitor {
class CdcWidthVisitor final : public CdcBaseVisitor {
private:
int m_maxLineno = 0;
size_t m_maxFilenameLen = 0;
@@ -194,7 +194,7 @@ private:
public:
// CONSTRUCTORS
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~CdcWidthVisitor() override {}
virtual ~CdcWidthVisitor() override = default;
// ACCESSORS
int maxWidth() const {
size_t width = 1;
@@ -209,7 +209,7 @@ public:
//######################################################################
// Cdc class functions
class CdcVisitor : public CdcBaseVisitor {
class CdcVisitor final : public CdcBaseVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -292,7 +292,7 @@ private:
told_file = true;
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
}
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << '\n';
}
void setNodeHazard(AstNode* nodep) {
@@ -311,13 +311,12 @@ private:
}
}
string spaces(int level) {
static string spaces(int level) {
string out;
while (level--) out += " ";
return out;
} // LCOV_EXCL_LINE
string pad(unsigned column, const string& in) {
static string pad(unsigned column, const string& in) {
string out = in;
while (out.length() < column) out += ' ';
return out;
@@ -463,7 +462,7 @@ private:
string front
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
if (VN_IS(nodep, VarScope)) {
*m_ofp << front << "Variable: " << nodep->prettyName() << endl;
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
} else {
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(),
vertexp->srcDomainp(), true);
@@ -510,7 +509,7 @@ private:
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
const std::unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
if (ofp->fail()) v3fatal("Can't write " << filename);
*ofp << "Edge Report for " << v3Global.opt.prefix() << endl;
*ofp << "Edge Report for " << v3Global.opt.prefix() << '\n';
std::deque<string> report; // Sort output by name
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
@@ -537,7 +536,7 @@ private:
V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
}
os << std::setw(0);
os << endl;
os << '\n';
report.push_back(os.str());
}
}
@@ -588,15 +587,15 @@ private:
// Convert list of senses into one sense node
AstSenTree* senoutp = nullptr;
bool senedited = false;
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
for (const auto& itr : senouts) {
if (!senoutp) {
senoutp = *it;
senoutp = itr;
} else {
if (!senedited) {
senedited = true;
senoutp = senoutp->cloneTree(true);
}
senoutp->addSensesp((*it)->sensesp()->cloneTree(true));
senoutp->addSensesp(itr->sensesp()->cloneTree(true));
}
}
// If multiple domains need to do complicated optimizations
@@ -661,7 +660,7 @@ private:
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
// When simplify we'll take the MAX weight
if (nodep->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
if (m_inDly) {
varvertexp->fromFlop(true);
@@ -733,7 +732,7 @@ public:
m_ofp = V3File::new_ofstream(filename);
if (m_ofp->fail()) v3fatal("Can't write " << filename);
m_ofFilename = filename;
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << endl;
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << '\n';
*m_ofp
<< "Each dump below traces logic from inputs/source flops to destination flop(s).\n";
*m_ofp << "First source logic is listed, then a variable that logic generates,\n";
@@ -746,7 +745,7 @@ public:
if (false) {
*m_ofp << "\nDBG-test-dumper\n";
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true);
*m_ofp << endl;
*m_ofp << '\n';
}
}
virtual ~CdcVisitor() override {
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Cdc {
class V3Cdc final {
public:
static void cdcAll(AstNetlist* nodep);
};
+9 -10
View File
@@ -38,7 +38,7 @@
//######################################################################
class ChangedState {
class ChangedState final {
public:
// STATE
AstNodeModule* m_topModp = nullptr; // Top module
@@ -48,8 +48,8 @@ public:
int m_numStmts = 0; // Number of statements added to m_chgFuncp
int m_funcNum = 0; // Number of change functions emitted
ChangedState() {}
~ChangedState() {}
ChangedState() = default;
~ChangedState() = default;
void maybeCreateChgFuncp() {
// Don't create an extra function call if splitting is disabled
@@ -94,7 +94,7 @@ public:
//######################################################################
// Utility visitor to find elements to be compared
class ChangedInsertVisitor : public AstNVisitor {
class ChangedInsertVisitor final : public AstNVisitor {
private:
// STATE
ChangedState* m_statep; // Shared state across visitors
@@ -117,10 +117,9 @@ private:
"Unsupported: Can't detect more than "
<< cvtToStr(DETECTARRAY_MAX_INDEXES)
<< " array indexes (probably with UNOPTFLAT warning suppressed): "
<< m_vscp->prettyName() << endl
<< m_vscp->prettyName() << '\n'
<< m_vscp->warnMore()
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased"
<< endl);
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased");
return;
}
m_statep->maybeCreateChgFuncp();
@@ -208,14 +207,14 @@ public:
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
}
virtual ~ChangedInsertVisitor() override {}
virtual ~ChangedInsertVisitor() override = default;
VL_UNCOPYABLE(ChangedInsertVisitor);
};
//######################################################################
// Changed state, as a visitor of each AstNode
class ChangedVisitor : public AstNVisitor {
class ChangedVisitor final : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -280,7 +279,7 @@ public:
: m_statep{statep} {
iterate(nodep);
}
virtual ~ChangedVisitor() override {}
virtual ~ChangedVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Changed {
class V3Changed final {
public:
static void changedAll(AstNetlist* nodep);
};
+37 -10
View File
@@ -29,12 +29,14 @@
//######################################################################
class ClassVisitor : public AstNVisitor {
class ClassVisitor final : public AstNVisitor {
private:
// MEMBERS
AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep = nullptr; // Package moving scopes into
AstScope* m_packageScopep = nullptr; // Class package scope
AstNodeFTask* m_ftaskp = nullptr; // Current task
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
MoveVector m_moves;
@@ -54,7 +56,7 @@ private:
// Note origName is the same as the class origName so errors look correct
AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName());
packagep->name(nodep->name() + "__Vclpkg");
nodep->packagep(packagep);
nodep->classOrPackagep(packagep);
packagep->classp(nodep);
v3Global.rootp()->addModulep(packagep);
// Add package to hierarchy
@@ -76,14 +78,17 @@ private:
packagep->addStmtp(scopep);
// Iterate
VL_RESTORER(m_prefix);
VL_RESTORER(m_classScopep);
VL_RESTORER(m_packageScopep);
{
m_classScopep = classScopep;
m_packageScopep = scopep;
m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep);
}
m_classScopep = nullptr;
}
virtual void visit(AstPackage* nodep) override {
virtual void visit(AstNodeModule* nodep) override {
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
VL_RESTORER(m_prefix);
{
m_prefix = nodep->name() + "__03a__03a"; // ::
@@ -94,11 +99,28 @@ private:
virtual void visit(AstVar* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move class statics only
// if (m_classScopep) {
// m_moves.push_back(make_pair(nodep, m_classScopep));
//}
// TODO move class statics too
if (m_packageScopep && m_ftaskp && m_ftaskp->lifetime().isStatic()) {
m_moves.push_back(make_pair(nodep, m_packageScopep));
}
}
virtual void visit(AstVarScope* nodep) override {
iterateChildren(nodep);
nodep->varp()->user1p(nodep);
}
virtual void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_ftaskp);
{
m_ftaskp = nodep;
iterateChildren(nodep);
if (m_packageScopep && nodep->lifetime().isStatic()) {
m_moves.push_back(make_pair(nodep, m_packageScopep));
}
}
}
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
@@ -116,8 +138,13 @@ public:
// CONSTRUCTORS
explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ClassVisitor() override {
for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) {
it->second->addVarp(it->first->unlinkFrBack());
for (auto moved : m_moves) {
if (VN_IS(moved.first, NodeFTask)) {
moved.second->addActivep(moved.first->unlinkFrBack());
} else if (VN_IS(moved.first, Var)) {
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
moved.second->addVarp(scopep->unlinkFrBack());
}
}
}
};
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Class {
class V3Class final {
public:
static void classAll(AstNetlist* nodep);
};
+7 -2
View File
@@ -35,7 +35,7 @@
//######################################################################
// Clean state, as a visitor of each AstNode
class CleanVisitor : public AstNVisitor {
class CleanVisitor final : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -285,6 +285,11 @@ private:
ensureCleanAndNext(nodep->pinsp());
setClean(nodep, true);
}
virtual void visit(AstWith* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->exprp());
setClean(nodep, true);
}
virtual void visit(AstIntfRef* nodep) override {
iterateChildren(nodep);
setClean(nodep, true); // generates a string, so not relevant
@@ -300,7 +305,7 @@ private:
public:
// CONSTRUCTORS
explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CleanVisitor() override {}
virtual ~CleanVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Clean {
class V3Clean final {
public:
static void cleanAll(AstNetlist* nodep);
};
+12 -12
View File
@@ -40,7 +40,7 @@
//######################################################################
// Clock state, as a visitor of each AstNode
class ClockVisitor : public AstNVisitor {
class ClockVisitor final : public AstNVisitor {
private:
// NODE STATE
// Cleared each Module:
@@ -293,7 +293,7 @@ private:
}
m_scopep = nullptr;
}
virtual void visit(AstAlways* nodep) override {
virtual void visit(AstNodeProcedure* nodep) override {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
@@ -311,6 +311,15 @@ private:
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstAlwaysPostponed* nodep) override {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCoverToggle* nodep) override {
// nodep->dumpTree(cout, "ct:");
// COVERTOGGLE(INC, ORIG, CHANGE) ->
@@ -328,15 +337,6 @@ private:
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstInitial* nodep) override {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Link to global function
@@ -454,7 +454,7 @@ public:
// easily without iterating through the tree.
nodep->evalp(m_evalFuncp);
}
virtual ~ClockVisitor() override {}
virtual ~ClockVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Clock {
class V3Clock final {
public:
static void clockAll(AstNetlist* nodep);
};
+16 -16
View File
@@ -51,19 +51,19 @@ constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth m
//######################################################################
class CombBaseVisitor : public AstNVisitor {
class CombBaseVisitor VL_NOT_FINAL : public AstNVisitor {
protected:
// STATE
// METHODS
virtual ~CombBaseVisitor() override {}
virtual ~CombBaseVisitor() override = default;
VL_DEBUG_FUNC; // Declare debug()
};
//######################################################################
// Combine replacement function
class CombCallVisitor : CombBaseVisitor {
class CombCallVisitor final : CombBaseVisitor {
// Find all CCALLS of each CFUNC, so that we can later rename them
private:
// NODE STATE
@@ -131,15 +131,15 @@ private:
public:
// CONSTRUCTORS
CombCallVisitor() {}
virtual ~CombCallVisitor() override {}
CombCallVisitor() = default;
virtual ~CombCallVisitor() override = default;
void main(AstNetlist* nodep) { iterate(nodep); }
};
//######################################################################
// Combine marking function
class CombMarkVisitor : CombBaseVisitor {
class CombMarkVisitor final : CombBaseVisitor {
// Mark all nodes under specified one.
private:
// OUTPUT:
@@ -153,13 +153,13 @@ private:
public:
// CONSTRUCTORS
explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~CombMarkVisitor() override {}
virtual ~CombMarkVisitor() override = default;
};
//######################################################################
// Combine state, as a visitor of each AstNode
class CombineVisitor : CombBaseVisitor {
class CombineVisitor final : CombBaseVisitor {
private:
// NODE STATE
// Entire netlist:
@@ -177,7 +177,7 @@ private:
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state = STATE_IDLE; // Major state
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs = 0; // Number of functions made
#ifdef VL_COMBINE_STATEMENTS
@@ -203,8 +203,8 @@ private:
}
#endif
void walkEmptyFuncs() {
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* node1p = it->second;
for (const auto& itr : m_hashed) {
AstNode* node1p = itr.second;
AstCFunc* oldfuncp = VN_CAST(node1p, CFunc);
if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) {
UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " "
@@ -330,7 +330,7 @@ private:
AstNode* last2p) { // Final node in linked list, maybe null if all statements
// to be grabbed
// Make new function
string oldname = m_funcp->name();
string oldname = m_cfuncp->name();
string::size_type pos;
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
@@ -423,7 +423,8 @@ private:
m_modp = nullptr;
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
VL_RESTORER(m_cfuncp);
m_cfuncp = nodep;
if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) {
hashStatement(nodep); // Hash the entire function - it might be identical
@@ -434,18 +435,17 @@ private:
}
#endif
}
m_funcp = nullptr;
}
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
if (m_state == STATE_HASH && m_funcp) {
if (m_state == STATE_HASH && m_cfuncp) {
hashStatement(nodep);
}
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP && m_funcp) {
else if (m_state == STATE_DUP && m_cfuncp) {
walkDupCodeStart(nodep);
}
#endif
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Combine {
class V3Combine final {
public:
static void combineAll(AstNetlist* nodep);
};
+26 -33
View File
@@ -33,13 +33,13 @@
// cache of resolved entities. Entities stored in this container need an update
// function that takes a reference of this type to join multiple entities into one.
template <typename T> class V3ConfigWildcardResolver {
typedef std::map<string, T> Map;
typedef std::map<const string, T> Map;
Map m_mapWildcard; // Wildcard strings to entities
Map m_mapResolved; // Resolved strings to converged entities
public:
V3ConfigWildcardResolver() {}
~V3ConfigWildcardResolver() {}
V3ConfigWildcardResolver() = default;
~V3ConfigWildcardResolver() = default;
/// Update into maps from other
void update(const V3ConfigWildcardResolver& other) {
@@ -82,7 +82,7 @@ public:
};
// Only public_flat_rw has the sensitity tree
class V3ConfigVarAttr {
class V3ConfigVarAttr final {
public:
AstAttrType m_type; // Type of attribute
AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw
@@ -92,7 +92,7 @@ public:
};
// Overload vector with the required update function and to apply all entries
class V3ConfigVar : public std::vector<V3ConfigVarAttr> {
class V3ConfigVar final : public std::vector<V3ConfigVarAttr> {
public:
// Update from other by copying all attributes
void update(const V3ConfigVar& node) {
@@ -116,14 +116,14 @@ typedef V3ConfigWildcardResolver<V3ConfigVar> V3ConfigVarResolver;
//######################################################################
// Function or task: Have variables and properties
class V3ConfigFTask {
class V3ConfigFTask final {
V3ConfigVarResolver m_vars; // Variables in function/task
bool m_isolate = false; // Isolate function return
bool m_noinline = false; // Don't inline function/task
bool m_public = false; // Public function/task
public:
V3ConfigFTask() {}
V3ConfigFTask() = default;
void update(const V3ConfigFTask& f) {
// Don't overwrite true with false
if (f.m_isolate) m_isolate = true;
@@ -153,7 +153,7 @@ typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
//######################################################################
// Modules have tasks, variables, named blocks and properties
class V3ConfigModule {
class V3ConfigModule final {
typedef std::unordered_set<string> StringSet;
typedef std::set<AstPragmaType> PragmaSet;
@@ -165,7 +165,7 @@ class V3ConfigModule {
bool m_inlineValue = false; // The inline value (on/off)
public:
V3ConfigModule() {}
V3ConfigModule() = default;
void update(const V3ConfigModule& m) {
m_tasks.update(m.m_tasks);
@@ -224,7 +224,7 @@ typedef V3ConfigWildcardResolver<V3ConfigModule> V3ConfigModuleResolver;
// - Line attributes: Attributes attached to lines
// lint/coverage/tracing on/off
class V3ConfigIgnoresLine {
class V3ConfigIgnoresLine final {
public:
int m_lineno; // Line number to make change at
V3ErrorCode m_code; // Error code
@@ -233,8 +233,8 @@ public:
: m_lineno{lineno}
, m_code{code}
, m_on{on} {}
~V3ConfigIgnoresLine() {}
inline bool operator<(const V3ConfigIgnoresLine& rh) const {
~V3ConfigIgnoresLine() = default;
bool operator<(const V3ConfigIgnoresLine& rh) const {
if (m_lineno < rh.m_lineno) return true;
if (m_lineno > rh.m_lineno) return false;
if (m_code < rh.m_code) return true;
@@ -253,7 +253,7 @@ std::ostream& operator<<(std::ostream& os, const V3ConfigIgnoresLine& rhs) {
typedef std::bitset<AstPragmaType::ENUM_SIZE> V3ConfigLineAttribute;
// File entity
class V3ConfigFile {
class V3ConfigFile final {
typedef std::map<int, V3ConfigLineAttribute> LineAttrMap; // Map line->bitset of attributes
typedef std::multiset<V3ConfigIgnoresLine> IgnLines; // list of {line,code,on}
typedef std::pair<V3ErrorCode, string> WaiverSetting; // Waive code if string matches
@@ -282,15 +282,9 @@ public:
}
void update(const V3ConfigFile& file) {
// Copy in all Attributes
for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin();
it != file.m_lineAttrs.end(); ++it) {
m_lineAttrs[it->first] |= it->second;
}
for (const auto& itr : file.m_lineAttrs) { m_lineAttrs[itr.first] |= itr.second; }
// Copy in all ignores
for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end();
++it) {
m_ignLines.insert(*it);
}
for (const auto& ignLine : file.m_ignLines) m_ignLines.insert(ignLine);
// Update the iterator after the list has changed
m_lastIgnore.it = m_ignLines.begin();
m_waivers.reserve(m_waivers.size() + file.m_waivers.size());
@@ -338,9 +332,9 @@ public:
}
}
bool waive(V3ErrorCode code, const string& match) {
for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) {
if (((it->first == code) || (it->first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, it->second)) {
for (const auto& itr : m_waivers) {
if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, itr.second)) {
return true;
}
}
@@ -353,16 +347,16 @@ typedef V3ConfigWildcardResolver<V3ConfigFile> V3ConfigFileResolver;
//######################################################################
// Resolve modules and files in the design
class V3ConfigResolver {
class V3ConfigResolver final {
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow)
V3ConfigResolver() {}
~V3ConfigResolver() {}
V3ConfigResolver() = default;
~V3ConfigResolver() = default;
public:
inline static V3ConfigResolver& s() { return s_singleton; }
static V3ConfigResolver& s() { return s_singleton; }
V3ConfigModuleResolver& modules() { return m_modules; }
V3ConfigFileResolver& files() { return m_files; }
@@ -411,7 +405,7 @@ void V3Config::addInline(FileLine* fl, const string& module, const string& ftask
V3ConfigResolver::s().modules().at(module).setInline(on);
} else {
if (!on) {
fl->v3error("no_inline not supported for tasks" << endl);
fl->v3error("no_inline not supported for tasks");
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setNoInline(on);
}
@@ -422,15 +416,14 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
const string& var, AstAttrType attr, AstSenTree* sensep) {
// Semantics: sensep only if public_flat_rw
if ((attr != AstAttrType::VAR_PUBLIC_FLAT_RW) && sensep) {
sensep->v3error("sensitivity not expected for attribute" << endl);
sensep->v3error("sensitivity not expected for attribute");
return;
}
// Semantics: Most of the attributes operate on signals
if (var.empty()) {
if (attr == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
if (ftask.empty()) {
fl->v3error("isolate_assignments only applies to signals or functions/tasks"
<< endl);
fl->v3error("isolate_assignments only applies to signals or functions/tasks");
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setIsolate(true);
}
@@ -443,7 +436,7 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
}
} else {
fl->v3error("missing -signal" << endl);
fl->v3error("missing -signal");
}
} else {
V3ConfigModule& mod = V3ConfigResolver::s().modules().at(module);
+1 -1
View File
@@ -26,7 +26,7 @@
//######################################################################
class V3Config {
class V3Config final {
public:
static void addCaseFull(const string& file, int lineno);
static void addCaseParallel(const string& file, int lineno);
+27 -21
View File
@@ -36,7 +36,7 @@
//######################################################################
// Utilities
class ConstVarMarkVisitor : public AstNVisitor {
class ConstVarMarkVisitor final : public AstNVisitor {
// NODE STATE
// AstVar::user4p -> bool, Var marked, 0=not set yet
private:
@@ -52,10 +52,10 @@ public:
AstNode::user4ClearTree(); // Check marked InUse before we're called
iterate(nodep);
}
virtual ~ConstVarMarkVisitor() override {}
virtual ~ConstVarMarkVisitor() override = default;
};
class ConstVarFindVisitor : public AstNVisitor {
class ConstVarFindVisitor final : public AstNVisitor {
// NODE STATE
// AstVar::user4p -> bool, input from ConstVarMarkVisitor
// MEMBERS
@@ -71,7 +71,7 @@ private:
public:
// CONSTRUCTORS
explicit ConstVarFindVisitor(AstNode* nodep) { iterateAndNextNull(nodep); }
virtual ~ConstVarFindVisitor() override {}
virtual ~ConstVarFindVisitor() override = default;
// METHODS
bool found() const { return m_found; }
};
@@ -79,7 +79,7 @@ public:
//######################################################################
// Const state, as a visitor of each AstNode
class ConstVisitor : public AstNVisitor {
class ConstVisitor final : public AstNVisitor {
private:
// NODE STATE
// ** only when m_warn/m_doExpensive is set. If state is needed other times,
@@ -314,7 +314,7 @@ private:
// It was an expression, then got constified. In reality, the WordSel
// must be wrapped in a Cond, that will be false.
return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef)
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isWrite()
&& VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isReadOnly()
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
}
@@ -1262,7 +1262,7 @@ private:
AstNode* errorp = simvis.whyNotNodep();
if (!errorp) errorp = nodep;
nodep->v3error("Expecting expression to be constant, but can't determine constant for "
<< nodep->prettyTypeName() << endl
<< nodep->prettyTypeName() << '\n'
<< errorp->warnOther() << "... Location of non-constant "
<< errorp->prettyTypeName() << ": " << simvis.whyNotMessage());
VL_DO_DANGLING(replaceZero(nodep), nodep);
@@ -1297,17 +1297,21 @@ private:
virtual void visit(AstCFunc* nodep) override {
// No ASSIGNW removals under funcs, we've long eliminated INITIALs
// (We should perhaps rename the assignw's to just assigns)
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
VL_RESTORER(m_wremove);
{
m_wremove = false;
iterateChildren(nodep);
}
}
virtual void visit(AstScope* nodep) override {
// No ASSIGNW removals under scope, we've long eliminated INITIALs
m_scopep = nodep;
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
m_scopep = nullptr;
VL_RESTORER(m_wremove);
VL_RESTORER(m_scopep);
{
m_wremove = false;
m_scopep = nodep;
iterateChildren(nodep);
}
}
void swapSides(AstNodeBiCom* nodep) {
@@ -1605,7 +1609,7 @@ private:
// if (debug()) valuep->dumpTree(cout, " visitvaref: ");
iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep()
AstNode* valuep = nodep->varp()->valuep();
if (!nodep->access().isWrite()
if (nodep->access().isReadOnly()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
@@ -1726,7 +1730,7 @@ private:
}
struct SenItemCmp {
inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
if (lhsp->type() < rhsp->type()) return true;
if (lhsp->type() > rhsp->type()) return false;
// Looks visually better if we keep sorted by name
@@ -1926,8 +1930,9 @@ private:
nodep->replaceWith(ifp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (ifSameAssign(nodep)) {
UINFO(4, "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"
<< endl);
UINFO(
4,
"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})\n");
AstNodeAssign* ifp = VN_CAST(nodep->ifsp(), NodeAssign);
AstNodeAssign* elsep = VN_CAST(nodep->elsesp(), NodeAssign);
ifp->unlinkFrBack();
@@ -1937,7 +1942,8 @@ private:
ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep));
nodep->replaceWith(ifp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
} else if (false // Disabled, as vpm assertions are faster
// without due to short-circuiting
&& operandIfIf(nodep)) {
UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl);
AstNodeIf* lowerIfp = VN_CAST(nodep->ifsp(), NodeIf);
@@ -2558,7 +2564,7 @@ public:
}
// clang-format on
}
virtual ~ConstVisitor() override {}
virtual ~ConstVisitor() override = default;
AstNode* mainAcceptEdit(AstNode* nodep) {
// Operate starting at a random place
return iterateSubtreeReturnEdits(nodep);
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Const {
class V3Const final {
public:
static AstNode* constifyParamsEdit(AstNode* nodep);
static AstNode* constifyGenerateParamsEdit(AstNode* nodep);
+8 -8
View File
@@ -37,7 +37,7 @@
//######################################################################
// Coverage state, as a visitor of each AstNode
class CoverageVisitor : public AstNVisitor {
class CoverageVisitor final : public AstNVisitor {
private:
// TYPES
typedef std::unordered_map<string, int> VarNameMap;
@@ -52,7 +52,7 @@ private:
: m_comment{comment}
, m_varRefp{vp}
, m_chgRefp{cp} {}
~ToggleEnt() {}
~ToggleEnt() = default;
void cleanup() {
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = nullptr);
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = nullptr);
@@ -64,7 +64,7 @@ private:
bool m_inModOff = false; // In module with no coverage
int m_handle = 0; // Opaque handle for index into line tracking
const AstNode* m_nodep = nullptr; // Node establishing this state
CheckState() {}
CheckState() = default;
bool lineCoverageOn(const AstNode* nodep) const {
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
&& v3Global.opt.coverageLine();
@@ -188,15 +188,15 @@ private:
const LinenoSet& lines = m_handleLines[state.m_handle];
int first = 0;
int last = 0;
for (LinenoSet::iterator it = lines.begin(); it != lines.end(); ++it) {
for (int linen : lines) {
if (!first) {
first = last = *it;
} else if (*it == last + 1) {
first = last = linen;
} else if (linen == last + 1) {
++last;
} else {
if (!out.empty()) out += ",";
out += linesFirstLast(first, last);
first = last = *it;
first = last = linen;
}
}
if (first) {
@@ -534,7 +534,7 @@ private:
public:
// CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }
virtual ~CoverageVisitor() override {}
virtual ~CoverageVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Coverage {
class V3Coverage final {
public:
// CONSTRUCTORS
static void coverage(AstNetlist* rootp);
+1 -1
View File
@@ -30,7 +30,7 @@
//######################################################################
// CoverageJoin state, as a visitor of each AstNode
class CoverageJoinVisitor : public AstNVisitor {
class CoverageJoinVisitor final : public AstNVisitor {
private:
// NODE STATE
// V3Hashed
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3CoverageJoin {
class V3CoverageJoin final {
public:
// CONSTRUCTORS
static void coverageJoin(AstNetlist* rootp);
+54 -55
View File
@@ -30,9 +30,8 @@
// Note on packagep: After the V3Scope/V3LinkDotScoped stage, package links
// are no longer used, but their presence prevents us from removing empty
// packages. As the links as no longer used after V3Scope, we remove them
// here after scoping to allow more dead node
// removal.
// *************************************************************************
// here after scoping to allow more dead node removal.
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -46,7 +45,7 @@
//######################################################################
class DeadModVisitor : public AstNVisitor {
class DeadModVisitor final : public AstNVisitor {
// In a module that is dead, cleanup the in-use counts of the modules
private:
// NODE STATE
@@ -63,13 +62,13 @@ private:
public:
// CONSTRUCTORS
explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); }
virtual ~DeadModVisitor() override {}
virtual ~DeadModVisitor() override = default;
};
//######################################################################
// Dead state, as a visitor of each AstNode
class DeadVisitor : public AstNVisitor {
class DeadVisitor final : public AstNVisitor {
private:
// NODE STATE
// Entire Netlist:
@@ -83,7 +82,7 @@ private:
typedef std::multimap<AstVarScope*, AstNodeAssign*> AssignMap;
// STATE
AstNodeModule* m_modp; // Current module
AstNodeModule* m_modp = nullptr; // Current module
// List of all encountered to avoid another loop through tree
std::vector<AstVar*> m_varsp;
std::vector<AstNode*> m_dtypesp;
@@ -93,10 +92,10 @@ private:
std::vector<AstClass*> m_classesp;
AssignMap m_assignMap; // List of all simple assignments for each variable
bool m_elimUserVars; // Allow removal of user's vars
bool m_elimDTypes; // Allow removal of DTypes
bool m_elimCells; // Allow removal of Cells
bool m_sideEffect; // Side effects discovered in assign RHS
const bool m_elimUserVars; // Allow removal of user's vars
const bool m_elimDTypes; // Allow removal of DTypes
const bool m_elimCells; // Allow removal of Cells
bool m_sideEffect = false; // Side effects discovered in assign RHS
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -107,6 +106,9 @@ private:
}
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
}
void checkVarRef(AstNodeVarRef* nodep) {
if (nodep->classOrPackagep() && m_elimCells) nodep->classOrPackagep(nullptr);
}
void checkDType(AstNodeDType* nodep) {
if (!nodep->generic() // Don't remove generic types
&& m_elimDTypes // dtypes stick around until post-widthing
@@ -120,6 +122,7 @@ private:
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
if (m_modp) m_modp->user1Inc(); // e.g. Class under Package
VL_RESTORER(m_modp);
{
m_modp = nodep;
@@ -128,7 +131,7 @@ private:
checkAll(nodep);
if (AstClass* classp = VN_CAST(nodep, Class)) {
if (classp->extendsp()) classp->extendsp()->user1Inc();
if (classp->packagep()) classp->packagep()->user1Inc();
if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc();
m_classesp.push_back(classp);
// TODO we don't reclaim dead classes yet - graph implementation instead?
classp->user1Inc();
@@ -160,29 +163,25 @@ private:
}
virtual void visit(AstNodeVarRef* nodep) override {
// Note NodeAssign skips calling this in some cases
iterateChildren(nodep);
checkAll(nodep);
checkVarRef(nodep);
if (nodep->varScopep()) {
nodep->varScopep()->user1Inc();
nodep->varScopep()->varp()->user1Inc();
}
if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->packagep()) {
if (m_elimCells) {
nodep->packagep(nullptr);
} else {
nodep->packagep()->user1Inc();
}
}
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc();
}
virtual void visit(AstNodeFTaskRef* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (nodep->classOrPackagep()) {
if (m_elimCells) {
nodep->packagep(nullptr);
nodep->classOrPackagep(nullptr);
} else {
nodep->packagep()->user1Inc();
nodep->classOrPackagep()->user1Inc();
}
}
}
@@ -196,11 +195,11 @@ private:
checkAll(nodep);
UASSERT_OBJ(!(m_elimCells && nodep->typedefp()), nodep,
"RefDType should point to data type before typedefs removed");
if (nodep->packagep()) {
if (nodep->classOrPackagep()) {
if (m_elimCells) {
nodep->packagep(nullptr);
nodep->classOrPackagep(nullptr);
} else {
nodep->packagep()->user1Inc();
nodep->classOrPackagep()->user1Inc();
}
}
}
@@ -208,11 +207,11 @@ private:
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (nodep->classOrPackagep()) {
if (m_elimCells) {
nodep->packagep(nullptr);
nodep->classOrPackagep(nullptr);
} else {
nodep->packagep()->user1Inc();
nodep->classOrPackagep()->user1Inc();
}
}
if (nodep->classp()) nodep->classp()->user1Inc();
@@ -225,11 +224,11 @@ private:
virtual void visit(AstEnumItemRef* nodep) override {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (nodep->classOrPackagep()) {
if (m_elimCells) {
nodep->packagep(nullptr);
nodep->classOrPackagep(nullptr);
} else {
nodep->packagep()->user1Inc();
nodep->classOrPackagep()->user1Inc();
}
}
checkAll(nodep);
@@ -277,19 +276,22 @@ private:
// See if simple assignments to variables may be eliminated because
// that variable is never used.
// Similar code in V3Life
m_sideEffect = false;
iterateAndNextNull(nodep->rhsp());
checkAll(nodep);
// Has to be direct assignment without any EXTRACTing.
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
if (varrefp && !m_sideEffect
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
m_assignMap.insert(make_pair(varrefp->varScopep(), nodep));
checkAll(varrefp); // Must track reference to dtype()
} else { // Track like any other statement
iterateAndNextNull(nodep->lhsp());
VL_RESTORER(m_sideEffect);
{
m_sideEffect = false;
iterateAndNextNull(nodep->rhsp());
checkAll(nodep);
// Has to be direct assignment without any EXTRACTing.
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
if (varrefp && !m_sideEffect
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
m_assignMap.insert(make_pair(varrefp->varScopep(), nodep));
checkAll(varrefp); // Must track reference to dtype()
checkVarRef(varrefp);
} else { // Track like any other statement
iterateAndNextNull(nodep->lhsp());
}
}
checkAll(nodep);
}
//-----
@@ -367,14 +369,13 @@ private:
void deadCheckClasses() {
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
++it) {
if (AstClass* nodep = *it) { // nullptr if deleted earlier
for (auto& itr : m_classesp) {
if (AstClass* nodep = itr) { // nullptr if deleted earlier
if (nodep->user1() == 0) {
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
if (nodep->packagep()) nodep->packagep()->user1Inc(-1);
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(-1);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
*it = nullptr;
itr = nullptr;
retry = true;
}
}
@@ -439,12 +440,10 @@ private:
public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
bool elimCells) {
m_modp = nullptr;
m_elimCells = elimCells;
m_elimUserVars = elimUserVars;
m_elimDTypes = elimDTypes;
m_sideEffect = false;
bool elimCells)
: m_elimUserVars{elimUserVars}
, m_elimDTypes{elimDTypes}
, m_elimCells{elimCells} {
// Prepare to remove some datatypes
nodep->typeTablep()->clearCache();
// Operate on whole netlist
@@ -462,7 +461,7 @@ public:
// We may have removed some datatypes, cleanup
nodep->typeTablep()->repairCache();
}
virtual ~DeadVisitor() override {}
virtual ~DeadVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Dead {
class V3Dead final {
public:
// Modules, no vars/dtypes
static void deadifyModules(AstNetlist* nodep);
+17 -14
View File
@@ -63,7 +63,7 @@
//######################################################################
// Delayed state, as a visitor of each AstNode
class DelayedVisitor : public AstNVisitor {
class DelayedVisitor final : public AstNVisitor {
private:
// NODE STATE
// Cleared each module:
@@ -95,10 +95,10 @@ private:
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
bool m_inInitial = false; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
typedef std::map<const std::pair<AstNodeModule*, string>, AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<AstVarScope*, int> ScopeVecMap;
typedef std::unordered_map<const AstVarScope*, int> ScopeVecMap;
ScopeVecMap m_scopeVecMap; // Next var number for each scope
// METHODS
@@ -160,10 +160,10 @@ private:
varrefp->varp()->v3warn(
MULTIDRIVEN,
"Signal has multiple driving blocks with different clocking: "
<< varrefp->varp()->prettyNameQ() << endl
<< varrefp->warnOther() << "... Location of first driving block" << endl
<< varrefp->warnContextPrimary() << endl
<< oldactivep->warnOther() << "... Location of other driving block" << endl
<< varrefp->varp()->prettyNameQ() << '\n'
<< varrefp->warnOther() << "... Location of first driving block\n"
<< varrefp->warnContextPrimary() << '\n'
<< oldactivep->warnOther() << "... Location of other driving block\n"
<< oldactivep->warnContextSecondary());
varrefp->varp()->user2(true);
}
@@ -289,7 +289,7 @@ private:
new AstConst(nodep->fileline(), 0));
AstAssign* setassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
new AstConst(nodep->fileline(), AstConst::BitTrue()));
nodep->addNextHere(setassignp);
}
if (m_nextDlyp) { // Tell next assigndly it can share the variable
@@ -358,9 +358,11 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) override {
m_cfuncp = nodep;
iterateChildren(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
@@ -408,10 +410,11 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->access().isWrite()) {
if (m_inDly && nodep->access().isWriteOrRW()) {
UINFO(4, "AssignDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_DLY);
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
UASSERT_OBJ(!nodep->access().isRW(), nodep, "<= on read+write method");
if (!m_activep->hasClocked()) {
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
"have converted in V3Active");
@@ -433,7 +436,7 @@ private:
prep = new AstAssignPre(
nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
new AstConst(nodep->fileline(), AstConst::BitFalse()));
} else {
prep = new AstAssignPre(
nodep->fileline(),
@@ -456,7 +459,7 @@ private:
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!m_inDly && nodep->access().isWrite()) {
} else if (!m_inDly && nodep->access().isWriteOrRW()) {
// UINFO(9, "NBA " << nodep << endl);
if (!m_inInitial) {
UINFO(4, "AssignNDlyVar: " << nodep << endl);
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Delayed {
class V3Delayed final {
public:
static void delayedAll(AstNetlist* nodep);
};
+23 -19
View File
@@ -34,13 +34,13 @@
//######################################################################
class DepthVisitor : public AstNVisitor {
class DepthVisitor final : public AstNVisitor {
private:
// NODE STATE
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current block
AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement
int m_depth = 0; // How deep in an expression
int m_maxdepth = 0; // Maximum depth in an expression
@@ -61,8 +61,8 @@ private:
// bitmask instead of widths....)
// See t_func_crc for an example test that requires this
VFlagLogicPacked(), nodep->width());
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
m_funcp->addInitsp(varp);
UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function");
m_cfuncp->addInitsp(varp);
// Replace node tree with reference to var
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
nodep->replaceWith(newp);
@@ -81,23 +81,27 @@ private:
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_funcp = nullptr;
m_cfuncp = nullptr;
iterateChildren(nodep);
}
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
}
}
void visitStmt(AstNodeStmt* nodep) {
m_depth = 0;
m_maxdepth = 0;
m_stmtp = nodep;
iterateChildren(nodep);
m_stmtp = nullptr;
VL_RESTORER(m_stmtp);
{
m_stmtp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
}
}
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
@@ -128,10 +132,10 @@ private:
// Marking of non-static functions (because they might need "this")
// (Here instead of new visitor after V3Descope just to avoid another visitor)
void needNonStaticFunc(AstNode* nodep) {
UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function");
if (m_funcp->isStatic().trueUnknown()) {
UASSERT_OBJ(m_cfuncp, nodep, "Non-static accessor not under a function");
if (m_cfuncp->isStatic().trueUnknown()) {
UINFO(5, "Mark non-public due to " << nodep << endl);
m_funcp->isStatic(false);
m_cfuncp->isStatic(false);
}
}
virtual void visit(AstUCFunc* nodep) override {
@@ -151,7 +155,7 @@ private:
public:
// CONSTRUCTORS
explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DepthVisitor() override {}
virtual ~DepthVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Depth {
class V3Depth final {
public:
static void depthAll(AstNetlist* nodep);
};
+7 -7
View File
@@ -32,13 +32,13 @@
//######################################################################
class DepthBlockVisitor : public AstNVisitor {
class DepthBlockVisitor final : public AstNVisitor {
private:
// NODE STATE
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
int m_depth = 0; // How deep in an expression
int m_deepNum = 0; // How many functions made
@@ -49,11 +49,11 @@ private:
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
// Create function
string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum);
string name = m_cfuncp->name() + "__deep" + cvtToStr(++m_deepNum);
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr);
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->symProlog(true);
funcp->slow(m_funcp->slow());
funcp->slow(m_cfuncp->slow());
funcp->addStmtsp(nodep);
m_modp->addStmtp(funcp);
// Call it at the point where the body was removed from
@@ -78,10 +78,10 @@ private:
virtual void visit(AstCFunc* nodep) override {
// We recurse into this.
VL_RESTORER(m_depth);
VL_RESTORER(m_funcp);
VL_RESTORER(m_cfuncp);
{
m_depth = 0;
m_funcp = nodep;
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
@@ -117,7 +117,7 @@ private:
public:
// CONSTRUCTORS
explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DepthBlockVisitor() override {}
virtual ~DepthBlockVisitor() override = default;
};
//######################################################################
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3DepthBlock {
class V3DepthBlock final {
public:
static void depthBlockAll(AstNetlist* nodep);
};
+21 -6
View File
@@ -34,7 +34,7 @@
//######################################################################
class DescopeVisitor : public AstNVisitor {
class DescopeVisitor final : public AstNVisitor {
private:
// NODE STATE
// Cleared entire netlist
@@ -76,7 +76,8 @@ private:
// Sets 'hierThisr' true if the object is local to this scope
// (and could be made into a function-local later in V3Localize),
// false if the object is in another scope.
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = nullptr) {
string descopedName(bool& hierThisr, string& hierUnprot, const AstScope* scopep,
const AstVar* varp) {
UASSERT(scopep, "Var/Func not scoped");
hierThisr = (scopep == m_scopep);
@@ -118,6 +119,9 @@ private:
} else if (relativeRefOk && scopep == m_scopep) {
m_needThis = true;
return "this->";
} else if (VN_IS(scopep->modp(), Class)) {
hierUnprot = v3Global.opt.modPrefix() + "_"; // Prefix before protected part
return scopep->modp()->name() + "::";
} else if (relativeRefOk && scopep->aboveScopep() && scopep->aboveScopep() == m_scopep) {
// Reference to scope of cell directly under this module, can just "cell->"
string name = scopep->name();
@@ -249,12 +253,17 @@ private:
virtual void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep);
// Convert the hierch name
UINFO(9, " ref-in " << nodep << endl);
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
bool hierThis;
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis /*ref*/,
nodep->varScopep()->varp()));
string hierUnprot;
nodep->hiernameToProt(descopedName(hierThis /*ref*/, hierUnprot /*ref*/,
nodep->varScopep()->scopep(),
nodep->varScopep()->varp()));
nodep->hiernameToUnprot(hierUnprot);
nodep->hierThis(hierThis);
nodep->varScopep(nullptr);
UINFO(9, " refout " << nodep << endl);
}
virtual void visit(AstNodeCCall* nodep) override {
// UINFO(9, " " << nodep << endl);
@@ -263,11 +272,16 @@ private:
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
UASSERT_OBJ(nodep->funcp()->scopep(), nodep, "CFunc not under scope");
bool hierThis;
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis /*ref*/));
string hierUnprot;
nodep->hiernameToProt(
descopedName(hierThis /*ref*/, hierUnprot /*ref*/, nodep->funcp()->scopep(), nullptr));
nodep->hiernameToUnprot(hierUnprot);
// Can't do this, as we may have more calls later
// nodep->funcp()->scopep(nullptr);
}
virtual void visit(AstCFunc* nodep) override {
VL_RESTORER(m_needThis);
VL_RESTORER(m_allowThis);
if (!nodep->user1()) {
m_needThis = false;
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
@@ -294,7 +308,7 @@ private:
public:
// CONSTRUCTORS
explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~DescopeVisitor() override {}
virtual ~DescopeVisitor() override = default;
};
//######################################################################
@@ -302,6 +316,7 @@ public:
void V3Descope::descopeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
v3Global.assertScoped(false);
{ DescopeVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3Descope {
class V3Descope final {
public:
static void descopeAll(AstNetlist* nodep);
};
+147 -63
View File
@@ -23,6 +23,7 @@
#include "V3EmitCBase.h"
#include "V3Number.h"
#include "V3PartitionGraph.h"
#include "V3Task.h"
#include "V3TSP.h"
#include <algorithm>
@@ -38,7 +39,7 @@ constexpr int EMITC_NUM_CONSTW
//######################################################################
// Emit statements and math operators
class EmitCStmts : public EmitCBaseVisitor {
class EmitCStmts VL_NOT_FINAL : public EmitCBaseVisitor {
private:
typedef std::vector<const AstVar*> VarVec;
typedef std::map<int, VarVec> VarSortMap; // Map size class to VarVec
@@ -156,6 +157,7 @@ public:
}
void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) {
bool anyi = false;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
@@ -172,12 +174,15 @@ public:
}
} else if (varp->isString()) {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
puts("const std::string ");
puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name())
+ "(");
iterateAndNextNull(varp->valuep());
puts(")");
puts(");\n");
anyi = true;
} else {
puts("const std::string " + protect("var_" + varp->name()) + ";\n");
puts("static const std::string " + protect("var_" + varp->name())
+ ";\n");
}
} else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output
// putsDecoration("// enum ..... "+varp->nameProtect()
@@ -187,10 +192,12 @@ public:
->isOpaque()) { // Can't put out e.g. doubles
} else {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name())
+ "(");
iterateAndNextNull(varp->valuep());
puts(")");
puts(");\n");
anyi = true;
} else {
// enum
puts(varp->isQuad() ? "enum _QData" : "enum _IData");
@@ -198,17 +205,18 @@ public:
iterateAndNextNull(varp->valuep());
puts("};\n");
// var
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(varp->isQuad() ? "static const QData " : "static const IData ");
puts(protect("var_" + varp->name()) + ";\n");
}
}
}
}
}
if (anyi) puts("\n");
}
struct CmpName {
inline bool operator()(const AstNode* lhsp, const AstNode* rhsp) const {
bool operator()(const AstNode* lhsp, const AstNode* rhsp) const {
return lhsp->name() < rhsp->name();
}
};
@@ -418,6 +426,22 @@ public:
UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep,
"Statement of non-void data type");
}
virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
virtual void visit(AstWith* nodep) override {
// With uses a C++11 lambda
putbs("[=](");
if (auto* argrefp = nodep->indexArgRefp()) {
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
puts(",");
}
if (auto* argrefp = nodep->valueArgRefp()) {
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
}
// Probably fragile, V3Task may need to convert to a AstCReturn
puts(") { return ");
iterateAndNextNull(nodep->exprp());
puts("; }\n");
}
virtual void visit(AstIntfRef* nodep) override {
putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect()));
}
@@ -816,6 +840,9 @@ public:
putsQuoted(nodep->timeunit().ascii());
puts(");\n");
}
virtual void visit(AstRand* nodep) override {
emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr);
}
virtual void visit(AstTime* nodep) override {
puts("VL_TIME_UNITED_Q(");
if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units");
@@ -1225,7 +1252,6 @@ public:
nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName());
}
public:
EmitCStmts() {
m_suppressSemi = false;
m_wideTempRefp = nullptr;
@@ -1239,25 +1265,25 @@ public:
m_trackText = trackText;
iterate(nodep);
}
virtual ~EmitCStmts() override {}
virtual ~EmitCStmts() override = default;
};
//######################################################################
// Establish mtask variable sort order in mtasks mode
class EmitVarTspSorter : public V3TSP::TspStateBase {
class EmitVarTspSorter final : public V3TSP::TspStateBase {
private:
// MEMBERS
const MTaskIdSet& m_mtaskIds; // Mtask we're ordering
static unsigned m_serialNext; // Unique ID to establish serial order
static unsigned s_serialNext; // Unique ID to establish serial order
unsigned m_serial; // Serial ordering
public:
// CONSTRUCTORS
explicit EmitVarTspSorter(const MTaskIdSet& mtaskIds)
: m_mtaskIds(mtaskIds) { // Cannot be {} or GCC 4.8 false warning
m_serial = ++m_serialNext; // Cannot be ()/{} or GCC 4.8 false warning
m_serial = ++s_serialNext; // Cannot be ()/{} or GCC 4.8 false warning
}
virtual ~EmitVarTspSorter() {}
virtual ~EmitVarTspSorter() = default;
// METHODS
virtual bool operator<(const TspStateBase& other) const override {
return operator<(dynamic_cast<const EmitVarTspSorter&>(other));
@@ -1275,19 +1301,19 @@ public:
// Returns the number of elements in set_a that don't appear in set_b
static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) {
int diffs = 0;
for (MTaskIdSet::iterator it = set_a.begin(); it != set_a.end(); ++it) {
if (set_b.find(*it) == set_b.end()) ++diffs;
for (int i : set_a) {
if (set_b.find(i) == set_b.end()) ++diffs;
}
return diffs;
}
};
unsigned EmitVarTspSorter::m_serialNext = 0;
unsigned EmitVarTspSorter::s_serialNext = 0;
//######################################################################
// Internal EmitC implementation
class EmitCImp : EmitCStmts {
class EmitCImp final : EmitCStmts {
// MEMBERS
AstNodeModule* m_modp = nullptr;
std::vector<AstChangeDet*> m_blkChangeDetVec; // All encountered changes in block
@@ -1568,6 +1594,55 @@ class EmitCImp : EmitCStmts {
}
}
virtual void visit(AstConsAssoc* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
iterateAndNextNull(nodep->defaultp());
puts(")");
}
}
virtual void visit(AstSetAssoc* nodep) override {
iterateAndNextNull(nodep->lhsp());
putbs(".set(");
iterateAndNextNull(nodep->keyp());
puts(", ");
putbs("");
iterateAndNextNull(nodep->valuep());
puts(")");
}
virtual void visit(AstConsDynArray* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
puts(")");
}
}
virtual void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
puts(")");
}
}
virtual void visit(AstChangeDet* nodep) override { //
m_blkChangeDetVec.push_back(nodep);
}
@@ -1656,19 +1731,16 @@ class EmitCImp : EmitCStmts {
} else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (initarp->defaultp()) {
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi=0;");
puts(" for (; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n");
emitSetVarConstant(varp->nameProtect() + "[__Vi]",
VN_CAST(initarp->defaultp(), Const));
puts("}}\n");
puts("}\n");
}
const AstInitArray::KeyItemMap& mapr = initarp->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end();
++it) {
AstNode* valuep = it->second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(it->first) + "]",
for (const auto& itr : mapr) {
AstNode* valuep = itr.second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]",
VN_CAST(valuep, Const));
}
} else {
@@ -1704,12 +1776,11 @@ class EmitCImp : EmitCStmts {
UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(depth);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
string pre = ("{ int " + ivar + "=" + cvtToStr(0) + ";" + " for (; " + ivar + "<"
string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<"
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1,
suffix + "[" + ivar + "]");
string post = "}}\n";
string post = "}\n";
return below.empty() ? "" : pre + below + post;
} else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) {
// String's constructor deals with it
@@ -1776,8 +1847,8 @@ class EmitCImp : EmitCStmts {
void maybeSplit(AstNodeModule* modp);
public:
EmitCImp() {}
virtual ~EmitCImp() override {}
EmitCImp() = default;
virtual ~EmitCImp() override = default;
void mainImp(AstNodeModule* modp, bool slow);
void mainInt(AstNodeModule* modp);
void mainDoFunc(AstCFunc* nodep) { iterate(nodep); }
@@ -1839,6 +1910,16 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
puts(");\n");
} else {
// strings and other fundamental c types
if (nodep->isFuncLocal() && nodep->isString()) {
const string name = nodep->name();
const string suffix = V3Task::dpiTemporaryVarSuffix();
// string temporary variable for DPI-C needs to be static because c_str() will be
// passed to C code and the lifetime of the variable must be long enough. See also
// Issue 2622.
const bool beStatic = name.size() >= suffix.size()
&& name.substr(name.size() - suffix.size()) == suffix;
if (beStatic) puts("static VL_THREAD_LOCAL ");
}
puts(nodep->vlArgType(true, false, false, prefixIfImp));
puts(";\n");
}
@@ -2161,7 +2242,12 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
}
emitDispState.pushFormat(pfmt);
if (!ignore) {
emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin()));
if (argp->dtypep()->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
// string in SystemVerilog is std::string in C++ which is not POD
emitDispState.pushArg(' ', nullptr, "-1");
} else {
emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin()));
}
emitDispState.pushArg(fmtLetter, argp, "");
} else {
emitDispState.pushArg(fmtLetter, nullptr, "");
@@ -2272,7 +2358,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, const str
//######################################################################
// Internal EmitC
void EmitCImp::emitCoverageDecl(AstNodeModule* modp) {
void EmitCImp::emitCoverageDecl(AstNodeModule*) {
if (v3Global.opt.coverage()) {
ofp()->putsPrivate(true);
putsDecoration("// Coverage\n");
@@ -2319,6 +2405,9 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) {
void EmitCImp::emitCtorImp(AstNodeModule* modp) {
puts("\n");
bool first = true;
string section;
emitParams(modp, true, &first, section /*ref*/);
if (VN_IS(modp, Class)) {
modp->v3fatalSrc("constructors should be AstCFuncs instead");
} else if (optSystemC() && modp->isTop()) {
@@ -2329,8 +2418,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
}
emitVarCtors(&first);
if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first);
string section("");
emitParams(modp, true, &first, section /*ref*/);
puts(" {\n");
emitCellCtors(modp);
emitSensitives();
@@ -2397,7 +2485,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
splitSizeInc(10);
}
void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
void EmitCImp::emitCoverageImp(AstNodeModule*) {
if (v3Global.opt.coverage()) {
puts("\n// Coverage\n");
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
@@ -2499,10 +2587,8 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)',
// so declare in sep block
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";");
puts(" for (; " + ivar + "<" + cvtToStr(arrayp->elementsConst()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0));
puts("; " + ivar + "<" + cvtToStr(arrayp->elementsConst()));
puts("; ++" + ivar + ") {\n");
elementp = arrayp->subDTypep()->skipRefp();
}
@@ -2513,14 +2599,14 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
&& !(basicp && basicp->keyword() == AstBasicDTypeKwd::STRING)) {
int vecnum = vects++;
string ivar = string("__Vi") + cvtToStr(vecnum);
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";");
puts(" for (; " + ivar + "<" + cvtToStr(elementp->widthWords()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0));
puts("; " + ivar + "<" + cvtToStr(elementp->widthWords()));
puts("; ++" + ivar + ") {\n");
}
puts("os" + op + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}}\n");
for (int v = 0; v < vects; ++v) puts("}\n");
}
}
}
@@ -2588,16 +2674,14 @@ void EmitCImp::emitSensitives() {
UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb())
+ ";");
puts(" for (; " + ivar + "<=" + cvtToStr(arrayp->msb()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb()));
puts("; " + ivar + "<=" + cvtToStr(arrayp->msb()));
puts("; ++" + ivar + ") {\n");
}
puts("sensitive << " + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}}\n");
for (int v = 0; v < vects; ++v) puts("}\n");
}
}
}
@@ -2824,8 +2908,8 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
if (!v3Global.opt.mtasks()) {
// Plain old serial mode. Sort by size, from small to large,
// to optimize for both packing and small offsets in code.
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
for (VarVec::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) {
for (const auto& itr : vmap) {
for (VarVec::const_iterator jt = itr.second.begin(); jt != itr.second.end(); ++jt) {
sortedp->push_back(*jt);
}
}
@@ -2833,7 +2917,7 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
}
// MacroTask mode. Sort by MTask-affinity group first, size second.
typedef std::map<MTaskIdSet, VarSortMap> MTaskVarSortMap;
typedef std::map<const MTaskIdSet, VarSortMap> MTaskVarSortMap;
MTaskVarSortMap m2v;
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
int size_class = it->first;
@@ -2954,7 +3038,7 @@ void EmitCImp::emitMTaskState() {
puts("bool __Vm_even_cycle;\n");
}
void EmitCImp::emitIntTop(AstNodeModule* modp) {
void EmitCImp::emitIntTop(AstNodeModule*) {
// Always have this first; gcc has short circuiting if #ifdef is first in a file
ofp()->putsGuard();
puts("\n");
@@ -3150,13 +3234,13 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n// INTERNAL METHODS\n");
if (modp->isTop()) {
ofp()->putsPrivate(true); // private:
ofp()->putsPrivate(false); // public: as accessed by another VL_MODULE
puts("static void " + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar()
+ ");\n");
if (v3Global.needTraceDumper()) {
if (!optSystemC()) puts("void _traceDump();");
puts("void _traceDumpOpen();");
puts("void _traceDumpClose();");
if (!optSystemC()) puts("void _traceDump();\n");
puts("void _traceDumpOpen();\n");
puts("void _traceDumpClose();\n");
}
}
@@ -3324,14 +3408,14 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow) {
//######################################################################
// Tracing routines
class EmitCTrace : EmitCStmts {
class EmitCTrace final : EmitCStmts {
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user1() -> int. Enum number
AstUser1InUse m_inuser1;
// MEMBERS
AstCFunc* m_funcp = nullptr; // Function we're in now
AstCFunc* m_cfuncp = nullptr; // Function we're in now
bool m_slow; // Making slow file
int m_enumNum = 0; // Enumeration number (whole netlist)
int m_baseCode = -1; // Code of first AstTraceInc in this function
@@ -3663,8 +3747,9 @@ class EmitCTrace : EmitCStmts {
virtual void visit(AstNodeModule* nodep) override { iterateChildren(nodep); }
virtual void visit(AstCFunc* nodep) override {
if (nodep->slow() != m_slow) return;
VL_RESTORER(m_cfuncp);
if (nodep->funcType().isTrace()) { // TRACE_*
m_funcp = nodep;
m_cfuncp = nodep;
if (splitNeeded()) {
// Splitting file, so using parallel build.
@@ -3734,7 +3819,6 @@ class EmitCTrace : EmitCStmts {
}
puts("}\n");
}
m_funcp = nullptr;
}
virtual void visit(AstTraceDecl* nodep) override {
int enumNum = emitTraceDeclDType(nodep->dtypep());
@@ -3763,7 +3847,7 @@ class EmitCTrace : EmitCStmts {
public:
explicit EmitCTrace(bool slow)
: m_slow{slow} {}
virtual ~EmitCTrace() override {}
virtual ~EmitCTrace() override = default;
void main() {
// Put out the file
newOutCFile(0);
+1 -1
View File
@@ -25,7 +25,7 @@
//============================================================================
class V3EmitC {
class V3EmitC final {
public:
static void emitc();
static void emitcInlines();

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