Compare commits

...
269 Commits
Author SHA1 Message Date
Wilson Snyder 67dfa37c56 Version bump 2023-10-31 19:50:01 -04:00
Wilson Snyder 590188820d Commentary: Changes update 2023-10-31 19:49:40 -04:00
Ryszard Rozak a764c70b4a Fix handling of static keyword in methods (#4649) 2023-10-31 08:15:54 -04:00
Wilson Snyder a27abab65f Fix PCH to recompile on version change 2023-10-31 08:10:41 -04:00
Wilson Snyder c241ec90ec Commentary: Changes update 2023-10-30 22:10:03 -04:00
Krzysztof Bieganski f789d28277 Fix signals read via virtual iface optimized out (#4645)
Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-10-30 21:26:46 -04:00
Wilson Snyder c1c8b30a35 CI: Add lint-py action (#4640) 2023-10-30 08:02:54 -04:00
Wilson Snyder 15046c6c59 Commentary: Icarus URL (#4639) 2023-10-30 08:01:12 -04:00
Ícaro Lima 1da15181da Update CONTRIBUTORS (#4641) 2023-10-29 16:44:42 -04:00
Wilson Snyder 3c6b755352 Tests: Rename t_opt_dead 2023-10-29 09:42:52 -04:00
Geza Lore 3c144ada53 Delete AstNode user5 (#4638)
This saves about 5% memory. V3AstUserAllocator is appropriate for most use
cases, performance is marginally up as we are mostly D-cache bound on
large designs.
2023-10-29 01:12:27 +01:00
Wilson Snyder 7ba6647c4f Internals: Cleanup some V3Graph constructors/funcs and docs. No functional change. 2023-10-28 20:11:28 -04:00
Geza Lore e708670f9a Minor memory optimizatoin of AstUser*Allocator 2023-10-28 20:31:57 +01:00
Geza Lore de4c6065dc make: add test-snap/test-diff targets (#4635) 2023-10-28 15:58:29 +01:00
Geza Lore d60f180f43 Avoid double traversal of maps
The typical find/if-not-exists-insert pattern can be achieved with 1
lookup instead of 2 using emplace with a sentinel value. Also maps value
initialize their values when inserted with the [] operator, this is
defined and so there is no need to explicitly insert zeroes for integer
values.
2023-10-28 13:41:43 +01:00
Geza Lore 30318a6654 C++11 cleanup 2023-10-28 11:26:48 +01:00
Geza Lore d8420413b7 test: fix FST trace file names 2023-10-28 10:40:07 +01:00
Geza Lore a5951babfc test: make output deterministic 2023-10-28 10:36:30 +01:00
Geza Lore 2cba167634 Make eval loop construction more unified and the output more readable 2023-10-28 08:48:04 +01:00
Krzysztof Boroński 89743aae5d Fix stable name generation in V3Fork (#4615) (#4624) 2023-10-27 15:08:02 -04:00
Ryszard Rozak e6135981a5 Fix dynamic casts of null values (#4631) 2023-10-27 15:58:40 +02:00
Kamil Rakoczy 739521333c Tests: Fix clang_check_attributes missing dataclass decorator (#4604) (#4611) 2023-10-27 08:24:27 -04:00
Ryszard Rozak 64af83161a Fix rand fields of reference types (#4627) 2023-10-26 17:17:23 -04:00
Chih-Mao Chen 98252634fc Include systemc instead of systemc.h in model header files (#4622) (#4623)
This may require that SystemC programs add:
using namespace sc_core;
using namespace sc_dt;
2023-10-26 14:36:18 -04:00
Krzysztof Boroński a87fb57656 Allow assigning events (#4403)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-10-26 16:38:47 +02:00
Geza Lore 34708bbba1 Respect --dump-tree-addrids in tree dumps 2023-10-25 18:17:26 +01:00
Krzysztof BorońskiandWilson Snyder f91259f46d Fix insertion at queue's end (#4619)
Signed-off-by: Krzysztof Boronski <[email protected]>
Co-authored-by: Wilson Snyder <[email protected]>
2023-10-25 17:41:28 +02:00
Marlon James cf6e362972 Support VPI variables of real and string data types (#4594) 2023-10-24 20:46:20 -04:00
Geza Lore 95c4ade718 Unify code generation for trace declarations in both trace formats (#4612)
This patch adds some abstract enums to pass to the trace decl* APIs, so
the VCD/FST specific code can be kept in verilated_{vcd,fst}_*.cc, and
removed from V3Emit*. It also reworks the generation of the trace init
functions (those that call 'decl*' for the signals) such that the scope
hierarchy is traversed precisely once during initialization, which
simplifies the FST writer. This later change also has the side effect of
fixing tracing of nested interfaces when traced via an interface
reference - see the change in the expected t_interface_ref_trace - which
previously were missed.
2023-10-24 16:33:29 +01:00
Ryszard Rozak 84125d7c92 Fix virtual methods (#4616) 2023-10-24 15:51:46 +02:00
Geza Lore 17721aff55 Remove unused IMPLICITWIRE var type 2023-10-24 10:02:00 +01:00
Geza Lore d1b6224c2b Associate trace codes with function indices (#4610)
For each traced variable, also register the trace function index that
will write it.
2023-10-23 16:01:55 +01:00
github action 1bd31742b9 Apply 'make format' 2023-10-23 14:07:52 +01:00
Geza Lore 165a2ef1b8 Separate tracing of const values from non-const values
Some values emitted to the trace files are constant (e.g.: actual
parameter values), and never change. Previously we used to trace these
in the 'full' dumps, which also included all other truly variable
signals. This patch introduces a new generated trace function 'const',
to complement the 'full' and 'chg' flavour, and 'const' now only
contains the constant signals, while 'full' and 'chg' contain only the
truly variable signals. The generate 'full' and 'chg' trace functions
now have exactly the same shape. Note that 'const' signals are still
traced using the 'full*' dump methods of the trace buffers, so there is
no need for a third flavour of those.
2023-10-23 14:07:52 +01:00
Ryszard Rozak 774c10396c Fix try_put method of unbounded mailbox (#4608) 2023-10-23 14:33:22 +02:00
Marlon James 33c5b5feb8 Add sv_vpi_user.h from IEEE 1800-2017 Annex M (#4606) 2023-10-22 20:41:40 -04:00
Wilson Snyder b83b9974ee Fix gcc -O0 incompatible allocator warning 2023-10-22 09:51:02 -04:00
Wilson Snyder bcbe5059a9 Internal: V3Graph style cleanup. No functional change 2023-10-22 09:50:38 -04:00
Wilson Snyder 5bda901146 Internals: Fix stats report to include main AstCFile made 2023-10-21 20:56:24 -04:00
Geza Lore 82565690c7 test driver.pl: don't redirect to STDOUT of interactive GDB 2023-10-22 00:56:10 +01:00
Geza Lore 978d900e36 Simplify and fix code stats
V3Stats for "fast" code have bit-rotted a little and is causing some
problems with tests that rely on stats outputs. The problem is that not
all code is necessarily reachable from eval() any more (due to the
complexity of some the features added over the past few years), so it
might miss some things, as for measuring the "fast" code, it is trying
to trace the execution paths via calls, starting from eval(). It also
appears the fast code can also contain calls to slow code in some
circumstances.

To avoid all that, removed trying to trace dynamic execution, and simply
report the static node counts, which is enough for testing.

Similarly, the variable counts are somewhat dubious, as they don't
include all data types, or all instances of a module in some stages.
Removing these as they are not widely used nor dependable. More specific
stats can be added if required and can be well defined.
2023-10-22 00:25:07 +01:00
Geza Lore d330100542 Create implicit nets for inputs of gate primitives.
Prior to this we failed to create implicit nets for inputs of gate
primitives, which is required by the standard (IEEE 1800-2017 6.10).
Note: outputs were covered due to being modeled as the LHS of
assignments, which do create implicit nets.
2023-10-21 22:45:26 +01:00
Geza Lore 4c0edd2efb Improve --prof-exec infrastructure and report
Again --prof-exec have bit-rotted a little with all the recent changes
to the structure of the generated code. This patch contains a few
improvements:
- Repalce the eval/evl_loop begin/end events with generic
  section_push/section_pop events, that can be arbitrarily sprinkled
  into the generate code (so long as they are matched correctly) to
  measure various sections. The report then contains a nested profile
  of the sections, and the VCD trace shows the section names.
- Better handling of exec graphs
- Clearer overall statistics
2023-10-21 21:09:03 +01:00
Geza Lore 146cdc020d Remove V3AstConstOnly.h
This is now redundant with the introduction of VNVisitorConst
2023-10-21 20:41:46 +01:00
Geza Lore 52f2b9ef58 Remove pointless test
t_optm_if_cond was a test for a then non-existent optimization to merge
conditionals. V3MergeCond implements this and has its own tests.
2023-10-21 20:41:46 +01:00
Geza Lore a09506a0ad Trivial simplification of V3EmitCModel
Still some remains of the --threads 0 mode. Remove unnecessary complexity
from V3EmitCModel. (Also don't pretend there is an MTask in single
threaded mode, when there really isn't.)
2023-10-21 20:41:46 +01:00
Geza Lore 10d33238b9 Do not merge entry/exit MTasks during coarsening 2023-10-21 19:31:52 +01:00
Geza Lore b78ea06829 Make VL_LOCK_SPINS configurable
It's unlikely one value fits all use case, so making VL_LOCK_SPINS
configurable at model build time.

For testing, we reduce the value as we expect high contention.
2023-10-21 18:05:53 +01:00
Wilson Snyder eae942b91c Internals: Fix some lint-py warnings 2023-10-21 12:48:36 -04:00
Geza Lore 1075b006b5 Consider children of AstConcat in V3InstrCount
Previously V3InstrCount used to completely ignore an AstConcat,
including its children (see the rational in the comment). The problem is
the operands can be huge and expensive compound expressions (especially
since DFG), and not just a simple variable reference. This fix gains
some MT speed improvement.
2023-10-21 17:15:40 +01:00
Wilson Snyder afaa02709c CI: Increase CCACHE_MAXSIZE (#4595) 2023-10-21 10:38:46 -04:00
Wilson Snyder 332a687aef Commentary 2023-10-21 10:35:07 -04:00
Geza Lore d1c7875406 Fix conditionals on obsolete --threads 0
Since we removed --threads 0 support, the 'threads()' option always
returns a value >= 1. Remove corresponding dead code.

Some of the coverage counters appear to use atomics even if the model is
single threaded. I'm under the impression this was a bug originally so
those ones I changed to use threads() > 1 instead.
2023-10-21 15:14:27 +01:00
Geza Lore cbc2f9eb32 Do not overwrite LD_LIBRARY_PATH in t_flag_ldflags 2023-10-21 11:34:36 +01:00
Quentin Corradi 26e3785963 Fix PLI/DPI user defined system task/function grammar (#4587) (#4588)
According to 1800-2017 36.3, 1800-2017 A.9.3, 1364-2005 20.2 and 1364-2005 A.9.3, user defined system task and function identifiers can use the same character set for the second character as all the following characters.
2023-10-21 02:43:49 -04:00
Wilson Snyder f8b7fb72b8 Fix fault on empty clocking block (#4593). 2023-10-21 02:40:08 -04:00
Krzysztof Bieganski 7b12f6a1dd Support NBAs in non-inlined functions/tasks (#4496) (#4572) 2023-10-20 20:01:45 -04:00
Mariusz Glebocki c7a0613c57 Support Clang 16 (#4592) 2023-10-20 15:47:09 -04:00
Aleksander Kiryk 83a0085c4d Support wait fork (#4586) 2023-10-20 07:13:57 -04:00
Wilson Snyder 05bb7fa821 Tests: Use UVM with UVM_NO_DPI defined 2023-10-20 02:37:11 -04:00
Wilson Snyder 4cc42133b5 Internals: Rename some parser rules. No functional change. 2023-10-19 20:13:27 -04:00
Wilson Snyder a773a52559 Cleanup some IEEE references 2023-10-19 19:26:36 -04:00
Wilson Snyder 5af271cf3a Fix display optimization ignoring side effects (#4585). 2023-10-19 18:33:58 -04:00
Wilson Snyder 0c2bab1f69 Fix method narrowing conversion compiler error (#4568). 2023-10-18 17:51:25 -04:00
Wilson Snyder b7233d063f Internals: Fix same() called outside of sameTree (#4561). 2023-10-18 17:36:21 -04:00
Krzysztof Bieganski 8720841c48 Fix to not remap local assign intravals in forks (#4583) 2023-10-18 16:49:20 -04:00
Wilson Snyder 263697e491 Commentary (#4580) 2023-10-18 08:15:55 -04:00
Wilson Snyder 493f1da266 Fix compile warning on unused member function variable (#4567). 2023-10-18 08:09:54 -04:00
Wilson Snyder 8b44a54bb2 Support Verilated precompiled header compilations (#4580) 2023-10-18 08:08:15 -04:00
Wilson Snyder b5828a7ce9 Fix header order botched by clang-format in recent commit. 2023-10-18 06:37:46 -04:00
Wilson Snyder 51a18225ad cmake: Fix missing headers 2023-10-18 06:37:38 -04:00
Wilson Snyder 28625451dd Fix MSVC makefile list (part of previous commit) 2023-10-18 06:07:05 -04:00
Wilson Snyder 3914176bc4 Internals: Remove unused IGNORED to fix MSVC warning. No functional change intended. 2023-10-18 06:06:00 -04:00
Wilson Snyder 13989b965d Tests: Add --binary with split, to check parallel builds 2023-10-17 23:13:04 -04:00
github action 770cd24f27 Apply 'make format' 2023-10-18 02:50:27 +00:00
Wilson Snyder 431bb1ed16 Support compiling Verilator with gcc/clang precompiled headers (#4579) 2023-10-17 22:49:28 -04:00
Ryszard Rozak 3bb9c7ee92 Fix dictionaries with keys of class types (#4576) 2023-10-17 17:15:24 +02:00
Ryszard Rozak 45edcbb03e Fix logical expressions with class objects - caching in v3Const (#4552) 2023-10-17 07:38:45 -04:00
Ryszard Rozak e99fd2892b Make VNDeleter a member of VNVisitor. No function change. (#4573) 2023-10-17 09:26:53 +02:00
Krzysztof Bieganski 99ea16d7fd Fix dynamic triggers for named events (#4571) 2023-10-16 11:06:41 -04:00
Krzysztof Bieganski bc9ff6d1bf Fix interface comparison (#4570) 2023-10-16 11:05:39 -04:00
Aleksander Kiryk ad3bcbb1bb Support disable fork (#4125) (#4569) 2023-10-16 14:02:29 +02:00
Yutetsu TAKATSUKASA 25dde58297 Internals: Use VN_AS instead of static_cast. Fix some wrong types. (#4561) 2023-10-16 05:17:52 -04:00
Anthony Donlon bba3487dc4 Internals: Fix hash and comparison function for AstBasicDType (#4564) 2023-10-15 15:15:46 -04:00
Anthony Donlon 4fdaa46328 Fix using functions/tasks following class definition inside module (#4553) 2023-10-15 13:01:32 -04:00
Anthony Donlon 4427f03b08 Fix error message for invalid parameter overrides (#4559) 2023-10-15 12:59:36 -04:00
Yutetsu TAKATSUKASA 4e2c63c8cb Support concatenation of unpacked arrays (#4558) 2023-10-15 12:53:35 -04:00
github action afecde87d8 Apply 'make format' 2023-10-15 11:00:14 +00:00
Wilson Snyder c14eae6d56 Add SIDEEFFECT warning on mishandled side effect cases (#487 partial) 2023-10-15 06:44:35 -04:00
Wilson Snyder 684aba0e90 Fix purity calculation during V3Const simplifying Ast 2023-10-15 06:25:42 -04:00
Wilson Snyder 46f8a659b3 Fix shift to remove operation side effects (#4563). 2023-10-14 22:34:37 -04:00
Wilson Snyder 3940a214d0 Internals: Reorder some shift functions for next commit. No functional change. 2023-10-14 22:23:58 -04:00
Wilson Snyder 411f563cbe Internals: Remove unneeded pure checks. No functional change. 2023-10-14 22:23:58 -04:00
Wilson Snyder b5a6b34968 Tests: Remove old hack from before unpacked structs 2023-10-14 22:23:58 -04:00
github action fa8eaf7355 Apply 'make format' 2023-10-14 19:20:22 +00:00
Wilson Snyder 7eb09c3445 Fix instance arrays connecting to array of structs (#4557). 2023-10-14 15:19:19 -04:00
Varun Koyyalagunta edfd3d7206 Fix large constant buffer overflow (#4556) 2023-10-13 07:08:58 +09:00
Wilson Snyder d699caf255 Revert fix Verilated Makefile to get CXX etc. from environment (#4549) (#4554). 2023-10-12 04:22:58 -04:00
Wilson Snyder bd4eede6b4 Commentary: Changes update 2023-10-10 20:43:32 -04:00
Wilson Snyder 1fd8e772b0 Fix loss of warning source content with `line enter (due to earlier commit 472ad90d83). 2023-10-10 20:40:21 -04:00
Anthony Donlon 7ce0bd1181 Fix broken link error for enum references (#4551) 2023-10-10 17:55:40 -04:00
Gus Smith a4b7c39a9a Fix Verilated Makefile to get CXX etc. from enviorment (#4549) (#4554) 2023-10-10 17:53:02 -04:00
Mariusz Glebocki a5ee8b39ef Internals: Remove use of V3Width code from V3AstNodes (#4537). No functional change intended.
`getCommonClassTypep` and its helper code has been moved to AstNode
class. This is a lot better place for this functionality. Moreover, it
allowed to get rid of the dependency on V3Width from generic AST-related
code.
2023-10-09 17:43:27 -04:00
Ryszard Rozak 5b06c60318 Internals: Change deleteTree to pushDeletep (#4548). No functional change intended. 2023-10-09 09:45:09 -04:00
Wilson Snyder b306715b4a Optimize empty expression statements (#4544). 2023-10-09 05:50:31 -04:00
Wilson Snyder 8d99bdac25 Internals: Move afterCommentp to AstNode. No functional change. 2023-10-09 05:03:57 -04:00
github action e114dfda6d Apply 'make format' 2023-10-09 08:14:14 +00:00
Wilson Snyder 472ad90d83 Change lint_off to not propagate upwards to files including where the lint_off is. 2023-10-09 04:12:01 -04:00
Wilson Snyder 622f0c047c Fix reporting `line at wrong spot. Rework some internal fileline parsing functions. 2023-10-08 20:38:45 -04:00
Wilson Snyder 7f38414276 Internals: Rename addIgnoreMatch. No functional change. 2023-10-08 01:02:23 -04:00
Wilson Snyder 1d3d59243c Fix preprocessor to show `line 2 on resumed file per IEEE. 2023-10-07 14:29:46 -04:00
Wilson Snyder e2343c03e0 Internals: Create V3WidthCommit from overly fat header. No functional change intended. 2023-10-06 23:18:26 -04:00
Wilson Snyder 0e0df1fb3b Fix enum functions in localparams (#3999). 2023-10-06 22:38:46 -04:00
Wilson Snyder 800a789f50 Fix inlining of real functions miscasting (#4543). 2023-10-06 21:33:31 -04:00
Wilson Snyder 106664b942 Internals: Fix long lines. No functional change. 2023-10-05 20:07:53 -04:00
Ryszard Rozak 1c738c6b83 Fix object destruction after a copy constructor (#4540) (#4541) 2023-10-05 07:21:33 -04:00
Wilson Snyder 25fa1d7c6a Commentary: Changes update 2023-10-04 20:17:14 -04:00
Wilson Snyder 45162652de Commentary 2023-10-04 20:13:59 -04:00
Wilson Snyder 537650a2cd Fix stream of 32 bit (#4536). 2023-10-03 22:10:50 -04:00
Todd Strader f849073137 Fix non-inlined interface tracing (#3984) (#4530) 2023-10-03 19:55:25 -04:00
Ryszard Rozak a3c154dcd3 Fix this in a constructor (#4533) 2023-10-03 14:32:18 +02:00
Ryszard Rozak 1b8228b642 Fix stream operations with operands of struct type (#4531) (#4532) 2023-10-03 07:23:20 -04:00
Wilson Snyder 732d03f4e5 Fix conversion of integers in $display %e (#4528). 2023-10-01 13:00:16 -04:00
Wilson Snyder 33787c6add Internals: Fix number nodep cloning, and assert stays consistent (#4528 partial) 2023-10-01 12:46:35 -04:00
Ryszard Rozak 44e7d2ebe6 Internals: rename VPurity class and related functions. No functional change (#4523) 2023-09-29 12:23:51 +02:00
Wilson Snyder e49ae663a6 Fix constification of $realtobits, $bitstoreal (#4522). 2023-09-28 22:45:00 -04:00
Wilson Snyder 2385ab8294 Tests: randc now supported 2023-09-26 22:53:25 -04:00
Wilson Snyder 84ccb23098 Fix C++11 compiler constexpr return error 2023-09-26 22:43:17 -04:00
Wilson Snyder ad343f8260 Add warning on interface instantiation without parens (#4094). 2023-09-26 22:15:48 -04:00
Wilson Snyder 018d766179 Fix clang error (#4462) 2023-09-26 21:07:43 -04:00
Justin Thiel a948be184c Tests: Add t_interface_localparam_unsup (#3857 partial) (#3858) 2023-09-26 20:35:23 -04:00
Wilson Snyder 72b4a74245 Fix clang error on last commit 2023-09-26 19:58:09 -04:00
Wilson Snyder 36c824d973 Add trace() API even when Verilated without --trace (#4462). 2023-09-26 18:37:50 -04:00
Anthony Donlon 229ce1aecf Fix handling input file path separator (#4515) (#4516) 2023-09-26 15:42:15 -04:00
Anthony Donlon be45a9b7d5 Style: Update clang-format config to make formatted code consistent between versions. No functional change (#4520) 2023-09-26 15:05:57 -04:00
Wilson Snyder d2c72a7f21 CI: Disable m32 runs 2023-09-25 12:30:25 -04:00
Anthony Donlon 60e9827ffe Support converting parameters inside modules to localparams (#4511) 2023-09-25 11:39:04 -04:00
Wilson Snyder a9256d4758 CI: Disable m32 runs 2023-09-25 11:28:44 -04:00
Anthony Donlon 750b5be5d3 Remove support for parameterized UDPs (#4518) 2023-09-25 10:40:44 -04:00
Mariusz Glebocki 28bd7e5b19 Rework multithreading handling to separate by code units that use/never use it. (#4228) 2023-09-24 22:12:23 -04:00
Anthony Donlon d64c023099 CI: Cancel previous runs for pull requests automatically (#4512) 2023-09-23 11:50:05 -04:00
Wilson Snyder 429cb1f7f7 Commentary (#4517) 2023-09-23 09:04:35 -04:00
Wilson Snyder 9f75068059 Cleanup some error messages to properly quote 2023-09-23 08:52:50 -04:00
Ryszard Rozak 4636e9cffb Fix passing arguments by reference (#3385 partial) (#4489) 2023-09-20 07:33:11 -04:00
Wilson Snyder 4b2bf556d8 Tests: Revert UVM upstream (chipsalliance/uvm-verilator#7) 2023-09-20 07:32:21 -04:00
Kamil Rakoczy a16ea94836 Fix detecting local vars in nested forks (#4493) (#4506) 2023-09-19 17:32:42 -04:00
Michal Czyz b9ea249f81 Rewrite usage of annotation options (#4486) (#4504) 2023-09-19 09:08:17 -04:00
Wilson Snyder 470f480bc1 Fix -m32 compile issue 2023-09-19 07:23:35 -04:00
Wilson Snyder 24ff3155ae Support randc (#4349). 2023-09-18 21:17:21 -04:00
Ryszard Rozak 47b3f464a9 Disable conversion of impure logical expressions to bitwise expressions (#487 partial) (#4437) 2023-09-18 09:21:30 -04:00
github action cd201f8eb8 Apply 'make format' 2023-09-18 01:44:43 +00:00
Wilson Snyder 016278a759 Commentary 2023-09-17 21:43:00 -04:00
Wilson Snyder b68f101e81 Support preprocessing __LINE__ 2023-09-17 19:49:38 -04:00
Wilson Snyder ab13548018 Support resizing function call inout arguments (#4467). 2023-09-17 18:23:44 -04:00
Wilson Snyder f507ee56b0 Fix warning in configure sc_main compile. (#4499) 2023-09-17 08:01:54 -04:00
Wilson Snyder 761adf1cf0 Internals: Add cloneTreePure to prepare for side effect check.
Use cloneTreePure when what is being cloned must be side-effect free.
Use cloneTree when safe to contain side effects (e.g. cloning module).
2023-09-16 22:50:54 -04:00
Wilson Snyder cd1fe64e6c devel release 2023-09-16 21:46:01 -04:00
Wilson Snyder 8f43e74288 Update CMakeList version 2023-09-16 20:54:54 -04:00
Wilson Snyder cef3960a4e Version bump 2023-09-16 18:36:39 -04:00
Wilson Snyder 783b7ecdab Fix clang override warning (last commit) 2023-09-16 17:52:02 -04:00
Wilson Snyder 8bd1c63b32 Support function non-constant default arguments (#4470). 2023-09-16 17:37:25 -04:00
Wilson Snyder e6fb7e970d Fix recursive display causing segfault (#4480). 2023-09-16 10:10:21 -04:00
Wilson Snyder 891cc0f9b6 Fix t_dist_cppstyle Perl performance issue (#4085). 2023-09-16 09:22:12 -04:00
Wilson Snyder 10fbe74cef Commentary: Changes update 2023-09-15 23:25:28 -04:00
Wilson Snyder 05d04a3959 Internals: Fix misnamed member. No functional change. 2023-09-15 23:02:34 -04:00
Wilson Snyder 19f7279542 Fix false INFINITELOOP on forever..mailbox.get() (#4323). 2023-09-15 22:05:55 -04:00
Wilson Snyder aa608472ae Support recursive function calls (#3267). 2023-09-15 20:46:31 -04:00
Wilson Snyder 26ed2a06a0 Tests: Add UVM test that generates ok with known issues commented out. (#1538) (#3267) (#4125) (#4323) (#4349) (#4465) (#4467) (#4468) (#4470) (#4493) (#4494) (#4495) (#4496) (#4497) 2023-09-15 20:26:46 -04:00
Wilson Snyder 07013da13d Tests: Disabled test (#4493) 2023-09-15 19:56:05 -04:00
Wilson Snyder d840c612d4 Fix IGNOREDRETURN to not warn on void-cast static function calls. 2023-09-15 19:01:11 -04:00
Wilson Snyder 188cf85b3f Suppress some debug unknown hash/simulate warnings in UVM. 2023-09-15 18:33:02 -04:00
Wilson Snyder c52ba28dd0 Tests: Fix commentary to unify issue references. 2023-09-15 18:12:11 -04:00
Wilson Snyder 10c1653e72 Fix ZERODLY to not warn on 'wait(0)'. 2023-09-15 08:53:29 -04:00
Wilson Snyder 2fbd41e13b Tests: Add t_queue_persistence.pl as broken test (#3385) (#4489) 2023-09-15 07:59:06 -04:00
Ryszard Rozak 96857c5f95 Fix the error message when the type of ref argument is wrong (#4490) 2023-09-15 07:17:24 -04:00
Wilson Snyder 131eb319e0 Tests: Advance UVM through V3LinkDot Param (#1538 partial) 2023-09-14 20:09:43 -04:00
Wilson Snyder 6e589377f4 Fix reference to extended class in parameterized class (#4466). 2023-09-14 20:07:49 -04:00
Wilson Snyder 2c84b37bf7 Internals: Rename some V3LinkDot variables. No functional change. 2023-09-14 20:06:20 -04:00
Kamil Rakoczy 0d67caff77 Internals: V3Task: refactor common code to connectPort. No functional change intended (#4488)
Signed-off-by: Kamil Rakoczy <[email protected]>
2023-09-14 07:24:49 -04:00
Anthony Donlon 3dde57d539 Fix lint of case statements with enum and wildcard bits (#4464) (#4487) 2023-09-14 07:22:49 -04:00
Kamil Rakoczy ec2e3ec0e4 Update clang_check_attributes to take into account MT_DISABLED (#4479) 2023-09-13 16:32:18 -04:00
Kamil Rakoczy 9fe459c820 Internals: V3LockGuard: Add constructor for adopting already locked mutex. (#4476) 2023-09-13 13:52:59 -04:00
Wilson Snyder 823e0723fb Internals: Remove legacy define. No functional change. 2023-09-13 08:46:51 -04:00
Kamil Rakoczy 8bd6d7c5b1 Internals: Add V3ThreadSafety (#4477) 2023-09-13 07:57:48 -04:00
Wilson Snyder 839a8fa4d9 Fix error on enum with VARHIDDEN of cell (#4482). 2023-09-12 17:47:57 -04:00
Krzysztof Boroński 24917a187a Fix V3CUse, do not consider implementations (.cpp) at all (#4386) 2023-09-12 17:59:57 +02:00
Ryszard Rozak 6c6f03cf7c Fix static cast from a stream type (#4469) (#4485) 2023-09-12 11:06:12 -04:00
Kamil RakoczyandMariusz Glebocki 5676443139 Internals: Rename and slightly change other threads stopping/resuming methods. (#4478)
Co-authored-by: Mariusz Glebocki <[email protected]>
2023-09-11 13:43:26 -04:00
Kamil RakoczyandMariusz Glebocki e77d847671 Check whether V3ERROR_NO_GLOBAL_ is not already defined. (#4475)
Co-authored-by: Mariusz Glebocki <[email protected]>
2023-09-11 09:01:34 -04:00
Kamil RakoczyandMariusz Glebocki 0baee84e96 Move dpiTemporaryVarSuffix() to header. (#4474)
Co-authored-by: Mariusz Glebocki <[email protected]>
2023-09-11 09:01:09 -04:00
Ryszard Rozak c446cc2596 Internals: Remove unused constructor. No functional change. (#4473)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-09-11 07:10:33 -04:00
Ryszard Rozak b66c4153b1 Compute purity of AstCMethodHard (#4460) 2023-09-11 13:06:15 +02:00
Wilson Snyder d72f1b89fc Internals: Minor internal code coverage cleanups 2023-09-10 18:53:51 -04:00
Wilson Snyder b5b278d072 Fix fork crash with no init, test for (#4471) 2023-09-10 08:53:21 -04:00
Wilson Snyder cb5466a90b Tests: UVM passes V3Param stage 2023-09-09 11:54:55 -04:00
Wilson Snyder 4de25369da Tests: Add t_uvm_all 2023-09-08 22:29:23 -04:00
Wilson Snyder cdd8953085 Disable Subst when not pure 2023-09-08 21:52:33 -04:00
Wilson Snyder 2f2f0164ff Internals: Use specific types on some cloneTrees. No functional change. 2023-09-08 21:51:59 -04:00
Kamil Rakoczy 6e977e1024 Generate compile_commands.json using bear (#4463) 2023-09-08 17:26:11 -04:00
Krzysztof Boroński 70b11f91b4 Support block_item_declaration in forks (#4455) 2023-09-08 16:40:14 +02:00
Wilson Snyder 014301587f Unsupported instead of syntax error on parameter var initial values 2023-09-08 08:37:17 -04:00
Krzysztof Bieganski 139e93d371 Internals: Reduce the number of typechecks in graphs (#4398). No functional change intended. 2023-09-08 07:35:52 -04:00
Krzysztof Bieganski fb1fc46b06 Internals: Rework self pointers (#4396) 2023-09-08 07:34:35 -04:00
Wilson Snyder 9882ab6c67 Tests: Remove unstable new test 2023-09-08 07:22:52 -04:00
Ryszard Rozak 1a1f919882 Check the output in t_class_method_str_literal.v (#4459) 2023-09-08 08:51:54 +02:00
Ryszard Rozak 91227d26bb Internals: Rename pure to dpiPure. No functional change. (#4461) 2023-09-08 08:51:19 +02:00
Wilson Snyder 11b5dae88d Support let 2023-09-07 21:45:51 -04:00
Wilson Snyder 0c7d485417 Fix error printing internal name() 2023-09-06 21:07:06 -04:00
Ryszard Rozak c40e34b134 Support assignments of stream expressions on queues to packed values (#4458) 2023-09-06 15:25:48 +02:00
Wilson Snyder 6cdf8da3f7 Fix documentation line wrap (#4456) 2023-09-05 07:25:33 -04:00
Wilson Snyder c65265477f Tests: Enable cover named property 2023-09-03 21:02:42 -04:00
Wilson Snyder de77f1ee5c Improve error that assert-under-assert is unsupported 2023-09-03 09:08:43 -04:00
Wilson Snyder c8c980c49d Fix mis-warning on #() in classes' own functions. 2023-09-02 08:33:56 -04:00
Wilson Snyder ad329612fd Internals: Remove unnecessary cloneTree. 2023-09-01 20:13:20 -04:00
Wilson Snyder c324895cbc Internals: Remove unnecessary cloneTree. 2023-09-01 19:49:57 -04:00
Wilson Snyder 679a4314dc Tests: Avoid side effect on array index 2023-09-01 19:26:50 -04:00
Wilson Snyder 36932d31c4 Fix C++11 missing C++14's std::make_unique. 2023-09-01 18:07:15 -04:00
Wilson Snyder ed25aaaad9 Internals: Fix g++ std11 warning. No functional change. 2023-09-01 17:59:30 -04:00
Wilson Snyder 147aa41ba5 Internals: Fix virt call in constructor warning. No functional change. 2023-09-01 17:58:17 -04:00
Ryszard Rozak 5b7e32581b Internals: Cleanup V3Task. No function change intended. (#4454) 2023-09-01 08:03:16 -04:00
Wilson Snyder 2f90fb2bec Set lifetime for repeat variable (#4451 partial) 2023-08-31 18:34:37 -04:00
Wilson Snyder 8c480fd39e Internals: Fix cppcheck warnings 2023-08-31 18:29:58 -04:00
Krzysztof Bieganski ffbbd438ae Internals: Use runtime type info instead of dynamic_cast for faster graph type checks (#4397) 2023-08-31 18:00:53 -04:00
Anthony Donlon 96ee81fa3f Fix unstable output of VHashSha256 (#4453) 2023-08-31 13:42:37 -04:00
Wilson Snyder 3d2399ea0f Tests: Enable fixed-earlier (#2314) 2023-08-30 18:10:30 -04:00
Wilson Snyder 6d5dde8645 Fix duplicate Vfork functions (#4418) 2023-08-30 17:59:25 -04:00
Wilson Snyder 048c9f3fe2 Support extra commas before $display 2023-08-30 17:31:11 -04:00
Wilson Snyder 373265752f Fix display %x formatting of real. 2023-08-30 17:21:33 -04:00
Wilson Snyder 5e6519c1b0 Commentary 2023-08-30 07:46:39 -04:00
Wilson Snyder ccdb52c1d9 Fix lifetime unknown error on enum.name (#4448). 2023-08-30 07:20:25 -04:00
Yinan Xu b4b74d72f0 Add prepareClone and atClone APIs for Verilated models (#3503) (#4444)
This API is used if the user copies the process using `fork`
and similar OS-level mechanisms. The `at_clone` member function
ensures that all model-allocated resources are re-allocated, such
that the copied child process/model can simulate correctly.

A typical allocated resource is the thread pool, which every model
has its own pool.
2023-08-30 07:02:55 -04:00
Wilson Snyder ca6ab584d0 Internals: Remove cloneTreeNull. No functional change intended. 2023-08-29 20:29:11 -04:00
github action 799a502cac Apply 'make format' 2023-08-29 23:56:25 +00:00
Ethan Sifferman 8d1570db28 Add check for conflicting options e.g. binary+lintonly (#4409) 2023-08-29 19:55:37 -04:00
Wilson Snyder 2a30bbe493 Fix internal error on real conversion (#4447). 2023-08-29 18:07:23 -04:00
Anthony Donlon cf6566b9bc Internal: Optimize program size by refactoring error reporting routines (#4446) 2023-08-29 16:54:32 -04:00
Krzysztof Boroński c3e19f2821 Move variables mutated under fork..join_none/join_any blocks into anonymous objects (#4356) 2023-08-29 20:01:00 +02:00
Ryszard Rozak e24197fd16 Don't move function calls before the expression (#4413) 2023-08-28 15:44:41 +02:00
Anthony Donlon 63db60f646 Fix using type in parameterized classes without #() (#4281) (#4440)
* Check whether a class is parameterized or not with AstClass::isParameterized method

* Fix usage conflict of user2 pointer in V3Param.cpp
2023-08-26 12:06:26 -01:00
Wilson Snyder e66b28823d Internals: Cleanup some spacing. No functional change. 2023-08-26 05:59:56 -04:00
Wilson Snyder 77bd565ef6 Commentary: Changes update 2023-08-25 08:28:26 -04:00
Wilson Snyder 00d63883f8 Fix false MULTITOP on bound interfaces (#4438). 2023-08-25 08:21:15 -04:00
Wilson Snyder 10dd675371 Fix false UNUSEDPARAM on generate localparam (#4427). 2023-08-25 07:59:29 -04:00
Ryszard Rozak 2daa32b98b Support assignments of packed values to stream expressions on queues (#4401) 2023-08-25 11:24:12 +02:00
Ryszard Rozak e8e7912871 Tests: Fix t_net_delay test (#4436) 2023-08-23 13:27:17 -01:00
Ryszard Rozak 90079c2974 Fix nested assignments on the LHS (#4435) 2023-08-23 12:08:22 +02:00
Wilson Snyder 967a8530dd Fix errors on some $past cases (#4425) 2023-08-22 01:49:06 -04:00
Krzysztof Boroński ef4794e36d Support parenthesesless calls to static methods (#4432) 2023-08-22 06:06:34 +01:00
Aleksander Kiryk 7c7c92d2dd Fix coroutine handle movement during queue manipulation (#4431) 2023-08-21 10:22:09 -04:00
Wilson Snyder 95f3dd0535 Commentary (#4429) 2023-08-21 06:23:35 -04:00
Anthony Donlon 768b78e7d0 Fix checking for parameter and port connections in the wrong place (#4428) 2023-08-20 08:55:16 -04:00
Aleksander Kiryk 4370254e73 Fix ++/-- under statements (#4399) 2023-08-19 07:03:21 -04:00
Wilson Snyder 436f72582b Update GTKWave from upstream. 2023-08-19 06:57:43 -04:00
Wilson Snyder af3aba7821 Commentary: Changes update 2023-08-19 04:56:49 -04:00
github action 7479db6ffc Apply 'make format' 2023-08-19 08:52:38 +00:00
Frans Skarman e9cc2786b7 Add --no-trace-top option (#4422) 2023-08-19 04:51:29 -04:00
Anthony Donlon cbdee5a804 Fix Windows filename format, etc. (#3873) (#4421)
* Ignore CLion project files and CMake outputs
* Supporting stripping file path that contains backslash
* Set /bigobj flag and increase stack size for windows platform
* Fix MSVC warnings
2023-08-16 07:34:57 -04:00
Anthony Donlon 0f66262fa1 Internals: Refactor AstNode::checkTreeIter for better stack size (#4420) 2023-08-16 07:32:39 -04:00
Jose Loyola 6c80457262 CI: Refactor docker build action to define DOCKER_HUB_NAMESPACE as repo variable (#4419) 2023-08-15 06:45:07 +02:00
Wilson Snyder 16008acdf1 Internals: Add disabled duplicate function check (#4418) 2023-08-12 10:51:35 -04:00
Wilson Snyder 5447ed2629 Fix multple function definitions in V3Sched (#4416). 2023-08-12 10:41:44 -04:00
Wilson Snyder 9eba61018a Tests: Ignore debug message in error line 2023-08-12 09:39:02 -04:00
Wilson Snyder bc97319402 Internals: State commentary. No functional change. 2023-08-12 08:55:08 -04:00
Wilson Snyder 709db5c648 Internals: Avoid unordered_set 2023-08-12 08:46:25 -04:00
Krzysztof Boroński b752faa107 Fix jumping over object initialization (#4411) 2023-08-11 18:28:37 +02:00
Krzysztof Boroński 8d512c3187 Fix variable lifetimes in extern methods (#4414) 2023-08-11 16:52:59 +02:00
Ryszard Rozak 2d9bc73709 Fix dtype of condition operation on class objects (#4345) (#4352) 2023-08-07 05:54:30 -04:00
Ryszard Rozak b0942ed8c7 Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404) 2023-08-07 11:35:44 +02:00
Wilson Snyder b1c1aa53a9 devel release 2023-08-06 10:53:16 -04:00
1024 changed files with 123255 additions and 37876 deletions
+5
View File
@@ -63,6 +63,8 @@ ForEachMacros:
SortIncludes: true
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '"V3Pch.*\.h"'
Priority: -2 # Precompiled headers
- Regex: '"(config_build|verilated_config|verilatedos)\.h"'
Priority: -1 # Sepecials before main header
- Regex: '(<|")verilated.*'
@@ -112,6 +114,9 @@ SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 0
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
+9 -4
View File
@@ -23,6 +23,10 @@ defaults:
shell: bash
working-directory: repo
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
build:
@@ -33,7 +37,8 @@ jobs:
compiler:
- { cc: clang, cxx: clang++ }
- { cc: gcc, cxx: g++ }
m32: [0, 1]
# m32 1 is deprecated, not here to speed up regressions
m32: [0]
exclude:
# Build pull requests only with ubuntu-22.04 and without m32
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
@@ -58,7 +63,7 @@ jobs:
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}
CCACHE_MAXSIZE: 250M # Per build matrix entry (2000M in total)
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
steps:
@@ -103,7 +108,7 @@ jobs:
compiler:
- { cc: clang, cxx: clang++ }
- { cc: gcc, cxx: g++ }
m32: [0, 1]
m32: [0]
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1]
exclude:
# Build pull requests only with ubuntu-22.04 and without m32
@@ -131,7 +136,7 @@ jobs:
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${{ matrix.suite }}
CCACHE_MAXSIZE: 64M # Per build matrix entry (2160M in total)
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
steps:
+3 -2
View File
@@ -1,6 +1,7 @@
# Build and push verilator docker image when tags are pushed to the repository.
# The following secrets must be configured in the github repository:
# The following variable(s) must be configured in the github repository:
# DOCKER_HUB_NAMESPACE: docker hub namespace.
# The following secrets must be configured in the github repository:
# DOCKER_HUB_USER: user name for logging into docker hub
# DOCKER_HUB_ACCESS_TOKEN: docker hub access token.
name: Build Verilator Container
@@ -52,7 +53,7 @@ jobs:
uses: docker/metadata-action@v4
with:
images: |
${{ secrets.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
tags: |
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
+53
View File
@@ -0,0 +1,53 @@
# DESCRIPTION: Github actions config
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
name: lint
on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # weekly
env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
defaults:
run:
shell: bash
working-directory: repo
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
lint-py:
runs-on: ubuntu-22.04
name: Lint Python
env:
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ubuntu-22.04
CI_M32: 0
steps:
- name: Checkout
uses: actions/checkout@v3
with:
path: repo
- name: Install packages for build
run: ./ci/ci-install.bash
# We use specific version numbers, otherwise a Python package
# update may add a warning and break our build
- name: Install packages for lint
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
- name: Configure
run: autoconf && ./configure --enable-longtests --enable-ccwarn
- name: Lint
run: make -k lint-py
+4
View File
@@ -22,6 +22,10 @@ defaults:
run:
working-directory: repo
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
windows:
+3
View File
@@ -41,3 +41,6 @@ verilator-config-version.cmake
**/_build/*
**/obj_dir/*
/.vscode/
/.idea/
/cmake-build-*/
/test_regress/snapshot/
+1 -1
View File
@@ -15,7 +15,7 @@
cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
project(Verilator
VERSION 5.014
VERSION 5.018
HOMEPAGE_URL https://verilator.org
LANGUAGES CXX
)
+127
View File
@@ -8,6 +8,133 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 5.018 2023-10-30
==========================
**Major:**
* Support compilation with precompiled headers with Make and GCC or CLang.
* Change include of systemc instead of systemc.h (#4622) (#4623). [Chih-Mao Chen]
This may require that SystemC programs add 'using namespace sc_core', 'using namespace sc_dt'.
**Minor:**
* Add SIDEEFFECT warning on mishandled side effect cases.
* Add trace() API even when Verilated without --trace (#4462). [phelter]
* Add warning on interface instantiation without parens (#4094). [Gökçe Aydos]
* Add sv_vpi_user.h from IEEE 1800-2017 Annex M (#4606). [Marlon James]
* Support 'disable fork' (#4125) (#4569). [Aleksander Kiryk, Antmicro Ltd.]
* Support 'wait fork' (#4586). [Aleksander Kiryk, Antmicro Ltd.]
* Support 'randc' (#4349).
* Support assigning events (#4403). [Krzysztof Boroński]
* Support resizing function call inout arguments (#4467).
* Support NBAs in non-inlined functions/tasks (#4496) (#4572). [Krzysztof Bieganski, Antmicro Ltd.]
* Support converting parameters inside modules to localparams (#4511). [Anthony Donlon]
* Support concatenation of unpacked arrays (#4558). [Yutetsu TAKATSUKASA]
* Support Clang 16 (#4592). [Mariusz Glebocki]
* Support VPI variables of real and string data types (#4594). [Marlon James]
* Support making VL_LOCK_SPINS configurable (#4599). [Geza Lore]
* Change code --stats output (#4597). [Geza Lore]
* Change --prof-exec infrastructure and report (#4602). [Geza Lore]
* Change lint_off to not propagate upwards to files including where the lint_off is.
* Optimize empty expression statements (#4544).
* Optimize trace internals (#4610) (#4612). [Geza Lore]
* Optimize internal performance issues (#4638). [Geza Lore]
* Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.]
* Fix enum functions in localparams (#3999). [Andrew Nolte]
* Fix passing arguments by reference (#3385 partial) (#4489). [Ryszard Rozak, Antmicro Ltd.]
* Fix multithreading handling to separate by code units that use/never use it (#4228). [Mariusz Glebocki, Antmicro Ltd.]
* Fix usage of annotation options (#4486) (#4504). [Michal Czyz]
* Fix detecting local vars in nested forks (#4493) (#4506). [Kamil Rakoczy]
* Fix handling input file path separator (#4515) (#4516). [Anthony Donlon]
* Fix mis-support for parameterized UDPs (#4518). [Anthony Donlon]
* Fix constant conversion of $realtobits, $bitstoreal (#4522). [Andrew Nolte]
* Fix conversion of integers in $display '%e' (#4528). [muzafferkal]
* Fix non-inlined interface tracing (#3984) (#4530). [Todd Strader]
* Fix stream operations with operands of struct type (#4531) (#4532). [Ryszard Rozak, Antmicro Ltd.]
* Fix 'this' in a constructor (#4533). [Ryszard Rozak, Antmicro Ltd.]
* Fix stream shift operator of 32 bits (#4536). [Julien Faucher]
* Fix object destruction after a copy constructor (#4540) (#4541). [Ryszard Rozak, Antmicro Ltd.]
* Fix inlining of real functions miscasting (#4543). [Andrew Nolte]
* Fix broken link error for enum references (#4551). [Anthony Donlon]
* Fix logical expressions with class objects - caching in v3Const (#4552). [Ryszard Rozak, Antmicro Ltd.]
* Fix using functions/tasks following class definition inside module (#4553). [Anthony Donlon]
* Fix large constant buffer overflow (#4556). [Varun Koyyalagunta]
* Fix instance arrays connecting to array of structs (#4557). [raphmaster]
* Fix error message for invalid parameter overrides (#4559). [Anthony Donlon]
* Fix shift to remove operation side effects (#4563).
* Fix compile warning on unused member function variable (#4567).
* Fix method narrowing conversion compiler error (#4568).
* Fix interface comparison (#4570). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix dynamic triggers for named events (#4571). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix dictionaries with keys of class types (#4576). [Ryszard Rozak, Antmicro Ltd.]
* Fix to not remap local assign intervals in forks (#4583). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix display optimization ignoring side effects (#4585).
* Fix PLI/DPI user defined system task/function grammar (#4587) (#4588). [Quentin Corradi]
* Fix fault on empty clocking block (#4593). [Alex Mykyta]
* Fix creating implicit nets for inputs of gate primitives (#4603). [Geza Lore]
* Fix try_put method of unbounded mailbox (#4608). [Ryszard Rozak, Antmicro Ltd.]
* Fix stable name generation in V3Fork (#4615) (#4624). [Krzysztof Boroński]
* Fix virtual methods (#4616). [Ryszard Rozak, Antmicro Ltd.]
* Fix insertion at queue end (#4619). [Krzysztof Boroński]
* Fix rand fields of reference types (#4627). [Ryszard Rozak, Antmicro Ltd.]
* Fix dynamic casts of null values (#4631). [Ryszard Rozak, Antmicro Ltd.]
* Fix signals read via virtual interfaces being misoptimized (#4645). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix handling of static keyword in methods (#4649). [Ryszard Rozak, Antmicro Ltd.]
* Fix preprocessor to show `line 2 on resumed file.
Verilator 5.016 2023-09-16
==========================
**Minor:**
* Add prepareClone and atClone APIs for Verilated models (#3503) (#4444). [Yinan Xu]
* Add check for conflicting options e.g. binary and lint-only (#4409). [Ethan Sifferman]
* Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman]
* Support recursive function calls (#3267).
* Support assignments of packed values to stream expressions on queues (#4401). [Ryszard Rozak, Antmicro Ltd]
* Support no-parentheses calls to static methods (#4432). [Krzysztof Boroński]
* Support block_item_declaration in forks (#4455). [Krzysztof Boroński]
* Support assignments of stream expressions on queues to packed values (#4458). [Ryszard Rozak, Antmicro Ltd]
* Support function non-constant default arguments (#4470).
* Support 'let'.
* Optimize Verilator executable size by refactoring error reporting routines (#4446). [Anthony Donlon]
* Optimize Verilation runtime pointers and graphs (#4396) (#4397) (#4398). [Krzysztof Bieganski, Antmicro Ltd]
* Optimize preparations towards multithreaded Verilation (#4291) (#4463) (#4476) (#4477) (#4479). [Kamil Rakoczy, Antmicro Ltd]
* Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon].
* Fix t_dist_cppstyle Perl performance issue (#4085). [Srinivasan Venkataramanan]
* Fix using type in parameterized classes without #() (#4281) (#4440). [Anthony Donlon]
* Fix false INFINITELOOP on forever..mailbox.get() (#4323). [Srinivasan Venkataramanan]
* Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd]
* Fix variables mutated under fork..join_none/join_any blocks into anonymous objects (#4356). [Krzysztof Boroński]
* Fix V3CUse, do not consider implementations (.cpp) at all (#4386). [Krzysztof Boroński]
* Fix ++/-- under statements (#4399). [Aleksander Kiryk, Antmicro Ltd]
* Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404). [Ryszard Rozak, Antmicro Ltd]
* Fix jumping over object initialization (#4411). [Krzysztof Boroński]
* Fix multiple issues towards short circuit support (#4413) (#4460). [Ryszard Rozak, Antmicro Ltd]
* Fix variable lifetimes in extern methods (#4414). [Krzysztof Boroński]
* Fix multiple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk]
* Fix false UNUSEDPARAM on generate localparam (#4427). [Bill Pringlemeir]
* Fix checking for parameter and port connections in the wrong place (#4428). [Anthony Donlon]
* Fix coroutine handle movement during queue manipulation (#4431). [Aleksander Kiryk, Antmicro Ltd]
* Fix nested assignments on the LHS (#4435). [Ryszard Rozak, Antmicro Ltd]
* Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov]
* Fix internal error on real conversion (#4447). [vdhotre-ventana]
* Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra]
* Fix unstable output of VHashSha256 (#4453). [Anthony Donlon]
* Fix static cast from a stream type (#4469) (#4485). [Ryszard Rozak, Antmicro Ltd]
* Fix error on enum with VARHIDDEN of cell (#4482). [Michail Rontionov]
* Fix lint of case statements with enum and wildcard bits (#4464) (#4487). [Anthony Donlon]
* Fix reference to extended class in parameterized class (#4466).
* Fix recursive display causing segfault (#4480). [Kuoping Hsu]
* Fix the error message when the type of ref argument is wrong (#4490). [Ryszard Rozak, Antmicro Ltd]
* Fix display %x formatting of real.
* Fix mis-warning on #() in classes' own functions.
* Fix IGNOREDRETURN to not warn on void-cast static function calls.
* Fix ZERODLY to not warn on 'wait(0)'.
Verilator 5.014 2023-08-06
==========================
+12 -2
View File
@@ -173,6 +173,10 @@ smoke-test: all_nomsg
test_regress: all_nomsg
$(MAKE) -C test_regress
.PHONY: test-snap test-diff
test-snap test-diff:
$(MAKE) -C test_regress $@
examples: all_nomsg
for p in $(EXAMPLES) ; do \
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
@@ -430,9 +434,15 @@ PYLINT_FLAGS = --score=n --disable=R0801
RUFF = ruff
RUFF_FLAGS = check --ignore=E402,E501,E701
# "make -k" so can see all tool result errors
lint-py:
-$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
-$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
$(MAKE) -k lint-py-pylint lint-py-ruff
lint-py-pylint:
$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
lint-py-ruff:
$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
format-pl-exec:
-chmod a+x test_regress/t/*.pl
+1 -1
View File
@@ -150,7 +150,7 @@ the terms of either the GNU Lesser General Public License Version 3 or the
Perl Artistic License Version 2.0. See the documentation for more details.
.. _CHIPS Alliance: https://chipsalliance.org
.. _Icarus Verilog: http://iverilog.icarus.com
.. _Icarus Verilog: https://steveicarus.github.io/iverilog
.. _Linux Foundation: https://www.linuxfoundation.org
.. |Logo| image:: https://www.veripool.org/img/verilator_256_200_min.png
.. |verilator multithreaded performance| image:: https://www.veripool.org/img/verilator_multithreaded_performance_bg-min.png
+1
View File
@@ -440,6 +440,7 @@ detailed descriptions of these arguments.
--trace-params Enable tracing of parameters
--trace-structs Enable tracing structure names
--trace-threads <threads> Enable FST waveform creation on separate threads
--no-trace-top Do not emit traces for signals in the top module generated by verilator
--trace-underscore Enable tracing of _signals
-U<var> Undefine preprocessor define
--no-unlimited-stack Don't disable stack size limit
+339 -276
View File
@@ -1,33 +1,32 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,eval-used
# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,W0603,eval-used
######################################################################
import argparse
import bisect
import collections
import math
import re
import statistics
# from pprint import pprint
Threads = collections.defaultdict(lambda: collections.defaultdict(lambda: {}))
Mtasks = collections.defaultdict(lambda: {})
Evals = collections.defaultdict(lambda: {})
EvalLoops = collections.defaultdict(lambda: {})
Sections = []
LongestVcdStrValueLength = 0
Threads = collections.defaultdict(lambda: []) # List of records per thread id
Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
Global = {
'args': {},
'cpuinfo': collections.defaultdict(lambda: {}),
'rdtsc_cycle_time': 0,
'stats': {}
}
ElapsedTime = None # total elapsed time
ExecGraphTime = 0 # total elapsed time excuting an exec graph
ExecGraphIntervals = [] # list of (start, end) pairs
######################################################################
def process(filename):
read_data(filename)
report()
def read_data(filename):
with open(filename, "r", encoding="utf8") as fh:
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
@@ -39,14 +38,17 @@ def read_data(filename):
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
re_arg2 = re.compile(r'VLPROF arg\s+(\S+)\s+([0-9.]*)\s*$')
re_stat = re.compile(r'VLPROF stat\s+(\S+)\s+([0-9.]+)')
re_time = re.compile(r'rdtsc time = (\d+) ticks')
re_proc_cpu = re.compile(r'VLPROFPROC processor\s*:\s*(\d+)\s*$')
re_proc_dat = re.compile(r'VLPROFPROC ([a-z_ ]+)\s*:\s*(.*)$')
cpu = None
thread = None
execGraphStart = None
lastEvalBeginTick = None
lastEvalLoopBeginTick = None
global LongestVcdStrValueLength
global ExecGraphTime
SectionStack = []
mTaskThread = {}
for line in fh:
recordMatch = re_record.match(line)
@@ -54,29 +56,31 @@ def read_data(filename):
kind, tick, payload = recordMatch.groups()
tick = int(tick)
payload = payload.strip()
if kind == "EVAL_BEGIN":
Evals[tick]['start'] = tick
lastEvalBeginTick = tick
elif kind == "EVAL_END":
Evals[lastEvalBeginTick]['end'] = tick
lastEvalBeginTick = None
elif kind == "EVAL_LOOP_BEGIN":
EvalLoops[tick]['start'] = tick
lastEvalLoopBeginTick = tick
elif kind == "EVAL_LOOP_END":
EvalLoops[lastEvalLoopBeginTick]['end'] = tick
lastEvalLoopBeginTick = None
if kind == "SECTION_PUSH":
LongestVcdStrValueLength = max(LongestVcdStrValueLength,
len(payload))
SectionStack.append(payload)
Sections.append((tick, tuple(SectionStack)))
elif kind == "SECTION_POP":
assert SectionStack, "SECTION_POP without SECTION_PUSH"
SectionStack.pop()
Sections.append((tick, tuple(SectionStack)))
elif kind == "MTASK_BEGIN":
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(
payload).groups()
mtask = int(mtask)
predict_start = int(predict_start)
ecpu = int(ecpu)
Threads[thread][tick]['mtask'] = mtask
Threads[thread][tick]['predict_start'] = predict_start
Threads[thread][tick]['cpu'] = ecpu
if 'elapsed' not in Mtasks[mtask]:
Mtasks[mtask] = {'end': 0, 'elapsed': 0}
mTaskThread[mtask] = thread
records = Threads[thread]
assert not records or records[-1]['start'] <= records[-1][
'end'] <= tick
records.append({
'start': tick,
'mtask': mtask,
'predict_start': predict_start,
'cpu': ecpu
})
Mtasks[mtask]['begin'] = tick
Mtasks[mtask]['thread'] = thread
Mtasks[mtask]['predict_start'] = predict_start
@@ -86,11 +90,18 @@ def read_data(filename):
mtask = int(mtask)
predict_cost = int(predict_cost)
begin = Mtasks[mtask]['begin']
Threads[thread][begin]['end'] = tick
Threads[thread][begin]['predict_cost'] = predict_cost
record = Threads[mTaskThread[mtask]][-1]
record['end'] = tick
record['predict_cost'] = predict_cost
Mtasks[mtask]['elapsed'] += tick - begin
Mtasks[mtask]['predict_cost'] = predict_cost
Mtasks[mtask]['end'] = max(Mtasks[mtask]['end'], tick)
elif kind == "EXEC_GRAPH_BEGIN":
execGraphStart = tick
elif kind == "EXEC_GRAPH_END":
ExecGraphTime += tick - execGraphStart
ExecGraphIntervals.append((execGraphStart, tick))
execGraphStart = None
elif Args.debug:
print("-Unknown execution trace record: %s" % line)
elif re_thread.match(line):
@@ -109,7 +120,7 @@ def read_data(filename):
elif re_proc_cpu.match(line):
match = re_proc_cpu.match(line)
cpu = int(match.group(1))
elif cpu and re_proc_dat.match(line):
elif cpu is not None and re_proc_dat.match(line):
match = re_proc_dat.match(line)
term = match.group(1)
value = match.group(2)
@@ -121,11 +132,6 @@ def read_data(filename):
pass
elif Args.debug:
print("-Unk: %s" % line)
# TODO -- this is parsing text printed by a client.
# Really, verilator proper should generate this
# if it's useful...
if re_time.match(line):
Global['rdtsc_cycle_time'] = re_time.group(1)
def re_match_result(regexp, line, result_to):
@@ -144,125 +150,33 @@ def report():
plus = "+" if re.match(r'^\+', arg) else " "
print(" %s%s%s" % (arg, plus, Global['args'][arg]))
for records in Threads.values():
for record in records:
cpu = record['cpu']
elapsed = record['end'] - record['start']
Cpus[cpu]['mtask_time'] += elapsed
global ElapsedTime
ElapsedTime = int(Global['stats']['ticks'])
nthreads = int(Global['stats']['threads'])
Global['cpus'] = {}
for thread in Threads:
# Make potentially multiple characters per column
for start in Threads[thread]:
if not Threads[thread][start]:
continue
cpu = Threads[thread][start]['cpu']
elapsed = Threads[thread][start]['end'] - start
if cpu not in Global['cpus']:
Global['cpus'][cpu] = {'cpu_time': 0}
Global['cpus'][cpu]['cpu_time'] += elapsed
ncpus = max(len(Cpus), 1)
measured_mt_mtask_time = 0
predict_mt_mtask_time = 0
long_mtask_time = 0
measured_last_end = 0
predict_last_end = 0
for mtask in Mtasks:
measured_mt_mtask_time += Mtasks[mtask]['elapsed']
predict_mt_mtask_time += Mtasks[mtask]['predict_cost']
measured_last_end = max(measured_last_end, Mtasks[mtask]['end'])
predict_last_end = max(
predict_last_end,
Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost'])
long_mtask_time = max(long_mtask_time, Mtasks[mtask]['elapsed'])
Global['measured_last_end'] = measured_last_end
Global['predict_last_end'] = predict_last_end
# If we know cycle time in the same (rdtsc) units,
# this will give us an actual utilization number,
# (how effectively we keep the cores busy.)
#
# It also gives us a number we can compare against
# serial mode, to estimate the overhead of data sharing,
# which will show up in the total elapsed time. (Overhead
# of synchronization and scheduling should not.)
print("\nAnalysis:")
print(" Total threads = %d" % nthreads)
print(" Total mtasks = %d" % len(Mtasks))
ncpus = max(len(Global['cpus']), 1)
print(" Total cpus used = %d" % ncpus)
print(" Total yields = %d" %
int(Global['stats'].get('yields', 0)))
print(" Total evals = %d" % len(Evals))
print(" Total eval loops = %d" % len(EvalLoops))
if Mtasks:
print(" Total eval time = %d rdtsc ticks" %
Global['measured_last_end'])
print(" Longest mtask time = %d rdtsc ticks" % long_mtask_time)
print(" All-thread mtask time = %d rdtsc ticks" %
measured_mt_mtask_time)
long_efficiency = long_mtask_time / (Global.get(
'measured_last_end', 1) or 1)
print(" Longest-thread efficiency = %0.1f%%" %
(long_efficiency * 100.0))
mt_efficiency = measured_mt_mtask_time / (
Global.get('measured_last_end', 1) * nthreads or 1)
print(" All-thread efficiency = %0.1f%%" %
(mt_efficiency * 100.0))
print(" All-thread speedup = %0.1f" %
(mt_efficiency * nthreads))
if Global['rdtsc_cycle_time'] > 0:
ut = measured_mt_mtask_time / Global['rdtsc_cycle_time']
print("tot_mtask_cpu=" + measured_mt_mtask_time + " cyc=" +
Global['rdtsc_cycle_time'] + " ut=" + ut)
predict_mt_efficiency = predict_mt_mtask_time / (
Global.get('predict_last_end', 1) * nthreads or 1)
print("\nPrediction (what Verilator used for scheduling):")
print(" All-thread efficiency = %0.1f%%" %
(predict_mt_efficiency * 100.0))
print(" All-thread speedup = %0.1f" %
(predict_mt_efficiency * nthreads))
p2e_ratios = []
min_p2e = 1000000
min_mtask = None
max_p2e = -1000000
max_mtask = None
for mtask in sorted(Mtasks.keys()):
if Mtasks[mtask]['elapsed'] > 0:
if Mtasks[mtask]['predict_cost'] == 0:
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
Mtasks[mtask]['elapsed'])
p2e_ratios.append(p2e_ratio)
if p2e_ratio > max_p2e:
max_p2e = p2e_ratio
max_mtask = mtask
if p2e_ratio < min_p2e:
min_p2e = p2e_ratio
min_mtask = mtask
print("\nMTask statistics:")
print(" min log(p2e) = %0.3f" % min_p2e, end="")
print(" from mtask %d (predict %d," %
(min_mtask, Mtasks[min_mtask]['predict_cost']),
end="")
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
print(" max log(p2e) = %0.3f" % max_p2e, end="")
print(" from mtask %d (predict %d," %
(max_mtask, Mtasks[max_mtask]['predict_cost']),
end="")
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
stddev = statistics.pstdev(p2e_ratios)
mean = statistics.mean(p2e_ratios)
print(" mean = %0.3f" % mean)
print(" stddev = %0.3f" % stddev)
print(" e ^ stddev = %0.3f" % math.exp(stddev))
print("\nSummary:")
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
print(" Parallelized code = {:.2%} of elapsed time".format(
ExecGraphTime / ElapsedTime))
print(" Total threads = %d" % nthreads)
print(" Total CPUs used = %d" % ncpus)
print(" Total mtasks = %d" % len(Mtasks))
print(" Total yields = %d" % int(Global['stats'].get('yields', 0)))
report_mtasks()
report_cpus()
report_sections()
if nthreads > ncpus:
print()
print("%%Warning: There were fewer CPUs (%d) then threads (%d)." %
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." %
(ncpus, nthreads))
print(" : See docs on use of numactl.")
else:
@@ -279,32 +193,130 @@ def report():
print()
def report_mtasks():
if not Mtasks:
return
nthreads = int(Global['stats']['threads'])
# If we know cycle time in the same (rdtsc) units,
# this will give us an actual utilization number,
# (how effectively we keep the cores busy.)
#
# It also gives us a number we can compare against
# serial mode, to estimate the overhead of data sharing,
# which will show up in the total elapsed time. (Overhead
# of synchronization and scheduling should not.)
total_mtask_time = 0
thread_mtask_time = collections.defaultdict(lambda: 0)
long_mtask_time = 0
long_mtask = None
predict_mtask_time = 0
predict_elapsed = 0
for mtaskId in Mtasks:
record = Mtasks[mtaskId]
predict_mtask_time += record['predict_cost']
total_mtask_time += record['elapsed']
thread_mtask_time[record['thread']] += record['elapsed']
predict_end = record['predict_start'] + record['predict_cost']
predict_elapsed = max(predict_elapsed, predict_end)
if record['elapsed'] > long_mtask_time:
long_mtask_time = record['elapsed']
long_mtask = mtaskId
Global['predict_last_end'] = predict_elapsed
serialTime = ElapsedTime - ExecGraphTime
def subReport(elapsed, work):
print(" Thread utilization = {:7.2%}".format(work /
(elapsed * nthreads)))
print(" Speedup = {:6.3}x".format(work / elapsed))
print("\nParallelized code, measured:")
subReport(ExecGraphTime, total_mtask_time)
print("\nParallelized code, predicted during static scheduling:")
subReport(predict_elapsed, predict_mtask_time)
print("\nAll code, measured:")
subReport(ElapsedTime, serialTime + total_mtask_time)
print("\nAll code, measured, scaled by predicted speedup:")
expectedParallelSpeedup = predict_mtask_time / predict_elapsed
scaledElapsed = serialTime + total_mtask_time / expectedParallelSpeedup
subReport(scaledElapsed, serialTime + total_mtask_time)
p2e_ratios = []
min_p2e = 1000000
min_mtask = None
max_p2e = -1000000
max_mtask = None
for mtask in sorted(Mtasks.keys()):
if Mtasks[mtask]['elapsed'] > 0:
if Mtasks[mtask]['predict_cost'] == 0:
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
Mtasks[mtask]['elapsed'])
p2e_ratios.append(p2e_ratio)
if p2e_ratio > max_p2e:
max_p2e = p2e_ratio
max_mtask = mtask
if p2e_ratio < min_p2e:
min_p2e = p2e_ratio
min_mtask = mtask
print("\nMTask statistics:")
print(" Longest mtask id = {}".format(long_mtask))
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".
format(long_mtask_time / ExecGraphTime))
print(" min log(p2e) = %0.3f" % min_p2e, end="")
print(" from mtask %d (predict %d," %
(min_mtask, Mtasks[min_mtask]['predict_cost']),
end="")
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
print(" max log(p2e) = %0.3f" % max_p2e, end="")
print(" from mtask %d (predict %d," %
(max_mtask, Mtasks[max_mtask]['predict_cost']),
end="")
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
stddev = statistics.pstdev(p2e_ratios)
mean = statistics.mean(p2e_ratios)
print(" mean = %0.3f" % mean)
print(" stddev = %0.3f" % stddev)
print(" e ^ stddev = %0.3f" % math.exp(stddev))
def report_cpus():
print("\nCPUs:")
print("\nCPU info:")
Global['cpu_sockets'] = collections.defaultdict(lambda: 0)
Global['cpu_socket_cores'] = collections.defaultdict(lambda: 0)
for cpu in sorted(Global['cpus'].keys()):
print(" cpu %d: " % cpu, end='')
print("cpu_time=%d" % Global['cpus'][cpu]['cpu_time'], end='')
socket = None
print(" Id | Time spent executing MTask | Socket | Core | Model")
print(" | % of elapsed ticks / ticks | | |")
print(" ====|============================|========|======|======")
for cpu in sorted(Cpus):
socket = ""
core = ""
model = ""
if cpu in Global['cpuinfo']:
cpuinfo = Global['cpuinfo'][cpu]
if 'physical_id' in cpuinfo and 'core_id' in cpuinfo:
socket = int(cpuinfo['physical_id'])
socket = cpuinfo['physical_id']
Global['cpu_sockets'][socket] += 1
print(" socket=%d" % socket, end='')
core = int(cpuinfo['core_id'])
Global['cpu_socket_cores'][str(socket) + "__" + str(core)] += 1
print(" core=%d" % core, end='')
core = cpuinfo['core_id']
Global['cpu_socket_cores'][socket + "__" + core] += 1
if 'model_name' in cpuinfo:
model = cpuinfo['model_name']
print(" %s" % model, end='')
print()
print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime,
Cpus[cpu]['mtask_time'], socket, core, model))
if len(Global['cpu_sockets']) > 1:
Global['cpu_sockets_warning'] = True
@@ -313,25 +325,68 @@ def report_cpus():
Global['cpu_socket_cores_warning'] = True
def report_sections():
if not Sections:
return
print("\nSection profile:")
totalTime = collections.defaultdict(lambda: 0)
selfTime = collections.defaultdict(lambda: 0)
sectionTree = [0, {}, 1] # [selfTime, childTrees, numberOfTimesEntered]
prevTime = 0
prevStack = ()
for time, stack in Sections:
if len(stack) > len(prevStack):
scope = sectionTree
for item in stack:
scope = scope[1].setdefault(item, [0, {}, 0])
scope[2] += 1
dt = time - prevTime
scope = sectionTree
for item in prevStack:
scope = scope[1].setdefault(item, [0, {}, 0])
scope[0] += dt
if prevStack:
for name in prevStack:
totalTime[name] += dt
selfTime[prevStack[-1]] += dt
prevTime = time
prevStack = stack
def treeSum(tree):
n = tree[0]
for subTree in tree[1].values():
n += treeSum(subTree)
return n
# Make sure the tree sums to the elapsed time
sectionTree[0] += ElapsedTime - treeSum(sectionTree)
def printTree(prefix, name, entries, tree):
print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2],
tree[2] / entries, prefix + name))
for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
printTree(prefix + " ", k, tree[2], tree[1][k])
print(" Total | Self | Total | Relative | Section")
print(" time | time | entries | entries | name ")
print("==========|=========|==========|============|========")
printTree("", "*TOTAL*", 1, sectionTree)
######################################################################
def write_vcd(filename):
print("Writing %s" % filename)
with open(filename, "w", encoding="utf8") as fh:
vcd = {
'values':
collections.defaultdict(lambda: {}), # {<time>}{<code>} = value
'sigs': {
'predicted_threads': {},
'measured_threads': {},
'cpus': {},
'evals': {},
'mtasks': {},
'Stats': {}
} # {<module>}{<sig}} = code
}
code = 0
# dict of dicts of hierarchy elements/signal name -> (code, width)
scopeSigs = {}
# map from time -> code -> value
values = collections.defaultdict(lambda: {})
parallelism = {
'measured': collections.defaultdict(lambda: 0),
@@ -340,132 +395,139 @@ def write_vcd(filename):
parallelism['measured'][0] = 0
parallelism['predicted'][0] = 0
# Measured graph
for thread in sorted(Threads.keys()):
sig = "thread%d_mtask" % thread
if sig not in vcd['sigs']['measured_threads']:
vcd['sigs']['measured_threads'][sig] = code
code += 1
mcode = vcd['sigs']['measured_threads'][sig]
nextFreeCode = 0
for start in sorted(Threads[thread]):
mtask = Threads[thread][start]['mtask']
end = Threads[thread][start]['end']
cpu = Threads[thread][start]['cpu']
vcd['values'][start][mcode] = mtask
vcd['values'][end][mcode] = None
def getCode(width, *names):
nonlocal nextFreeCode
scope = scopeSigs
*path, name = names
for item in path:
scope = scope.setdefault(item, {})
code, oldWidth = scope.setdefault(name, (nextFreeCode, width))
assert oldWidth == width
if code == nextFreeCode:
nextFreeCode += 1
return code
def addValue(code, time, val):
if isinstance(val, str):
buf = ""
for c in val:
buf += bin(ord(c))[2:].rjust(8, "0")
val = buf.ljust(LongestVcdStrValueLength * 8, "0")
values[time][code] = val
# Measured graph
for thread in sorted(Threads):
mcode = getCode(32, 'measured', 't%d_mtask' % thread)
for record in Threads[thread]:
start = record['start']
mtask = record['mtask']
end = record['end']
cpu = record['cpu']
addValue(mcode, start, mtask)
addValue(mcode, end, None)
parallelism['measured'][start] += 1
parallelism['measured'][end] -= 1
sig = "cpu%d_thread" % cpu
if sig not in vcd['sigs']['cpus']:
vcd['sigs']['cpus'][sig] = code
code += 1
ccode = vcd['sigs']['cpus'][sig]
vcd['values'][start][ccode] = thread
vcd['values'][end][ccode] = None
code = getCode(32, 'measured', 'cpu%d_thread' % cpu)
addValue(code, start, thread)
addValue(code, end, None)
sig = "mtask%d_cpu" % mtask
if sig not in vcd['sigs']['mtasks']:
vcd['sigs']['mtasks'][sig] = code
code += 1
ccode = vcd['sigs']['mtasks'][sig]
vcd['values'][start][ccode] = cpu
vcd['values'][end][ccode] = None
code = getCode(32, 'measured', 'cpu%d_mtask' % cpu)
addValue(code, start, mtask)
addValue(code, end, None)
# Eval graph
vcd['sigs']['evals']["eval"] = code
elcode = code
code += 1
n = 0
for eval_start in Evals:
eval_end = Evals[eval_start]['end']
n += 1
vcd['values'][eval_start][elcode] = n
vcd['values'][eval_end][elcode] = None
tStart = sorted(_['start'] for records in Threads.values()
for _ in records)
tEnd = sorted(_['end'] for records in Threads.values()
for _ in records)
# Eval_loop graph
vcd['sigs']['evals']["eval_loop"] = code
elcode = code
code += 1
n = 0
for eval_start in EvalLoops:
eval_end = EvalLoops[eval_start]['end']
n += 1
vcd['values'][eval_start][elcode] = n
vcd['values'][eval_end][elcode] = None
# Predicted graph
for start, end in ExecGraphIntervals:
# Find the earliest MTask start after the start point, and the
# latest MTask end before the end point, so we can scale to the
# same range
start = tStart[bisect.bisect_left(tStart, start)]
end = tEnd[bisect.bisect_right(tEnd, end) - 1]
# Compute scale so predicted graph is of same width as interval
measured_scaling = (end - start) / Global['predict_last_end']
# Predict mtasks that fill the time the execution occupied
for mtask in Mtasks:
thread = Mtasks[mtask]['thread']
pred_scaled_start = start + int(
Mtasks[mtask]['predict_start'] * measured_scaling)
pred_scaled_end = start + int(
(Mtasks[mtask]['predict_start'] +
Mtasks[mtask]['predict_cost']) * measured_scaling)
if pred_scaled_start == pred_scaled_end:
continue
if Mtasks:
# Predicted graph
for eval_start in EvalLoops:
eval_end = EvalLoops[eval_start]['end']
# Compute scale so predicted graph is of same width as eval
measured_scaling = (eval_end -
eval_start) / Global['predict_last_end']
# Predict mtasks that fill the time the eval occupied
for mtask in Mtasks:
thread = Mtasks[mtask]['thread']
pred_scaled_start = eval_start + int(
Mtasks[mtask]['predict_start'] * measured_scaling)
pred_scaled_end = eval_start + int(
(Mtasks[mtask]['predict_start'] +
Mtasks[mtask]['predict_cost']) * measured_scaling)
if pred_scaled_start == pred_scaled_end:
continue
mcode = getCode(32, 'predicted', 't%d_mtask' % thread)
addValue(mcode, pred_scaled_start, mtask)
addValue(mcode, pred_scaled_end, None)
sig = "predicted_thread%d_mtask" % thread
if sig not in vcd['sigs']['predicted_threads']:
vcd['sigs']['predicted_threads'][sig] = code
code += 1
mcode = vcd['sigs']['predicted_threads'][sig]
parallelism['predicted'][pred_scaled_start] += 1
parallelism['predicted'][pred_scaled_end] -= 1
vcd['values'][pred_scaled_start][mcode] = mtask
vcd['values'][pred_scaled_end][mcode] = None
# Parallelism graph
for measpred in ('measured', 'predicted'):
pcode = getCode(32, 'stats', '%s_parallelism' % measpred)
value = 0
for time in sorted(parallelism[measpred].keys()):
value += parallelism[measpred][time]
addValue(pcode, time, value)
parallelism['predicted'][pred_scaled_start] += 1
parallelism['predicted'][pred_scaled_end] -= 1
# Parallelism graph
for measpred in ('measured', 'predicted'):
vcd['sigs']['Stats']["%s_parallelism" % measpred] = code
pcode = code
code += 1
value = 0
for time in sorted(parallelism[measpred].keys()):
value += parallelism[measpred][time]
vcd['values'][time][pcode] = value
# Section graph
if Sections:
scode = getCode(LongestVcdStrValueLength * 8, "section", "trace")
dcode = getCode(32, "section", "depth")
for time, stack in Sections:
addValue(scode, time, stack[-1] if stack else None)
addValue(dcode, time, len(stack))
# Create output file
fh.write("$version Generated by verilator_gantt $end\n")
fh.write("$timescale 1ns $end\n")
fh.write("\n")
all_codes = {}
all_codes = set()
def writeScope(scope):
assert isinstance(scope, dict)
for key in sorted(scope):
val = scope[key]
if isinstance(val, dict):
fh.write(" $scope module %s $end\n" % key)
writeScope(val)
fh.write(" $upscope $end\n")
else:
(code, width) = val
all_codes.add(code)
fh.write(" $var wire %d v%x %s [%d:0] $end\n" %
(width, code, key, width - 1))
fh.write(" $scope module gantt $end\n")
for module in sorted(vcd['sigs'].keys()):
fh.write(" $scope module %s $end\n" % module)
for sig in sorted(vcd['sigs'][module].keys()):
code = vcd['sigs'][module][sig]
fh.write(" $var wire 32 v%x %s [31:0] $end\n" % (code, sig))
all_codes[code] = 1
fh.write(" $upscope $end\n")
writeScope(scopeSigs)
fh.write(" $upscope $end\n")
fh.write("$enddefinitions $end\n")
fh.write("\n")
first = True
for time in sorted(vcd['values']):
for time in sorted(values):
if first:
first = False
# Start with Z for any signals without time zero data
for code in sorted(all_codes.keys()):
if code not in vcd['values'][time]:
vcd['values'][time][code] = None
for code in sorted(all_codes):
if code not in values[time]:
addValue(code, time, None)
fh.write("#%d\n" % time)
for code in sorted(vcd['values'][time].keys()):
value = vcd['values'][time][code]
for code in sorted(values[time]):
value = values[time][code]
if value is None:
fh.write("bz v%x\n" % code)
elif isinstance(value, str):
fh.write("b%s v%x\n" % (value, code))
else:
fh.write("b%s v%x\n" % (format(value, 'b'), code))
@@ -504,7 +566,8 @@ parser.add_argument('filename',
Args = parser.parse_args()
process(Args.filename)
read_data(Args.filename)
report()
if not Args.no_vcd:
write_vcd(Args.vcd)
+1
View File
@@ -26,4 +26,5 @@ if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[CI\s\+ccache\s\+clear\]';
fi
# Dump stats, then zero stats
# 22.04: ccache -s -v -z
ccache -s -z
+2 -2
View File
@@ -71,8 +71,8 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
sudo apt-get install libsystemc libsystemc-dev
fi
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
sudo apt-get install mold ||
sudo apt-get install mold
sudo apt-get install bear mold ||
sudo apt-get install bear mold
fi
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Parallel::Forker
+2
View File
@@ -49,6 +49,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
./configure --enable-longtests --enable-ccwarn ${CI_M32:+--enable-m32}
ccache -z
"$MAKE" -j "$NPROC" -k
# 22.04: ccache -s -v
ccache -s
if [ "$CI_OS_NAME" = "osx" ]; then
file bin/verilator_bin
@@ -180,6 +181,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
fatal "Unknown test: $TESTS"
;;
esac
# 22.04: ccache -s -v
ccache -s
# Upload coverage data
+32 -9
View File
@@ -10,7 +10,7 @@
# Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[5.014 2023-08-06],
AC_INIT([Verilator],[5.018 2023-10-30],
[https://verilator.org],
[verilator],[https://verilator.org])
@@ -24,6 +24,10 @@ AC_SUBST(PACKAGE_VERSION_NUMBER)
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_NUMBER_STRING],["$PACKAGE_VERSION_NUMBER"],[Package version as a number])
VERILATOR_VERSION_INTEGER=`AS_ECHO("$PACKAGE_VERSION") | [sed 's/\([0-9]\)\.\([0-9][0-9][0-9]\) .*/\1\2000/g']`
AC_SUBST(VERILATOR_VERSION_INTEGER)
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_STRING_CHAR],
[static const char* const PACKAGE_STRING_UNUSED = "$PACKAGE_STRING";],
[Package version as a number])
AC_SUBST(PACKAGE_VERSION_STRING_CHAR)
# Ignore automake flags passed by Ubuntu builds
AC_ARG_ENABLE([dependency-tracking],
@@ -371,10 +375,9 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
# Flags for coroutine support for dynamic scheduling
_MY_CXX_CHECK_IFELSE(
-fcoroutines-ts,
[CFG_CXXFLAGS_COROUTINES="-fcoroutines-ts"],
[CFG_CXXFLAGS_COROUTINES="-fcoroutines"])
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines)
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts -Wno-deprecated-experimental-coroutine)
AC_SUBST(CFG_CXXFLAGS_COROUTINES)
# HAVE_COROUTINES
@@ -442,14 +445,19 @@ m4_foreach([cflag],[
[-mno-cet],
[-Qunused-arguments],
[-Wno-bool-operation],
[-Wno-tautological-bitwise-compare],
[-Wno-c++11-narrowing],
[-Wno-constant-logical-operand],
[-Wno-non-pod-varargs],
[-Wno-overloaded-virtual],
[-Wno-parentheses-equality],
[-Wno-shadow],
[-Wno-sign-compare],
[-Wno-tautological-bitwise-compare],
[-Wno-uninitialized],
[-Wno-unused-but-set-parameter],
[-Wno-unused-but-set-variable],
[-Wno-unused-parameter],
[-Wno-unused-variable],
[-Wno-shadow]],[
[-Wno-unused-variable]],[
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,cflag)
# CMake will test what flags work itself, so pass all flags through to it
CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE cflag"
@@ -559,6 +567,21 @@ Verilator requires a C++11 or newer compiler.]])
fi
AC_SUBST(CFG_CXXFLAGS_STD)
# Compiler precompiled header options (assumes either gcc or clang++)
AC_MSG_CHECKING([for $CXX precompile header include option])
if $CXX --help | grep include-pch >/dev/null 2>/dev/null ; then
# clang
CFG_CXXFLAGS_PCH_I=-include-pch
CFG_GCH_IF_CLANG=.gch
else
# GCC
CFG_CXXFLAGS_PCH_I=-include
CFG_GCH_IF_CLANG=
fi
AC_MSG_RESULT($CFG_CXXFLAGS_PCH_I)
AC_SUBST(CFG_CXXFLAGS_PCH_I)
AC_SUBST(CFG_GCH_IF_CLANG)
# Checks for library functions.
AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
@@ -573,7 +596,7 @@ ACO_SAVE_LIBS="$LIBS"
LIBS="$LIBS -lsystemc"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <systemc.h>
extern "C" int sc_main(int argc, char* argv[]) {}
extern "C" int sc_main(int argc, char* argv[]) { return 0; }
]],[[sc_version()]])],
[_my_result=yes
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
+8
View File
@@ -19,6 +19,7 @@ Anthony Donlon
Arkadiusz Kozdra
Aylon Chaim Porat
Cameron Kirk
Chih-Mao Chen
Chris Randall
Chuxuan Wang
Conor McCullough
@@ -40,6 +41,7 @@ Fan Shupei
february cozzocrea
Felix Neumärker
Felix Yan
Frans Skarman
G-A. Kamendje
Garrett Smith
Geza Lore
@@ -48,6 +50,7 @@ Glen Gibb
Gökçe Aydos
Graham Rushton
Guokai Chen
Gus Smith
Gustav Svensk
Harald Heckmann
Hennadii Chernyshchyk
@@ -56,6 +59,7 @@ Huang Rui
Huanghuang Zhou
HungMingWu
HyungKi Jeong
Ícaro Lima
Ilya Barkov
Iru Cai
Ivan Vnučec
@@ -87,6 +91,7 @@ Josh Redford
Julian Daube
Julie Schwartz
Julien Margetts
Justin Thiel
Kaleb Barrett
Kamil Rakoczy
Kanad Kanhere
@@ -113,6 +118,7 @@ Martin Stadler
Matthew Ballance
Michael Killough
Michaël Lefebvre
Michal Czyz
Mike Popoloski
Miodrag Milanović
Mladen Slijepcevic
@@ -133,6 +139,7 @@ Pierre-Henri Horrein
Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Quentin Corradi
Rafal Kapuscik
Raynard Qiao
Richard Myers
@@ -178,5 +185,6 @@ Yuri Victorovich
Yutetsu TAKATSUKASA
Yves Mathieu
Zhanglei Wang
Zhou Shen
Zixi Li
أحمد المحمودي
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0201,R0903
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0903
# -*- Python -*- See copyright, etc below
######################################################################
+1 -1
View File
@@ -230,4 +230,4 @@ spelling_ignore_contributor_names = True
breathe_projects = {"verilated": "_build/doxygen/verilated/xml/"}
breathe_default_project = "verilated"
breathe_default_members = ('members')
breathe_default_members = 'members'
+37
View File
@@ -128,6 +128,43 @@ in the distribution. These headers use Doxygen comments, `///` and `//<`,
to indicate and document those functions that are part of the Verilated
public API.
Process-Level Clone APIs
--------------------------
Modern operating systems support process-level clone (a.k.a copying, forking)
with system call interfaces in C/C++, e.g., :code:`fork()` in Linux.
However, after cloning a parent process, some resources cannot be inherited
in the child process. For example, in POSIX systems, when you fork a process,
the child process inherits all the memory of the parent process. However,
only the thread that called fork is replicated in the child process. Other
threads are not.
Therefore, to support the process-level clone mechanisms, Verilator supports
:code:`prepareClone()` and :code:`atClone()` APIs to allow the user to manually
re-construct the model in the child process. The two APIs handle all necessary
resources required for releasing and re-initializing before and after cloning.
The two APIs are supported in the verilated models. Here is an example of usage
with Linux :code:`fork()` and :code:`pthread_atfork` APIs:
.. code-block:: C++
// static function pointers to fit pthread_atfork
static auto prepareClone = [](){ topp->prepareClone(); };
static auto atClone = [](){ topp->atClone(); };
// in main function, register the handlers:
pthread_atfork(prepareClone, atClone, atClone);
For better flexibility, you can also manually call the handlers before and
after :code:`fork()`.
With the process-level clone APIs, users can create process-level snapshots
for the verilated models. While the Verilator save/restore option provides
persistent and circuit-dependent snapshots, the process-level clone APIs
enable in-memory, circuit-transparent, and highly efficient snapshots.
Direct Programming Interface (DPI)
==================================
+21
View File
@@ -7,6 +7,21 @@ Environment
This section describes the environment variables used by Verilator and
associated programs.
.. option:: AR
Optionally overrides the default :command:`ar` (archive) binary used by
the Verilated makefiles. If AR is not set, the version found at
configure time is used.
.. option:: CXX
Optionally overrides the default compiler binary used by the Verilated
makefiles. If CXX is not set, the version found at configure time is
used. Note the default flags passed to the compiler are determined at
configuration time, so changing the CXX compiler version using this
variable, as opposed to passing it at configuration time, may not give
desired results.
.. option:: LD_LIBRARY_PATH
A generic Linux/OS variable specifying what directories have shared
@@ -35,6 +50,12 @@ associated programs.
those programs. If OBJCACHE is not set, and at configure time ccache
was present, ccache will be used as a default.
.. option:: PYTHON3
Optionally overrides the default :command:`python3` binary used by the
Verilated makefiles. If PYTHON3 is not set, the version found at
configure time is used.
.. option:: SYSTEMC
Deprecated. Used only if :option:`SYSTEMC_INCLUDE` or
+47 -24
View File
@@ -125,9 +125,12 @@ Summary:
After generating the SystemC/C++ code, Verilator will invoke the
toolchain to build the model library (and executable when :vlopt:`--exe`
is also used). Verilator manages the build itself, and for this --build
is also used). Verilator manages the build itself, and for this --build
requires GNU Make to be available on the platform.
:vlopt:`--build` cannot be specified when using :vlopt:`-E`,
:vlopt:`--dpi-hdr-only`, :vlopt:`--lint-only`, or :vlopt:`--xml-only`.
.. option:: --build-dep-bin <filename>
Rarely needed. When a dependency (.d) file is created, this filename
@@ -1314,6 +1317,7 @@ Summary:
This is not needed with standard designs with only one top. See also
:option:`MULTITOP` warning.
.. option:: --trace
Adds waveform tracing code to the model using VCD format. This overrides
@@ -1392,6 +1396,17 @@ Summary:
This option is accepted, but has absolutely no effect with
:vlopt:`--trace`, which respects :vlopt:`--threads` instead.
.. option:: --no-trace-top
Disables tracing for the input and output signals in the top wrapper which
Verilator adds to the design. The signals are still traced in the original
verilog top modules.
When combined with :option:`--main-top-name` set to "-" or when the name of
the top module is set to "" in its constructor, the generated trace file
will have the verilog top module as its root, rather than another module
added by Verilator.
.. option:: --trace-underscore
Enable tracing of signals or modules that start with an
@@ -1523,13 +1538,15 @@ Summary:
.. option:: -Wno-lint
Disable all lint-related warning messages, and all style warnings. This is
equivalent to ``-Wno-ALWCOMBORDER -Wno-ASCRANGE -Wno-BSSPACE -Wno-CASEINCOMPLETE
-Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS
-Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-PINCONNECTEMPTY
-Wno-PINMISSING -Wno-STATICVAR -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
-Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL
-Wno-WIDTH`` plus the list shown for Wno-style.
Disable all lint-related warning messages, and all style warnings. This
is equivalent to ``-Wno-ALWCOMBORDER`` ``-Wno-ASCRANGE``
``-Wno-BSSPACE`` ``-Wno-CASEINCOMPLETE`` ``-Wno-CASEOVERLAP``
``-Wno-CASEX`` ``-Wno-CASTCONST`` ``-Wno-CASEWITHX`` ``-Wno-CMPCONST``
``-Wno-COLONPLUS`` ``-Wno-IMPLICIT`` ``-Wno-IMPLICITSTATIC``
``-Wno-PINCONNECTEMPTY`` ``-Wno-PINMISSING`` ``-Wno-STATICVAR``
``-Wno-SYNCASYNCNET`` ``-Wno-UNDRIVEN`` ``-Wno-UNSIGNED``
``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL``
``-Wno-WIDTH``, plus the list shown for :vlopt:`-Wno-style`.
It is strongly recommended that you clean up your code rather than using this
option; it is only intended to be used when running test-cases of code
@@ -1537,12 +1554,13 @@ Summary:
.. option:: -Wno-style
Disable all code style related warning messages (note that by default, they are
already disabled). This is equivalent to ``-Wno-DECLFILENAME -Wno-DEFPARAM
-Wno-EOFNEWLINE -Wno-GENUNNAMED -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY
-Wno-PINNOCONNECT -Wno-SYNCASYNCNET -Wno-UNDRIVEN
-Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL
-Wno-VARHIDDEN``.
Disable all code style related warning messages (note that by default,
they are already disabled). This is equivalent to ``-Wno-DECLFILENAME``
``-Wno-DEFPARAM`` ``-Wno-EOFNEWLINE`` ``-Wno-GENUNNAMED``
``-Wno-IMPORTSTAR`` ``-Wno-INCABSPATH`` ``-Wno-PINCONNECTEMPTY``
``-Wno-PINNOCONNECT`` ``-Wno-SYNCASYNCNET`` ``-Wno-UNDRIVEN``
``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL``
``-Wno-VARHIDDEN``.
.. option:: -Wpedantic
@@ -1560,20 +1578,25 @@ Summary:
.. option:: -Wwarn-lint
Enable all lint-related warning messages (note that by default, they are already
enabled), but do not affect style messages. This is equivalent to
``-Wwarn-ALWCOMBORDER -Wwarn-ASCRANGE -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE
-Wwarn-CASEOVERLAP -Wwarn-CASEWITHX -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CMPCONST
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-IMPLICITSTATIC -Wwarn-LATCH -Wwarn-MISINDENT
-Wwarn-NEWERSTD -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-STATICVAR -Wwarn-UNSIGNED
-Wwarn-WIDTHTRUNC -Wwarn-WIDTHEXPAND -Wwarn-WIDTHXZEXPAND``.
Enable all lint-related warning messages (note that by default, they are
already enabled), but do not affect style messages. This is equivalent
to ``-Wwarn-ALWCOMBORDER`` ``-Wwarn-ASCRANGE`` ``-Wwarn-BSSPACE``
``-Wwarn-CASEINCOMPLETE`` ``-Wwarn-CASEOVERLAP`` ``-Wwarn-CASEWITHX``
``-Wwarn-CASEX`` ``-Wwarn-CASTCONST`` ``-Wwarn-CMPCONST``
``-Wwarn-COLONPLUS`` ``-Wwarn-IMPLICIT`` ``-Wwarn-IMPLICITSTATIC``
``-Wwarn-LATCH`` ``-Wwarn-MISINDENT`` ``-Wwarn-NEWERSTD``
``-Wwarn-PINMISSING`` ``-Wwarn-REALCVT`` ``-Wwarn-STATICVAR``
``-Wwarn-UNSIGNED`` ``-Wwarn-WIDTHTRUNC`` ``-Wwarn-WIDTHEXPAND``
``-Wwarn-WIDTHXZEXPAND``.
.. option:: -Wwarn-style
Enable all code style-related warning messages. This is equivalent to
``-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-EOFNEWLINE
-Wwarn-GENUNNAMED -Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN
-Wwarn-UNUSEDGENVAR -Wwarn-UNUSEDPARAM -Wwarn-UNUSEDSIGNAL -Wwarn-VARHIDDEN``.
``-Wwarn-ASSIGNDLY`` ``-Wwarn-DECLFILENAME`` ``-Wwarn-DEFPARAM``
``-Wwarn-EOFNEWLINE`` ``-Wwarn-GENUNNAMED`` ``-Wwarn-INCABSPATH``
``-Wwarn-PINNOCONNECT`` ``-Wwarn-SYNCASYNCNET`` ``-Wwarn-UNDRIVEN``
``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDPARAM`` ``-Wwarn-UNUSEDSIGNAL``
``-Wwarn-VARHIDDEN``.
.. option:: --x-assign 0
+39 -10
View File
@@ -64,30 +64,59 @@ if there are multiple coverage points on a single line they will merge.
The minimum coverage across all merged points will be used to report
coverage of the line.
The first character of the line shows a summary of the coverage; this
allows use of grep to filter the report. `%` indicates at least one point
on the line was below the coverage limit. `+` indicates an
:option:`--annotate-points` point was at or above the limit, and `-` that
the point was below the limit.
Coverage data is annotated at the beginning of the line and is formatted
as a special character followed by the number of coverage hits. The special
characters " ,%,+,-" indicate summary of the coverage, and allow use of grep
to filter the report.
* " " (whitespace) indicates that all points on the line are above the coverage limit.
* "%" indicates at least one point on the line was below the coverage limit.
* "+" coverage point was at or above the limit. Only used with :option:`--annotate-points`.
* "-" coverage point was below the limit. Only used with :option:`--annotate-points`.
.. code-block::
100000 input logic a; // Begins with whitespace, because
// number of hits (100000) is above the limit.
+100000 point: comment=a // Begins with +, because
// number of hits (100000) is above the limit.
%000000 input logic b; // Begins with %, because
// number of hits (0) is below the limit.
-000000 point: comment=b // Begins with -, because
// number of hits (0) is below the limit.
.. option:: --annotate-all
Specifies all files should be shown. By default, only those source files
with low coverage are written to the output directory.
This option should be used together with :option:`--annotate`.
.. option:: --annotate-min <count>
Specifies if the coverage point does not include the count number of
coverage hits, then the coverage point will be considered above the
threshold, and the coverage report will put a "%" to indicate the coverage
is insufficient. Defaults to 10.
Specifies the threshold (<count>) below which coverage point is considered
sufficient. If the threshold is not exceeded, then the annotation will begin
with a "%" symbol to indicate the coverage is insufficient.
The <count> threshold defaults to 10.
This option should be used together with :option:`--annotate`.
.. option:: --annotate-points
Specifies all coverage points should be shown after each line of text. By
default, only source lines are shown.
with low coverage are written to the output directory.
.. code-block::
100000 input logic a, b, c;
+100000 point: comment=a // These lines are only shown
+200000 point: comment=b // with option --annotate-points
+300000 point: comment=c // enabled.
This option should be used together with :option:`--annotate`.
.. option:: --help
+6 -8
View File
@@ -30,15 +30,13 @@ Gantt Chart VCD Signals
In waveforms, there are the following signals. In GTKWave, use "decimal"
data format to remove the leading zeros and make the traces easier to read.
evals
Increments each time when eval_step was measured to be active. This
allow visualization of how much time eval_step was active.
trace/section
Shows the name of the current top of the execution section stack.
Set GTKWave data format to "ASCII".
eval_loop
Increments each time when the evaluation loop within eval_step was
measured to be active. For best performance, there is only a single
evaluation loop within each eval_step call; that is, the eval_loop
waveform looks identical to the evals waveform.
trace/depth
Shows the depth of the execution section stack.
Set GTKWave data format to "Analog".
measured_parallelism
The number of mtasks active at this time, for best performance, this will
+10 -3
View File
@@ -17,14 +17,21 @@ or "`ifdef`"'s may break other tools.
.. option:: `__LINE__
The :option:`\`__LINE__` define expands to the current filename as a
string, like C++'s __LINE__. This Verilator feature added in 2006 was
incorporated into IEEE 1800-2009.
The :option:`\`__LINE__` define expands to the current line number like
C++'s __LINE__. This Verilator feature added in 2006 was incorporated
into IEEE 1800-2009.
.. option:: `error [string]
This will report an error when encountered, like C++'s #error.
.. option:: `line
As a special case `\`line \`__LINE__ "filename"` allows setting the
filename, without changing the line number. This is used for some
internal tests, so that debugging can leave the line numbers correctly
referring to the test file's line numbers.
.. option:: """ [string] """
A triple-quoted block specifies a string that may include newlines and
+1 -1
View File
@@ -126,7 +126,7 @@ Those developing Verilator itself may also want these (see internals.rst):
::
sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov
sudo apt-get install libclang-dev yapf3
sudo apt-get install libclang-dev yapf3 bear
sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
cpan install Pod::Perldoc
cpan install Parallel::Forker
+18 -37
View File
@@ -237,11 +237,9 @@ optimizations will be disabled around the latch.
Structures and Unions
---------------------
Presently Verilator only supports packed structs and packed unions. Rand
and randc tags on members are ignored. All structures and unions are
represented as a single vector, which means that generating one member of a
structure from blocking, and another from non-blocking assignments is
unsupported.
All structures and unions are scheduled together, which means that
generating one member of a structure from blocking, and another from
non-blocking assignments is unsupported.
.. _Unknown States:
@@ -320,20 +318,6 @@ there will be considered a two-state variable that is read and written
instead of a four-state variable.
Functions & Tasks
-----------------
All functions and tasks will be inlined (will not become functions in C.)
The only support provided is simple statements in tasks (which may
affect global variables).
Recursive functions and tasks are not supported. All inputs and outputs
are automatic as if they had the Verilog 2001 "automatic" keyword
prepended. (If you don't know what this means, Verilator will do what you
probably expect, what C does. The default behavior of Verilog is
different.)
Gate Primitives
---------------
@@ -383,24 +367,6 @@ Verilator does not support SEREs yet. All assertion and coverage
statements must be simple expressions that complete in one cycle.
Force statement
---------------
Verilator supports the procedural `force` (and corresponding `release`)
statement. However, the behavior of the `force` statement does not entirely
comply with IEEE 1800. According to the standard,
when a procedural statement of the form `force a = b;` is executed, the
simulation should behave as if, from that point forwards, a continuous
assignment `assign a = b;` has been added to override the drivers of `a`.
More specifically: the value of `a` should be updated whenever the value of
`b` changes, until a `release a;` statement is executed.
Verilator instead evaluates the current value of `b` when the `force`
statement is executed, and forces `a` to that value, without updating it
until a new `force` or `release` statement is encountered that applies to
`a`. This non-standard behavior is nevertheless consistent with some other
simulators.
Encrypted Verilog
-----------------
@@ -471,6 +437,21 @@ disable
provide loop break and continue functionality before SystemVerilog added
the break and continue keywords.
force, release
Verilator supports the procedural `force` (and corresponding `release`)
statement. However, the behavior of the `force` statement does not
entirely comply with IEEE 1800. According to the standard, when a
procedural statement of the form `force a = b;` is executed, the
simulation should behave as if, from that point forwards, a continuous
assignment `assign a = b;` has been added to override the drivers of `a`.
More specifically: the value of `a` should be updated whenever the value
of `b` changes, until a `release a;` statement is executed. Verilator
instead evaluates the current value of `b` when the `force` statement is
executed, and forces `a` to that value, without updating it until a new
`force` or `release` statement is encountered that applies to `a`. This
non-standard behavior is nevertheless consistent with some other
simulators.
inside
Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.
+1 -1
View File
@@ -44,7 +44,7 @@ The best place to get started is to try the :ref:`Examples`.
.. [#] Verilog is defined by the `Institute of Electrical and Electronics
Engineers (IEEE) Standard for Verilog Hardware Description
Language`, Std. 1364, released in 1995, 2001, and 2005. The
Verilator documentation uses the shorthand, e.g., "IEEE 1394-2005",
Verilator documentation uses the shorthand, e.g., "IEEE 1364-2005",
to refer to the, e.g., 2005 version of this standard.
.. [#] SystemVerilog is defined by the `Institute of Electrical and
+65 -16
View File
@@ -12,10 +12,18 @@ Disabling Warnings
Warnings may be disabled in multiple ways:
#. Disable the warning in the source code. When the warning is printed, it
will include a warning code. Surround the offending line with a
:code:`/*verilator&32;lint_off*/` and :code:`/*verilator&32;lint_on*/`
metacomment pair:
#. Disable the warning globally by invoking Verilator with the
:code:`-Wno-{warning-code}` option.
Global disables should be avoided, as they removes all checking across
the source files, and prevents other users from compiling the sources
without knowing the magic set of disables needed to compile those
sources successfully.
#. Disable the warning in the design source code. When the warning is
printed, it will include a warning code. Surround the offending line
with a :code:`/*verilator&32;lint_off*/` and
:code:`/*verilator&32;lint_on*/` metacomment pair:
.. code-block:: sv
@@ -23,6 +31,12 @@ Warnings may be disabled in multiple ways:
if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop;
// verilator lint_on UNSIGNED
A lint_off in the design source code will propagate down to any child
files (files later included by the file with the lint_off), but will not
propagate upwards to any parent file (file that included the file with
the lint_off).
#. Disable the warning using :ref:`Configuration Files` with a
:option:`lint_off` command. This is useful when a script suppresses
warnings, and the Verilog source should not be changed. This method also
@@ -32,12 +46,6 @@ Warnings may be disabled in multiple ways:
lint_off -rule UNSIGNED -file "*/example.v" -line 1
#. Disable the warning globally invoking Verilator with the
:code:`-Wno-{warning-code}` option. This should be avoided, as it
removes all checking across the designs, and prevents other users from
compiling your code without knowing the magic set of disables needed to
compile your design successfully.
Error And Warning Format
========================
@@ -1166,7 +1174,7 @@ List Of Warnings
Warns that a feature requires a newer standard of Verilog or SystemVerilog
than the one specified by the :vlopt:`--language` option. For example, unsized
unbased literals (`'0`, `'1`, `'z`, `'x`) require 1800-2005 or later.
unbased literals (`'0`, `'1`, `'z`, `'x`) require IEEE 1800-2005 or later.
To avoid this warning, use a Verilog or SystemVerilog standard that
supports the feature. Alternatively, modify your code to use a different
@@ -1360,7 +1368,10 @@ List Of Warnings
.. option:: RANDC
Warns that the :code:`randc` keyword is unsupported and being converted
Historical, never issued since version 5.018, when :code:`randc` became
fully supported.
Warned that the :code:`randc` keyword was unsupported and was converted
to :code:`rand`.
@@ -1503,6 +1514,39 @@ List Of Warnings
modeled values, or DPI calls.
.. option:: SIDEEFFECT
Warns that an expression has a side effect that might not properly be
executed by Verilator.
This often represents a bug in Verilator, as opposed to a bad code
construct, however the Verilog code can typically be changed to avoid
the warning.
Faulty example:
.. code-block:: sv
:linenos:
:emphasize-lines: 1
x = y[a++];
This example warns because Verilator does not currently handle side
effects inside array subscripts; the a++ may be executed multiple times.
Rewrite the code to avoid expression side effects, typically by using a
temporary:
.. code-block:: sv
:linenos:
temp = a++;
x = y[temp];
Ignoring this warning may make Verilator simulations differ from other
simulators.
.. option:: SPLITVAR
Warns that a variable with a :option:`/*verilator&32;split_var*/`
@@ -1990,11 +2034,15 @@ List Of Warnings
.. code-block:: sv
wait(0); // Blocks forever
wait(1); // Blocks forever
Warns that a `wait` statement awaits a constant condition, which means it
either blocks forever or never blocks.
As a special case `wait(0)` with the literal constant `0` (as opposed to
something that elaborates to zero), does not warn, as it is presumed the
code is making the intent clear.
.. option:: WIDTH
@@ -2039,17 +2087,18 @@ List Of Warnings
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst
.. option:: WIDTHTRUNC
A more granular WIDTH warning, for when a value is truncated
A more granular WIDTH warning, for when a value is truncated.
.. option:: WIDTHEXPAND
A more granular WIDTH warning, for when a value is zero expanded
A more granular WIDTH warning, for when a value is zero expanded.
.. option:: WIDTHXZEXPAND
A more granular WIDTH warning, for when a value is X/Z expanded
A more granular WIDTH warning, for when a value is X/Z expanded.
.. option:: WIDTHCONCAT
+18 -5
View File
@@ -1222,9 +1222,9 @@ There are three ways data is passed between visitor functions.
2. User attributes. Each ``AstNode`` (**Note.** The AST node, not the
visitor) has five user attributes, which may be accessed as an
integer using the ``user1()`` through ``user5()`` methods, or as a
integer using the ``user1()`` through ``user4()`` methods, or as a
pointer (of type ``AstNUser``) using the ``user1p()`` through
``user5p()`` methods (a common technique lifted from graph traversal
``user4p()`` methods (a common technique lifted from graph traversal
packages).
A visitor first clears the one it wants to use by calling
@@ -1400,7 +1400,7 @@ Controlling the Test Driver
---------------------------
The test driver script `driver.pl` runs tests; see the `Test Driver`
section. The individual test drivers are written in PERL; see `Test
section. The individual test drivers are written in Perl; see `Test
Language`.
@@ -1432,7 +1432,7 @@ Developers will also want to call ./configure with two extra flags:
disabled by default, as SystemC installation problems would otherwise
falsely indicate a Verilator problem.
When enabling the long tests, some additional PERL modules are needed,
When enabling the long tests, some additional Perl modules are needed,
which you can install using cpan.
::
@@ -1462,6 +1462,19 @@ There are some traps to avoid when running regression tests
system-dependent, but on Fedora Linux it would require editing the
``/etc/security/limits.conf`` file as root.
Diffing generated code after changes
------------------------------------
When making a change in the code generation area that should not change the
actual emitted code, it is useful to perform a diff to make sure the emitted
code really did not change. To do this, the top level Makefile provides the
*test-snap* and *test-diff* targets:
- Run the test suite with ``make test``
- Take a snapshot with ``make test-snap``
- Apply your changes
- Run the test suite again with ``make test``
- See the changes in the output with ``make test-diff``
Continuous Integration
----------------------
@@ -1640,7 +1653,7 @@ Source file and line
file is ``a``, the 26th is ``z``, the 27th is ``aa``, and so on.
User pointers
Shows the value of the node's user1p...user5p, if non-NULL.
Shows the value of the node's user1p...user4p, if non-NULL.
Data type
Many nodes have an explicit data type. "@dt=0x..." indicates the
+19
View File
@@ -35,11 +35,13 @@ Briquet
Brownlee
Buckenmaier
Bybell
CLang
CMake
Cai
Cavium
Cfuncs
Chandan
Chih
Chitlesh
Christophe
Cochrane
@@ -89,6 +91,7 @@ Engstrom
Enzo
Eugen
Fabrizio
Faucher
Fekete
Ferrandi
Flachs
@@ -214,6 +217,7 @@ Maupin
Mdir
Mednick
Menküc
Michail
Michiels
Microsystems
Milanovic
@@ -229,6 +233,7 @@ Mong
Muhlestein
Multithreaded
Multithreading
Mykyta
NOUNOPTFLAT
NaN
Nalbantis
@@ -263,6 +268,7 @@ Pre
Preprocess
Pretet
Pretl
Pringlemeir
Priyadharshini
Pullup
Pulver
@@ -277,6 +283,7 @@ Renga
Requin
Rodionov
Rolfe
Rontionov
Roodselaar
Runtime
Ruud
@@ -415,6 +422,7 @@ arrarys
assertOn
astgen
async
atClone
ato
atoi
autoconf
@@ -482,6 +490,7 @@ countbits
countones
cout
cpp
cppstyle
cpu
ctor
ctrace
@@ -516,6 +525,7 @@ doxygen
dpiGetContext
dpic
dsvf
dt
dtor
dumpall
dumpfile
@@ -653,6 +663,7 @@ ish
isunbounded
isunknown
jobserver
jwoutersymatra
killua
lang
lcov
@@ -716,6 +727,7 @@ multithreading
musl
mutexes
mux
muzafferkal
myftptoyman
mysignal
namespace
@@ -754,6 +766,7 @@ pdf
perf
perftools
pgo
phelter
picoChip
pinIndex
pinout
@@ -771,7 +784,9 @@ pragma
pragmas
pre
precisions
precompiled
predefines
prepareClone
prepend
prepended
preprocess
@@ -799,6 +814,7 @@ radix
randc
randcase
randstate
raphmaster
rarr
rdtsc
reStructuredText
@@ -808,6 +824,7 @@ readmemb
readmemh
realpath
realtime
realtobits
recoding
recrem
redeclaring
@@ -930,7 +947,9 @@ vc
vcd
vcddiff
vcoverage
vdhotre
vec
ventana
ver
verFiles
verible
+2 -1
View File
@@ -24,6 +24,7 @@
#include "Vtop.h"
using namespace sc_core;
using namespace sc_dt;
int sc_main(int argc, char* argv[]) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
@@ -52,7 +53,7 @@ int sc_main(int argc, char* argv[]) {
Verilated::commandArgs(argc, argv);
// General logfile
ios::sync_with_stdio();
std::ios::sync_with_stdio();
// Define clocks
sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true};
+2 -2
View File
@@ -60,8 +60,8 @@ class VlFileCopy:
print("\t%s " % command)
status = subprocess.call(command, shell=True)
if status != 0:
raise Exception("Command failed running Verilator with '" +
command + "', stopped")
raise RuntimeError("Command failed running Verilator with '" +
command + "', stopped")
#######################################################################
+2 -2
View File
@@ -83,8 +83,8 @@ class VlHierGraph:
print("\t%s " % command)
status = subprocess.call(command, shell=True)
if status != 0:
raise Exception("Command failed running Verilator with '" +
command + "', stopped")
raise RuntimeError("Command failed running Verilator with '" +
command + "', stopped")
#######################################################################
+1 -1
View File
@@ -4181,7 +4181,7 @@ if(!(isfeof=feof(xc->fh)))
if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM))
{
int sidx_skiplen_dummy = 0;
xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy);
xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_attr, &sidx_skiplen_dummy);
}
}
break;
+12 -3
View File
@@ -320,7 +320,7 @@ std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
const char* const stateCharsp = reinterpret_cast<const char*>(&m_state);
static_assert(sizeof(m_state) == 16, "");
std::string result{"R00112233445566770011223344556677"};
for (int i = 0; i < sizeof(m_state); ++i) {
for (size_t i = 0; i < sizeof(m_state); ++i) {
result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15);
result[1 + i * 2 + 1] = 'a' + (stateCharsp[i] & 15);
}
@@ -332,7 +332,7 @@ void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
return;
}
char* const stateCharsp = reinterpret_cast<char*>(&m_state);
for (int i = 0; i < sizeof(m_state); ++i) {
for (size_t i = 0; i < sizeof(m_state); ++i) {
stateCharsp[i]
= (((state[1 + i * 2] - 'a') & 15) << 4) | ((state[1 + i * 2 + 1] - 'a') & 15);
}
@@ -2094,7 +2094,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end && !m_anyAddr)) {
VL_WARN_MT(m_filename.c_str(), m_linenum, "",
"$readmem file ended before specified final address (IEEE 2017 21.4)");
"$readmem file ended before specified final address (IEEE 1800-2017 21.4)");
}
return false; // EOF
@@ -2608,6 +2608,14 @@ VerilatedVirtualBase* VerilatedContext::threadPoolp() {
return m_threadPool.get();
}
void VerilatedContext::prepareClone() { delete m_threadPool.release(); }
VerilatedVirtualBase* VerilatedContext::threadPoolpOnClone() {
if (VL_UNLIKELY(m_threadPool)) m_threadPool.release();
m_threadPool = std::unique_ptr<VlThreadPool>(new VlThreadPool{this, m_threads - 1});
return m_threadPool.get();
}
VerilatedVirtualBase*
VerilatedContext::enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&)) {
if (!m_executionProfiler) m_executionProfiler.reset(construct(*this));
@@ -3016,6 +3024,7 @@ void Verilated::endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
// It should be ok to call into endOfEvalGuts, it returns immediately
// if there are no transactions.
VL_DEBUG_IF(VL_DBG_MSGF("End-of-eval cleanup\n"););
VerilatedThreadMsgQueue::flush(evalMsgQp);
evalMsgQp->process();
}
+7 -1
View File
@@ -133,7 +133,8 @@ enum VerilatedVarType : uint8_t {
VLVT_UINT32, // AKA IData
VLVT_UINT64, // AKA QData
VLVT_WDATA, // AKA WData
VLVT_STRING // C++ string
VLVT_STRING, // C++ string
VLVT_REAL // AKA double
};
enum VerilatedVarFlags {
@@ -164,7 +165,9 @@ inline constexpr size_t roundUpToMultipleOf(size_t value) {
// Return current thread ID (or 0), not super fast, cache if needed
extern uint32_t VL_THREAD_ID() VL_MT_SAFE;
#ifndef VL_LOCK_SPINS
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
#endif
/// Mutex, wrapped to allow -fthread_safety checks
class VL_CAPABILITY("mutex") VerilatedMutex final {
@@ -568,6 +571,8 @@ public:
void addModel(VerilatedModel*);
VerilatedVirtualBase* threadPoolp();
void prepareClone();
VerilatedVirtualBase* threadPoolpOnClone();
VerilatedVirtualBase*
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
@@ -917,6 +922,7 @@ public:
// Internal: Called at end of each thread mtask, before finishing eval
static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
mtaskId(0);
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp);
}
// Internal: Called at end of eval loop
+52 -14
View File
@@ -9,6 +9,9 @@
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
######################################################################
# Tool names.
# These are computed at configuration time, and most are not ?=
# to avoid picking up potentilly incorrect Make implicit variables
AR = @AR@
CXX = @CXX@
LINK = @CXX@
@@ -16,6 +19,7 @@ OBJCACHE ?= @OBJCACHE@
PERL = @PERL@
PYTHON3 = @PYTHON3@
# Configuration time options
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
@@ -31,6 +35,12 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
# Compiler flags that enable coroutine support
CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
# Compiler flags when creating a precompiled header
CFG_CXXFLAGS_PCH = -x c++-header
# Compiler option to put in front of filename to read precompiled header
CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
# Linker flags
CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
# Linker libraries for multithreading
@@ -43,6 +53,12 @@ VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
VERILATOR_INCLUDER = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_includer
VERILATOR_CCACHE_REPORT = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_ccache_report
######################################################################
# CCACHE flags (via environment as no command line option available)
CCACHE_SLOPPINESS ?= pch_defines,time_macros
export CCACHE_SLOPPINESS
######################################################################
# Make checks
@@ -162,11 +178,17 @@ endif
VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
# Precompiled header filename
VK_PCH_H = $(VM_PREFIX)__pch.h
# Compiler read-a-precompiled-header option for precompiled header filename
VK_PCH_I_FAST = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.fast$(CFG_GCH_IF_CLANG)
VK_PCH_I_SLOW = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.slow$(CFG_GCH_IF_CLANG)
#######################################################################
### Overall Objects Linking
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
VK_OBJS_FAST = $(addsuffix .o, $(VM_FAST))
VK_OBJS_SLOW = $(addsuffix .o, $(VM_SLOW))
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
@@ -193,7 +215,7 @@ else
# Parallel build: Each .cpp file by itself. This can be somewhat slower for
# very small designs and examples, but is a lot faster for large designs.
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
VK_OBJS += $(VK_OBJS_FAST) $(VK_OBJS_SLOW)
endif
# When archiving just objects (.o), use single $(AR) run
@@ -237,18 +259,32 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
### Compile rules
ifneq ($(VM_DEFAULT_RULES),0)
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
# and user files passed on the Verilator command line use this rule.
# We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
# Compilation rule for anything not in $(VK_OBJS_FAST), $(VK_OBJS_SLOW), or
# $(VK_GLOBAL_OBJS) including verilated.o. This typically means user files
# passed on the Verilator command line.
#
# These rules put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
# allow USER_CPPFLAGS to override them
%.o: %.cpp
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
$(VK_SLOW_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
$(VK_OBJS_FAST): %.o: %.cpp $(VK_PCH_H).fast.gch
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_FAST) -c -o $@ $<
$(VK_OBJS_SLOW): %.o: %.cpp $(VK_PCH_H).slow.gch
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_SLOW) -c -o $@ $<
$(VK_GLOBAL_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
# Precompile a header file
# PCH's compiler flags must match exactly the rules' above FAST/SLOW
# arguments used for the .cpp files, or the PCH file won't be used.
%.fast.gch: %
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
%.slow.gch: %
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
endif
#Default rule embedded in make:
@@ -296,19 +332,21 @@ endif
debug-make::
@echo
@echo CXXFLAGS: $(CXXFLAGS)
@echo CPPFLAGS: $(CPPFLAGS)
@echo CXXFLAGS: $(CXXFLAGS)
@echo OPT_FAST: $(OPT_FAST)
@echo OPT_SLOW: $(OPT_SLOW)
@echo VM_PREFIX: $(VM_PREFIX)
@echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS)
@echo VK_OBJS: $(VK_OBJS)
@echo VK_OBJS_FAST: $(VK_OBJS_FAST)
@echo VK_OBJS_SLOW: $(VK_OBJS_SLOW)
@echo VM_CLASSES_FAST: $(VM_CLASSES_FAST)
@echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW)
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
@echo VK_OBJS: $(VK_OBJS)
@echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS)
@echo VM_PREFIX: $(VM_PREFIX)
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
@echo
######################################################################
+115 -106
View File
@@ -23,7 +23,6 @@
// clang-format off
#define __STDC_LIMIT_MACROS // UINT64_MAX
#include "verilated.h"
#include "verilated_fst_c.h"
@@ -40,6 +39,7 @@
#include <algorithm>
#include <iterator>
#include <sstream>
#include <type_traits>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
@@ -50,33 +50,10 @@
// clang-format on
//=============================================================================
// Check that vltscope_t matches fstScopeType
// Check that forward declared types matches the FST API types
static_assert(static_cast<int>(FST_ST_VCD_MODULE) == static_cast<int>(VLT_TRACE_SCOPE_MODULE),
"VLT_TRACE_SCOPE_MODULE mismatches");
static_assert(static_cast<int>(FST_ST_VCD_TASK) == static_cast<int>(VLT_TRACE_SCOPE_TASK),
"VLT_TRACE_SCOPE_TASK mismatches");
static_assert(static_cast<int>(FST_ST_VCD_FUNCTION) == static_cast<int>(VLT_TRACE_SCOPE_FUNCTION),
"VLT_TRACE_SCOPE_FUNCTION mismatches");
static_assert(static_cast<int>(FST_ST_VCD_BEGIN) == static_cast<int>(VLT_TRACE_SCOPE_BEGIN),
"VLT_TRACE_SCOPE_BEGIN mismatches");
static_assert(static_cast<int>(FST_ST_VCD_FORK) == static_cast<int>(VLT_TRACE_SCOPE_FORK),
"VLT_TRACE_SCOPE_FORK mismatches");
static_assert(static_cast<int>(FST_ST_VCD_GENERATE) == static_cast<int>(VLT_TRACE_SCOPE_GENERATE),
"VLT_TRACE_SCOPE_GENERATE mismatches");
static_assert(static_cast<int>(FST_ST_VCD_STRUCT) == static_cast<int>(VLT_TRACE_SCOPE_STRUCT),
"VLT_TRACE_SCOPE_STRUCT mismatches");
static_assert(static_cast<int>(FST_ST_VCD_UNION) == static_cast<int>(VLT_TRACE_SCOPE_UNION),
"VLT_TRACE_SCOPE_UNION mismatches");
static_assert(static_cast<int>(FST_ST_VCD_CLASS) == static_cast<int>(VLT_TRACE_SCOPE_CLASS),
"VLT_TRACE_SCOPE_CLASS mismatches");
static_assert(static_cast<int>(FST_ST_VCD_INTERFACE)
== static_cast<int>(VLT_TRACE_SCOPE_INTERFACE),
"VLT_TRACE_SCOPE_INTERFACE mismatches");
static_assert(static_cast<int>(FST_ST_VCD_PACKAGE) == static_cast<int>(VLT_TRACE_SCOPE_PACKAGE),
"VLT_TRACE_SCOPE_PACKAGE mismatches");
static_assert(static_cast<int>(FST_ST_VCD_PROGRAM) == static_cast<int>(VLT_TRACE_SCOPE_PROGRAM),
"VLT_TRACE_SCOPE_PROGRAM mismatches");
static_assert(std::is_same<vlFstHandle, fstHandle>::value, "vlFstHandle mismatch");
static_assert(std::is_same<vlFstEnumHandle, fstEnumHandle>::value, "vlFstHandle mismatch");
//=============================================================================
// Specialization of the generics for this trace format
@@ -104,19 +81,11 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref
if (m_useFstWriterThread) fstWriterSetParallelMode(m_fst, 1);
constDump(true); // First dump must contain the const signals
fullDump(true); // First dump must be full for fst
m_curScope.clear();
Super::traceInit();
// Clear the scope stack
auto it = m_curScope.begin();
while (it != m_curScope.end()) {
fstWriterSetUpscope(m_fst);
it = m_curScope.erase(it);
}
// convert m_code2symbol into an array for fast lookup
if (!m_symbolp) {
m_symbolp = new fstHandle[nextCode()]{0};
@@ -154,102 +123,142 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, uint32_t elemen
m_local2fstdtype[dtypenum] = enumNum;
}
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, bool bussed, int msb,
int lsb) {
// TODO: should return std::optional<fstScopeType>, but I can't have C++17
static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType type) {
switch (type) {
case VerilatedTracePrefixType::SCOPE_MODULE: return {true, FST_ST_VCD_MODULE};
case VerilatedTracePrefixType::SCOPE_INTERFACE: return {true, FST_ST_VCD_INTERFACE};
case VerilatedTracePrefixType::STRUCT_PACKED:
case VerilatedTracePrefixType::STRUCT_UNPACKED: return {true, FST_ST_VCD_STRUCT};
case VerilatedTracePrefixType::UNION_PACKED: return {true, FST_ST_VCD_UNION};
default: return {false, /* unused so whatever, just need a value */ FST_ST_VCD_SCOPE};
}
}
void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
const std::string newPrefix = m_prefixStack.back().first + name;
const auto pair = toFstScopeType(type);
const bool properScope = pair.first;
const fstScopeType scopeType = pair.second;
m_prefixStack.emplace_back(newPrefix + (properScope ? " " : ""), type);
if (properScope) {
const std::string scopeName = lastWord(newPrefix);
fstWriterSetScope(m_fst, scopeType, scopeName.c_str(), nullptr);
}
}
void VerilatedFst::popPrefix() {
const bool properScope = toFstScopeType(m_prefixStack.back().second).first;
if (properScope) fstWriterSetUpscope(m_fst);
m_prefixStack.pop_back();
assert(!m_prefixStack.empty());
}
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum, bool bussed,
int msb, int lsb) {
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
const bool enabled = Super::declCode(code, name, bits, false);
const std::string hierarchicalName = m_prefixStack.back().first + name;
const bool enabled = Super::declCode(code, hierarchicalName, bits);
if (!enabled) return;
std::string nameasstr = namePrefix() + name;
std::istringstream nameiss{nameasstr};
std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
std::list<std::string> tokens(beg, end); // Split name
std::string symbol_name{tokens.back()};
tokens.pop_back(); // Remove symbol name from hierarchy
std::string tmpModName;
// Find point where current and new scope diverge
auto cur_it = m_curScope.begin();
auto new_it = tokens.begin();
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
if (*cur_it != *new_it) break;
++cur_it;
++new_it;
}
// Go back to the common point
while (cur_it != m_curScope.end()) {
fstWriterSetUpscope(m_fst);
cur_it = m_curScope.erase(cur_it);
}
// Follow the hierarchy of the new variable from the common scope point
while (new_it != tokens.end()) {
if ((new_it->back() & 0x80)) {
tmpModName = *new_it;
tmpModName.pop_back();
// If the scope ends with a non-ASCII character, it will be 0x80 + fstScopeType
fstWriterSetScope(m_fst, static_cast<fstScopeType>(new_it->back() & 0x7f),
tmpModName.c_str(), nullptr);
} else {
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), nullptr);
}
m_curScope.push_back(*new_it);
new_it = tokens.erase(new_it);
}
assert(hierarchicalName.rfind(' ') != std::string::npos);
std::stringstream name_ss;
name_ss << symbol_name;
name_ss << lastWord(hierarchicalName);
if (array) name_ss << "[" << arraynum << "]";
if (bussed) name_ss << " [" << msb << ":" << lsb << "]";
std::string name_str = name_ss.str();
const std::string name_str = name_ss.str();
if (dtypenum > 0) {
const fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
fstWriterEmitEnumTableRef(m_fst, enumNum);
if (dtypenum > 0) fstWriterEmitEnumTableRef(m_fst, m_local2fstdtype[dtypenum]);
fstVarDir varDir;
switch (direction) {
case VerilatedTraceSigDirection::INOUT: varDir = FST_VD_INOUT; break;
case VerilatedTraceSigDirection::OUTPUT: varDir = FST_VD_OUTPUT; break;
case VerilatedTraceSigDirection::INPUT: varDir = FST_VD_INPUT; break;
case VerilatedTraceSigDirection::NONE: varDir = FST_VD_IMPLICIT; break;
}
fstVarType varType;
// Doubles have special decoding properties, so must indicate if a double
if (type == VerilatedTraceSigType::DOUBLE) {
if (kind == VerilatedTraceSigKind::PARAMETER) {
varType = FST_VT_VCD_REAL_PARAMETER;
} else {
varType = FST_VT_VCD_REAL;
}
}
// clang-format off
else if (kind == VerilatedTraceSigKind::PARAMETER) varType = FST_VT_VCD_PARAMETER;
else if (kind == VerilatedTraceSigKind::SUPPLY0) varType = FST_VT_VCD_SUPPLY0;
else if (kind == VerilatedTraceSigKind::SUPPLY1) varType = FST_VT_VCD_SUPPLY1;
else if (kind == VerilatedTraceSigKind::TRI) varType = FST_VT_VCD_TRI;
else if (kind == VerilatedTraceSigKind::TRI0) varType = FST_VT_VCD_TRI0;
else if (kind == VerilatedTraceSigKind::TRI1) varType = FST_VT_VCD_TRI1;
else if (kind == VerilatedTraceSigKind::WIRE) varType = FST_VT_VCD_WIRE;
//
else if (type == VerilatedTraceSigType::INTEGER) varType = FST_VT_VCD_INTEGER;
else if (type == VerilatedTraceSigType::BIT) varType = FST_VT_SV_BIT;
else if (type == VerilatedTraceSigType::LOGIC) varType = FST_VT_SV_LOGIC;
else if (type == VerilatedTraceSigType::INT) varType = FST_VT_SV_INT;
else if (type == VerilatedTraceSigType::SHORTINT) varType = FST_VT_SV_SHORTINT;
else if (type == VerilatedTraceSigType::LONGINT) varType = FST_VT_SV_LONGINT;
else if (type == VerilatedTraceSigType::BYTE) varType = FST_VT_SV_BYTE;
else if (type == VerilatedTraceSigType::EVENT) varType = FST_VT_VCD_EVENT;
else if (type == VerilatedTraceSigType::TIME) varType = FST_VT_VCD_TIME;
else { assert(0); /* Unreachable */ }
// clang-format on
const auto it = vlstd::as_const(m_code2symbol).find(code);
if (it == m_code2symbol.end()) { // New
m_code2symbol[code]
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
= fstWriterCreateVar(m_fst, varType, varDir, bits, name_str.c_str(), 0);
} else { // Alias
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
fstWriterCreateVar(m_fst, varType, varDir, bits, name_str.c_str(), it->second);
}
}
void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
void VerilatedFst::declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum) {
declare(code, name, dtypenum, direction, kind, type, array, arraynum, false, 0, 0);
}
void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
void VerilatedFst::declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum) {
declare(code, name, dtypenum, direction, kind, type, array, arraynum, false, 0, 0);
}
void VerilatedFst::declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
void VerilatedFst::declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum, int msb,
int lsb) {
declare(code, name, dtypenum, direction, kind, type, array, arraynum, true, msb, lsb);
}
void VerilatedFst::declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
void VerilatedFst::declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum, int msb,
int lsb) {
declare(code, name, dtypenum, direction, kind, type, array, arraynum, true, msb, lsb);
}
void VerilatedFst::declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
void VerilatedFst::declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum, int msb,
int lsb) {
declare(code, name, dtypenum, direction, kind, type, array, arraynum, true, msb, lsb);
}
void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 63, 0);
void VerilatedFst::declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
VerilatedTraceSigType type, bool array, int arraynum) {
declare(code, name, dtypenum, direction, kind, type, array, arraynum, false, 63, 0);
}
//=============================================================================
// Get/commit trace buffer
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer() {
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer(uint32_t fidx) {
if (offload()) return new OffloadBuffer{*this};
return new Buffer{*this};
}
@@ -284,7 +293,7 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitEvent(uint32_t code, VlEvent newval) {
void VerilatedFstBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
}
+37 -23
View File
@@ -24,13 +24,14 @@
#include "verilated.h"
#include "verilated_trace.h"
#include "gtkwave/fstapi.h"
#include <list>
#include <map>
#include <string>
#include <vector>
typedef uint32_t vlFstHandle;
typedef uint32_t vlFstEnumHandle;
class VerilatedFstBuffer;
//=============================================================================
@@ -49,18 +50,22 @@ private:
// FST specific internals
void* m_fst = nullptr;
std::map<uint32_t, fstHandle> m_code2symbol;
std::map<int, fstEnumHandle> m_local2fstdtype;
std::list<std::string> m_curScope;
fstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
std::map<uint32_t, vlFstHandle> m_code2symbol;
std::map<int, vlFstEnumHandle> m_local2fstdtype;
vlFstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
char* m_strbufp = nullptr; // String buffer long enough to hold maxBits() chars
bool m_useFstWriterThread = false; // Whether to use the separate FST writer thread
// Prefixes to add to signal names/scope types
std::vector<std::pair<std::string, VerilatedTracePrefixType>> m_prefixStack{
{"", VerilatedTracePrefixType::SCOPE_MODULE}};
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFst);
void declare(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, bool bussed, int msb, int lsb);
void declare(uint32_t code, const char* name, int dtypenum, VerilatedTraceSigDirection,
VerilatedTraceSigKind, VerilatedTraceSigType, bool array, int arraynum,
bool bussed, int msb, int lsb);
protected:
//=========================================================================
@@ -74,7 +79,7 @@ protected:
bool preChangeDump() override { return isOpen(); }
// Trace buffer management
Buffer* getTraceBuffer() override;
Buffer* getTraceBuffer(uint32_t fidx) override;
void commitTraceBuffer(Buffer*) override;
// Configure sub-class
@@ -101,18 +106,27 @@ public:
//=========================================================================
// Internal interface to Verilator generated code
void declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void pushPrefix(const std::string&, VerilatedTracePrefixType);
void popPrefix();
void declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declDTypeEnum(int dtypenum, const char* name, uint32_t elements, unsigned int minValbits,
const char** itemNamesp, const char** itemValuesp);
@@ -149,7 +163,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// The FST file handle
void* const m_fst = m_owner.m_fst;
// code to fstHande map, as an array
const fstHandle* const m_symbolp = m_owner.m_symbolp;
const vlFstHandle* const m_symbolp = m_owner.m_symbolp;
// String buffer long enough to hold maxBits() chars
char* const m_strbufp = m_owner.m_strbufp;
@@ -163,7 +177,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
+100 -63
View File
@@ -344,8 +344,8 @@ uint64_t vl_time_pow10(int n) VL_PURE;
// Output clean
// EMIT_RULE: VL_CLEAN: oclean=clean; obits=lbits;
#define VL_CLEAN_II(obits, lbits, lhs) ((lhs)&VL_MASK_I(obits))
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits))
#define VL_CLEAN_II(obits, lbits, lhs) ((lhs) & (VL_MASK_I(obits)))
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs) & (VL_MASK_Q(obits)))
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (owp), (lwp))
@@ -449,7 +449,7 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
#define VL_ASSIGN_WSB(obits, owp, svar) \
{ \
const int words = VL_WORDS_I(obits); \
sc_biguint<(obits)> _butemp = (svar).read(); \
sc_dt::sc_biguint<(obits)> _butemp = (svar).read(); \
uint32_t* chunkp = _butemp.get_raw(); \
int32_t lsb = 0; \
while (lsb < obits - BITS_PER_DIGIT) { \
@@ -475,20 +475,20 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
#define VL_ASSIGN_SWI(obits, svar, rd) \
{ \
sc_bv<(obits)> _bvtemp; \
sc_dt::sc_bv<(obits)> _bvtemp; \
_bvtemp.set_word(0, (rd)); \
(svar).write(_bvtemp); \
}
#define VL_ASSIGN_SWQ(obits, svar, rd) \
{ \
sc_bv<(obits)> _bvtemp; \
sc_dt::sc_bv<(obits)> _bvtemp; \
_bvtemp.set_word(0, static_cast<IData>(rd)); \
_bvtemp.set_word(1, static_cast<IData>((rd) >> VL_IDATASIZE)); \
(svar).write(_bvtemp); \
}
#define VL_ASSIGN_SWW(obits, svar, rwp) \
{ \
sc_bv<(obits)> _bvtemp; \
sc_dt::sc_bv<(obits)> _bvtemp; \
for (int i = 0; i < VL_WORDS_I(obits); ++i) _bvtemp.set_word(i, (rwp)[i]); \
(svar).write(_bvtemp); \
}
@@ -504,7 +504,7 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT
#define VL_ASSIGN_SBW(obits, svar, rwp) \
{ \
sc_biguint<(obits)> _butemp; \
sc_dt::sc_biguint<(obits)> _butemp; \
int32_t lsb = 0; \
uint32_t* chunkp = _butemp.get_raw(); \
while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \
@@ -1437,7 +1437,7 @@ static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_P
if (rd_log2) {
const uint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2); // max multiple of rd <= lbits
const uint32_t lbitsRem = lbits - lbitsFloor; // number of bits in most-sig slice (MSS)
const IData msbMask = VL_MASK_I(lbitsRem) << lbitsFloor; // mask to sel only bits in MSS
const IData msbMask = lbitsFloor == 32 ? 0UL : VL_MASK_I(lbitsRem) << lbitsFloor;
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_UL(1) << rd_log2) - lbitsRem));
}
switch (rd_log2) {
@@ -1526,6 +1526,28 @@ static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const
return owp;
}
template <typename T>
static inline void VL_ASSIGN_DYN_Q(VlQueue<T>& q, int elem_size, int lbits, QData from) {
const int size = (lbits + elem_size - 1) / elem_size;
q.renew(size);
const QData mask = VL_MASK_Q(elem_size);
for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask);
}
template <typename T>
static inline IData VL_DYN_TO_I(const VlQueue<T>& q, int elem_size) {
IData ret = 0;
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size);
return ret;
}
template <typename T>
static inline QData VL_DYN_TO_Q(const VlQueue<T>& q, int elem_size) {
QData ret = 0;
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size);
return ret;
}
// Because concats are common and wide, it's valuable to always have a clean output.
// Thus we specify inputs must be clean, so we don't need to clean the output.
// Note the bit shifts are always constants, so the adds in these constify out.
@@ -1625,6 +1647,24 @@ static inline void _vl_shiftl_inplace_w(int obits, WDataOutP iowp,
// EMIT_RULE: VL_SHIFTL: oclean=lclean; rclean==clean;
// Important: Unlike most other funcs, the shift might well be a computed
// expression. Thus consider this when optimizing. (And perhaps have 2 funcs?)
// If RHS (rd/rwp) is larger than the output, zeros (or all ones for >>>) must be returned
// (This corresponds to AstShift*Ovr Ast nodes)
static inline IData VL_SHIFTL_III(int obits, int, int, IData lhs, IData rhs) VL_MT_SAFE {
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
return lhs << rhs; // Small is common so not clean return
}
static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE {
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
return VL_CLEAN_II(obits, obits, lhs << rhs);
}
static inline QData VL_SHIFTL_QQI(int obits, int, int, QData lhs, IData rhs) VL_MT_SAFE {
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
return lhs << rhs; // Small is common so not clean return
}
static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE {
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
return VL_CLEAN_QQ(obits, obits, lhs << rhs);
}
static inline WDataOutP VL_SHIFTL_WWI(int obits, int, int, WDataOutP owp, WDataInP const lwp,
IData rd) VL_MT_SAFE {
const int word_shift = VL_BITWORD_E(rd);
@@ -1662,11 +1702,7 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs,
return 0;
}
}
return VL_CLEAN_II(obits, obits, lhs << rwp[0]);
}
static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE {
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
return VL_CLEAN_II(obits, obits, lhs << rhs);
return VL_SHIFTL_III(obits, obits, 32, lhs, rwp[0]);
}
static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs,
WDataInP const rwp) VL_MT_SAFE {
@@ -1676,16 +1712,28 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs,
}
}
// Above checks rwp[1]==0 so not needed in below shift
return VL_CLEAN_QQ(obits, obits, lhs << (static_cast<QData>(rwp[0])));
}
static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE {
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
return VL_CLEAN_QQ(obits, obits, lhs << rhs);
return VL_SHIFTL_QQI(obits, obits, 32, lhs, rwp[0]);
}
// EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean;
// Important: Unlike most other funcs, the shift might well be a computed
// expression. Thus consider this when optimizing. (And perhaps have 2 funcs?)
static inline IData VL_SHIFTR_III(int obits, int, int, IData lhs, IData rhs) VL_PURE {
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
return lhs >> rhs; // Small is common so assumed not clean
}
static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
}
static inline QData VL_SHIFTR_QQI(int obits, int, int, QData lhs, IData rhs) VL_PURE {
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
return lhs >> rhs; // Small is common so assumed not clean
}
static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
}
static inline WDataOutP VL_SHIFTR_WWI(int obits, int, int, WDataOutP owp, WDataInP const lwp,
IData rd) VL_MT_SAFE {
const int word_shift = VL_BITWORD_E(rd); // Maybe 0
@@ -1729,29 +1777,16 @@ static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits, WDataOutP
static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs,
WDataInP const rwp) VL_PURE {
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
return 0;
}
if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more
}
return VL_CLEAN_II(obits, obits, lhs >> rwp[0]);
return VL_SHIFTR_III(obits, obits, 32, lhs, rwp[0]);
}
static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs,
WDataInP const rwp) VL_PURE {
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
return 0;
}
if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more
}
// Above checks rwp[1]==0 so not needed in below shift
return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast<QData>(rwp[0])));
}
static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
}
static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
return VL_SHIFTR_QQI(obits, obits, 32, lhs, rwp[0]);
}
// EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean;
@@ -1761,11 +1796,13 @@ static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData r
// must use lbits for sign; lbits might != obits,
// an EXTEND(SHIFTRS(...)) can became a SHIFTRS(...) within same 32/64 bit word length
const IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return sign & VL_MASK_I(obits);
const IData signext = ~(VL_MASK_I(lbits) >> rhs); // One with bits where we've shifted "past"
return (lhs >> rhs) | (sign & VL_CLEAN_II(obits, obits, signext));
}
static inline QData VL_SHIFTRS_QQI(int obits, int lbits, int, QData lhs, IData rhs) VL_PURE {
const QData sign = -(lhs >> (lbits - 1));
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return sign & VL_MASK_Q(obits);
const QData signext = ~(VL_MASK_Q(lbits) >> rhs);
return (lhs >> rhs) | (sign & VL_CLEAN_QQ(obits, obits, signext));
}
@@ -2089,60 +2126,60 @@ static inline WDataOutP VL_CONST_W_8X(int obits, WDataOutP o,
VL_C_END_(obits, 8);
}
//
static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP o,
EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0;
VL_C_END_(obits, VL_WORDS_I(lsb) + 1);
}
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP o,
EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1;
VL_C_END_(obits, VL_WORDS_I(lsb) + 2);
}
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP o,
EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2;
VL_C_END_(obits, VL_WORDS_I(lsb) + 3);
}
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP o,
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
VL_C_END_(obits, VL_WORDS_I(lsb) + 4);
}
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP o,
EData d4,
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
ohi[4] = d4;
VL_C_END_(obits, VL_WORDS_I(lsb) + 5);
}
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP o,
EData d5, EData d4,
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4; o[5] = d5;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
ohi[4] = d4; ohi[5] = d5;
VL_C_END_(obits, VL_WORDS_I(lsb) + 6);
}
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP o,
EData d6, EData d5, EData d4,
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4; o[5] = d5; o[6] = d6;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
ohi[4] = d4; ohi[5] = d5; ohi[6] = d6;
VL_C_END_(obits, VL_WORDS_I(lsb) + 7);
}
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP o,
EData d7, EData d6, EData d5, EData d4,
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
WDataOutP o = obase + VL_WORDS_I(lsb);
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
o[4] = d4; o[5] = d5; o[6] = d6; o[7] = d7;
WDataOutP ohi = o + VL_WORDS_I(lsb);
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
ohi[4] = d4; ohi[5] = d5; ohi[6] = d6; ohi[7] = d7;
VL_C_END_(obits, VL_WORDS_I(lsb) + 8);
}
+17 -6
View File
@@ -161,12 +161,18 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
// TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc.
fprintf(fp, "VLPROFVERSION 2.0 # Verilator execution profile version 2.0\n");
fprintf(fp, "VLPROFVERSION 2.1 # Verilator execution profile version 2.1\n");
fprintf(fp, "VLPROF arg +verilator+prof+exec+start+%" PRIu64 "\n",
Verilated::threadContextp()->profExecStart());
fprintf(fp, "VLPROF arg +verilator+prof+exec+window+%u\n",
Verilated::threadContextp()->profExecWindow());
const unsigned threads = static_cast<unsigned>(m_traceps.size());
// Note that VerilatedContext will by default create as many threads as there are hardware
// processors, but not all of them might be utilized. Report the actual number that has trace
// entries to avoid over-counting.
unsigned threads = 0;
for (const auto& pair : m_traceps) {
if (!pair.second->empty()) ++threads;
}
fprintf(fp, "VLPROF stat threads %u\n", threads);
fprintf(fp, "VLPROF stat yields %" PRIu64 "\n", VlMTaskVertex::yields());
@@ -183,6 +189,7 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
for (const auto& pair : m_traceps) {
const uint32_t threadId = pair.first;
ExecutionTrace* const tracep = pair.second;
if (tracep->empty()) continue;
fprintf(fp, "VLPROFTHREAD %" PRIu32 "\n", threadId);
for (const VlExecutionRecord& er : *tracep) {
@@ -191,10 +198,9 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
fprintf(fp, "VLPROFEXEC %s %" PRIu64, name, time);
switch (er.m_type) {
case VlExecutionRecord::Type::EVAL_BEGIN:
case VlExecutionRecord::Type::EVAL_END:
case VlExecutionRecord::Type::EVAL_LOOP_BEGIN:
case VlExecutionRecord::Type::EVAL_LOOP_END:
case VlExecutionRecord::Type::SECTION_POP:
case VlExecutionRecord::Type::EXEC_GRAPH_BEGIN:
case VlExecutionRecord::Type::EXEC_GRAPH_END:
// No payload
fprintf(fp, "\n");
break;
@@ -209,6 +215,11 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
fprintf(fp, " id %u predictCost %u\n", payload.m_id, payload.m_predictCost);
break;
}
case VlExecutionRecord::Type::SECTION_PUSH: {
const auto& payload = er.m_payload.sectionPush;
fprintf(fp, " %s\n", payload.m_name);
break;
}
default: abort(); // LCOV_EXCL_LINE
}
}
+15 -9
View File
@@ -58,12 +58,12 @@ VL_ATTR_ALWINLINE QData VL_CPU_TICK() {
// clang-format off
#define FOREACH_VlExecutionRecord_TYPE(macro) \
_VL_FOREACH_APPLY(macro, EVAL_BEGIN) \
_VL_FOREACH_APPLY(macro, EVAL_END) \
_VL_FOREACH_APPLY(macro, EVAL_LOOP_BEGIN) \
_VL_FOREACH_APPLY(macro, EVAL_LOOP_END) \
_VL_FOREACH_APPLY(macro, SECTION_PUSH) \
_VL_FOREACH_APPLY(macro, SECTION_POP) \
_VL_FOREACH_APPLY(macro, MTASK_BEGIN) \
_VL_FOREACH_APPLY(macro, MTASK_END)
_VL_FOREACH_APPLY(macro, MTASK_END) \
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_BEGIN) \
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_END)
// clang-format on
class VlExecutionRecord final {
@@ -83,6 +83,9 @@ class VlExecutionRecord final {
};
union Payload {
struct {
const char* m_name; // Name of section being entered
} sectionPush;
struct {
uint32_t m_id; // MTask id
uint32_t m_predictStart; // Time scheduler predicted would start
@@ -109,10 +112,11 @@ public:
VlExecutionRecord() = default;
// METHODS
void evalBegin() { m_type = Type::EVAL_BEGIN; }
void evalEnd() { m_type = Type::EVAL_END; }
void evalLoopBegin() { m_type = Type::EVAL_LOOP_BEGIN; }
void evalLoopEnd() { m_type = Type::EVAL_LOOP_END; }
void sectionPush(const char* name) {
m_payload.sectionPush.m_name = name;
m_type = Type::SECTION_PUSH;
}
void sectionPop() { m_type = Type::SECTION_POP; }
void mtaskBegin(uint32_t id, uint32_t predictStart) {
m_payload.mtaskBegin.m_id = id;
m_payload.mtaskBegin.m_predictStart = predictStart;
@@ -124,6 +128,8 @@ public:
m_payload.mtaskEnd.m_predictCost = predictCost;
m_type = Type::MTASK_END;
}
void execGraphBegin() { m_type = Type::EXEC_GRAPH_BEGIN; }
void execGraphEnd() { m_type = Type::EXEC_GRAPH_END; }
};
static_assert(std::is_trivially_destructible<VlExecutionRecord>::value,
+1 -1
View File
@@ -47,7 +47,7 @@ package std;
endtask
function int try_put(T message);
if (num() < m_bound) begin
if (m_bound == 0 || num() < m_bound) begin
m_queue.push_back(message);
return 1;
end
+2 -1
View File
@@ -153,11 +153,12 @@ void VlTriggerScheduler::dump(const char* eventDescription) const {
// VlDynamicTriggerScheduler:: Methods
bool VlDynamicTriggerScheduler::evaluate() {
m_anyTriggered = false;
VL_DEBUG_IF(dump(););
std::swap(m_suspended, m_evaluated);
for (auto& coro : m_evaluated) coro.resume();
m_evaluated.clear();
return !m_triggered.empty();
return m_anyTriggered;
}
void VlDynamicTriggerScheduler::doPostUpdates() {
+11 -1
View File
@@ -102,6 +102,8 @@ class VlCoroutineHandle final {
public:
// CONSTRUCTORS
// Construct
// non-explicit:
// cppcheck-suppress noExplicitConstructor
VlCoroutineHandle(VlProcessRef process)
: m_coro{nullptr}
, m_process{process} {
@@ -114,9 +116,11 @@ public:
if (m_process) m_process->state(VlProcess::WAITING);
}
// Move the handle, leaving a nullptr
// non-explicit:
// cppcheck-suppress noExplicitConstructor
VlCoroutineHandle(VlCoroutineHandle&& moved)
: m_coro{std::exchange(moved.m_coro, nullptr)}
, m_process{moved.m_process}
, m_process{std::exchange(moved.m_process, nullptr)}
, m_fileline{moved.m_fileline} {}
// Destroy if the handle isn't null
~VlCoroutineHandle() {
@@ -133,6 +137,8 @@ public:
// Move the handle, leaving a null handle
auto& operator=(VlCoroutineHandle&& moved) {
m_coro = std::exchange(moved.m_coro, nullptr);
m_process = std::exchange(moved.m_process, nullptr);
m_fileline = moved.m_fileline;
return *this;
}
// Resume the coroutine if the handle isn't null and the process isn't killed
@@ -269,6 +275,7 @@ public:
// co_await __VdynSched.evaluation();
// <pre updates>;
// __Vtrigger = <trigger eval>;
// __VdynShed.anyTriggered(__Vtrigger);
// [optionally] co_await __VdynSched.postUpdate();
// <post updates>;
// }
@@ -282,6 +289,7 @@ class VlDynamicTriggerScheduler final {
using VlCoroutineVec = std::vector<VlCoroutineHandle>;
// MEMBERS
bool m_anyTriggered = false; // If true, at least one trigger was set
VlCoroutineVec m_suspended; // Suspended coroutines awaiting trigger evaluation
VlCoroutineVec m_evaluated; // Coroutines currently being evaluated (for evaluate())
VlCoroutineVec m_triggered; // Coroutines whose triggers were set, and are awaiting resumption
@@ -307,6 +315,8 @@ class VlDynamicTriggerScheduler final {
public:
// Evaluates all dynamic triggers (resumed coroutines that co_await evaluation())
bool evaluate();
// Called by coroutines that evaluate triggers to notify the scheduler if any triggers were set
void anyTriggered(bool triggered) { m_anyTriggered = m_anyTriggered || triggered; }
// Runs post updates for all dynamic triggers (resumes coroutines that co_await postUpdate())
void doPostUpdates();
// Resumes all coroutines whose triggers are set (those that co_await resumption())
+82 -28
View File
@@ -25,7 +25,6 @@
// clang-format off
#include "verilated.h"
#include "verilated_trace_defs.h"
#include <bitset>
#include <condition_variable>
@@ -46,6 +45,54 @@ class VerilatedTraceBuffer;
template <class T_Buffer>
class VerilatedTraceOffloadBuffer;
//=============================================================================
// Common enumerations
enum class VerilatedTracePrefixType : uint32_t {
// Note: Entries must match VTracePrefixType (by name, not necessarily by value)
ARRAY_PACKED,
ARRAY_UNPACKED,
SCOPE_MODULE,
SCOPE_INTERFACE,
STRUCT_PACKED,
STRUCT_UNPACKED,
UNION_PACKED
};
// Direction attribute for ports
enum class VerilatedTraceSigDirection : uint32_t {
NONE,
INPUT,
OUTPUT,
INOUT,
};
// Kind of signal. Similar to nettype but with a few more alternatives
enum class VerilatedTraceSigKind : uint32_t {
PARAMETER,
SUPPLY0,
SUPPLY1,
TRI,
TRI0,
TRI1,
WIRE,
VAR,
};
// Base data type of signal
enum class VerilatedTraceSigType : uint32_t {
DOUBLE,
INTEGER,
BIT,
LOGIC,
INT,
SHORTINT,
LONGINT,
BYTE,
EVENT,
TIME,
};
//=============================================================================
// Offloaded tracing
@@ -162,24 +209,29 @@ private:
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
// assignment operator on inserting into collections, so they don't work
// with const fields...
union { // The callback
const union { // The callback
initCb_t m_initCb;
dumpCb_t m_dumpCb;
dumpOffloadCb_t m_dumpOffloadCb;
cleanupCb_t m_cleanupCb;
};
void* m_userp; // The user pointer to pass to the callback (the symbol table)
const uint32_t m_fidx; // The index of the tracing function
void* const m_userp; // The user pointer to pass to the callback (the symbol table)
CallbackRecord(initCb_t cb, void* userp)
: m_initCb{cb}
, m_fidx{0}
, m_userp{userp} {}
CallbackRecord(dumpCb_t cb, void* userp)
CallbackRecord(dumpCb_t cb, uint32_t fidx, void* userp)
: m_dumpCb{cb}
, m_fidx{fidx}
, m_userp{userp} {}
CallbackRecord(dumpOffloadCb_t cb, void* userp)
CallbackRecord(dumpOffloadCb_t cb, uint32_t fidx, void* userp)
: m_dumpOffloadCb{cb}
, m_fidx{fidx}
, m_userp{userp} {}
CallbackRecord(cleanupCb_t cb, void* userp)
: m_cleanupCb{cb}
, m_fidx{0}
, m_userp{userp} {}
};
@@ -212,18 +264,20 @@ protected:
private:
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
std::vector<CallbackRecord> m_constCbs; // Routines to perform const dump
std::vector<CallbackRecord> m_constOffloadCbs; // Routines to perform offloaded const dump
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
std::vector<CallbackRecord> m_fullOffloadCbs; // Routines to perform offloaded full dump
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
std::vector<CallbackRecord> m_chgOffloadCbs; // Routines to perform offloaded incremental dump
std::vector<CallbackRecord> m_cleanupCbs; // Routines to call at the end of dump
bool m_constDump = true; // Whether a const dump is required on the next call to 'dump'
bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump'
uint32_t m_nextCode = 0; // Next code number to assign
uint32_t m_numSignals = 0; // Number of distinct signals
uint32_t m_maxBits = 0; // Number of bits in the widest signal
std::vector<std::string> m_namePrefixStack{""}; // Path prefixes to add to signal names
// TODO: Should keep this as a Trie, that is how it's accessed all the time.
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
char m_scopeEscape = '.';
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
double m_timeUnit = 1e-0; // Time units (ns/ms etc)
uint64_t m_timeLastDump = 0; // Last time we did a dump
@@ -289,6 +343,7 @@ protected:
uint32_t nextCode() const { return m_nextCode; }
uint32_t numSignals() const { return m_numSignals; }
uint32_t maxBits() const { return m_maxBits; }
void constDump(bool value) { m_constDump = value; }
void fullDump(bool value) { m_fullDump = value; }
double timeRes() const { return m_timeRes; }
@@ -298,14 +353,7 @@ protected:
void traceInit() VL_MT_UNSAFE;
// Declare new signal and return true if enabled
bool declCode(uint32_t code, const char* namep, uint32_t bits, bool tri);
// Is this an escape?
bool isScopeEscape(char c) { return std::isspace(c) || c == m_scopeEscape; }
// Character that splits scopes. Note whitespace are ALWAYS escapes.
char scopeEscape() { return m_scopeEscape; }
// Prefix to assume in signal declarations
const std::string& namePrefix() const { return m_namePrefixStack.back(); }
bool declCode(uint32_t code, const std::string& declName, uint32_t bits);
void closeBase();
void flushBase();
@@ -313,6 +361,13 @@ protected:
bool offload() const { return m_offload; }
bool parallel() const { return m_parallel; }
// Return last ' ' separated word. Assumes string does not end in ' '.
static std::string lastWord(const std::string& str) {
const size_t idx = str.rfind(' ');
if (idx == std::string::npos) return str;
return str.substr(idx + 1);
}
//=========================================================================
// Virtual functions to be provided by the format specific implementation
@@ -325,7 +380,7 @@ protected:
virtual bool preChangeDump() = 0;
// Trace buffer management
virtual Buffer* getTraceBuffer() = 0;
virtual Buffer* getTraceBuffer(uint32_t fidx) = 0;
virtual void commitTraceBuffer(Buffer*) = 0;
// Configure sub-class
@@ -359,16 +414,13 @@ public:
void addModel(VerilatedModel*) VL_MT_SAFE_EXCLUDES(m_mutex);
void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE;
void addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
void addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE;
void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
void addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE;
void addConstCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
void addConstCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
void addFullCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
void addFullCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
void addChgCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
void addChgCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
void addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE;
void scopeEscape(char flag) { m_scopeEscape = flag; }
void pushNamePrefix(const std::string&);
void popNamePrefix(unsigned count = 1);
};
//=============================================================================
@@ -423,7 +475,7 @@ public:
void fullQData(uint32_t* oldp, QData newval, int bits);
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
void fullDouble(uint32_t* oldp, double newval);
void fullEvent(uint32_t* oldp, VlEvent newval);
void fullEvent(uint32_t* oldp, const VlEventBase* newval);
// In non-offload mode, these are called directly by the trace callbacks,
// and are called chg*. In offload mode, they are called by the worker
@@ -460,7 +512,9 @@ public:
}
}
}
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); }
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newval) {
fullEvent(oldp, newval);
}
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
double old;
std::memcpy(&old, oldp, sizeof(old));
@@ -539,7 +593,7 @@ public:
m_offloadBufferWritep += 4;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
}
void chgEvent(uint32_t code, VlEvent newval) {
void chgEvent(uint32_t code, const VlEventBase* newval) {
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
m_offloadBufferWritep[1] = code;
m_offloadBufferWritep += 2;
-42
View File
@@ -1,42 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Code available from: https://verilator.org
//
// Copyright 2001-2023 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//=============================================================================
///
/// \file
/// \brief Verilated tracing types
///
/// This file is not part of the Verilated public-facing API.
/// It is only for internal use by Verilated tracing routines.
///
//=============================================================================
#ifndef VERILATOR_VERILATED_TRACE_DEFS_H_
#define VERILATOR_VERILATED_TRACE_DEFS_H_
// Verilator tracing scope types:
// The values should match FST_ST_VCD_* from fstScopeType in gtkwave/fstapi.h
// verilated_fst_c.cpp contains assertions to enforce this
enum VltTraceScope {
VLT_TRACE_SCOPE_MODULE = 0,
VLT_TRACE_SCOPE_TASK = 1,
VLT_TRACE_SCOPE_FUNCTION = 2,
VLT_TRACE_SCOPE_BEGIN = 3,
VLT_TRACE_SCOPE_FORK = 4,
VLT_TRACE_SCOPE_GENERATE = 5,
VLT_TRACE_SCOPE_STRUCT = 6,
VLT_TRACE_SCOPE_UNION = 7,
VLT_TRACE_SCOPE_CLASS = 8,
VLT_TRACE_SCOPE_INTERFACE = 9,
VLT_TRACE_SCOPE_PACKAGE = 10,
VLT_TRACE_SCOPE_PROGRAM = 11
};
#endif // guard
+41 -34
View File
@@ -185,7 +185,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
continue;
case VerilatedTraceOffloadCommand::CHG_EVENT:
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
traceBufp->chgEvent(oldp, *reinterpret_cast<const VlEvent*>(readp));
traceBufp->chgEvent(oldp, reinterpret_cast<const VlEventBase*>(readp));
continue;
//===
@@ -378,13 +378,12 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
}
template <>
bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const char* namep, uint32_t bits,
bool tri) {
bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const std::string& declName,
uint32_t bits) {
if (VL_UNCOVERABLE(!code)) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
}
// To keep it simple, this is O(enables * signals), but we expect few enables
std::string declName = namePrefix() + namep;
bool enabled = false;
if (m_dumpvars.empty()) enabled = true;
for (const auto& item : m_dumpvars) {
@@ -410,10 +409,7 @@ bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const char* nam
break;
}
// Note: The tri-state flag is not used by Verilator, but is here for
// compatibility with some foreign code.
int codesNeeded = VL_WORDS_I(bits);
if (tri) codesNeeded *= 2;
m_nextCode = std::max(m_nextCode, code + codesNeeded);
++m_numSignals;
m_maxBits = std::max(m_maxBits, bits);
@@ -457,7 +453,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dumpvars(int level, const std::string&
for (auto& i : hierSpaced) {
if (i == '.') i = ' ';
}
m_dumpvars.push_back(std::make_pair(level, hierSpaced));
m_dumpvars.emplace_back(level, hierSpaced);
}
}
@@ -498,16 +494,15 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<Callback
// Main thread executes all jobs with index % threads == 0
std::vector<ParallelWorkerData*> mainThreadWorkerData;
// Enqueue all the jobs
for (unsigned i = 0; i < cbVec.size(); ++i) {
const CallbackRecord& cbr = cbVec[i];
for (const CallbackRecord& cbr : cbVec) {
// Always get the trace buffer on the main thread
Buffer* const bufp = getTraceBuffer();
Buffer* const bufp = getTraceBuffer(cbr.m_fidx);
// Create new work item
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
// Grab the new work item
ParallelWorkerData* const itemp = &workerData.back();
// Enqueue task to thread pool, or main thread
if (unsigned rem = i % threads) {
if (unsigned rem = cbr.m_fidx % threads) {
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp);
} else {
mainThreadWorkerData.push_back(itemp);
@@ -530,7 +525,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<Callback
}
// Fall back on sequential execution
for (const CallbackRecord& cbr : cbVec) {
Buffer* const traceBufferp = getTraceBuffer();
Buffer* const traceBufferp = getTraceBuffer(cbr.m_fidx);
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
commitTraceBuffer(traceBufferp);
}
@@ -541,7 +536,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
const std::vector<CallbackRecord>& cbVec) {
// Fall back on sequential execution
for (const CallbackRecord& cbr : cbVec) {
Buffer* traceBufferp = getTraceBuffer();
Buffer* traceBufferp = getTraceBuffer(cbr.m_fidx);
cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp));
commitTraceBuffer(traceBufferp);
}
@@ -610,6 +605,15 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
}
}
if (VL_UNLIKELY(m_constDump)) {
m_constDump = false;
if (offload()) {
runOffloadedCallbacks(m_constOffloadCbs);
} else {
runCallbacks(m_constCbs);
}
}
for (uint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
const CallbackRecord& cbr = m_cleanupCbs[i];
cbr.m_cleanupCb(cbr.m_userp, self());
@@ -695,37 +699,40 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp) VL_
addCallbackRecord(m_initCbs, CallbackRecord{cb, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE {
addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp});
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addConstCb(dumpCb_t cb, uint32_t fidx,
void* userp) VL_MT_SAFE {
addCallbackRecord(m_constCbs, CallbackRecord{cb, fidx, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE {
addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, userp});
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addConstCb(dumpOffloadCb_t cb, uint32_t fidx,
void* userp) VL_MT_SAFE {
addCallbackRecord(m_constOffloadCbs, CallbackRecord{cb, fidx, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE {
addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp});
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, uint32_t fidx,
void* userp) VL_MT_SAFE {
addCallbackRecord(m_fullCbs, CallbackRecord{cb, fidx, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE {
addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, userp});
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpOffloadCb_t cb, uint32_t fidx,
void* userp) VL_MT_SAFE {
addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, fidx, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, uint32_t fidx,
void* userp) VL_MT_SAFE {
addCallbackRecord(m_chgCbs, CallbackRecord{cb, fidx, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpOffloadCb_t cb, uint32_t fidx,
void* userp) VL_MT_SAFE {
addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, fidx, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE {
addCallbackRecord(m_cleanupCbs, CallbackRecord{cb, userp});
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::pushNamePrefix(const std::string& prefix) {
m_namePrefixStack.push_back(m_namePrefixStack.back() + prefix);
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::popNamePrefix(unsigned count) {
while (count--) m_namePrefixStack.pop_back();
assert(!m_namePrefixStack.empty());
}
//=========================================================================
// Primitives converting binary values to strings...
@@ -839,7 +846,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
}
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, VlEvent newval) {
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newval) {
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = 1; // Do we really store an "event" ?
emitEvent(code, newval);
+162 -17
View File
@@ -33,6 +33,7 @@
#include <atomic>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
@@ -69,16 +70,28 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
#define VL_INOUTW(name, msb, lsb, words) VlWide<words> name ///< Declare bidir signal, 65+ bits
#define VL_OUT8(name, msb, lsb) CData name ///< Declare output signal, 1-8 bits
#define VL_OUT16(name, msb, lsb) SData name ///< Declare output signal, 9-16 bits
#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64bits
#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64 bits
#define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits
#define VL_OUTW(name, msb, lsb, words) VlWide<words> name ///< Declare output signal, 65+ bits
//===================================================================
// VlProcess stores metadata of running processes
// Functions needed here
constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE {
// constexpr usage only! Recuses to meet C++11 constexpr func limitations
return lhs <= 1 ? 0 : VL_CLOG2_CE_Q((lhs + 1) >> 1ULL) + 1;
}
// Metadata of processes
class VlProcess;
using VlProcessRef = std::shared_ptr<VlProcess>;
class VlProcess final {
// MEMBERS
int m_state; // Current state of the process
VlProcessRef m_parentp = nullptr; // Parent process, if exists
std::set<VlProcess*> m_children; // Active child processes
public:
// TYPES
@@ -91,16 +104,40 @@ public:
};
// CONSTRUCTORS
// Construct independent process
VlProcess()
: m_state{RUNNING} {}
// Construct child process of parent
VlProcess(VlProcessRef parentp)
: m_state{RUNNING}
, m_parentp{parentp} {
m_parentp->attach(this);
}
// METHODS
int state() { return m_state; }
~VlProcess() {
if (m_parentp) m_parentp->detach(this);
}
void attach(VlProcess* childp) { m_children.insert(childp); }
void detach(VlProcess* childp) { m_children.erase(childp); }
int state() const { return m_state; }
void state(int s) { m_state = s; }
void disable() {
state(KILLED);
disableFork();
}
void disableFork() {
for (VlProcess* childp : m_children) childp->disable();
}
bool completed() const { return state() == FINISHED || state() == KILLED; }
bool completedFork() const {
for (const VlProcess* const childp : m_children)
if (!childp->completed()) return false;
return true;
}
};
using VlProcessRef = std::shared_ptr<VlProcess>;
inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); }
//===================================================================
@@ -155,7 +192,18 @@ public:
//===================================================================
// SystemVerilog event type
class VlEvent final {
class VlEventBase VL_NOT_FINAL {
public:
virtual ~VlEventBase() = default;
virtual void fire() = 0;
virtual bool isFired() const = 0;
virtual bool isTriggered() const = 0;
virtual void clearFired() = 0;
virtual void clearTriggered() = 0;
};
class VlEvent final : public VlEventBase {
// MEMBERS
bool m_fired = false; // Fired on this scheduling iteration
bool m_triggered = false; // Triggered state of event persisting until next time step
@@ -163,20 +211,50 @@ class VlEvent final {
public:
// CONSTRUCTOR
VlEvent() = default;
~VlEvent() = default;
~VlEvent() override = default;
friend std::string VL_TO_STRING(const VlEvent& e);
friend class VlAssignableEvent;
// METHODS
void fire() { m_fired = m_triggered = true; }
bool isFired() const { return m_fired; }
bool isTriggered() const { return m_triggered; }
void clearFired() { m_fired = false; }
void clearTriggered() { m_triggered = false; }
void fire() override { m_fired = m_triggered = true; }
bool isFired() const override { return m_fired; }
bool isTriggered() const override { return m_triggered; }
void clearFired() override { m_fired = false; }
void clearTriggered() override { m_triggered = false; }
};
class VlAssignableEvent final : public std::shared_ptr<VlEvent>, public VlEventBase {
public:
// Constructor
VlAssignableEvent()
: std::shared_ptr<VlEvent>(new VlEvent) {}
~VlAssignableEvent() override = default;
// METHODS
void fire() override { (*this)->m_fired = (*this)->m_triggered = true; }
bool isFired() const override { return (*this)->m_fired; }
bool isTriggered() const override { return (*this)->m_triggered; }
void clearFired() override { (*this)->m_fired = false; }
void clearTriggered() override { (*this)->m_triggered = false; }
};
inline std::string VL_TO_STRING(const VlEventBase& e);
inline std::string VL_TO_STRING(const VlEvent& e) {
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
}
inline std::string VL_TO_STRING(const VlAssignableEvent& e) {
return "&{ " + VL_TO_STRING(*e) + " }";
}
inline std::string VL_TO_STRING(const VlEventBase& e) {
if (const VlAssignableEvent& assignable = dynamic_cast<const VlAssignableEvent&>(e)) {
return VL_TO_STRING(assignable);
}
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
}
//===================================================================
// Random
@@ -210,6 +288,58 @@ public:
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
};
template <class T_Value, uint64_t T_numValues>
class VlRandC final {
T_Value m_remaining = 0; // Number of values to pull before re-randomize
T_Value m_lfsr = 1; // LFSR state
public:
// CONSTRUCTORS
VlRandC() {
static_assert(T_numValues >= 1, "");
static_assert(sizeof(T_Value) == 8 || (T_numValues < (1ULL << (8 * sizeof(T_Value)))), "");
}
// METHODS
T_Value randomize(VlRNG& rngr) {
if (VL_UNLIKELY(!m_remaining)) reseed(rngr);
// Polynomials are first listed at https://users.ece.cmu.edu/~koopman/lfsr/
static constexpr uint64_t s_polynomials[] = {
0x0ULL, // 0 never used (constant, no randomization)
0x0ULL, // 1
0x3ULL, 0x5ULL, 0x9ULL, 0x12ULL, 0x21ULL,
0x41ULL, 0x8eULL, 0x108ULL, 0x204ULL, 0x402ULL,
0x829ULL, 0x100dULL, 0x2015ULL, 0x4001ULL,
0x8016ULL, // 16
0x10004ULL, 0x20040ULL, 0x40013ULL, 0x80004ULL, 0x100002ULL,
0x200001ULL, 0x400010ULL, 0x80000dULL, 0x1000004ULL, 0x2000023ULL,
0x4000013ULL, 0x8000004ULL, 0x10000002ULL, 0x20000029ULL, 0x40000004ULL,
0x80000057ULL, // 32
0x100000029ULL // 33
};
constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth;
constexpr T_Value polynomial = static_cast<T_Value>(s_polynomials[lfsrWidth]);
// printf(" numV=%ld w=%d poly=%x\n", T_numValues, lfsrWidth, polynomial);
// Loop until get reasonable value. Because we picked a LFSR of at most one
// extra bit in width, this will only require at most on average 1.5 loops
do {
m_lfsr = (m_lfsr & 1ULL) ? ((m_lfsr >> 1ULL) ^ polynomial) : (m_lfsr >> 1ULL);
} while (m_lfsr > T_numValues); // Note if == then output value 0
--m_remaining;
T_Value result = (m_lfsr == T_numValues) ? 0 : m_lfsr;
// printf(" result=%x (numv=%ld, rem=%d)\n", result, T_numValues, m_remaining);
return result;
}
void reseed(VlRNG& rngr) {
constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
m_remaining = T_numValues;
do {
m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth);
// printf(" lfsr.reseed=%x\n", m_lfsr);
} while (!m_lfsr); // 0 not a legal seed
}
};
// These require the class object to have the thread safety lock
inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
@@ -457,7 +587,7 @@ public:
// function void q.insert(index, value);
void insert(int32_t index, const T_Value& value) {
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
if (VL_UNLIKELY(index < 0 || index > m_deque.size())) return;
m_deque.insert(m_deque.begin() + index, value);
}
@@ -1418,8 +1548,8 @@ class VlClass VL_NOT_FINAL : public VlDeletable {
public:
// CONSTRUCTORS
VlClass() = default;
VlClass(const VlClass& copied) {}
VlClass() { refCountInc(); }
VlClass(const VlClass& copied) { refCountInc(); }
~VlClass() override = default;
};
@@ -1467,8 +1597,9 @@ public:
// () required here to avoid narrowing conversion warnings,
// when a new() has an e.g. CData type and passed a 1U.
: m_objp{new T_Class(std::forward<T_Args>(args)...)} {
// refCountInc was moved to the constructor of T_Class
// to fix self references in constructor.
m_objp->m_deleterp = &deleter;
refCountInc();
}
// Explicit to avoid implicit conversion from 0
explicit VlClassRef(T_Class* objp)
@@ -1546,10 +1677,18 @@ public:
bool operator!=(const VlClassRef<T_OtherClass>& rhs) const {
return m_objp != rhs.m_objp;
};
template <typename T_OtherClass>
bool operator<(const VlClassRef<T_OtherClass>& rhs) const {
return m_objp < rhs.m_objp;
};
};
template <typename T, typename U>
static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
if (!in) {
outr = VlNull{};
return true;
}
VlClassRef<U> casted = in.template dynamicCast<U>();
if (VL_LIKELY(casted)) {
outr = casted;
@@ -1559,6 +1698,12 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
}
}
template <typename T>
static inline bool VL_CAST_DYNAMIC(VlNull in, VlClassRef<T>& outr) {
outr = VlNull{};
return true;
}
//=============================================================================
// VlSampleQueue stores samples for input clockvars in clocking blocks. At a clocking event,
// samples from this queue should be written to the correct input clockvar.
+124 -219
View File
@@ -112,7 +112,19 @@ void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
openNextImp(m_rolloverSize != 0);
if (!isOpen()) return;
dumpHeader();
printStr("$version Generated by VerilatedVcd $end\n");
printStr("$timescale ");
printStr(timeResStr().c_str()); // lintok-begin-on-ref
printStr(" $end\n");
// Scope and signal definitions
assert(m_indent == 0);
++m_indent;
Super::traceInit();
--m_indent;
assert(m_indent == 0);
printStr("$enddefinitions $end\n\n\n");
// When using rollover, the first chunk contains the header only.
if (m_rolloverSize) openNextImp(true);
@@ -164,6 +176,7 @@ void VerilatedVcd::openNextImp(bool incFilename) {
}
}
m_isOpen = true;
constDump(true); // First dump must containt the const signals
fullDump(true); // First dump must be full
m_wroteBytes = 0;
}
@@ -175,49 +188,14 @@ bool VerilatedVcd::preChangeDump() {
void VerilatedVcd::emitTimeChange(uint64_t timeui) {
printStr("#");
printQuad(timeui);
const std::string str = std::to_string(timeui);
printStr(str.c_str());
printStr("\n");
}
void VerilatedVcd::makeNameMap() {
// Take signal information from each module and build m_namemapp
deleteNameMap();
m_namemapp = new NameMap;
Super::traceInit();
// Though not speced, it's illegal to generate a vcd with signals
// not under any module - it crashes at least two viewers.
// If no scope was specified, prefix everything with a "top"
// This comes from user instantiations with no name - IE Vtop("").
bool nullScope = false;
for (const auto& i : *m_namemapp) {
const std::string& hiername = i.first;
if (!hiername.empty() && hiername[0] == '\t') nullScope = true;
}
if (nullScope) {
NameMap* const newmapp = new NameMap;
for (const auto& i : *m_namemapp) {
const std::string& hiername = i.first;
const std::string& decl = i.second;
std::string newname{"top"};
if (hiername[0] != '\t') newname += ' ';
newname += hiername;
newmapp->emplace(newname, decl);
}
deleteNameMap();
m_namemapp = newmapp;
}
}
void VerilatedVcd::deleteNameMap() {
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = nullptr);
}
VerilatedVcd::~VerilatedVcd() {
close();
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = nullptr);
deleteNameMap();
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = nullptr);
if (parallel()) {
assert(m_numBuffers == m_freeBuffers.size());
@@ -270,13 +248,6 @@ void VerilatedVcd::printStr(const char* str) {
}
}
void VerilatedVcd::printQuad(uint64_t n) {
constexpr size_t LEN_STR_QUAD = 40;
char buf[LEN_STR_QUAD];
VL_SNPRINTF(buf, LEN_STR_QUAD, "%" PRIu64, n);
printStr(buf);
}
void VerilatedVcd::bufferResize(size_t minsize) {
// minsize is size of largest write. We buffer at least 8 times as much data,
// writing when we are 3/4 full (with thus 2*minsize remaining free)
@@ -325,127 +296,59 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
m_writep = m_wrBufp;
}
//=============================================================================
// VCD string code
char* VerilatedVcd::writeCode(char* writep, uint32_t code) {
*writep++ = static_cast<char>('!' + code % 94);
code /= 94;
while (code) {
--code;
*writep++ = static_cast<char>('!' + code % 94);
code /= 94;
}
return writep;
}
//=============================================================================
// Definitions
void VerilatedVcd::printIndent(int level_change) {
if (level_change < 0) m_modDepth += level_change;
assert(m_modDepth >= 0);
for (int i = 0; i < m_modDepth; i++) printStr(" ");
if (level_change > 0) m_modDepth += level_change;
if (level_change < 0) m_indent += level_change;
for (int i = 0; i < m_indent; i++) printStr(" ");
if (level_change > 0) m_indent += level_change;
}
void VerilatedVcd::dumpHeader() {
printStr("$version Generated by VerilatedVcd $end\n");
// Verilator used to put in a $date here. Although $date is shown in
// IEEE examples, and it is common in VCD writers, VCD readers don't
// seem to care about it. Thus, we omit the $date so artifacts are
// more likely to be reproducible. If use cases show up that require
// the $date command to be present, it could be re-added with support
// for the SOURCE_DATE_EPOCH hook.
printStr("$timescale ");
printStr(timeResStr().c_str()); // lintok-begin-on-ref
printStr(" $end\n");
makeNameMap();
// Signal header
assert(m_modDepth == 0);
printIndent(1);
printStr("\n");
// We detect the spaces in module names to determine hierarchy. This
// allows signals to be declared without fixed ordering, which is
// required as Verilog signals might be separately declared from
// SC module signals.
// Print the signal names
const char* lastName = "";
for (const auto& i : *m_namemapp) {
const std::string& hiernamestr = i.first;
const std::string& decl = i.second;
// Determine difference between the old and new names
const char* const hiername = hiernamestr.c_str();
const char* lp = lastName;
const char* np = hiername;
lastName = hiername;
// Skip common prefix, it must break at a space or tab
for (; *np && (*np == *lp); np++, lp++) {}
while (np != hiername && *np && *np != ' ' && *np != '\t') {
--np;
--lp;
}
// printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np);
// Any extra spaces in last name are scope ups we need to do
bool first = true;
for (; *lp; lp++) {
if (*lp == ' ' || (first && *lp != '\t')) {
printIndent(-1);
printStr("$upscope $end\n");
}
first = false;
}
// Any new spaces are scope downs we need to do
while (*np) {
if (*np == ' ') np++;
if (*np == '\t') break; // tab means signal name starts
printIndent(1);
printStr("$scope module ");
for (; *np && *np != ' ' && *np != '\t'; np++) {
if (*np == '[') {
printStr("[");
} else if (*np == ']') {
printStr("]");
} else {
*m_writep++ = *np;
}
}
printStr(" $end\n");
}
printIndent(0);
printStr(decl.c_str());
void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
std::string newPrefix = m_prefixStack.back().first + name;
switch (type) {
case VerilatedTracePrefixType::SCOPE_MODULE:
case VerilatedTracePrefixType::SCOPE_INTERFACE:
case VerilatedTracePrefixType::STRUCT_PACKED:
case VerilatedTracePrefixType::STRUCT_UNPACKED:
case VerilatedTracePrefixType::UNION_PACKED: {
printIndent(1);
printStr("$scope module ");
const std::string n = lastWord(newPrefix);
printStr(n.c_str());
printStr(" $end\n");
newPrefix += ' ';
break;
}
default: break;
}
m_prefixStack.emplace_back(newPrefix, type);
}
while (m_modDepth > 1) {
void VerilatedVcd::popPrefix() {
switch (m_prefixStack.back().second) {
case VerilatedTracePrefixType::SCOPE_MODULE:
case VerilatedTracePrefixType::SCOPE_INTERFACE:
case VerilatedTracePrefixType::STRUCT_PACKED:
case VerilatedTracePrefixType::STRUCT_UNPACKED:
case VerilatedTracePrefixType::UNION_PACKED:
printIndent(-1);
printStr("$upscope $end\n");
break;
default: break;
}
printIndent(-1);
printStr("$enddefinitions $end\n\n\n");
assert(m_modDepth == 0);
// Reclaim storage
deleteNameMap();
m_prefixStack.pop_back();
assert(!m_prefixStack.empty());
}
void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, bool array,
int arraynum, bool tri, bool bussed, int msb, int lsb) {
int arraynum, bool bussed, int msb, int lsb) {
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
const bool enabled = Super::declCode(code, name, bits, tri);
const std::string hierarchicalName = m_prefixStack.back().first + name;
const bool enabled = Super::declCode(code, hierarchicalName, bits);
if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) {
m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
@@ -458,93 +361,95 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b
if (!enabled) return;
// Split name into basename
// Spaces and tabs aren't legal in VCD signal names, so:
// Space separates each level of scope
// Tab separates final scope from signal name
// Tab sorts before spaces, so signals nicely will print before scopes
// Note the hiername may be nothing, if so we'll add "\t{name}"
std::string nameasstr = namePrefix() + name;
std::string hiername;
std::string basename;
for (const char* cp = nameasstr.c_str(); *cp; cp++) {
if (isScopeEscape(*cp)) {
// Ahh, we've just read a scope, not a basename
if (!hiername.empty()) hiername += " ";
hiername += basename;
basename = "";
} else {
basename += *cp;
}
// Create the VCD code and build the suffix array entry
char vcdCode[VL_TRACE_SUFFIX_ENTRY_SIZE];
{
// Render the VCD code
char* vcdCodeWritep = vcdCode;
uint32_t codeEnc = code;
do {
*vcdCodeWritep++ = static_cast<char>('!' + codeEnc % 94);
codeEnc /= 94;
} while (codeEnc--);
*vcdCodeWritep = '\0';
const size_t vcdCodeLength = vcdCodeWritep - vcdCode;
assert(vcdCodeLength <= VL_TRACE_MAX_VCD_CODE_SIZE);
// Build suffix array entry
char* const entryBeginp = &m_suffixes[code * VL_TRACE_SUFFIX_ENTRY_SIZE];
entryBeginp[0] = ' '; // Separator
// 1 bit values don't have a ' ' separator between value and string code
char* entryWritep = bits == 1 ? entryBeginp : entryBeginp + 1;
// Use memcpy as we know the size, and strcpy is flagged unsafe
std::memcpy(entryWritep, vcdCode, vcdCodeLength);
entryWritep += vcdCodeLength;
// Line terminator
*entryWritep++ = '\n';
// Set length of suffix (used to increment write pointer)
assert(entryWritep <= entryBeginp + VL_TRACE_SUFFIX_ENTRY_SIZE - 1);
entryBeginp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1] = static_cast<char>(entryWritep - entryBeginp);
}
hiername += "\t" + basename;
// Print reference
// Assemble the declaration
std::string decl = "$var ";
decl += wirep; // usually "wire"
constexpr size_t bufsize = 1000;
char buf[bufsize];
VL_SNPRINTF(buf, bufsize, " %2d ", bits);
decl += buf;
// Add string code to decl
char* const endp = writeCode(buf, code);
*endp = '\0';
decl += buf;
// Build suffix array entry
char* const entryp = &m_suffixes[code * VL_TRACE_SUFFIX_ENTRY_SIZE];
const size_t length = endp - buf;
assert(length <= VL_TRACE_MAX_VCD_CODE_SIZE);
// 1 bit values don't have a ' ' separator between value and string code
const bool isBit = bits == 1;
entryp[0] = ' '; // Separator
// Use memcpy as we checked size above, and strcpy is flagged unsafe
std::memcpy(entryp + !isBit, buf,
std::strlen(buf)); // Code (overwrite separator if isBit)
entryp[length + !isBit] = '\n'; // Replace '\0' with line termination '\n'
// Set length of suffix (used to increment write pointer)
entryp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1] = static_cast<char>(length + !isBit + 1);
decl += " ";
decl += basename;
decl += wirep;
decl += ' ';
decl += std::to_string(bits);
decl += ' ';
decl += vcdCode;
decl += ' ';
decl += lastWord(hierarchicalName);
if (array) {
VL_SNPRINTF(buf, bufsize, "[%d]", arraynum);
decl += buf;
hiername += buf;
decl += '[';
decl += std::to_string(arraynum);
decl += ']';
}
if (bussed) {
VL_SNPRINTF(buf, bufsize, " [%d:%d]", msb, lsb);
decl += buf;
decl += " [";
decl += std::to_string(msb);
decl += ':';
decl += std::to_string(lsb);
decl += ']';
}
decl += " $end\n";
m_namemapp->emplace(hiername, decl);
printIndent(0);
printStr(decl.c_str());
}
void VerilatedVcd::declEvent(uint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "event", array, arraynum, false, false, 0, 0);
void VerilatedVcd::declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind,
VerilatedTraceSigType, bool array, int arraynum) {
declare(code, name, "event", array, arraynum, false, 0, 0);
}
void VerilatedVcd::declBit(uint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "wire", array, arraynum, false, false, 0, 0);
void VerilatedVcd::declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind,
VerilatedTraceSigType, bool array, int arraynum) {
declare(code, name, "wire", array, arraynum, false, 0, 0);
}
void VerilatedVcd::declBus(uint32_t code, const char* name, bool array, int arraynum, int msb,
int lsb) {
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
void VerilatedVcd::declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind,
VerilatedTraceSigType, bool array, int arraynum, int msb, int lsb) {
declare(code, name, "wire", array, arraynum, true, msb, lsb);
}
void VerilatedVcd::declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb,
int lsb) {
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
void VerilatedVcd::declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind,
VerilatedTraceSigType, bool array, int arraynum, int msb, int lsb) {
declare(code, name, "wire", array, arraynum, true, msb, lsb);
}
void VerilatedVcd::declArray(uint32_t code, const char* name, bool array, int arraynum, int msb,
int lsb) {
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
void VerilatedVcd::declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind,
VerilatedTraceSigType, bool array, int arraynum, int msb, int lsb) {
declare(code, name, "wire", array, arraynum, true, msb, lsb);
}
void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 63, 0);
void VerilatedVcd::declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind,
VerilatedTraceSigType, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, 63, 0);
}
//=============================================================================
// Get/commit trace buffer
VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer() {
VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer(uint32_t fidx) {
VerilatedVcd::Buffer* const bufp = new Buffer{*this};
if (parallel()) {
// Note: This is called from VerilatedVcd::dump, which already holds the lock
@@ -669,8 +574,8 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitEvent(uint32_t code, VlEvent newval) {
const bool triggered = newval.isTriggered();
void VerilatedVcdBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
const bool triggered = newval->isTriggered();
// TODO : It seems that untriggered events are not filtered
// should be tested before this last step
if (triggered) {
+28 -21
View File
@@ -24,7 +24,6 @@
#include "verilated.h"
#include "verilated_trace.h"
#include <map>
#include <string>
#include <vector>
@@ -51,7 +50,7 @@ private:
bool m_isOpen = false; // True indicates open file
std::string m_filename; // Filename we're writing to (if open)
uint64_t m_rolloverSize = 0; // File size to rollover at
int m_modDepth = 0; // Depth of module hierarchy
unsigned m_indent = 0; // Indentation depth
char* m_wrBufp; // Output buffer
char* m_wrFlushp; // Output buffer flush trigger location
@@ -62,8 +61,9 @@ private:
std::vector<char> m_suffixes; // VCD line end string codes + metadata
using NameMap = std::map<const std::string, const std::string>;
NameMap* m_namemapp = nullptr; // List of names for the header
// Prefixes to add to signal names/scope types
std::vector<std::pair<std::string, VerilatedTracePrefixType>> m_prefixStack{
{"", VerilatedTracePrefixType::SCOPE_MODULE}};
// Vector of free trace buffers as (pointer, size) pairs.
std::vector<std::pair<char*, size_t>> m_freeBuffers;
@@ -79,18 +79,10 @@ private:
void openNextImp(bool incFilename);
void closePrev();
void closeErr();
void makeNameMap();
void deleteNameMap();
void printIndent(int level_change);
void printStr(const char* str);
void printQuad(uint64_t n);
void printTime(uint64_t timeui);
void declare(uint32_t code, const char* name, const char* wirep, bool array, int arraynum,
bool tri, bool bussed, int msb, int lsb);
void dumpHeader();
static char* writeCode(char* writep, uint32_t code);
bool bussed, int msb, int lsb);
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedVcd);
@@ -107,7 +99,7 @@ protected:
bool preChangeDump() override;
// Trace buffer management
Buffer* getTraceBuffer() override;
Buffer* getTraceBuffer(uint32_t fidx) override;
void commitTraceBuffer(Buffer*) override;
// Configure sub-class
@@ -140,12 +132,27 @@ public:
//=========================================================================
// Internal interface to Verilator generated code
void declEvent(uint32_t code, const char* name, bool array, int arraynum);
void declBit(uint32_t code, const char* name, bool array, int arraynum);
void declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declArray(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declDouble(uint32_t code, const char* name, bool array, int arraynum);
void pushPrefix(const std::string&, VerilatedTracePrefixType);
void popPrefix();
void declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
};
#ifndef DOXYGEN
@@ -207,7 +214,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
// Implementation of VerilatedTraceBuffer interface
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
+254 -17
View File
@@ -175,7 +175,7 @@ public:
VerilatedVpioVarBase(const VerilatedVar* varp, const VerilatedScope* scopep)
: m_varp{varp}
, m_scopep{scopep}
, m_fullname{std::string{m_scopep->name()} + '.' + name()} {}
, m_fullname{std::string{m_scopep->name()} + '.' + m_varp->name()} {}
explicit VerilatedVpioVarBase(const VerilatedVpioVarBase* varp) {
if (varp) {
m_varp = varp->m_varp;
@@ -303,7 +303,13 @@ public:
uint32_t entSize() const { return m_entSize; }
uint32_t index() const { return m_index; }
uint32_t type() const override {
return (varp()->dims() > 1) ? vpiMemory : vpiReg; // but might be wire, logic
uint32_t type = vpiReg;
switch (varp()->vltype()) {
case VLVT_REAL: type = vpiRealVar; break;
case VLVT_STRING: type = vpiStringVar; break;
default: break;
}
return (varp()->dims() > 1) ? vpiMemory : type; // but might be wire, logic
}
void* prevDatap() const { return m_prevDatap; }
void* varDatap() const { return m_varDatap; }
@@ -536,8 +542,7 @@ public:
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb reason=%d id=%" PRId64 " time=%" PRIu64
" obj=%p\n",
cb_data_p->reason, id, time, cb_data_p->obj););
s().m_futureCbs.emplace(std::piecewise_construct,
std::forward_as_tuple(std::make_pair(time, id)),
s().m_futureCbs.emplace(std::piecewise_construct, std::forward_as_tuple(time, id),
std::forward_as_tuple(id, cb_data_p, nullptr));
}
static void cbNextAdd(uint64_t id, const s_cb_data* cb_data_p, QData time) {
@@ -545,8 +550,7 @@ public:
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb reason=%d(NEXT) id=%" PRId64
" time=%" PRIu64 " obj=%p\n",
cb_data_p->reason, id, time, cb_data_p->obj););
s().m_nextCbs.emplace(std::piecewise_construct,
std::forward_as_tuple(std::make_pair(time, id)),
s().m_nextCbs.emplace(std::piecewise_construct, std::forward_as_tuple(time, id),
std::forward_as_tuple(id, cb_data_p, nullptr));
}
static void cbReasonRemove(uint64_t id, uint32_t reason, QData time) {
@@ -985,9 +989,117 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_PURE {
"vpiGenVar",
"vpiAutomatics"
};
static const char* const sv_names1[] = {
"vpiPackage",
"vpiInterface",
"vpiProgram",
"vpiInterfaceArray",
"vpiProgramArray",
"vpiTypespec",
"vpiModport",
"vpiInterfaceTfDecl",
"vpiRefObj",
"vpiTypeParameter",
"vpiLongIntVar",
"vpiShortIntVar",
"vpiIntVar",
"vpiShortRealVar",
"vpiByteVar",
"vpiClassVar",
"vpiStringVar",
"vpiEnumVar",
"vpiStructVar",
"vpiUnionVar",
"vpiBitVar",
"vpiClassObj",
"vpiChandleVar",
"vpiPackedArrayVar",
"*undefined*", // 624 is not defined for object types
"vpiLongIntTypespec",
"vpiShortRealTypespec",
"vpiByteTypespec",
"vpiShortIntTypespec",
"vpiIntTypespec",
"vpiClassTypespec",
"vpiStringTypespec",
"vpiChandleTypespec",
"vpiEnumTypespec",
"vpiEnumConst",
"vpiIntegerTypespec",
"vpiTimeTypespec",
"vpiRealTypespec",
"vpiStructTypespec",
"vpiUnionTypespec",
"vpiBitTypespec",
"vpiLogicTypespec",
"vpiArrayTypespec",
"vpiVoidTypespec",
"vpiTypespecMember",
"vpiDistItem",
"vpiAliasStmt",
"vpiThread",
"vpiMethodFuncCall",
"vpiMethodTaskCall",
"vpiClockingBlock",
"vpiClockingIODecl",
"vpiClassDefn",
"vpiConstraint",
"vpiConstraintOrdering",
"vpiPropertyDecl",
"vpiPropertySpec",
"vpiPropertyExpr",
"vpiMulticlockSequenceExpr",
"vpiClockedSeq",
"vpiPropertyInst",
"vpiSequenceDecl",
"vpiCaseProperty",
"*undefined*", // 663 is not defined for object types
"vpiSequenceInst",
"vpiImmediateAssert",
"vpiReturn",
"vpiAnyPattern",
"vpiTaggedPattern",
"vpiStructPattern",
"vpiDoWhile",
"vpiOrderedWait",
"vpiWaitFork",
"vpiDisableFork",
"vpiExpectStmt",
"vpiForeachStmt",
"vpiFinal",
"vpiExtends",
"vpiDistribution",
"vpiSeqFormalDecl",
"vpiEnumNet",
"vpiIntegerNet",
"vpiTimeNet",
"vpiStructNet",
"vpiBreak",
"vpiContinue",
"vpiAssert",
"vpiAssume",
"vpiCover",
"vpiDisableCondition",
"vpiClockingEvent",
"vpiReturnStmt",
"vpiPackedArrayTypespec",
"vpiPackedArrayNet",
"vpiImmediateAssume",
"vpiImmediateCover",
"vpiSequenceTypespec",
"vpiPropertyTypespec",
"vpiEventTypespec",
"vpiPropFormalDecl",
};
// clang-format on
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiAutomatics) ? vpiVal : 0];
if (VL_UNCOVERABLE(vpiVal < 0))
return names[0];
else if (vpiVal <= vpiAutomatics)
return names[vpiVal];
else if (vpiVal >= vpiPackage && vpiVal <= vpiPropFormalDecl)
return sv_names1[(vpiVal - vpiPackage)];
else
return names[0];
}
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_PURE {
// clang-format off
@@ -1313,6 +1425,104 @@ void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE {
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiGenScope);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAutomatics);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackage);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiInterface);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiProgram);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiInterfaceArray);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiProgramArray);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiModport);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiInterfaceTfDecl);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiRefObj);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTypeParameter);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiLongIntVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortIntVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortRealVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiByteVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStringVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassObj);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiChandleVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackedArrayVar);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiLongIntTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortRealTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiByteTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortIntTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStringTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiChandleTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumConst);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntegerTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTimeTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiRealTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiLogicTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiArrayTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiVoidTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTypespecMember);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDistItem);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAliasStmt);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiThread);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiMethodFuncCall);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiMethodTaskCall);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockingBlock);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockingIODecl);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassDefn);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiConstraint);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiConstraintOrdering);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyDecl);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertySpec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyExpr);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiMulticlockSequenceExpr);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockedSeq);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyInst);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSequenceDecl);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiCaseProperty);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSequenceInst);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiImmediateAssert);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiReturn);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAnyPattern);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTaggedPattern);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructPattern);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDoWhile);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiOrderedWait);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiWaitFork);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDisableFork);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiExpectStmt);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiForeachStmt);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiFinal);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiExtends);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDistribution);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSeqFormalDecl);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumNet);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntegerNet);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTimeNet);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructNet);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBreak);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiContinue);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAssert);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAssume);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiCover);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDisableCondition);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockingEvent);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiReturnStmt);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackedArrayTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackedArrayNet);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiImmediateAssume);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiImmediateCover);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSequenceTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEventTypespec);
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropFormalDecl);
SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiCondition);
SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiStmt);
@@ -1734,7 +1944,8 @@ bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const c
case VLVT_UINT64:
case VLVT_WDATA: return status;
case VLVT_STRING:
if (isGetValue) {
// string parameter values can't be changed
if (isGetValue || !varp->isParam()) {
return status;
} else {
status = false;
@@ -1749,6 +1960,11 @@ bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const c
case VLVT_UINT32: return status;
default: status = false;
}
} else if (valuep->format == vpiRealVal) {
switch (varp->vltype()) {
case VLVT_REAL: return status;
default: status = false;
}
} else if (valuep->format == vpiSuppressVal) {
return status;
} else {
@@ -1766,6 +1982,8 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
static thread_local char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// cppcheck-suppress variableScope
static const thread_local int t_outStrSz = sizeof(t_outStr) - 1;
// string data type is dynamic and may vary in size during simulation
static thread_local std::string t_outDynamicStr;
// 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) {
@@ -1918,8 +2136,14 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
return;
} else if (valuep->format == vpiStringVal) {
if (varp->vltype() == VLVT_STRING) {
valuep->value.str = reinterpret_cast<char*>(varDatap);
return;
if (varp->isParam()) {
valuep->value.str = reinterpret_cast<char*>(varDatap);
return;
} else {
t_outDynamicStr = *(reinterpret_cast<std::string*>(varDatap));
valuep->value.str = const_cast<char*>(t_outDynamicStr.c_str());
return;
}
} else {
valuep->value.str = t_outStr;
int bytes = VL_BYTES_I(varp->packed().elements());
@@ -1954,6 +2178,9 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
valuep->value.integer = *(reinterpret_cast<IData*>(varDatap));
return;
}
} else if (valuep->format == vpiRealVal) {
valuep->value.real = *(reinterpret_cast<double*>(varDatap));
return;
} else if (valuep->format == vpiSuppressVal) {
return;
}
@@ -2171,12 +2398,17 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1);
return object;
} else if (valuep->format == vpiStringVal) {
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
const int len = std::strlen(valuep->value.str);
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
for (int i = 0; i < bytes; ++i) {
// prepend with 0 values before placing string the least significant bytes
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
if (vop->varp()->vltype() == VLVT_STRING) {
*(reinterpret_cast<std::string*>(vop->varDatap())) = valuep->value.str;
return object;
} else {
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
const int len = std::strlen(valuep->value.str);
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
for (int i = 0; i < bytes; ++i) {
// prepend with 0 values before placing string the least significant bytes
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
}
}
return object;
} else if (valuep->format == vpiIntVal) {
@@ -2190,6 +2422,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
*(reinterpret_cast<IData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
return object;
}
} else if (valuep->format == vpiRealVal) {
if (vop->varp()->vltype() == VLVT_REAL) {
*(reinterpret_cast<double*>(vop->varDatap())) = valuep->value.real;
return object;
}
}
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
__func__, VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
+2 -2
View File
@@ -30,9 +30,9 @@
#include "verilated_syms.h"
//======================================================================
// From IEEE 1800-2009 annex K
// From IEEE 1800-2017 annex M
#include "vltstd/vpi_user.h"
#include "vltstd/sv_vpi_user.h"
//======================================================================
+33 -16
View File
@@ -94,20 +94,6 @@
// Function requires a capability inbound (-fthread-safety)
#define VL_CAPABILITY(x) \
VL_CLANG_ATTR(capability(x))
// Function requires not having a capability inbound (-fthread-safety)
#define VL_REQUIRES(x) \
VL_CLANG_ATTR(annotate("REQUIRES")) \
VL_CLANG_ATTR(requires_capability(x))
// Name of capability/lock (-fthread-safety)
#define VL_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("GUARDED_BY")) \
VL_CLANG_ATTR(guarded_by(x))
// The data that the annotated pointer points to is protected by the given capability.
// The pointer itself is not protected.
// Allowed on: pointer data member. (-fthread-safety)
#define VL_PT_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \
VL_CLANG_ATTR(pt_guarded_by(x))
// Name of mutex protecting this variable (-fthread-safety)
#define VL_EXCLUDES(x) \
VL_CLANG_ATTR(annotate("EXCLUDES")) \
@@ -124,6 +110,32 @@
#define VL_ASSERT_CAPABILITY(x) \
VL_CLANG_ATTR(assert_capability(x))
// Require mutex locks only in code units which work with enabled multi-threading.
#if !defined(VL_MT_DISABLED_CODE_UNIT)
// Function requires not having a capability inbound (-fthread-safety)
# define VL_REQUIRES(x) \
VL_CLANG_ATTR(annotate("REQUIRES")) \
VL_CLANG_ATTR(requires_capability(x))
// Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("GUARDED_BY")) \
VL_CLANG_ATTR(guarded_by(x))
// The data that the annotated pointer points to is protected by the given capability.
// The pointer itself is not protected.
// Allowed on: pointer data member. (-fthread-safety)
# define VL_PT_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \
VL_CLANG_ATTR(pt_guarded_by(x))
#else
// Keep annotations for clang_check_attributes
# define VL_REQUIRES(x) \
VL_CLANG_ATTR(annotate("REQUIRES"))
# define VL_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("GUARDED_BY"))
# define VL_PT_GUARDED_BY(x) \
VL_CLANG_ATTR(annotate("PT_GUARDED_BY"))
#endif
// Defaults for unsupported compiler features
#ifndef VL_ATTR_ALWINLINE
# define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing
@@ -430,6 +442,11 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
Type(const Type& other) = delete; \
Type& operator=(const Type&) = delete
// Declare a class as unmovable; put after a private:
#define VL_UNMOVABLE(Type) \
Type(Type&& other) = delete; \
Type& operator=(Type&&) = delete
//=========================================================================
// Verilated function size macros
@@ -577,8 +594,8 @@ static inline double VL_ROUND(double n) {
//=========================================================================
// Stringify macros
#define VL_STRINGIFY(x) VL_STRINGIFY2(x)
#define VL_STRINGIFY2(x) #x
#define VL_STRINGIFY(...) VL_STRINGIFY2(__VA_ARGS__)
#define VL_STRINGIFY2(...) #__VA_ARGS__
//=========================================================================
// Offset of field in type
+570
View File
@@ -0,0 +1,570 @@
/***************************************************************************
* sv_vpi_user.h
*
* SystemVerilog VPI extensions.
*
* This file contains the constant definitions, structure definitions, and
* routine declarations used by the SystemVerilog Verification Procedural
* Interface (VPI) access routines.
*
**************************************************************************/
/***************************************************************************
* NOTE:
* The constant values 600 through 999 are reserved for use in this file.
* - the range 600-749 is reserved for SV VPI model extensions
* - the range 750-779 is reserved for the Coverage VPI
* - the range 800-899 is reserved for future use
* Overlaps in the numerical ranges are permitted for different categories
* of identifiers; e.g.
* - object types
* - properties
* - callbacks
**************************************************************************/
#ifndef SV_VPI_USER_H
#define SV_VPI_USER_H
#include "vpi_user.h"
#ifdef __cplusplus
extern "C" {
#endif
/****************************** OBJECT TYPES ******************************/
#define vpiPackage 600
#define vpiInterface 601
#define vpiProgram 602
#define vpiInterfaceArray 603
#define vpiProgramArray 604
#define vpiTypespec 605
#define vpiModport 606
#define vpiInterfaceTfDecl 607
#define vpiRefObj 608
#define vpiTypeParameter 609
/* variables */
#define vpiVarBit vpiRegBit
#define vpiLongIntVar 610
#define vpiShortIntVar 611
#define vpiIntVar 612
#define vpiShortRealVar 613
#define vpiByteVar 614
#define vpiClassVar 615
#define vpiStringVar 616
#define vpiEnumVar 617
#define vpiStructVar 618
#define vpiUnionVar 619
#define vpiBitVar 620
#define vpiLogicVar vpiReg
#define vpiArrayVar vpiRegArray
#define vpiClassObj 621
#define vpiChandleVar 622
#define vpiPackedArrayVar 623
#define vpiVirtualInterfaceVar 728
/* typespecs */
#define vpiLongIntTypespec 625
#define vpiShortRealTypespec 626
#define vpiByteTypespec 627
#define vpiShortIntTypespec 628
#define vpiIntTypespec 629
#define vpiClassTypespec 630
#define vpiStringTypespec 631
#define vpiChandleTypespec 632
#define vpiEnumTypespec 633
#define vpiEnumConst 634
#define vpiIntegerTypespec 635
#define vpiTimeTypespec 636
#define vpiRealTypespec 637
#define vpiStructTypespec 638
#define vpiUnionTypespec 639
#define vpiBitTypespec 640
#define vpiLogicTypespec 641
#define vpiArrayTypespec 642
#define vpiVoidTypespec 643
#define vpiTypespecMember 644
#define vpiPackedArrayTypespec 692
#define vpiSequenceTypespec 696
#define vpiPropertyTypespec 697
#define vpiEventTypespec 698
#define vpiInterfaceTypespec 906
#define vpiClockingBlock 650
#define vpiClockingIODecl 651
#define vpiClassDefn 652
#define vpiConstraint 653
#define vpiConstraintOrdering 654
#define vpiDistItem 645
#define vpiAliasStmt 646
#define vpiThread 647
#define vpiMethodFuncCall 648
#define vpiMethodTaskCall 649
/* concurrent assertions */
#define vpiAssert 686
#define vpiAssume 687
#define vpiCover 688
#define vpiRestrict 901
#define vpiDisableCondition 689
#define vpiClockingEvent 690
/* property decl, spec */
#define vpiPropertyDecl 655
#define vpiPropertySpec 656
#define vpiPropertyExpr 657
#define vpiMulticlockSequenceExpr 658
#define vpiClockedSeq 659
#define vpiClockedProp 902
#define vpiPropertyInst 660
#define vpiSequenceDecl 661
#define vpiCaseProperty 662 /* property case */
#define vpiCasePropertyItem 905 /* property case item */
#define vpiSequenceInst 664
#define vpiImmediateAssert 665
#define vpiImmediateAssume 694
#define vpiImmediateCover 695
#define vpiReturn 666
/* pattern */
#define vpiAnyPattern 667
#define vpiTaggedPattern 668
#define vpiStructPattern 669
/* do .. while */
#define vpiDoWhile 670
/* waits */
#define vpiOrderedWait 671
#define vpiWaitFork 672
/* disables */
#define vpiDisableFork 673
#define vpiExpectStmt 674
#define vpiForeachStmt 675
#define vpiReturnStmt 691
#define vpiFinal 676
#define vpiExtends 677
#define vpiDistribution 678
#define vpiSeqFormalDecl 679
#define vpiPropFormalDecl 699
#define vpiArrayNet vpiNetArray
#define vpiEnumNet 680
#define vpiIntegerNet 681
#define vpiLogicNet vpiNet
#define vpiTimeNet 682
#define vpiStructNet 683
#define vpiBreak 684
#define vpiContinue 685
#define vpiPackedArrayNet 693
#define vpiConstraintExpr 747
#define vpiElseConst 748
#define vpiImplication 749
#define vpiConstrIf 738
#define vpiConstrIfElse 739
#define vpiConstrForEach 736
#define vpiSoftDisable 733
#define vpiLetDecl 903
#define vpiLetExpr 904
/******************************** METHODS *********************************/
/************* methods used to traverse 1 to 1 relationships **************/
#define vpiActual 700
#define vpiTypedefAlias 701
#define vpiIndexTypespec 702
#define vpiBaseTypespec 703
#define vpiElemTypespec 704
#define vpiInputSkew 706
#define vpiOutputSkew 707
#define vpiGlobalClocking 708
#define vpiDefaultClocking 709
#define vpiDefaultDisableIff 710
#define vpiOrigin 713
#define vpiPrefix 714
#define vpiWith 715
#define vpiProperty 718
#define vpiValueRange 720
#define vpiPattern 721
#define vpiWeight 722
#define vpiConstraintItem 746
/************ methods used to traverse 1 to many relationships ************/
#define vpiTypedef 725
#define vpiImport 726
#define vpiDerivedClasses 727
#define vpiInterfaceDecl vpiVirtualInterfaceVar /* interface decl deprecated */
#define vpiMethods 730
#define vpiSolveBefore 731
#define vpiSolveAfter 732
#define vpiWaitingProcesses 734
#define vpiMessages 735
#define vpiLoopVars 737
#define vpiConcurrentAssertions 740
#define vpiMatchItem 741
#define vpiMember 742
#define vpiElement 743
/************* methods used to traverse 1 to many relationships ***************/
#define vpiAssertion 744
/*********** methods used to traverse both 1-1 and 1-many relations ***********/
#define vpiInstance 745
/**************************************************************************/
/************************ generic object properties ***********************/
/**************************************************************************/
#define vpiTop 600
#define vpiUnit 602
#define vpiJoinType 603
#define vpiJoin 0
#define vpiJoinNone 1
#define vpiJoinAny 2
#define vpiAccessType 604
#define vpiForkJoinAcc 1
#define vpiExternAcc 2
#define vpiDPIExportAcc 3
#define vpiDPIImportAcc 4
#define vpiArrayType 606
#define vpiStaticArray 1
#define vpiDynamicArray 2
#define vpiAssocArray 3
#define vpiQueueArray 4
#define vpiArrayMember 607
#define vpiIsRandomized 608
#define vpiLocalVarDecls 609
#define vpiOpStrong 656 /* strength of temporal operator */
#define vpiRandType 610
#define vpiNotRand 1
#define vpiRand 2
#define vpiRandC 3
#define vpiPortType 611
#define vpiInterfacePort 1
#define vpiModportPort 2
/* vpiPort is also a port type. It is defined in vpi_user.h */
#define vpiConstantVariable 612
#define vpiStructUnionMember 615
#define vpiVisibility 620
#define vpiPublicVis 1
#define vpiProtectedVis 2
#define vpiLocalVis 3
/* Return values for vpiConstType property */
#define vpiOneStepConst 9
#define vpiUnboundedConst 10
#define vpiNullConst 11
#define vpiAlwaysType 624
#define vpiAlwaysComb 2
#define vpiAlwaysFF 3
#define vpiAlwaysLatch 4
#define vpiDistType 625
#define vpiEqualDist 1 /* constraint equal distribution */
#define vpiDivDist 2 /* constraint divided distribution */
#define vpiPacked 630
#define vpiTagged 632
#define vpiRef 6 /* Return value for vpiDirection property */
#define vpiVirtual 635
#define vpiHasActual 636
#define vpiIsConstraintEnabled 638
#define vpiSoft 639
#define vpiClassType 640
#define vpiMailboxClass 1
#define vpiSemaphoreClass 2
#define vpiUserDefinedClass 3
#define vpiProcessClass 4
#define vpiMethod 645
#define vpiIsClockInferred 649
#define vpiIsDeferred 657
#define vpiIsFinal 670
#define vpiIsCoverSequence 659
#define vpiQualifier 650
#define vpiNoQualifier 0
#define vpiUniqueQualifier 1
#define vpiPriorityQualifier 2
#define vpiTaggedQualifier 4
#define vpiRandQualifier 8
#define vpiInsideQualifier 16
#define vpiInputEdge 651 /* returns vpiNoEdge, vpiPosedge,
vpiNegedge */
#define vpiOutputEdge 652 /* returns vpiNoEdge, vpiPosedge,
vpiNegedge */
#define vpiGeneric 653
/* Compatibility-mode property and values (object argument == NULL) */
#define vpiCompatibilityMode 654
#define vpiMode1364v1995 1
#define vpiMode1364v2001 2
#define vpiMode1364v2005 3
#define vpiMode1800v2005 4
#define vpiMode1800v2009 5
#define vpiPackedArrayMember 655
#define vpiStartLine 661
#define vpiColumn 662
#define vpiEndLine 663
#define vpiEndColumn 664
/* memory allocation scheme for transient objects */
#define vpiAllocScheme 658
#define vpiAutomaticScheme 1
#define vpiDynamicScheme 2
#define vpiOtherScheme 3
#define vpiObjId 660
#define vpiDPIPure 665
#define vpiDPIContext 666
#define vpiDPICStr 667
#define vpiDPI 1
#define vpiDPIC 2
#define vpiDPICIdentifier 668
#define vpiIsModPort 669
/******************************** Operators *******************************/
#define vpiImplyOp 50 /* -> implication operator */
#define vpiNonOverlapImplyOp 51 /* |=> nonoverlapped implication */
#define vpiOverlapImplyOp 52 /* |-> overlapped implication operator */
#define vpiAcceptOnOp 83 /* accept_on operator */
#define vpiRejectOnOp 84 /* reject_on operator */
#define vpiSyncAcceptOnOp 85 /* sync_accept_on operator */
#define vpiSyncRejectOnOp 86 /* sync_reject_on operator */
#define vpiOverlapFollowedByOp 87 /* overlapped followed_by operator */
#define vpiNonOverlapFollowedByOp 88 /* nonoverlapped followed_by operator */
#define vpiNexttimeOp 89 /* nexttime operator */
#define vpiAlwaysOp 90 /* always operator */
#define vpiEventuallyOp 91 /* eventually operator */
#define vpiUntilOp 92 /* until operator */
#define vpiUntilWithOp 93 /* until_with operator */
#define vpiUnaryCycleDelayOp 53 /* binary cycle delay (##) operator */
#define vpiCycleDelayOp 54 /* binary cycle delay (##) operator */
#define vpiIntersectOp 55 /* intersection operator */
#define vpiFirstMatchOp 56 /* first_match operator */
#define vpiThroughoutOp 57 /* throughout operator */
#define vpiWithinOp 58 /* within operator */
#define vpiRepeatOp 59 /* [=] nonconsecutive repetition */
#define vpiConsecutiveRepeatOp 60 /* [*] consecutive repetition */
#define vpiGotoRepeatOp 61 /* [->] goto repetition */
#define vpiPostIncOp 62 /* ++ post-increment */
#define vpiPreIncOp 63 /* ++ pre-increment */
#define vpiPostDecOp 64 /* -- post-decrement */
#define vpiPreDecOp 65 /* -- pre-decrement */
#define vpiMatchOp 66 /* match() operator */
#define vpiCastOp 67 /* type'() operator */
#define vpiIffOp 68 /* iff operator */
#define vpiWildEqOp 69 /* ==? operator */
#define vpiWildNeqOp 70 /* !=? operator */
#define vpiStreamLROp 71 /* left-to-right streaming {>>} operator */
#define vpiStreamRLOp 72 /* right-to-left streaming {<<} operator */
#define vpiMatchedOp 73 /* the .matched sequence operation */
#define vpiTriggeredOp 74 /* the .triggered sequence operation */
#define vpiAssignmentPatternOp 75 /* '{} assignment pattern */
#define vpiMultiAssignmentPatternOp 76 /* '{n{}} multi assignment pattern */
#define vpiIfOp 77 /* if operator */
#define vpiIfElseOp 78 /* if-else operator */
#define vpiCompAndOp 79 /* Composite and operator */
#define vpiCompOrOp 80 /* Composite or operator */
#define vpiImpliesOp 94 /* implies operator */
#define vpiInsideOp 95 /* inside operator */
#define vpiTypeOp 81 /* type operator */
#define vpiAssignmentOp 82 /* Normal assignment */
/*********************** task/function properties ***********************/
#define vpiOtherFunc 6 /* returns other types; for property vpiFuncType */
/* vpiValid and vpiValidUnknown were deprecated in 1800-2009 */
/*********************** value for vpiValid *****************************/
#define vpiValidUnknown 2 /* Validity of variable is unknown */
/************************** STRUCTURE DEFINITIONS *************************/
/***************************** structure *****************************/
/**************************** CALLBACK REASONS ****************************/
#define cbStartOfThread 600 /* callback on thread creation */
#define cbEndOfThread 601 /* callback on thread termination */
#define cbEnterThread 602 /* callback on reentering thread */
#define cbStartOfFrame 603 /* callback on frame creation */
#define cbEndOfFrame 604 /* callback on frame exit */
#define cbSizeChange 605 /* callback on array variable size change */
#define cbCreateObj 700 /* callback on class object creation */
#define cbReclaimObj 701 /* callback on class object reclaimed by
automatic memory management */
#define cbEndOfObject 702 /* callback on transient object deletion */
/************************* FUNCTION DECLARATIONS **************************/
/**************************************************************************/
/*************************** Coverage VPI *********************************/
/**************************************************************************/
/* coverage control */
#define vpiCoverageStart 750
#define vpiCoverageStop 751
#define vpiCoverageReset 752
#define vpiCoverageCheck 753
#define vpiCoverageMerge 754
#define vpiCoverageSave 755
/* coverage type properties */
#define vpiAssertCoverage 760
#define vpiFsmStateCoverage 761
#define vpiStatementCoverage 762
#define vpiToggleCoverage 763
/* coverage status properties */
#define vpiCovered 765
#define vpiCoverMax 766 /* preserved for backward compatibility */
#define vpiCoveredMax 766
#define vpiCoveredCount 767
/* assertion-specific coverage status properties */
#define vpiAssertAttemptCovered 770
#define vpiAssertSuccessCovered 771
#define vpiAssertFailureCovered 772
#define vpiAssertVacuousSuccessCovered 773
#define vpiAssertDisableCovered 774
#define vpiAssertKillCovered 777
/* FSM-specific coverage status properties */
#define vpiFsmStates 775
#define vpiFsmStateExpression 776
/* FSM handle types */
#define vpiFsm 758
#define vpiFsmHandle 759
/***************************************************************************/
/***************************** Assertion VPI *******************************/
/***************************************************************************/
/* assertion callback types */
#define cbAssertionStart 606
#define cbAssertionSuccess 607
#define cbAssertionFailure 608
#define cbAssertionVacuousSuccess 657
#define cbAssertionDisabledEvaluation 658
#define cbAssertionStepSuccess 609
#define cbAssertionStepFailure 610
#define cbAssertionLock 661
#define cbAssertionUnlock 662
#define cbAssertionDisable 611
#define cbAssertionEnable 612
#define cbAssertionReset 613
#define cbAssertionKill 614
#define cbAssertionEnablePassAction 645
#define cbAssertionEnableFailAction 646
#define cbAssertionDisablePassAction 647
#define cbAssertionDisableFailAction 648
#define cbAssertionEnableNonvacuousAction 649
#define cbAssertionDisableVacuousAction 650
/* assertion "system" callback types */
#define cbAssertionSysInitialized 615
#define cbAssertionSysOn 616
#define cbAssertionSysOff 617
#define cbAssertionSysKill 631
#define cbAssertionSysLock 659
#define cbAssertionSysUnlock 660
#define cbAssertionSysEnd 618
#define cbAssertionSysReset 619
#define cbAssertionSysEnablePassAction 651
#define cbAssertionSysEnableFailAction 652
#define cbAssertionSysDisablePassAction 653
#define cbAssertionSysDisableFailAction 654
#define cbAssertionSysEnableNonvacuousAction 655
#define cbAssertionSysDisableVacuousAction 656
/* assertion control constants */
#define vpiAssertionLock 645
#define vpiAssertionUnlock 646
#define vpiAssertionDisable 620
#define vpiAssertionEnable 621
#define vpiAssertionReset 622
#define vpiAssertionKill 623
#define vpiAssertionEnableStep 624
#define vpiAssertionDisableStep 625
#define vpiAssertionClockSteps 626
#define vpiAssertionSysLock 647
#define vpiAssertionSysUnlock 648
#define vpiAssertionSysOn 627
#define vpiAssertionSysOff 628
#define vpiAssertionSysKill 632
#define vpiAssertionSysEnd 629
#define vpiAssertionSysReset 630
#define vpiAssertionDisablePassAction 633
#define vpiAssertionEnablePassAction 634
#define vpiAssertionDisableFailAction 635
#define vpiAssertionEnableFailAction 636
#define vpiAssertionDisableVacuousAction 637
#define vpiAssertionEnableNonvacuousAction 638
#define vpiAssertionSysEnablePassAction 639
#define vpiAssertionSysEnableFailAction 640
#define vpiAssertionSysDisablePassAction 641
#define vpiAssertionSysDisableFailAction 642
#define vpiAssertionSysEnableNonvacuousAction 643
#define vpiAssertionSysDisableVacuousAction 644
typedef struct t_vpi_assertion_step_info {
PLI_INT32 matched_expression_count;
vpiHandle *matched_exprs; /* array of expressions */
PLI_INT32 stateFrom, stateTo; /* identify transition */
} s_vpi_assertion_step_info, *p_vpi_assertion_step_info;
typedef struct t_vpi_attempt_info {
union {
vpiHandle failExpr;
p_vpi_assertion_step_info step;
} detail;
s_vpi_time attemptStartTime; /* Time attempt triggered */
} s_vpi_attempt_info, *p_vpi_attempt_info;
/* typedef for vpi_register_assertion_cb callback function */
typedef PLI_INT32(vpi_assertion_callback_func)(
PLI_INT32 reason, /* callback reason */
p_vpi_time cb_time, /* callback time */
vpiHandle assertion, /* handle to assertion */
p_vpi_attempt_info info, /* attempt related information */
PLI_BYTE8 *user_data /* user data entered upon registration */
);
vpiHandle vpi_register_assertion_cb(
vpiHandle assertion, /* handle to assertion */
PLI_INT32 reason, /* reason for which callbacks needed */
vpi_assertion_callback_func *cb_rtn,
PLI_BYTE8 *user_data /* user data to be supplied to cb */
);
#ifdef __cplusplus
}
#endif
#endif
+268 -50
View File
@@ -10,16 +10,36 @@ import argparse
import os
import sys
import shlex
from typing import Callable, Iterable, Optional, Union
from typing import Callable, Iterable, Optional, Union, TYPE_CHECKING
import dataclasses
from dataclasses import dataclass
import enum
from enum import Enum
import multiprocessing
import re
import tempfile
import clang.cindex
from clang.cindex import CursorKind, Index, TranslationUnitSaveError, TranslationUnitLoadError
from clang.cindex import (
Index,
TranslationUnitSaveError,
TranslationUnitLoadError,
CompilationDatabase,
)
if not TYPE_CHECKING:
from clang.cindex import CursorKind
else:
# Workaround for missing support for members defined out-of-class in Pylance:
# https://github.com/microsoft/pylance-release/issues/2365#issuecomment-1035803067
class CursorKindMeta(type):
def __getattr__(cls, name: str) -> clang.cindex.CursorKind:
return getattr(clang.cindex.CursorKind, name)
class CursorKind(clang.cindex.CursorKind, metaclass=CursorKindMeta):
pass
def fully_qualified_name(node):
@@ -60,6 +80,7 @@ class VlAnnotations:
stable_tree: bool = False
mt_safe_postinit: bool = False
mt_unsafe: bool = False
mt_disabled: bool = False
mt_unsafe_one: bool = False
pure: bool = False
guarded: bool = False
@@ -81,7 +102,7 @@ class VlAnnotations:
return self.stable_tree or self.mt_start
def is_mt_unsafe_call(self):
return self.mt_unsafe or self.mt_unsafe_one
return self.mt_unsafe or self.mt_unsafe_one or self.mt_disabled
def is_mt_safe_call(self):
return (not self.is_mt_unsafe_call()
@@ -131,6 +152,8 @@ class VlAnnotations:
result.mt_unsafe = True
elif node.displayname == "MT_UNSAFE_ONE":
result.mt_unsafe_one = True
elif node.displayname == "MT_DISABLED":
result.mt_disabled = True
elif node.displayname == "PURE":
result.pure = True
elif node.displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
@@ -203,6 +226,19 @@ class FunctionInfo:
def copy(self, /, **changes):
return dataclasses.replace(self, **changes)
@staticmethod
def from_decl_file_line_and_refd_node(file: str, line: int,
refd: clang.cindex.Cursor,
annotations: VlAnnotations):
file = os.path.abspath(file)
refd = refd.canonical
assert refd is not None
name_parts = fully_qualified_name(refd)
usr = refd.get_usr()
ftype = FunctionType.from_node(refd)
return FunctionInfo(name_parts, usr, file, line, annotations, ftype)
@staticmethod
def from_node(node: clang.cindex.Cursor,
refd: Optional[clang.cindex.Cursor] = None,
@@ -228,6 +264,7 @@ class DiagnosticKind(Enum):
NON_PURE_CALL_IN_PURE_CTX = enum.auto()
NON_MT_SAFE_CALL_IN_MT_SAFE_CTX = enum.auto()
NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX = enum.auto()
MISSING_MT_DISABLED_ANNOTATION = enum.auto()
def __lt__(self, other):
return self.value < other.value
@@ -265,35 +302,142 @@ class CallAnnotationsValidator:
self._index = Index.create()
self._processed_headers: set[str] = set()
# Map key represents translation unit initial defines
# (from command line and source's lines before any include)
self._processed_headers: dict[str, set[str]] = {}
self._external_decls: dict[str, set[tuple[str, int]]] = {}
# Current context
self._main_source_file: str = ""
self._defines: dict[str, str] = {}
self._call_location: Optional[FunctionInfo] = None
self._caller: Optional[FunctionInfo] = None
self._level: int = 0
self._constructor_context: list[clang.cindex.Cursor] = []
self._level: int = 0
def is_mt_disabled_code_unit(self):
return "VL_MT_DISABLED_CODE_UNIT" in self._defines
def is_constructor_context(self):
return len(self._constructor_context) > 0
# Parses all lines in a form: `#define KEY VALUE` located before any `#include` line.
# The parsing is very simple, there is no support for line breaks, etc.
@staticmethod
def parse_initial_defines(source_file: str) -> dict[str, str]:
defs: dict[str, str] = {}
with open(source_file, "r", encoding="utf-8") as file:
for line in file:
line = line.strip()
match = re.fullmatch(
r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
if match:
if match.group(1).startswith("define"):
key = match.group(2)
value = match.groups("1")[2]
defs[key] = value
elif match.group(1).startswith("include"):
break
return defs
@staticmethod
def filter_out_unsupported_compiler_args(
args: list[str]) -> tuple[list[str], dict[str, str]]:
filtered_args = []
defines = {}
args_iter = iter(args)
try:
while arg := next(args_iter):
# Skip positional arguments (input file name).
if not arg.startswith("-") and (arg.endswith(".cpp")
or arg.endswith(".c")
or arg.endswith(".h")):
continue
# Skipped options with separate value argument.
if arg in ["-o", "-T", "-MT", "-MQ", "-MF"
"-L"]:
next(args_iter)
continue
# Skipped options without separate value argument.
if arg == "-c" or arg.startswith("-W") or arg.startswith("-L"):
continue
# Preserved options with separate value argument.
if arg in [
"-x"
"-Xclang", "-I", "-isystem", "-iquote", "-include",
"-include-pch"
]:
filtered_args += [arg, next(args_iter)]
continue
kv_str = None
d_or_u = None
# Preserve define/undefine with separate value argument.
if arg in ["-D", "-U"]:
filtered_args.append(arg)
d_or_u = arg[1]
kv_str = next(args_iter)
filtered_args.append(kv_str)
# Preserve define/undefine without separate value argument.
elif arg[0:2] in ["-D", "-U"]:
filtered_args.append(arg)
kv_str = arg[2:]
d_or_u = arg[1]
# Preserve everything else.
else:
filtered_args.append(arg)
continue
# Keep track of defines for class' internal purposes.
key_value = kv_str.split("=", 1)
key = key_value[0]
val = "1" if len(key_value) == 1 else key_value[1]
if d_or_u == "D":
defines[key] = val
elif d_or_u == "U" and key in defines:
del defines[key]
except StopIteration:
pass
return (filtered_args, defines)
def compile_and_analyze_file(self, source_file: str,
compiler_args: list[str],
build_dir: Optional[str]):
filename = os.path.abspath(source_file)
initial_cwd = "."
filtered_args, defines = self.filter_out_unsupported_compiler_args(
compiler_args)
defines.update(self.parse_initial_defines(source_file))
if build_dir:
initial_cwd = os.getcwd()
os.chdir(build_dir)
translation_unit = self._index.parse(filename, compiler_args)
has_errors = False
for diag in translation_unit.diagnostics:
if diag.severity > clang.cindex.Diagnostic.Error:
has_errors = True
if translation_unit and not has_errors:
try:
translation_unit = self._index.parse(filename, filtered_args)
except TranslationUnitLoadError:
translation_unit = None
errors = []
if translation_unit:
for diag in translation_unit.diagnostics:
if diag.severity >= clang.cindex.Diagnostic.Error:
errors.append(str(diag))
if translation_unit and len(errors) == 0:
self._defines = defines
self._main_source_file = filename
self.process_translation_unit(translation_unit)
self._main_source_file = ""
self._defines = {}
else:
print(f"%Error: parsing failed: {filename}", file=sys.stderr)
for error in errors:
print(f" {error}", file=sys.stderr)
if build_dir:
os.chdir(initial_cwd)
@@ -563,6 +707,18 @@ class CallAnnotationsValidator:
f" from: {node.location.file.name}:{node.location.line}")
return True
def process_function_declaration(self, node: clang.cindex.Cursor):
# Ignore declarations in main .cpp file
if node.location.file.name != self._main_source_file:
children = list(node.get_children())
annotations = VlAnnotations.from_nodes_list(children)
if not annotations.mt_disabled:
self._external_decls.setdefault(node.get_usr(), set()).add(
(str(node.location.file.name), int(node.location.line)))
return self.iterate_children(children, self.dispatch_node)
return self.iterate_children(node.get_children(), self.dispatch_node)
# Definition handling
def dispatch_node_inside_definition(self, node: clang.cindex.Cursor):
@@ -593,6 +749,18 @@ class CallAnnotationsValidator:
assert refd is not None
def_annotations = VlAnnotations.from_nodes_list(node_children)
# Implicitly mark definitions in VL_MT_DISABLED_CODE_UNIT .cpp files as
# VL_MT_DISABLED. Existence of the annotation on declarations in .h
# files is verified below.
# Also sets VL_REQUIRES, as this annotation is added together with
# explicit VL_MT_DISABLED.
if self.is_mt_disabled_code_unit():
if node.location.file.name == self._main_source_file:
annotations.mt_disabled = True
annotations.requires = True
if refd.location.file.name == self._main_source_file:
def_annotations.mt_disabled = True
def_annotations.requires = True
if not (def_annotations.is_empty() or def_annotations == annotations):
# Use definition's annotations for the diagnostic
@@ -605,12 +773,26 @@ class CallAnnotationsValidator:
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
# Use concatenation of definition and declaration annotations
# for callees validation.
# for calls validation.
self._caller = FunctionInfo.from_node(node, refd,
def_annotations | annotations)
prev_call_location = self._call_location
self._call_location = self._caller
if self.is_mt_disabled_code_unit():
# Report declarations of this functions that don't have MT_DISABLED annotation
# and are located in headers.
if node.location.file.name == self._main_source_file:
usr = node.get_usr()
declarations = self._external_decls.get(usr, set())
for file, line in declarations:
self.emit_diagnostic(
FunctionInfo.from_decl_file_line_and_refd_node(
file, line, refd, def_annotations),
DiagnosticKind.MISSING_MT_DISABLED_ANNOTATION)
if declarations:
del self._external_decls[usr]
self.iterate_children(node_children,
self.dispatch_node_inside_definition)
@@ -622,34 +804,36 @@ class CallAnnotationsValidator:
# Nodes not located inside definition
def dispatch_node(self, node: clang.cindex.Cursor):
if node.is_definition() and node.kind in [
if node.kind in [
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
]:
return self.process_function_definition(node)
if node.is_definition() and node.kind in [
CursorKind.NAMESPACE, CursorKind.STRUCT_DECL,
CursorKind.UNION_DECL, CursorKind.CLASS_DECL
]:
return self.iterate_children(node.get_children(),
self.dispatch_node)
if node.is_definition():
return self.process_function_definition(node)
# else:
return self.process_function_declaration(node)
return self.iterate_children(node.get_children(), self.dispatch_node)
def process_translation_unit(
self, translation_unit: clang.cindex.TranslationUnit):
self._level += 1
kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()])
concat_defines = '\n'.join(kv_defines)
# List of headers already processed in a TU with specified set of defines.
tu_processed_headers = self._processed_headers.setdefault(
concat_defines, set())
for child in translation_unit.cursor.get_children():
if self._is_ignored_top_level(child):
continue
if self._processed_headers:
if tu_processed_headers:
filename = os.path.abspath(child.location.file.name)
if filename in self._processed_headers:
if filename in tu_processed_headers:
continue
self.dispatch_node(child)
self._level -= 1
self._processed_headers.update([
tu_processed_headers.update([
os.path.abspath(str(hdr.source))
for hdr in translation_unit.get_includes()
])
@@ -711,34 +895,40 @@ def get_filter_funcs(verilator_root: str):
def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
initial_cwd = os.getcwd()
errors = []
try:
initial_cwd = os.getcwd()
os.chdir(compile_command.directory)
index = Index.create()
translation_unit = index.parse(compile_command.filename,
compile_command.args)
for diag in translation_unit.diagnostics:
if diag.severity > clang.cindex.Diagnostic.Error:
pch_file = None
break
else:
if diag.severity >= clang.cindex.Diagnostic.Error:
errors.append(str(diag))
if len(errors) == 0:
pch_file = os.path.join(
tmp_dir,
f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch"
)
translation_unit.save(pch_file)
if pch_file:
return pch_file
except (TranslationUnitSaveError, TranslationUnitLoadError,
OSError) as exception:
print(f"%Warning: {exception}", file=sys.stderr)
finally:
os.chdir(initial_cwd)
if pch_file:
return pch_file
except (TranslationUnitSaveError, TranslationUnitLoadError, OSError):
pass
print(
f"%Warning: Precompiling failed, skipping: {compile_command.filename}")
f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
file=sys.stderr)
for error in errors:
print(f" {error}", file=sys.stderr)
return ""
@@ -761,10 +951,11 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
is_ignored_def, is_ignored_call)
for compile_command in ccl:
cav.compile_and_analyze_file(compile_command.filename,
compile_command.args + extra_args,
extra_args + compile_command.args,
compile_command.directory)
@dataclass
class ParallelAnalysisProcess:
cav: Optional[CallAnnotationsValidator] = None
diags: set[Diagnostic] = dataclasses.field(default_factory=set)
@@ -881,6 +1072,10 @@ class TopDownSummaryPrinter():
name += "is pure but calls non-pure function(s)"
elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX:
name += "is stable_tree but calls non-stable_tree or non-mtsafe"
elif func.reason == DiagnosticKind.MISSING_MT_DISABLED_ANNOTATION:
name += ("defined in a file marked as " +
"VL_MT_DISABLED_CODE_UNIT has declaration(s) " +
"without VL_MT_DISABLED annotation")
else:
name += "for unknown reason (please add description)"
@@ -947,10 +1142,15 @@ def main():
type=int,
default=0,
help="Number of parallel jobs to use.")
parser.add_argument(
"--compile-commands-dir",
type=str,
default=None,
help="Path to directory containing compile_commands.json.")
parser.add_argument("--cxxflags",
type=str,
default=None,
help="Flags passed to clang++.")
help="Extra flags passed to clang++.")
parser.add_argument(
"--compilation-root",
type=str,
@@ -975,34 +1175,52 @@ def main():
cmdline.compilation_root = cmdline.verilator_root
verilator_root = os.path.abspath(cmdline.verilator_root)
compilation_root = os.path.abspath(cmdline.compilation_root)
default_compilation_root = os.path.abspath(cmdline.compilation_root)
compdb: Optional[CompilationDatabase] = None
if cmdline.compile_commands_dir:
compdb = CompilationDatabase.fromDirectory(
cmdline.compile_commands_dir)
default_cxx_flags = [
f"-I{verilator_root}/src",
f"-I{verilator_root}/include",
f"-I{verilator_root}/src/obj_opt",
"-fcoroutines-ts",
]
if cmdline.cxxflags is not None:
cxxflags = shlex.split(cmdline.cxxflags)
common_cxxflags = shlex.split(cmdline.cxxflags)
else:
cxxflags = default_cxx_flags
common_cxxflags = []
precompile_commands_list = []
if cmdline.precompile:
hdr_cxxflags = ['-xc++-header'] + cxxflags
hdr_cxxflags = ['-xc++-header'] + common_cxxflags
for refid, file in enumerate(cmdline.precompile):
filename = os.path.abspath(file)
compile_command = CompileCommand(refid, filename, hdr_cxxflags,
compilation_root)
default_compilation_root)
precompile_commands_list.append(compile_command)
compile_commands_list = []
for refid, file in enumerate(cmdline.file):
filename = os.path.abspath(file)
compile_command = CompileCommand(refid, filename, cxxflags,
compilation_root)
root = default_compilation_root
cxxflags = []
if compdb:
entry = compdb.getCompileCommands(filename)
entry_list = list(entry)
# Compilation database can contain multiple entries for single file,
# e.g. when it has been updated by appending new entries.
# Use last entry for the file, if it exists, as it is the newest one.
if len(entry_list) > 0:
last_entry = entry_list[-1]
root = last_entry.directory
entry_args = list(last_entry.arguments)
# First argument in compile_commands.json arguments list is
# compiler executable name/path. CIndex (libclang) always
# implicitly prepends executable name, so it shouldn't be passed
# here.
cxxflags = common_cxxflags + entry_args[1:]
else:
cxxflags = common_cxxflags[:]
compile_command = CompileCommand(refid, filename, cxxflags, root)
compile_commands_list.append(compile_command)
summary_printer = TopDownSummaryPrinter()
+1 -1
View File
@@ -316,7 +316,7 @@ def run(command):
print("\t%s" % command)
status = subprocess.call(command, shell=True)
if status < 0:
raise Exception("%Error: Command failed " + command + ", stopped")
raise RuntimeError("%Error: Command failed " + command + ", stopped")
def unlink_ok(filename):
+1 -1
View File
@@ -104,7 +104,7 @@ def run(command):
os.system(command)
status = subprocess.call(command, shell=True)
if status < 0:
raise Exception("%Error: Command failed " + command + ", stopped")
raise RuntimeError("%Error: Command failed " + command + ", stopped")
#######################################################################
+19 -6
View File
@@ -35,7 +35,6 @@ set(HEADERS
V3Assert.h
V3AssertPre.h
V3Ast.h
V3AstConstOnly.h
V3AstInlines.h
V3AstNodeDType.h
V3AstNodeExpr.h
@@ -44,9 +43,10 @@ set(HEADERS
V3Begin.h
V3Branch.h
V3Broken.h
V3CCtors.h
V3CUse.h
V3Case.h
V3Cast.h
V3CCtors.h
V3Class.h
V3Clean.h
V3Clock.h
@@ -56,7 +56,6 @@ set(HEADERS
V3Const.h
V3Coverage.h
V3CoverageJoin.h
V3CUse.h
V3Dead.h
V3Delayed.h
V3Depth.h
@@ -96,6 +95,7 @@ set(HEADERS
V3Inline.h
V3Inst.h
V3InstrCount.h
V3Interface.h
V3LangCode.h
V3LanguageWords.h
V3Life.h
@@ -104,13 +104,16 @@ set(HEADERS
V3LinkDot.h
V3LinkInc.h
V3LinkJump.h
V3LinkLevel.h
V3LinkLValue.h
V3LinkLevel.h
V3LinkParse.h
V3LinkResolve.h
V3List.h
V3Localize.h
V3MemberMap.h
V3MergeCond.h
V3Mutex.h
V3Name.h
V3Name.h
V3Number.h
V3OptionParser.h
@@ -126,13 +129,16 @@ set(HEADERS
V3ParseSym.h
V3Partition.h
V3PartitionGraph.h
V3PchAstMT.h
V3PchAstNoMT.h
V3PreLex.h
V3Premit.h
V3PreProc.h
V3PreShell.h
V3Premit.h
V3ProtectLib.h
V3Randomize.h
V3Reloop.h
V3Rtti.h
V3Sched.h
V3Scope.h
V3Scoreboard.h
@@ -148,14 +154,15 @@ set(HEADERS
V3String.h
V3Subst.h
V3SymTable.h
V3TSP.h
V3Table.h
V3Task.h
V3ThreadPool.h
V3ThreadSafety.h
V3Timing.h
V3Trace.h
V3TraceDecl.h
V3Tristate.h
V3TSP.h
V3Undriven.h
V3UniqueNames.h
V3Unknown.h
@@ -164,6 +171,7 @@ set(HEADERS
V3Waiver.h
V3Width.h
V3WidthCommit.h
V3WidthRemove.h
VlcBucket.h
VlcOptions.h
VlcPoint.h
@@ -219,6 +227,7 @@ set(COMMON_SOURCES
V3EmitCMain.cpp
V3EmitCMake.cpp
V3EmitCModel.cpp
V3EmitCPch.cpp
V3EmitCSyms.cpp
V3EmitMk.cpp
V3EmitV.cpp
@@ -242,6 +251,7 @@ set(COMMON_SOURCES
V3Inline.cpp
V3Inst.cpp
V3InstrCount.cpp
V3Interface.cpp
V3Life.cpp
V3LifePost.cpp
V3LinkCells.cpp
@@ -295,6 +305,7 @@ set(COMMON_SOURCES
V3VariableOrder.cpp
V3Waiver.cpp
V3Width.cpp
V3WidthCommit.cpp
V3WidthSel.cpp
V3ParseImp.cpp
V3ParseGrammar.cpp
@@ -490,11 +501,13 @@ target_include_directories(${verilator}
)
if (WIN32)
target_compile_options(${verilator} PRIVATE /bigobj)
target_compile_definitions(${verilator} PRIVATE
YY_NO_UNISTD_H
)
target_include_directories(${verilator} PRIVATE ../platform/win32)
target_link_libraries(${verilator} PRIVATE bcrypt psapi)
target_link_options(${verilator} PRIVATE /STACK:10000000)
endif()
install(TARGETS ${verilator})
+23 -4
View File
@@ -18,14 +18,13 @@
#### Start of system configuration section. ####
srcdir = @srcdir@
PYTHON3 = @PYTHON3@
EXEEXT = @EXEEXT@
PYTHON3 = @PYTHON3@
# VPATH only does sources; fix install_test's not creating ../bin
vpath %.h @srcdir@
#### End of system configuration section. ####
default: dbg opt
debug: dbg
optimize: opt
@@ -36,6 +35,26 @@ endif
UNDER_GIT = $(wildcard ${srcdir}/../.git/logs/HEAD)
ifeq (,$(wildcard obj_dbg/bear.o))
ifneq (, $(shell which bear 2>/dev/null))
BEAR := $(shell which bear)
ifeq (, $(shell $(BEAR) --output obj_dbg/comptest.json -- true))
$(shell which bear 2>/dev/null >obj_dbg/bear.o)
else
# unsupported version
BEAR :=
endif
endif
else
BEAR := $(shell cat obj_dbg/bear.o)
endif
ifneq ($(BEAR),)
BEAR_OBJ_OPT := $(BEAR) --append --output obj_dbg/compile_commands.json --
else
BEAR_OBJ_OPT :=
endif
#*********************************************************************
obj_opt:
@@ -62,8 +81,8 @@ endif
dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT)
../bin/verilator_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles
$(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
$(BEAR_OBJ_OPT) $(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
$(BEAR_OBJ_OPT) $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
../bin/verilator_coverage_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
+85 -49
View File
@@ -67,6 +67,11 @@ CFG_CXXFLAGS_PARSER = @CFG_CXXFLAGS_PARSER@
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
CFG_LDFLAGS_SRC = @CFG_LDFLAGS_SRC@
CFG_LIBS = @CFG_LIBS@
CFG_CXXFLAGS_PCH = -x c++-header
# Compiler option to put in front of filename to read precompiled header
CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
#### End of system configuration section. ####
@@ -129,6 +134,11 @@ BISONPRE = $(srcdir)/bisonpre
FLEXFIX = $(srcdir)/flexfix
VLCOVGEN = $(srcdir)/vlcovgen
######################################################################
# CCACHE flags (via environment as no command line option available)
CCACHE_SLOPPINESS ?= pch_defines,time_macros
export CCACHE_SLOPPINESS
######################################################################
#### Top level
@@ -151,16 +161,55 @@ maintainer-copy::
#### Top executable
RAW_OBJS = \
V3Const__gen.o \
V3Error.o \
V3FileLine.o \
V3Graph.o \
V3GraphAcyc.o \
V3GraphAlg.o \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hash.o \
V3OptionParser.o \
V3Os.o \
V3ParseGrammar.o \
V3ParseImp.o \
V3ParseLex.o \
V3PreProc.o \
V3PreShell.o \
V3String.o \
V3ThreadPool.o \
V3Waiver.o \
Verilator.o \
RAW_OBJS_PCH_ASTMT = \
V3Ast.o \
V3AstNodes.o \
V3Broken.o \
V3Config.o \
V3EmitCBase.o \
V3EmitCConstPool.o \
V3EmitCFunc.o \
V3EmitCHeaders.o \
V3EmitCImp.o \
V3EmitCInlines.o \
V3EmitCPch.o \
V3EmitV.o \
V3File.o \
V3Global.o \
V3Hasher.o \
V3Number.o \
V3Options.o \
V3Stats.o \
V3StatsReport.o \
RAW_OBJS_PCH_ASTNOMT = \
V3Active.o \
V3ActiveTop.o \
V3Assert.o \
V3AssertPre.o \
V3Ast.o \
V3AstNodes.o \
V3Begin.o \
V3Branch.o \
V3Broken.o \
V3CCtors.o \
V3CUse.o \
V3Case.o \
@@ -170,8 +219,6 @@ RAW_OBJS = \
V3Clock.o \
V3Combine.o \
V3Common.o \
V3Config.o \
V3Const__gen.o \
V3Coverage.o \
V3CoverageJoin.o \
V3Dead.o \
@@ -187,38 +234,21 @@ RAW_OBJS = \
V3DfgPasses.o \
V3DfgPeephole.o \
V3DupFinder.o \
V3EmitCBase.o \
V3EmitCConstPool.o \
V3EmitCFunc.o \
V3EmitCHeaders.o \
V3EmitCImp.o \
V3EmitCInlines.o \
V3EmitCMain.o \
V3EmitCMake.o \
V3EmitCModel.o \
V3EmitCSyms.o \
V3EmitMk.o \
V3EmitV.o \
V3EmitXml.o \
V3Error.o \
V3Expand.o \
V3File.o \
V3FileLine.o \
V3Force.o \
V3Fork.o \
V3Gate.o \
V3Global.o \
V3Graph.o \
V3GraphAcyc.o \
V3GraphAlg.o \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hash.o \
V3Hasher.o \
V3HierBlock.o \
V3Inline.o \
V3Inst.o \
V3InstrCount.o \
V3Interface.o \
V3Life.o \
V3LifePost.o \
V3LinkCells.o \
@@ -232,18 +262,9 @@ RAW_OBJS = \
V3Localize.o \
V3MergeCond.o \
V3Name.o \
V3Number.o \
V3OptionParser.o \
V3Options.o \
V3Order.o \
V3Os.o \
V3Param.o \
V3ParseGrammar.o \
V3ParseImp.o \
V3ParseLex.o \
V3Partition.o \
V3PreProc.o \
V3PreShell.o \
V3Premit.o \
V3ProtectLib.o \
V3Randomize.o \
@@ -259,14 +280,10 @@ RAW_OBJS = \
V3Split.o \
V3SplitAs.o \
V3SplitVar.o \
V3Stats.o \
V3StatsReport.o \
V3String.o \
V3Subst.o \
V3TSP.o \
V3Table.o \
V3Task.o \
V3ThreadPool.o \
V3Timing.o \
V3Trace.o \
V3TraceDecl.o \
@@ -275,8 +292,8 @@ RAW_OBJS = \
V3Unknown.o \
V3Unroll.o \
V3VariableOrder.o \
V3Waiver.o \
V3Width.o \
V3WidthCommit.o \
V3WidthSel.o \
# verilator_coverage
@@ -284,20 +301,21 @@ VLCOV_OBJS = \
VlcMain.o \
NON_STANDALONE_HEADERS = \
V3AstInlines.h \
V3AstNodeDType.h \
V3AstNodeExpr.h \
V3AstNodeOther.h \
V3DfgVertices.h \
V3WidthCommit.h \
V3AstInlines.h \
V3AstNodeDType.h \
V3AstNodeExpr.h \
V3AstNodeOther.h \
V3DfgVertices.h \
V3ThreadPool.h \
V3WidthRemove.h \
AST_DEFS := \
V3AstNodeDType.h \
V3AstNodeExpr.h \
V3AstNodeOther.h \
V3AstNodeDType.h \
V3AstNodeExpr.h \
V3AstNodeOther.h \
DFG_DEFS := \
V3DfgVertices.h
V3DfgVertices.h
#### astgen common flags
@@ -309,7 +327,7 @@ ASTGENFLAGS += $(foreach f,$(DFG_DEFS),--dfgdef $f)
ifeq ($(VL_VLCOV),)
PREDEP_H = V3Ast__gen_forward_class_decls.h
OBJS += $(RAW_OBJS)
OBJS += $(RAW_OBJS) $(RAW_OBJS_PCH_ASTMT) $(RAW_OBJS_PCH_ASTNOMT)
else
PREDEP_H =
OBJS += $(VLCOV_OBJS)
@@ -329,6 +347,8 @@ V3Number_test: V3Number_test.o
.SECONDARY:
%.gch: %
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} $< -o $@
%.o: %.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
%.o: %.c
@@ -346,6 +366,22 @@ V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
define CXX_ASTMT_template
$(1): $(basename $(1)).cpp V3PchAstMT.h.gch
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH_I} V3PchAstMT.h${CFG_GCH_IF_CLANG} -c $(srcdir)/$(basename $(1)).cpp -o $(1)
endef
$(foreach obj,$(RAW_OBJS_PCH_ASTMT),$(eval $(call CXX_ASTMT_template,$(obj))))
define CXX_ASTNOMT_template
$(1): $(basename $(1)).cpp V3PchAstNoMT.h.gch
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH_I} V3PchAstNoMT.h${CFG_GCH_IF_CLANG} -c $(srcdir)/$(basename $(1)).cpp -o $(1)
endef
$(foreach obj,$(RAW_OBJS_PCH_ASTNOMT),$(eval $(call CXX_ASTNOMT_template,$(obj))))
#### Generated files
# Target rule called before parallel build to make generated files
@@ -388,7 +424,7 @@ HEADER_CC_H := $(filter-out $(NON_STANDALONE_HEADERS), $(notdir $(wildcard $(src
header_cc: $(addsuffix __header_cc.o, $(basename $(HEADER_CC_H)))
%__header_cc.cpp: %.h
$(PYTHON3) $(srcdir)/../bin/verilator_includer $^ > $@
$(PYTHON3) $(srcdir)/../bin/verilator_includer -DVL_MT_DISABLED_CODE_UNIT=1 $^ > $@
.SUFFIXES:
+2 -4
View File
@@ -26,14 +26,11 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Active.h"
#include "V3Ast.h"
#include "V3Const.h"
#include "V3Global.h"
#include "V3Graph.h"
#include <unordered_map>
@@ -47,6 +44,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
// Extend V3GraphVertex class for use in latch detection graph
class LatchDetectGraphVertex final : public V3GraphVertex {
VL_RTTI_IMPL(LatchDetectGraphVertex, V3GraphVertex)
public:
enum VertexType : uint8_t { VT_BLOCK, VT_BRANCH, VT_OUTPUT };
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Active final {
public:
static void activeAll(AstNetlist* nodep);
static void activeAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+1 -4
View File
@@ -23,14 +23,11 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3ActiveTop.h"
#include "V3Ast.h"
#include "V3Const.h"
#include "V3Global.h"
#include "V3SenTree.h"
VL_DEFINE_DEBUG_FUNCTIONS;
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3ActiveTop final {
public:
static void activeTopAll(AstNetlist* nodep);
static void activeTopAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+11 -15
View File
@@ -14,14 +14,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Assert.h"
#include "V3Ast.h"
#include "V3Error.h"
#include "V3Global.h"
#include "V3Stats.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -158,7 +154,7 @@ private:
if (m_procedurep) {
// To support this need queue of asserts to activate
nodep->v3error("Unsupported: Procedural concurrent assertion with"
" clocking event inside always (IEEE 1800-2917 16.14.6)");
" clocking event inside always (IEEE 1800-2017 16.14.6)");
}
}
//
@@ -243,7 +239,7 @@ private:
}
// Build a bitmask of the true predicates
AstNodeExpr* const predp = ifp->condp()->cloneTree(false);
AstNodeExpr* const predp = ifp->condp()->cloneTreePure(false);
if (propp) {
propp = new AstConcat{nodep->fileline(), predp, propp};
} else {
@@ -256,7 +252,7 @@ private:
ifp = nextifp;
} while (ifp);
AstNode* const newifp = nodep->cloneTree(false);
AstIf* const newifp = nodep->cloneTree(false);
const bool allow_none = nodep->unique0Pragma();
// Empty case means no property
@@ -312,17 +308,17 @@ private:
icondp = VN_AS(icondp->nextp(), NodeExpr)) {
AstNodeExpr* onep;
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
onep = rcondp->newAndFromInside(nodep->exprp(),
rcondp->lhsp()->cloneTree(true),
rcondp->rhsp()->cloneTree(true));
onep = rcondp->newAndFromInside(
nodep->exprp(), rcondp->lhsp()->cloneTreePure(true),
rcondp->rhsp()->cloneTreePure(true));
} else if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
onep = AstEqWild::newTyped(itemp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
nodep->exprp()->cloneTreePure(false),
icondp->cloneTreePure(false));
} else {
onep = AstEq::newTyped(icondp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
nodep->exprp()->cloneTreePure(false),
icondp->cloneTreePure(false));
}
if (propp) {
propp = new AstConcat{icondp->fileline(), onep, propp};
+2 -1
View File
@@ -21,12 +21,13 @@
#include "verilatedos.h"
#include "V3Ast.h"
#include "V3ThreadSafety.h"
//============================================================================
class V3Assert final {
public:
static void assertAll(AstNetlist* nodep);
static void assertAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+10 -13
View File
@@ -15,18 +15,15 @@
//*************************************************************************
// Pre steps:
// Attach clocks to each assertion
// Substitute property references by property body (IEEE Std 1800-2012, section 16.12.1).
// Substitute property references by property body (IEEE 1800-2012 16.12.1).
// Transform clocking blocks into imperative logic
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3AssertPre.h"
#include "V3Ast.h"
#include "V3Const.h"
#include "V3Global.h"
#include "V3Task.h"
#include "V3UniqueNames.h"
@@ -177,7 +174,7 @@ private:
if (nodep->direction() == VDirection::OUTPUT) {
AstVarRef* const skewedRefp = new AstVarRef{flp, varp, VAccess::READ};
skewedRefp->user1(true);
AstAssign* const assignp = new AstAssign{flp, exprp->cloneTree(false), skewedRefp};
AstAssign* const assignp = new AstAssign{flp, exprp->cloneTreePure(false), skewedRefp};
if (skewp->isZero()) {
// Drive the var in Re-NBA (IEEE 1800-2017 14.16)
m_clockingp->addNextHere(new AstAlwaysReactive{
@@ -208,12 +205,12 @@ private:
refp->user1(true);
if (skewp->num().is1Step()) {
// Assign the sampled expression to the clockvar (IEEE 1800-2017 14.13)
AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTree(false)};
AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTreePure(false)};
sampledp->dtypeFrom(exprp);
m_clockingp->addNextHere(new AstAssignW{flp, refp, sampledp});
} else if (skewp->isZero()) {
// #0 means the var has to be sampled in Observed (IEEE 1800-2017 14.13)
AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTree(false)};
AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTreePure(false)};
m_clockingp->addNextHere(new AstAlwaysObserved{
flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, assignp});
} else {
@@ -230,7 +227,7 @@ private:
AstCMethodHard* const pushp = new AstCMethodHard{
flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push",
new AstTime{nodep->fileline(), m_modp->timeunit()}};
pushp->addPinsp(exprp->cloneTree(false));
pushp->addPinsp(exprp->cloneTreePure(false));
pushp->dtypeSetVoid();
m_clockingp->addNextHere(
new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, pushp->makeStmt()});
@@ -372,7 +369,7 @@ private:
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}};
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTreePure(false)}};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep, sentreep));
@@ -393,7 +390,7 @@ private:
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)};
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTreePure(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep, sentreep));
@@ -408,7 +405,7 @@ private:
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstEq{fl, past, exprp->cloneTree(false)};
exprp = new AstEq{fl, past, exprp->cloneTreePure(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep, sentreep));
@@ -442,7 +439,7 @@ private:
// Block is the new expression to evaluate
AstNodeExpr* blockp = VN_AS(nodep->propp()->unlinkFrBack(), NodeExpr);
if (AstNodeExpr* const disablep = nodep->disablep()) {
m_disablep = disablep->cloneTree(false);
m_disablep = disablep->cloneTreePure(false);
if (VN_IS(nodep->backp(), Cover)) {
blockp = new AstAnd{disablep->fileline(),
new AstNot{disablep->fileline(), disablep->unlinkFrBack()},
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3AssertPre final {
public:
static void assertPreAll(AstNetlist* nodep);
static void assertPreAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+197 -50
View File
@@ -14,16 +14,11 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3Ast.h"
#include "V3PchAstMT.h"
#include "V3Broken.h"
#include "V3EmitV.h"
#include "V3File.h"
#include "V3Global.h"
#include "V3String.h"
#include <iomanip>
#include <memory>
@@ -33,6 +28,8 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//======================================================================
// Statics
uint64_t VIsCached::s_cachedCntGbl = 1;
uint64_t AstNode::s_editCntLast = 0;
uint64_t AstNode::s_editCntGbl = 0; // Hot cache line
@@ -44,23 +41,37 @@ uint32_t VNUser1InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
uint32_t VNUser2InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
uint32_t VNUser3InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
uint32_t VNUser4InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
uint32_t VNUser5InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
bool VNUser1InUse::s_userBusy = false;
bool VNUser2InUse::s_userBusy = false;
bool VNUser3InUse::s_userBusy = false;
bool VNUser4InUse::s_userBusy = false;
bool VNUser5InUse::s_userBusy = false;
int AstNodeDType::s_uniqueNum = 0;
//######################################################################
// V3AstType
// VNType
const VNTypeInfo VNType::typeInfoTable[] = {
#include "V3Ast__gen_type_info.h" // From ./astgen
};
std::ostream& operator<<(std::ostream& os, VNType rhs);
//######################################################################
// Creators
// VSelfPointerText
const std::shared_ptr<const string> VSelfPointerText::s_emptyp = std::make_shared<string>("");
const std::shared_ptr<const string> VSelfPointerText::s_thisp = std::make_shared<string>("this");
string VSelfPointerText::protect(bool useSelfForThis, bool protect) const {
const string& sp
= useSelfForThis ? VString::replaceWord(asString(), "this", "vlSelf") : asString();
return VIdProtect::protectWordsIf(sp, protect);
}
//######################################################################
// AstNode
AstNode::AstNode(VNType t, FileLine* fl)
: m_type{t}
@@ -356,8 +367,8 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp) {
void AstNode::addNextHere(AstNode* newp) {
// Add to m_nextp on exact node passed, not at the end.
// This could be at head, tail, or both (single)
// New could be head of single node, or list
// 'this' could be at head, tail, or both (single)
// 'newp' could be head of single node, or list
UASSERT(newp, "Null item passed to addNext");
UASSERT_OBJ(!newp->backp(), newp, "New node (back) already assigned?");
debugTreeChange(this, "-addHereThs: ", __LINE__, false);
@@ -783,26 +794,34 @@ void AstNode::swapWith(AstNode* bp) {
//======================================================================
// Clone
AstNode* AstNode::cloneTreeIter() {
AstNode* AstNode::cloneTreeIter(bool needPure) {
// private: Clone single node and children
if (VL_UNLIKELY(needPure && !isPure())) {
this->v3warn(SIDEEFFECT,
"Expression side effect may be mishandled\n"
<< this->warnMore()
<< "... Suggest use a temporary variable in place of this expression");
// this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused
// it
}
AstNode* const newp = this->clone();
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList());
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList());
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList(needPure));
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList(needPure));
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList(needPure));
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList(needPure));
newp->m_iterpp = nullptr;
newp->clonep(this); // Save pointers to/from both to simplify relinking.
this->clonep(newp); // Save pointers to/from both to simplify relinking.
return newp;
}
AstNode* AstNode::cloneTreeIterList() {
AstNode* AstNode::cloneTreeIterList(bool needPure) {
// private: Clone list of nodes, set m_headtailp
AstNode* newheadp = nullptr;
AstNode* newtailp = nullptr;
// Audited to make sure this is never nullptr
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
AstNode* const newp = oldp->cloneTreeIter();
AstNode* const newp = oldp->cloneTreeIter(needPure);
newp->m_headtailp = nullptr;
newp->m_backp = newtailp;
if (newtailp) newtailp->m_nextp = newp;
@@ -814,14 +833,14 @@ AstNode* AstNode::cloneTreeIterList() {
return newheadp;
}
AstNode* AstNode::cloneTree(bool cloneNextLink) {
AstNode* AstNode::cloneTree(bool cloneNextLink, bool needPure) {
debugTreeChange(this, "-cloneThs: ", __LINE__, cloneNextLink);
cloneClearTree();
AstNode* newp;
if (cloneNextLink && this->m_nextp) {
newp = cloneTreeIterList();
newp = cloneTreeIterList(needPure);
} else {
newp = cloneTreeIter();
newp = cloneTreeIter(needPure);
newp->m_nextp = nullptr;
newp->m_headtailp = newp;
}
@@ -1098,9 +1117,57 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
// private: Check a tree and children
UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent");
switch (this->type()) {
#include "V3Ast__gen_op_checks.h"
default: VL_UNREACHABLE; // LCOV_EXCL_LINE
const VNTypeInfo& typeInfo = *type().typeInfo();
for (int i = 1; i <= 4; i++) {
AstNode* nodep = nullptr;
switch (i) {
case 1: nodep = op1p(); break;
case 2: nodep = op2p(); break;
case 3: nodep = op3p(); break;
case 4: nodep = op4p(); break;
default: this->v3fatalSrc("Bad case"); break;
}
const char* opName = typeInfo.m_opNamep[i - 1];
switch (typeInfo.m_opType[i - 1]) {
case VNTypeInfo::OP_UNUSED:
UASSERT_OBJ(!nodep, this, typeInfo.m_namep << " must not use " << opName << "()");
break;
case VNTypeInfo::OP_USED:
UASSERT_OBJ(nodep, this,
typeInfo.m_namep << " must have non nullptr " << opName << "()");
UASSERT_OBJ(!nodep->nextp(), this,
typeInfo.m_namep << "::" << opName
<< "() cannot have a non nullptr nextp()");
nodep->checkTreeIter(this);
break;
case VNTypeInfo::OP_LIST:
if (const AstNode* const headp = nodep) {
const AstNode* backp = this;
const AstNode* tailp = headp;
const AstNode* opp = headp;
do {
opp->checkTreeIter(backp);
UASSERT_OBJ(opp == headp || !opp->nextp() || !opp->m_headtailp, opp,
"Headtailp should be null in middle of lists");
backp = tailp = opp;
opp = opp->nextp();
} while (opp);
UASSERT_OBJ(headp->m_headtailp == tailp, headp,
"Tail in headtailp is inconsistent");
UASSERT_OBJ(tailp->m_headtailp == headp, tailp,
"Head in headtailp is inconsistent");
}
break;
case VNTypeInfo::OP_OPTIONAL:
if (nodep) {
UASSERT_OBJ(!nodep->nextp(), this,
typeInfo.m_namep << "::" << opName
<< "() cannot have a non-nullptr nextp()");
nodep->checkTreeIter(this);
}
break;
default: this->v3fatalSrc("Bad case"); break;
}
}
}
@@ -1166,7 +1233,6 @@ void AstNode::dumpPtrs(std::ostream& os) const {
if (user2p()) os << " user2p=" << cvtToHex(user2p());
if (user3p()) os << " user3p=" << cvtToHex(user3p());
if (user4p()) os << " user4p=" << cvtToHex(user4p());
if (user5p()) os << " user5p=" << cvtToHex(user5p());
if (m_iterpp) {
os << " iterpp=" << cvtToHex(m_iterpp);
// This may cause address sanitizer failures as iterpp can be stale
@@ -1279,49 +1345,29 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump)
}
}
bool AstNode::isTreePureRecurse() const {
// Should memoize this if call commonly
if (!this->isPure()) return false;
if (this->op1p() && !this->op1p()->isTreePureRecurse()) return false;
if (this->op2p() && !this->op2p()->isTreePureRecurse()) return false;
if (this->op3p() && !this->op3p()->isTreePureRecurse()) return false;
if (this->op4p() && !this->op4p()->isTreePureRecurse()) return false;
return true;
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;
}
string AstNode::instanceStr() const {
// Max iterations before giving up on location search,
// in case we have some circular reference bug.
constexpr unsigned maxIterations = 10000;
unsigned iterCount = 0;
for (const AstNode* backp = this; backp; backp = backp->backp(), ++iterCount) {
if (VL_UNCOVERABLE(iterCount >= maxIterations)) return ""; // LCOV_EXCL_LINE
// Prefer the enclosing scope, if there is one. This is always under the enclosing module,
// so just pick it up when encountered
if (const AstScope* const scopep = VN_CAST(backp, Scope)) {
return scopep->isTop() ? "" : "... In instance " + scopep->prettyName();
return scopep->isTop() ? "" : "... note: In instance " + scopep->prettyNameQ();
}
// If scopes don't exist, report an example instance of the enclosing module
if (const AstModule* const modp = VN_CAST(backp, Module)) {
const string instanceName = modp->someInstanceName();
return instanceName.empty() ? "" : "... In instance " + instanceName;
return instanceName.empty() ? "" : "... note: In instance '" + instanceName + "'";
}
}
return "";
}
void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
void AstNode::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
if (!m_fileline) {
V3Error::s().v3errorEnd(str, instanceStr());
V3Error::v3errorEnd(str, instanceStr());
} else {
std::ostringstream nsstr;
nsstr << str.str();
@@ -1338,6 +1384,11 @@ void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s()
nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr());
}
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;
}
//======================================================================
// Data type conversion
@@ -1410,6 +1461,102 @@ AstNodeDType* AstNode::findStreamDType() const {
return v3Global.rootp()->typeTablep()->findStreamDType(fileline());
}
static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) {
while (true) {
if (const AstPackArrayDType* const packp = VN_CAST(nodep, PackArrayDType)) {
nodep = packp->subDTypep();
continue;
} else if (const AstNodeDType* const refp = nodep->skipRefToEnump()) {
if (refp != nodep) {
nodep = refp;
continue;
}
}
return nodep;
}
}
static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
const AstNode* fromConstp) {
const VCastable castable = VCastable::UNSUPPORTED;
toDtp = toDtp->skipRefToEnump();
fromDtp = fromDtp->skipRefToEnump();
if (toDtp == fromDtp) return VCastable::SAMEISH;
if (toDtp->similarDType(fromDtp)) return VCastable::SAMEISH;
// UNSUP unpacked struct/unions (treated like BasicDType)
const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp);
const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType)
|| VN_IS(fromBaseDtp, StreamDType)
|| VN_IS(fromBaseDtp, NodeUOrStructDType);
const AstNodeDType* toBaseDtp = computeCastableBase(toDtp);
const bool toNumericable
= VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType);
if (toBaseDtp == fromBaseDtp) {
return VCastable::COMPATIBLE;
} else if (toNumericable) {
if (fromNumericable) return VCastable::COMPATIBLE;
} else if (VN_IS(toDtp, EnumDType)) {
if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp))
return VCastable::ENUM_IMPLICIT;
if (fromNumericable) return VCastable::ENUM_EXPLICIT;
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) {
if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull())
return VCastable::COMPATIBLE;
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) {
const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp();
const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp();
const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp);
const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp);
if (upcast) {
return VCastable::COMPATIBLE;
} else if (downcast) {
return VCastable::DYNAMIC_CLASS;
} else {
return VCastable::INCOMPATIBLE;
}
}
return castable;
}
VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
const AstNode* fromConstp) {
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
UINFO(9, " castable=" << castable << " for " << toDtp << endl);
UINFO(9, " =?= " << fromDtp << endl);
UINFO(9, " const= " << fromConstp << endl);
return castable;
}
AstNodeDType* AstNode::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) {
// Return the class type that both nodep1 and nodep2 are castable to.
// If both are null, return the type of null constant.
// If one is a class and one is null, return AstClassRefDType that points to that class.
// If no common class type exists, return nullptr.
// First handle cases with null values and when one class is a super class of the other.
if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2);
{
const VCastable castable = computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2);
if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) {
return nodep1->dtypep();
} else if (castable == VCastable::DYNAMIC_CLASS) {
return nodep2->dtypep();
}
}
AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType);
while (classDtypep1) {
const VCastable castable = computeCastable(classDtypep1, nodep2->dtypep(), nodep2);
if (castable == VCastable::COMPATIBLE) return classDtypep1;
AstClassExtends* const extendsp = classDtypep1->classp()->extendsp();
classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr;
}
return nullptr;
}
//######################################################################
// VNDeleter
+379 -125
View File
@@ -98,7 +98,20 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
//######################################################################
struct VNTypeInfo {
const char* m_namep;
enum uint8_t {
OP_UNUSED,
OP_USED,
OP_LIST,
OP_OPTIONAL,
} m_opType[4];
const char* m_opNamep[4];
};
class VNType final {
static const VNTypeInfo typeInfoTable[];
public:
#include "V3Ast__gen_type_enum.h" // From ./astgen
// Above include has:
@@ -111,6 +124,7 @@ public:
constexpr VNType(en _e) VL_MT_SAFE : m_e{_e} {}
explicit VNType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
const VNTypeInfo* typeInfo() const VL_MT_SAFE { return &typeInfoTable[m_e]; }
constexpr operator en() const VL_MT_SAFE { return m_e; }
};
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_PURE {
@@ -153,6 +167,37 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
// ######################################################################
class VIsCached final {
// Used in some nodes to cache results of boolean methods
// If cachedCnt == 0, not cached
// else if cachedCnt == s_cachedCntGbl, then m_state is if cached
uint64_t m_cachedCnt : 63; // Mark of when cache was computed
uint64_t m_state : 1;
static uint64_t s_cachedCntGbl; // Global computed count
public:
VIsCached()
: m_cachedCnt{0}
, m_state{0} {}
bool isCached() const { return m_cachedCnt == s_cachedCntGbl; }
bool get() const { return m_state; }
void set(bool flag) {
m_cachedCnt = s_cachedCntGbl;
m_state = flag;
}
void clearCache() {
m_cachedCnt = 0;
m_state = 0;
}
static void clearCacheTree() {
++s_cachedCntGbl;
// 64 bits so won't overflow
// UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting");
}
};
// ######################################################################
class VAccess final {
public:
enum en : uint8_t {
@@ -279,7 +324,7 @@ public:
ET_BOTHEDGE, // POSEDGE | NEGEDGE (i.e.: 'edge' in Verilog)
ET_POSEDGE,
ET_NEGEDGE,
ET_EVENT, // VlEvent::isFired
ET_EVENT, // VlEventBase::isFired
// Involving an expression
ET_TRUE,
//
@@ -630,6 +675,39 @@ public:
default: return false;
}
}
const char* traceSigType() const {
// VerilatedTraceSigType to used in trace signal declaration
static const char* const lut[] = {
/* UNKNOWN: */ "", // Should not be traced
/* BIT: */ "BIT",
/* BYTE: */ "BYTE",
/* CHANDLE: */ "",
/* EVENT: */ "EVENT",
/* INT: */ "INT",
/* INTEGER: */ "INTEGER",
/* LOGIC: */ "LOGIC",
/* LONGINT: */ "LONGINT",
/* DOUBLE: */ "DOUBLE",
/* SHORTINT: */ "SHORTINT",
/* TIME: */ "TIME",
/* STRING: */ "",
/* UNTYPED: */ "", // Should not be traced
/* SCOPEPTR: */ "", // Should not be traced
/* CHARPTR: */ "", // Should not be traced
/* MTASKSTATE: */ "", // Should not be traced
/* TRIGGERVEC: */ "", // Should not be traced
/* DELAY_SCHEDULER: */ "", // Should not be traced
/* TRIGGER_SCHEDULER: */ "", // Should not be traced
/* DYNAMIC_TRIGGER_SCHEDULER: */ "", // Should not be traced
/* FORK_SYNC: */ "", // Should not be traced
/* PROCESS_REFERENCE: */ "", // Should not be traced
/* UINT32: */ "BIT",
/* UINT64: */ "BIT",
/* LOGIC_IMPLICIT: */ "", // Should not be traced
};
return lut[m_e];
}
};
constexpr bool operator==(const VBasicDTypeKwd& lhs, const VBasicDTypeKwd& rhs) VL_MT_SAFE {
return lhs.m_e == rhs.m_e;
@@ -676,7 +754,8 @@ public:
}
bool isReadOnly() const VL_MT_SAFE { return m_e == INPUT || m_e == CONSTREF; }
bool isWritable() const VL_MT_SAFE { return m_e == OUTPUT || m_e == INOUT || m_e == REF; }
bool isRefOrConstRef() const VL_MT_SAFE { return m_e == REF || m_e == CONSTREF; }
bool isRef() const VL_MT_SAFE { return m_e == REF; }
bool isConstRef() const VL_MT_SAFE { return m_e == CONSTREF; }
};
constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) {
return lhs.m_e == rhs.m_e;
@@ -776,7 +855,6 @@ public:
SUPPLY1,
WIRE,
WREAL,
IMPLICITWIRE,
TRIWIRE,
TRI0,
TRI1,
@@ -796,25 +874,25 @@ public:
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {
"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
"WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT",
"BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
static const char* const names[]
= {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
"WIRE", "WREAL", "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP",
"MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
return names[m_e];
}
bool isParam() const { return m_e == GPARAM || m_e == LPARAM; }
bool isSignal() const {
return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0
|| m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
return (m_e == WIRE || m_e == WREAL || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
}
bool isNet() const {
return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|| m_e == SUPPLY0 || m_e == SUPPLY1);
return (m_e == WIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == SUPPLY0
|| m_e == SUPPLY1);
}
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL
|| m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|| m_e == PORT || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP
|| m_e == XTEMP || m_e == IFACEREF);
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == TRIWIRE
|| m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == BLOCKTEMP
|| m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF);
}
bool isProcAssignable() const {
return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP
@@ -828,6 +906,32 @@ public:
return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == PORT || m_e == WIRE
|| m_e == TRI0 || m_e == TRI1);
}
const char* traceSigKind() const {
// VerilatedTraceSigKind to used in trace signal declaration
static const char* const lut[] = {
/* UNKNOWN: */ "", // Should not be traced
/* GPARAM: */ "PARAMETER",
/* LPARAM: */ "PARAMETER",
/* GENVAR: */ "PARAMETER",
/* VAR: */ "VAR",
/* SUPPLY0: */ "SUPPLY0",
/* SUPPLY1: */ "SUPPLY1",
/* WIRE: */ "WIRE",
/* WREAL: */ "WIRE",
/* TRIWIRE: */ "TRI",
/* TRI0: */ "TRI0",
/* TRI1: */ "TRI1",
/* PORT: */ "WIRE",
/* BLOCKTEMP: */ "VAR",
/* MODULETEMP: */ "VAR",
/* STMTTEMP: */ "VAR",
/* XTEMP: */ "VAR",
/* IFACEREF: */ "", // Should not be traced directly
/* MEMBER: */ "VAR",
};
return lut[m_e];
}
};
constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) VL_MT_SAFE {
return lhs.m_e == rhs.m_e;
@@ -1168,34 +1272,148 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) {
class VUseType final {
public:
enum en : uint8_t {
IMP_INCLUDE, // Implementation (.cpp) needs an include
INT_INCLUDE, // Interface (.h) needs an include
IMP_FWD_CLASS, // Implementation (.cpp) needs a forward class declaration
INT_FWD_CLASS, // Interface (.h) needs a forward class declaration
// Enum values are compared with <, so order matters
INT_FWD_CLASS = 1 << 0, // Interface (.h) needs a forward class declaration
INT_INCLUDE = 1 << 1, // Interface (.h) needs an include
};
enum en m_e;
VUseType()
: m_e{IMP_FWD_CLASS} {}
: m_e{INT_FWD_CLASS} {}
// cppcheck-suppress noExplicitConstructor
constexpr VUseType(en _e)
: m_e{_e} {}
explicit VUseType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; }
bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; }
constexpr operator en() const { return m_e; }
bool containsAny(VUseType other) { return m_e & other.m_e; }
const char* ascii() const {
static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"};
return names[m_e];
static const char* const names[] = {"INT_FWD", "INT_INC", "INT_FWD_INC"};
return names[m_e - 1];
}
};
constexpr bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; }
constexpr bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; }
constexpr bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; }
constexpr VUseType::en operator|(VUseType::en lhs, VUseType::en rhs) {
return VUseType::en((uint8_t)lhs | (uint8_t)rhs);
}
constexpr VUseType::en operator&(VUseType::en lhs, VUseType::en rhs) {
return VUseType::en((uint8_t)lhs & (uint8_t)rhs);
}
inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
return os << rhs.ascii();
}
//######################################################################
class VTraceType final {
public:
enum en : uint8_t {
CONSTANT, // Constant value dump (once at the beginning)
FULL, // Full value dump (always emitted)
CHANGE // Incremental value dump (emitted only if the value changed)
};
enum en m_e;
VTraceType()
: m_e{CONSTANT} {}
// cppcheck-suppress noExplicitConstructor
constexpr VTraceType(en _e)
: m_e{_e} {}
explicit VTraceType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {"CONSTANT", "FULL", "CHANGE"};
return names[m_e];
}
};
constexpr bool operator==(const VTraceType& lhs, const VTraceType& rhs) {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VTraceType& lhs, VTraceType::en rhs) { return lhs.m_e == rhs; }
constexpr bool operator==(VTraceType::en lhs, const VTraceType& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VTraceType& rhs) {
return os << rhs.ascii();
}
//######################################################################
class VTracePrefixType final {
public:
enum en : uint8_t {
// Note: Entries must match VerilatedTracePrefixType
ARRAY_PACKED,
ARRAY_UNPACKED,
SCOPE_MODULE,
SCOPE_INTERFACE,
STRUCT_PACKED,
STRUCT_UNPACKED,
UNION_PACKED,
};
enum en m_e;
// cppcheck-suppress noExplicitConstructor
constexpr VTracePrefixType(en _e)
: m_e{_e} {}
constexpr operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[]
= {"ARRAY_PACKED", "ARRAY_UNPACKED", "SCOPE_MODULE", "SCOPE_INTERFACE",
"STRUCT_PACKED", "STRUCT_UNPACKED", "UNION_PACKED"};
return names[m_e];
}
};
constexpr bool operator==(const VTracePrefixType& lhs, const VTracePrefixType& rhs) {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VTracePrefixType& lhs, VTracePrefixType::en rhs) {
return lhs.m_e == rhs;
}
constexpr bool operator==(VTracePrefixType::en lhs, const VTracePrefixType& rhs) {
return lhs == rhs.m_e;
}
inline std::ostream& operator<<(std::ostream& os, const VTracePrefixType& rhs) {
return os << rhs.ascii();
}
// ######################################################################
class VCastable final {
public:
enum en : uint8_t {
UNSUPPORTED,
SAMEISH,
COMPATIBLE,
ENUM_EXPLICIT,
ENUM_IMPLICIT,
DYNAMIC_CLASS,
INCOMPATIBLE,
_ENUM_MAX // Leave last
};
enum en m_e;
const char* ascii() const {
static const char* const names[]
= {"UNSUPPORTED", "SAMEISH", "COMPATIBLE", "ENUM_EXPLICIT",
"ENUM_IMPLICIT", "DYNAMIC_CLASS", "INCOMPATIBLE"};
return names[m_e];
}
VCastable()
: m_e{UNSUPPORTED} {}
// cppcheck-suppress noExplicitConstructor
constexpr VCastable(en _e)
: m_e{_e} {}
explicit VCastable(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const { return m_e; }
};
constexpr bool operator==(const VCastable& lhs, const VCastable& rhs) {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VCastable& lhs, VCastable::en rhs) { return lhs.m_e == rhs; }
constexpr bool operator==(VCastable::en lhs, const VCastable& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
return os << rhs.ascii();
}
// ######################################################################
class VBasicTypeKey final {
@@ -1232,6 +1450,44 @@ public:
~VBasicTypeKey() = default;
};
// ######################################################################
// VSelfPointerText - Represents text to be emitted before a given var reference, call, etc. to
// serve as a pointer to a 'self' object. For example, it could be empty (no self pointer), or the
// string 'this', or 'vlSymsp->...'
class VSelfPointerText final {
private:
// STATIC MEMBERS
// Keep these in shared pointers to avoid branching for special cases
static const std::shared_ptr<const string> s_emptyp; // Holds ""
static const std::shared_ptr<const string> s_thisp; // Holds "this"
// MEMBERS
std::shared_ptr<const string> m_strp;
public:
// CONSTRUCTORS
class Empty {}; // for creator type-overload selection
VSelfPointerText(Empty)
: m_strp{s_emptyp} {}
class This {}; // for creator type-overload selection
VSelfPointerText(This)
: m_strp{s_thisp} {}
VSelfPointerText(This, const string& field)
: m_strp{std::make_shared<const string>("this->" + field)} {}
class VlSyms {}; // for creator type-overload selection
VSelfPointerText(VlSyms, const string& field)
: m_strp{std::make_shared<const string>("(&vlSymsp->" + field + ')')} {}
// METHODS
bool isEmpty() const { return m_strp == s_emptyp; }
bool isVlSym() const { return m_strp->find("vlSymsp") != string::npos; }
bool hasThis() const { return m_strp == s_thisp || VString::startsWith(*m_strp, "this"); }
string protect(bool useSelfForThis, bool protect) const;
const std::string& asString() const { return *m_strp; }
bool operator==(const VSelfPointerText& other) const { return *m_strp == *other.m_strp; }
};
//######################################################################
// AstNUser - Generic base class for AST User nodes.
// - Also used to allow parameter passing up/down iterate calls
@@ -1314,58 +1570,47 @@ protected:
class VNUser1InUse final : VNUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
VNUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
VNUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class VNUser2InUse final : VNUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
VNUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
VNUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class VNUser3InUse final : VNUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
VNUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
VNUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class VNUser4InUse final : VNUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
VNUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
VNUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class VNUser5InUse final : VNUserInUseBase {
protected:
friend class AstNode;
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
VNUser5InUse() { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~VNUser5InUse() { free (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
// clang-format on
//######################################################################
@@ -1374,7 +1619,7 @@ public:
// nodes needs to be deferred to a later time, because pointers to the
// removed nodes might still exist.
class VNDeleter VL_NOT_FINAL {
class VNDeleter final {
// MEMBERS
std::vector<AstNode*> m_deleteps; // Nodes to delete
@@ -1387,11 +1632,11 @@ public:
m_deleteps.push_back(nodep);
}
// Delete all previously pushed nodes (by callint deleteTree)
// Delete all previously pushed nodes (by calling deleteTree)
void doDeletes();
// Do the deletions on destruction
virtual ~VNDeleter() { doDeletes(); }
~VNDeleter() { doDeletes(); }
};
//######################################################################
@@ -1400,7 +1645,7 @@ public:
// This only has the constant fuctions for non-modifying visitors.
// For more typical usage see VNVisitor
class VNVisitorConst VL_NOT_FINAL : public VNDeleter {
class VNVisitorConst VL_NOT_FINAL {
friend class AstNode;
public:
@@ -1418,6 +1663,7 @@ public:
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
virtual void visit(AstNode* nodep) = 0;
virtual ~VNVisitorConst() {}
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
};
@@ -1426,6 +1672,7 @@ public:
// type without changing the base classes. See "Modern C++ Design".
class VNVisitor VL_NOT_FINAL : public VNVisitorConst {
VNDeleter m_deleter; // Used to delay deletion of nodes
public:
/// Call visit()s on nodep
inline void iterate(AstNode* nodep);
@@ -1437,6 +1684,10 @@ public:
inline void iterateAndNextNull(AstNode* nodep);
/// Return edited nodep; see comments in V3Ast.cpp
inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
VNDeleter& deleter() { return m_deleter; }
void pushDeletep(AstNode* nodep) { deleter().pushDeletep(nodep); }
void doDeletes() { deleter().doDeletes(); }
};
//######################################################################
@@ -1563,8 +1814,6 @@ class AstNode VL_NOT_FINAL {
uint32_t m_user3Cnt = 0; // Mark of when userp was set
uint32_t m_user4Cnt = 0; // Mark of when userp was set
VNUser m_user4u{0}; // Contains any information the user iteration routine wants
VNUser m_user5u{0}; // Contains any information the user iteration routine wants
uint32_t m_user5Cnt = 0; // Mark of when userp was set
// METHODS
void op1p(AstNode* nodep) {
@@ -1585,8 +1834,8 @@ class AstNode VL_NOT_FINAL {
}
private:
AstNode* cloneTreeIter();
AstNode* cloneTreeIterList();
AstNode* cloneTreeIter(bool needPure);
AstNode* cloneTreeIterList(bool needPure);
void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE;
bool gateTreeIter() const;
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
@@ -1639,13 +1888,16 @@ protected:
UASSERT_STATIC(s_cloneCntGbl, "Rollover");
}
// Use instead isSame(), this is for each Ast* class, and assumes node is of same type
virtual bool same(const AstNode*) const { return true; }
public:
// ACCESSORS
VNType type() const VL_MT_SAFE { return m_type; }
const char* typeName() const VL_MT_SAFE { return type().ascii(); } // See also prettyTypeName
AstNode* nextp() const VL_MT_STABLE { return m_nextp; }
AstNode* backp() const VL_MT_STABLE { return m_backp; }
AstNode* abovep() const; // Parent node above, only when no nextp() as otherwise slow
AstNode* abovep() const; // Get parent node above, only for list head and tail
AstNode* op1p() const VL_MT_STABLE { return m_op1p; }
AstNode* op2p() const VL_MT_STABLE { return m_op2p; }
AstNode* op3p() const VL_MT_STABLE { return m_op3p; }
@@ -1751,83 +2003,71 @@ public:
inline bool isDouble() const VL_MT_STABLE;
inline bool isSigned() const VL_MT_STABLE;
inline bool isString() const VL_MT_STABLE;
inline bool isEvent() const VL_MT_STABLE;
// clang-format off
VNUser user1u() const VL_MT_STABLE {
VNUser user1u() const VL_MT_STABLE {
// Slows things down measurably, so disabled by default
//UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy");
return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0});
//UASSERT_STATIC(VNUser1InUse::s_userBusy, "user1p used without AstUserInUse");
return ((m_user1Cnt == VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0});
}
AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); }
void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; }
void user1p(void* userp) { user1u(VNUser{userp}); }
int user1() const { return user1u().toInt(); }
void user1(int val) { user1u(VNUser{val}); }
int user1Inc(int val=1) { int v=user1(); user1(v+val); return v; }
int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc()
AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); }
void user1u(const VNUser& user) { m_user1u = user; m_user1Cnt = VNUser1InUse::s_userCntGbl; }
void user1p(void* userp) { user1u(VNUser{userp}); }
void user1(int val) { user1u(VNUser{val}); }
int user1() const { return user1u().toInt(); }
int user1Inc(int val = 1) { int v = user1(); user1(v + val); return v; }
int user1SetOnce() { int v = user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc()
static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree
VNUser user2u() const VL_MT_STABLE {
VNUser user2u() const VL_MT_STABLE {
// Slows things down measurably, so disabled by default
//UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy");
return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0});
//UASSERT_STATIC(VNUser2InUse::s_userBusy, "user2p used without AstUserInUse");
return ((m_user2Cnt == VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0});
}
AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); }
void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; }
void user2p(void* userp) { user2u(VNUser{userp}); }
int user2() const { return user2u().toInt(); }
void user2(int val) { user2u(VNUser{val}); }
int user2Inc(int val=1) { int v=user2(); user2(v+val); return v; }
int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc()
AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); }
void user2u(const VNUser& user) { m_user2u = user; m_user2Cnt = VNUser2InUse::s_userCntGbl; }
void user2p(void* userp) { user2u(VNUser{userp}); }
void user2(int val) { user2u(VNUser{val}); }
int user2() const { return user2u().toInt(); }
int user2Inc(int val = 1) { int v = user2(); user2(v + val); return v; }
int user2SetOnce() { int v = user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc()
static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree
VNUser user3u() const VL_MT_STABLE {
VNUser user3u() const VL_MT_STABLE {
// Slows things down measurably, so disabled by default
//UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy");
return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0});
//UASSERT_STATIC(VNUser3InUse::s_userBusy, "user3p used without AstUserInUse");
return ((m_user3Cnt == VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0});
}
AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); }
void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; }
void user3p(void* userp) { user3u(VNUser{userp}); }
int user3() const { return user3u().toInt(); }
void user3(int val) { user3u(VNUser{val}); }
int user3Inc(int val=1) { int v=user3(); user3(v+val); return v; }
int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc()
AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); }
void user3u(const VNUser& user) { m_user3u = user; m_user3Cnt = VNUser3InUse::s_userCntGbl; }
void user3p(void* userp) { user3u(VNUser{userp}); }
void user3(int val) { user3u(VNUser{val}); }
int user3() const { return user3u().toInt(); }
int user3Inc(int val = 1) { int v = user3(); user3(v + val); return v; }
int user3SetOnce() { int v = user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc()
static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree
VNUser user4u() const VL_MT_STABLE {
VNUser user4u() const VL_MT_STABLE {
// Slows things down measurably, so disabled by default
//UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy");
return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0});
//UASSERT_STATIC(VNUser4InUse::s_userBusy, "user4p used without AstUserInUse");
return ((m_user4Cnt == VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0});
}
AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); }
void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; }
void user4p(void* userp) { user4u(VNUser{userp}); }
int user4() const { return user4u().toInt(); }
void user4(int val) { user4u(VNUser{val}); }
int user4Inc(int val=1) { int v=user4(); user4(v+val); return v; }
int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc()
AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); }
void user4u(const VNUser& user) { m_user4u = user; m_user4Cnt = VNUser4InUse::s_userCntGbl; }
void user4p(void* userp) { user4u(VNUser{userp}); }
void user4(int val) { user4u(VNUser{val}); }
int user4() const { return user4u().toInt(); }
int user4Inc(int val = 1) { int v = user4(); user4(v + val); return v; }
int user4SetOnce() { int v = user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc()
static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree
VNUser user5u() const VL_MT_STABLE {
// Slows things down measurably, so disabled by default
//UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy");
return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0});
}
AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); }
void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; }
void user5p(void* userp) { user5u(VNUser{userp}); }
int user5() const { return user5u().toInt(); }
void user5(int val) { user5u(VNUser{val}); }
int user5Inc(int val=1) { int v=user5(); user5(v+val); return v; }
int user5SetOnce() { int v=user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc()
static void user5ClearTree() { VNUser5InUse::clear(); } // Clear userp()'s across the entire tree
// clang-format on
#ifdef VL_DEBUG
uint64_t editCount() const { return m_editCount; }
void editCountInc() {
m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##"
VIsCached::clearCacheTree(); // Any edit clears all caching
}
#else
void editCountInc() { ++s_editCntGbl; }
@@ -1900,10 +2140,14 @@ public:
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const;
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
const AstNode* fromConstp);
static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2);
// METHODS - dump and error
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex);
VL_RELEASE(V3Error::s().m_mutex);
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
return fileline()->warnContextPrimary();
}
@@ -1941,11 +2185,9 @@ public:
AstNode* belowp); // When calling, "this" is second argument
// METHODS - Iterate on a tree
// Clone or return nullptr if nullptr
static AstNode* cloneTreeNull(AstNode* nodep, bool cloneNextLink) {
return nodep ? nodep->cloneTree(cloneNextLink) : nullptr;
}
AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep
AstNode* cloneTree(bool cloneNextLink,
bool needPure = false); // Not const, as sets clonep() on original nodep
AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink, true); }
bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable?
inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p?
// Does tree of this == node2p?, not allowing non-isGateOptimizable
@@ -1970,7 +2212,14 @@ public:
void dumpTreeDot(std::ostream& os = std::cout) const;
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
bool isTreePureRecurse() const;
// METHODS - static advancement
static AstNode* afterCommentp(AstNode* nodep) {
// Skip over comments starting at provided nodep,
// such as to determine if a AstIf is empty.
// nodep may be null, if so return nullptr.
while (nodep && VN_IS(nodep, Comment)) nodep = nodep->nextp();
return nodep;
}
// METHODS - queries
// Changes control flow, disable some optimizations
@@ -1980,11 +2229,13 @@ public:
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isGateDedupable() const { return isGateOptimizable(); }
// Else creates output or exits, etc, not unconsumed
virtual bool isOutputter() const { return false; }
virtual bool isOutputter() { return false; }
// Else a AstTime etc which output can't be predicted from input
virtual bool isPredictOptimizable() const { return !isTimingControl(); }
// Else a $display, etc, that must be ordered with other displays
virtual bool isPure() const { return true; }
virtual bool isPure() { return true; }
// Iff isPure on current node and any nextp()
bool isPureAndNext() { return isPure() && (!nextp() || nextp()->isPure()); }
// Else a AstTime etc that can't be substituted out
virtual bool isSubstOptimizable() const { return true; }
// An event control, delay, wait, etc.
@@ -1993,7 +2244,10 @@ public:
// statement is unlikely to be taken
virtual bool isUnlikely() const { return false; }
virtual int instrCount() const { return 0; }
virtual bool same(const AstNode*) const { return true; }
// Iff node is identical to anouther node
virtual bool isSame(const AstNode* samep) const {
return type() == samep->type() && same(samep);
}
// Iff has a data type; dtype() must be non null
virtual bool hasDType() const VL_MT_SAFE { return false; }
// Iff has a non-null childDTypep(), as generic node function
+5 -1
View File
@@ -39,6 +39,10 @@ bool AstNode::isDouble() const VL_MT_STABLE {
bool AstNode::isString() const VL_MT_STABLE {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
}
bool AstNode::isEvent() const VL_MT_STABLE {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isEvent();
}
bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); }
bool AstNode::isClassHandleValue() const {
@@ -176,7 +180,7 @@ bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
return (varScopep() == samep->varScopep());
} else {
return (selfPointer() == samep->selfPointer()
&& (!selfPointer().empty() || !samep->selfPointer().empty())
&& (!selfPointer().isEmpty() || !samep->selfPointer().isEmpty())
&& varp()->name() == samep->varp()->name());
}
}
+73 -25
View File
@@ -160,14 +160,14 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstNodeArrayDType* const asamep = VN_DBG_AS(samep, NodeArrayDType);
return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
&& rangenp()->sameTree(asamep->rangenp()));
} // HashedDT doesn't recurse, so need to check children
bool similarDType(const AstNodeDType* samep) const override {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return (asamep && type() == samep->type() && hi() == asamep->hi()
&& rangenp()->sameTree(asamep->rangenp())
if (type() != samep->type()) return false;
const AstNodeArrayDType* const asamep = VN_DBG_AS(samep, NodeArrayDType);
return (hi() == asamep->hi() && rangenp()->sameTree(asamep->rangenp())
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
@@ -314,14 +314,15 @@ public:
if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep();
}
bool same(const AstNode* samep) const override {
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
const AstAssocArrayDType* const asamep = VN_DBG_AS(samep, AssocArrayDType);
if (!asamep->subDTypep()) return false;
if (!asamep->keyDTypep()) return false;
return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep());
}
bool similarDType(const AstNodeDType* samep) const override {
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
if (type() != samep->type()) return false;
const AstAssocArrayDType* const asamep = VN_DBG_AS(samep, AssocArrayDType);
return asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
string prettyDTypeName() const override;
@@ -494,6 +495,41 @@ public:
int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); }
bool isCompound() const override { return true; }
};
class AstCDType final : public AstNodeDType {
// Raw "C" data type passed directly to output
string m_name; // Name of data type, printed when do V3EmitC
public:
AstCDType(FileLine* fl, const string& name)
: ASTGEN_SUPER_CDType(fl)
, m_name{name} {
this->dtypep(this);
}
public:
ASTGEN_MEMBERS_AstCDType;
bool same(const AstNode* samep) const override {
const AstCDType* const asamep = VN_DBG_AS(samep, CDType);
return m_name == asamep->m_name;
}
bool similarDType(const AstNodeDType* samep) const override { return same(samep); }
string name() const override VL_MT_STABLE { return m_name; }
string prettyDTypeName() const override { return m_name; }
const char* broken() const override { return nullptr; }
// METHODS
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
int widthAlignBytes() const override { return 8; } // Assume
int widthTotalBytes() const override { return 8; } // Assume
bool isCompound() const override { return true; }
static string typeToHold(uint64_t maxItem) {
return (maxItem < (1ULL << 8)) ? "CData"
: (maxItem < (1ULL << 16)) ? "SData"
: (maxItem < (1ULL << 32)) ? "IData"
: "QData";
}
};
class AstClassRefDType final : public AstNodeDType {
// Reference to a class
// @astgen op1 := paramsp: List[AstPin]
@@ -512,7 +548,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
bool same(const AstNode* samep) const override {
const AstClassRefDType* const asamep = static_cast<const AstClassRefDType*>(samep);
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep);
}
bool similarDType(const AstNodeDType* samep) const override {
@@ -561,7 +597,7 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override {
const AstConstDType* const sp = static_cast<const AstConstDType*>(samep);
const AstConstDType* const sp = VN_DBG_AS(samep, ConstDType);
return (m_refDTypep == sp->m_refDTypep);
}
bool similarDType(const AstNodeDType* samep) const override {
@@ -610,7 +646,7 @@ public:
ASTGEN_MEMBERS_AstDefImplicitDType;
int uniqueNum() const { return m_uniqueNum; }
bool same(const AstNode* samep) const override {
const AstDefImplicitDType* const sp = static_cast<const AstDefImplicitDType*>(samep);
const AstDefImplicitDType* const sp = VN_DBG_AS(samep, DefImplicitDType);
return uniqueNum() == sp->uniqueNum();
}
bool similarDType(const AstNodeDType* samep) const override {
@@ -661,13 +697,14 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override {
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
const AstDynArrayDType* const asamep = VN_DBG_AS(samep, DynArrayDType);
if (!asamep->subDTypep()) return false;
return subDTypep() == asamep->subDTypep();
}
bool similarDType(const AstNodeDType* samep) const override {
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
if (type() != samep->type()) return false;
const AstDynArrayDType* const asamep = VN_DBG_AS(samep, DynArrayDType);
return asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
string prettyDTypeName() const override;
@@ -719,10 +756,14 @@ class AstEnumDType final : public AstNodeDType {
// Parents: TYPEDEF/MODULE
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := itemsp : List[AstEnumItem]
public:
using TableMap = std::map<VAttrType, AstVar*>;
private:
string m_name; // Name from upper typedef, if any
AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width
const int m_uniqueNum = 0;
TableMap m_tableMap; // Created table for V3Width only to remove duplicates
public:
AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstEnumItem* itemsp)
@@ -735,9 +776,12 @@ public:
widthFromSub(subDTypep());
}
ASTGEN_MEMBERS_AstEnumDType;
const char* broken() const override {
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())));
BROKEN_RTN(std::any_of(m_tableMap.begin(), m_tableMap.end(),
[](const auto& p) { return !p.second->brokeExists(); }));
return nullptr;
}
void cloneRelink() override {
@@ -745,7 +789,7 @@ public:
}
int uniqueNum() const { return m_uniqueNum; }
bool same(const AstNode* samep) const override {
const AstEnumDType* const sp = static_cast<const AstEnumDType*>(samep);
const AstEnumDType* const sp = VN_DBG_AS(samep, EnumDType);
return uniqueNum() == sp->uniqueNum();
}
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
@@ -774,6 +818,8 @@ public:
return count;
}
bool isCompound() const override { return false; }
TableMap& tableMap() { return m_tableMap; }
const TableMap& tableMap() const { return m_tableMap; }
};
class AstIfaceRefDType final : public AstNodeDType {
// Reference to an interface, either for a port, or inside parent cell
@@ -938,9 +984,9 @@ public:
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
bool similarDType(const AstNodeDType* samep) const override {
const AstParamTypeDType* const sp = static_cast<const AstParamTypeDType*>(samep);
return type() == samep->type() && sp
&& this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp());
if (type() != samep->type()) return false;
const AstParamTypeDType* const sp = VN_DBG_AS(samep, ParamTypeDType);
return this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp());
}
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
@@ -1011,13 +1057,14 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override {
const AstQueueDType* const asamep = static_cast<const AstQueueDType*>(samep);
const AstQueueDType* const asamep = VN_DBG_AS(samep, QueueDType);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool similarDType(const AstNodeDType* samep) const override {
const AstQueueDType* const asamep = static_cast<const AstQueueDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
if (type() != samep->type()) return false;
const AstQueueDType* const asamep = VN_DBG_AS(samep, QueueDType);
return asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
void dumpSmall(std::ostream& str) const override;
@@ -1075,7 +1122,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
bool same(const AstNode* samep) const override {
const AstRefDType* const asamep = static_cast<const AstRefDType*>(samep);
const AstRefDType* const asamep = VN_DBG_AS(samep, RefDType);
return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep
&& m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep);
}
@@ -1153,13 +1200,14 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstSampleQueueDType* const asamep = VN_DBG_AS(samep, SampleQueueDType);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool similarDType(const AstNodeDType* samep) const override {
const AstSampleQueueDType* const asamep = static_cast<const AstSampleQueueDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
if (type() != samep->type()) return false;
const AstSampleQueueDType* const asamep = VN_DBG_AS(samep, SampleQueueDType);
return asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
void dumpSmall(std::ostream& str) const override;
@@ -1352,7 +1400,7 @@ public:
ASTGEN_MEMBERS_AstUnpackArrayDType;
string prettyDTypeName() const override;
bool same(const AstNode* samep) const override {
const AstUnpackArrayDType* const sp = static_cast<const AstUnpackArrayDType*>(samep);
const AstUnpackArrayDType* const sp = VN_DBG_AS(samep, UnpackArrayDType);
return m_isCompound == sp->m_isCompound;
}
// Outer dimension comes first. The first element is this node.
+259 -97
View File
@@ -69,6 +69,8 @@ class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
// Binary expression
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: AstNodeExpr{t, fl} {
@@ -93,6 +95,11 @@ public:
virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors?
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure(); }
};
class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop {
// Binary expr with commutative properties
@@ -176,6 +183,7 @@ class AstNodeCCall VL_NOT_FINAL : public AstNodeExpr {
// @astgen op2 := argsp : List[AstNodeExpr] // Note: op1 used by some sub-types only
AstCFunc* m_funcp;
string m_argTypes;
bool m_superReference = false; // Called with super reference
protected:
AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
@@ -191,13 +199,13 @@ public:
const char* broken() const override;
int instrCount() const override { return INSTR_COUNT_CALL; }
bool same(const AstNode* samep) const override {
const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
const AstNodeCCall* const asamep = VN_DBG_AS(samep, NodeCCall);
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override;
bool isOutputter() const override { return !isPure(); }
bool isPure() override;
bool isOutputter() override { return !isPure(); }
AstCFunc* funcp() const { return m_funcp; }
void funcp(AstCFunc* funcp) { m_funcp = funcp; }
void argTypes(const string& str) { m_argTypes = str; }
@@ -206,6 +214,8 @@ public:
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { return true; }
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
// A reference to a task (or function)
@@ -219,6 +229,8 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
bool m_pli = false; // Pli system call ($name)
VIsCached m_purity; // Pure state
protected:
AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNodeExpr* pinsp)
: AstNodeExpr{t, fl} {
@@ -249,11 +261,14 @@ public:
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
bool pli() const { return m_pli; }
void pli(bool flag) { m_pli = flag; }
bool isPure() const override;
bool isPure() override;
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
private:
bool getPurityRecurse() const;
};
class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr {
// Something that becomes an AstSel
@@ -261,6 +276,8 @@ class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr {
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := thsp : Optional[AstNodeExpr]
// @astgen op4 := attrp : Optional[AstAttrOf]
VIsCached m_purity; // Pure state
protected:
AstNodePreSel(VNType t, FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: AstNodeExpr{t, fl} {
@@ -277,6 +294,13 @@ public:
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const {
return fromp()->isPure() && rhsp()->isPure() && (!thsp() || thsp()->isPure());
}
};
class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr {
// 4-ary expression
@@ -284,6 +308,8 @@ class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr {
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := thsp : AstNodeExpr
// @astgen op4 := fhsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeQuadop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp,
AstNodeExpr* fhsp)
@@ -311,6 +337,13 @@ public:
virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const {
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure() && fhsp()->isPure();
}
};
class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr {
// Terminal operator -- an operator with no "inputs"
@@ -330,6 +363,8 @@ class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := thsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: AstNodeExpr{t, fl} {
@@ -354,20 +389,21 @@ public:
virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const {
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure();
}
};
class AstNodeCond VL_NOT_FINAL : public AstNodeTriop {
// @astgen alias op1 := condp
// @astgen alias op2 := thenp
// @astgen alias op3 := elsep
protected:
AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
: AstNodeTriop{t, fl, condp, thenp, elsep} {
if (thenp) {
dtypeFrom(thenp);
} else if (elsep) {
dtypeFrom(elsep);
}
}
AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
AstNodeExpr* elsep);
public:
ASTGEN_MEMBERS_AstNodeCond;
@@ -409,6 +445,8 @@ public:
class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr {
// Unary expression
// @astgen op1 := lhsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeUniop(VNType t, FileLine* fl, AstNodeExpr* lhsp)
: AstNodeExpr{t, fl} {
@@ -430,6 +468,8 @@ public:
virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors?
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
};
class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop {
public:
@@ -450,8 +490,9 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr {
AstVar* m_varp; // [AfterLink] Pointer to variable itself
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the variable
string m_selfPointer; // Output code object pointer (e.g.: 'this')
VSelfPointerText m_selfPointer
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
// pointer (e.g.: 'this')
protected:
AstNodeVarRef(VNType t, FileLine* fl, const VAccess& access)
: AstNodeExpr{t, fl}
@@ -480,9 +521,11 @@ public:
}
AstVarScope* varScopep() const { return m_varScopep; }
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
string selfPointer() const { return m_selfPointer; }
void selfPointer(const string& value) { m_selfPointer = value; }
string selfPointerProtect(bool useSelfForThis) const;
const VSelfPointerText& selfPointer() const { return m_selfPointer; }
void selfPointer(const VSelfPointerText& selfPointer) { m_selfPointer = selfPointer; }
string selfPointerProtect(bool useSelfForThis) const {
return selfPointer().protect(useSelfForThis, protect());
}
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
// Know no children, and hot function, so skip iterator for speed
@@ -577,6 +620,7 @@ public:
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool same(const AstNode* /*samep*/) const override { return true; }
bool isPure() override { return pure(); }
bool pure() const { return m_pure; }
void pure(bool flag) { m_pure = flag; }
};
@@ -588,35 +632,29 @@ class AstCMethodHard final : public AstNodeExpr {
string m_name; // Name of method
bool m_pure = false; // Pure optimizable
public:
AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name,
AstNodeExpr* pinsp = nullptr)
: ASTGEN_SUPER_CMethodHard(fl)
, m_name{name} {
// TODO: this constructor is exactly the same as the other, bar the ignored tag argument
this->fromp(fromp);
this->addPinsp(pinsp);
dtypep(nullptr); // V3Width will resolve
}
AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, const string& name,
AstNodeExpr* pinsp = nullptr)
: ASTGEN_SUPER_CMethodHard(fl)
, m_name{name} {
this->fromp(fromp);
this->addPinsp(pinsp);
setPurity();
}
ASTGEN_MEMBERS_AstCMethodHard;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
bool same(const AstNode* samep) const override {
const AstCMethodHard* asamep = static_cast<const AstCMethodHard*>(samep);
const AstCMethodHard* const asamep = VN_DBG_AS(samep, CMethodHard);
return (m_name == asamep->m_name);
}
bool isPure() const override { return m_pure; }
void pure(bool flag) { m_pure = flag; }
bool isPure() override { return m_pure; }
int instrCount() const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
private:
void setPurity();
};
class AstCast final : public AstNodeExpr {
// Cast to appropriate data type
@@ -738,7 +776,7 @@ public:
}
bool same(const AstNode* samep) const override {
return (m_classOrPackageNodep
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
== VN_DBG_AS(samep, ClassOrPackageRef)->m_classOrPackageNodep);
}
void dump(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
@@ -1009,9 +1047,14 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool same(const AstNode* samep) const override {
const AstConst* const sp = static_cast<const AstConst*>(samep);
const AstConst* const sp = VN_DBG_AS(samep, Const);
return num().isCaseEq(sp->num());
}
void cloneRelink() override { m_num.nodep(this); }
const char* broken() const override {
BROKEN_RTN(m_num.nodep() && m_num.nodep() != this);
return nullptr;
}
int instrCount() const override { return widthInstrs(); }
bool isEqAllOnes() const { return num().isEqAllOnes(width()); }
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); }
@@ -1019,6 +1062,34 @@ public:
// May return nullptr on parse failure.
static AstConst* parseParamLiteral(FileLine* fl, const string& literal);
};
class AstCvtDynArrayToPacked final : public AstNodeExpr {
// Cast from dynamic queue data type to packed array
// @astgen op1 := fromp : AstNodeExpr
public:
AstCvtDynArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtDynArrayToPacked(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtDynArrayToPacked;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstCvtPackedToDynArray final : public AstNodeExpr {
// Cast from packed array to dynamic queue data type
// @astgen op1 := fromp : AstNodeExpr
public:
AstCvtPackedToDynArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtPackedToDynArray(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtPackedToDynArray;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstDot final : public AstNodeExpr {
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage
@@ -1070,11 +1141,9 @@ public:
string name() const override VL_MT_STABLE { return itemp()->name(); }
int instrCount() const override { return 0; }
const char* broken() const override;
void cloneRelink() override {
if (m_itemp->clonep()) m_itemp = m_itemp->clonep();
}
void cloneRelink() override;
bool same(const AstNode* samep) const override {
const AstEnumItemRef* const sp = static_cast<const AstEnumItemRef*>(samep);
const AstEnumItemRef* const sp = VN_DBG_AS(samep, EnumItemRef);
return itemp() == sp->itemp();
}
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
@@ -1102,6 +1171,10 @@ public:
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool isPure() override {
if (AstNode::afterCommentp(stmtsp())) return false;
return resultp()->isPure();
}
bool same(const AstNode*) const override { return true; }
};
class AstFError final : public AstNodeExpr {
@@ -1119,7 +1192,7 @@ public:
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs() * 64; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstFOpen final : public AstNodeExpr {
@@ -1138,8 +1211,8 @@ public:
string verilogKwd() const override { return "$fopen"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -1157,8 +1230,8 @@ public:
string verilogKwd() const override { return "$fopen"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -1181,8 +1254,8 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: makes output
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -1199,8 +1272,8 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -1224,11 +1297,11 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: makes output
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool same(const AstNode* samep) const override {
return text() == static_cast<const AstFScanF*>(samep)->text();
return text() == VN_DBG_AS(samep, FScanF)->text();
}
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text = text; }
@@ -1250,8 +1323,8 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: makes output
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -1268,8 +1341,8 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -1308,7 +1381,9 @@ public:
bool cleanOut() const override { return true; }
};
class AstImplication final : public AstNodeExpr {
// Verilog |-> |=>
// Verilog Implication Operator
// Nonoverlapping "|=>"
// Overlapping "|->" (doesn't currently use this - might make new Ast type)
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := sentreep : Optional[AstSenTree]
@@ -1355,7 +1430,7 @@ public:
bool same(const AstNode* samep) const override {
// Only works if exact same children, instead should override comparison
// of children list, and instead use map-vs-map key/value compare
return m_map == static_cast<const AstInitArray*>(samep)->m_map;
return m_map == VN_DBG_AS(samep, InitArray)->m_map;
}
void addValuep(AstNodeExpr* newp) { addIndexValuep(m_map.size(), newp); }
const KeyItemMap& map() const { return m_map; }
@@ -1511,7 +1586,7 @@ public:
void dump(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool same(const AstNode* samep) const override {
const AstParseRef* const asamep = static_cast<const AstParseRef*>(samep);
const AstParseRef* const asamep = VN_DBG_AS(samep, ParseRef);
return (expect() == asamep->expect() && m_name == asamep->m_name);
}
void name(const string& name) override { m_name = name; }
@@ -1706,7 +1781,7 @@ public:
string name() const override VL_MT_STABLE { return m_text; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool same(const AstNode* samep) const override {
return text() == static_cast<const AstSFormatF*>(samep)->text();
return text() == VN_DBG_AS(samep, SFormatF)->text();
}
string verilogKwd() const override { return "$sformatf"; }
string text() const { return m_text; } // * = Text to display
@@ -1744,11 +1819,11 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: makes output
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool same(const AstNode* samep) const override {
return text() == static_cast<const AstSScanF*>(samep)->text();
return text() == VN_DBG_AS(samep, SScanF)->text();
}
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text = text; }
@@ -1788,8 +1863,8 @@ public:
}
ASTGEN_MEMBERS_AstScopeName;
bool same(const AstNode* samep) const override {
return (m_dpiExport == static_cast<const AstScopeName*>(samep)->m_dpiExport
&& m_forFormat == static_cast<const AstScopeName*>(samep)->m_forFormat);
const AstScopeName* const sp = VN_DBG_AS(samep, ScopeName);
return (m_dpiExport == sp->m_dpiExport && m_forFormat == sp->m_forFormat);
}
string emitVerilog() override { return ""; }
string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -1902,8 +1977,8 @@ public:
string emitC() override { return "VL_STACKTRACE_N()"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -1932,7 +2007,7 @@ public:
return VN_IS(fromp()->dtypep()->skipRefp(), StructDType);
}
bool same(const AstNode* samep) const override {
const AstStructSel* const sp = static_cast<const AstStructSel*>(samep);
const AstStructSel* const sp = VN_DBG_AS(samep, StructSel);
return m_name == sp->m_name;
}
int instrCount() const override { return widthInstrs(); }
@@ -1948,8 +2023,8 @@ public:
string verilogKwd() const override { return "$ignored"; }
bool isGateOptimizable() const override { return false; } // Though deleted before opt
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
bool isPure() const override { return false; } // Though deleted before opt
bool isOutputter() const override { return true; } // Though deleted before opt
bool isPure() override { return false; } // Though deleted before opt
bool isOutputter() override { return true; } // Though deleted before opt
int instrCount() const override { return INSTR_COUNT_PLI; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
@@ -1970,8 +2045,8 @@ public:
string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -2054,8 +2129,8 @@ public:
bool cleanOut() const override { return false; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
bool isGateOptimizable() const override { return false; }
bool isSubstOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
@@ -2110,7 +2185,7 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return !outp(); }
bool isPure() override { return !outp(); }
bool cleanOut() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -2217,7 +2292,7 @@ public:
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 20; }
bool isPure() const override { return true; }
bool isPure() override { return true; }
};
class AstCompareNN final : public AstNodeBiop {
// Verilog str.compare() and str.icompare()
@@ -2441,7 +2516,7 @@ public:
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 64; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
AstNode* filep() const { return lhsp(); }
AstNode* charp() const { return rhsp(); }
};
@@ -2726,11 +2801,6 @@ public:
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
};
class AstLogOr final : public AstNodeBiop {
// LOGOR with optional side effects
// Side effects currently used in some V3Width code
// TBD if this concept is generally adopted for side-effect tracking
// versus V3Const tracking it itself
bool m_sideEffect = false; // Has side effect, relies on short-circuiting
public:
AstLogOr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) {
@@ -2743,11 +2813,6 @@ public:
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLogOr(lhs, rhs);
}
bool same(const AstNode* samep) const override {
const AstLogOr* const sp = static_cast<const AstLogOr*>(samep);
return m_sideEffect == sp->m_sideEffect;
}
void dump(std::ostream& str = std::cout) const override;
string emitVerilog() override { return "%k(%l %f|| %r)"; }
string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return "||"; }
@@ -2757,9 +2822,6 @@ public:
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
bool isPure() const override { return !m_sideEffect; }
void sideEffect(bool flag) { m_sideEffect = flag; }
bool sideEffect() const { return m_sideEffect; }
};
class AstLt final : public AstNodeBiop {
public:
@@ -3214,6 +3276,30 @@ public:
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftLOvr final : public AstNodeBiop {
// Like ShiftL but checks for an over shift and returns zeros
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftL
public:
AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftLOvr(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstShiftLOvr;
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
return new AstShiftLOvr{fileline(), lhsp, rhsp};
}
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftL(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<< %r)"; }
string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftR final : public AstNodeBiop {
public:
AstShiftR(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
@@ -3239,6 +3325,31 @@ public:
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftROvr final : public AstNodeBiop {
// Like ShiftR but checks for an over shift and returns zeros
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftR
public:
AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftROvr(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstShiftROvr;
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
return new AstShiftROvr{fileline(), lhsp, rhsp};
}
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftR(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>> %r)"; }
string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
// LHS size might be > output size, so don't want to force size
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftRS final : public AstNodeBiop {
// Shift right with sign extension, >>> operator
// Output data type's width determines which bit is used for sign extension
@@ -3265,6 +3376,33 @@ public:
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstShiftRSOvr final : public AstNodeBiop {
// Shift right with sign extension, >>> operator, checks for an over shift and returns zeros
// Output data type's width determines which bit is used for sign extension
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftRSOvr
public:
AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) {
// Important that widthMin be correct, as opExtend requires it after V3Expand
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED);
}
ASTGEN_MEMBERS_AstShiftRSOvr;
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
return new AstShiftRSOvr{fileline(), lhsp, rhsp};
}
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftRS(lhs, rhs, lhsp()->widthMinV());
}
string emitVerilog() override { return "%k(%l %f>>> %r)"; }
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstSub final : public AstNodeBiop {
public:
AstSub(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
@@ -4023,16 +4161,19 @@ public:
// === AstNodeCCall ===
class AstCCall final : public AstNodeCCall {
// C++ function call
string m_selfPointer; // Output code object pointer (e.g.: 'this')
VSelfPointerText m_selfPointer
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
// pointer (e.g.: 'this')
public:
AstCCall(FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
: ASTGEN_SUPER_CCall(fl, funcp, argsp) {}
ASTGEN_MEMBERS_AstCCall;
string selfPointer() const { return m_selfPointer; }
void selfPointer(const string& value) { m_selfPointer = value; }
string selfPointerProtect(bool useSelfForThis) const;
const VSelfPointerText& selfPointer() const { return m_selfPointer; }
void selfPointer(const VSelfPointerText& selfPointer) { m_selfPointer = selfPointer; }
string selfPointerProtect(bool useSelfForThis) const {
return selfPointer().protect(useSelfForThis, protect());
}
};
class AstCMethodCall final : public AstNodeCCall {
// C++ method call
@@ -4060,12 +4201,15 @@ public:
// === AstNodeFTaskRef ===
class AstFuncRef final : public AstNodeFTaskRef {
// A reference to a function
bool m_superReference = false; // Called with super reference
public:
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp)
: ASTGEN_SUPER_FuncRef(fl, (AstNode*)namep, pinsp) {}
AstFuncRef(FileLine* fl, const string& name, AstNodeExpr* pinsp)
: ASTGEN_SUPER_FuncRef(fl, name, pinsp) {}
ASTGEN_MEMBERS_AstFuncRef;
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
class AstMethodCall final : public AstNodeFTaskRef {
// A reference to a member task (or function)
@@ -4102,6 +4246,7 @@ public:
};
class AstTaskRef final : public AstNodeFTaskRef {
// A reference to a task
bool m_superReference = false; // Called with super reference
public:
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp)
: ASTGEN_SUPER_TaskRef(fl, (AstNode*)namep, pinsp) {
@@ -4112,6 +4257,8 @@ public:
dtypeSetVoid();
}
ASTGEN_MEMBERS_AstTaskRef;
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
// === AstNodePreSel ===
@@ -4162,10 +4309,10 @@ class AstCountBits final : public AstNodeQuadop {
// Number of bits set in vector
public:
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p)
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false),
ctrl1p->cloneTree(false)) {}
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTreePure(false),
ctrl1p->cloneTreePure(false)) {}
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p)
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {}
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTreePure(false)) {}
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p,
AstNodeExpr* ctrl3p)
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {}
@@ -4612,7 +4759,7 @@ public:
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast
bool same(const AstNode* samep) const override {
return size() == static_cast<const AstCCast*>(samep)->size();
return size() == VN_DBG_AS(samep, CCast)->size();
}
void dump(std::ostream& str = std::cout) const override;
//
@@ -4735,7 +4882,7 @@ public:
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 16; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
AstNode* filep() const { return lhsp(); }
};
class AstFGetC final : public AstNodeUniop {
@@ -4752,7 +4899,7 @@ public:
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 64; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
AstNode* filep() const { return lhsp(); }
};
class AstISToRD final : public AstNodeUniop {
@@ -5058,6 +5205,21 @@ public:
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return 1 + V3Number::log2b(width()); }
};
class AstResizeLValue final : public AstNodeUniop {
// Resize a LValue into a wider/narrower entity at function argument boundry
// Width and signness is implied from nodep->width()
public:
AstResizeLValue(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ResizeLValue(fl, lhsp) {}
ASTGEN_MEMBERS_AstResizeLValue;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { return "%l"; }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return 0; }
};
class AstSigned final : public AstNodeUniop {
// $signed(lhs)
public:
@@ -5391,7 +5553,7 @@ public:
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* samep) const override {
const AstVarXRef* asamep = static_cast<const AstVarXRef*>(samep);
const AstVarXRef* asamep = VN_DBG_AS(samep, VarXRef);
return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp()
&& name() == asamep->name() && dotted() == asamep->dotted());
}
+205 -122
View File
@@ -32,7 +32,7 @@
class AstNodeBlock VL_NOT_FINAL : public AstNode {
// A Begin/fork block
// @astgen op1 := stmtsp : List[AstNode]
// @astgen op2 := stmtsp : List[AstNode]
// Parents: statement
private:
string m_name; // Name of block
@@ -81,13 +81,16 @@ private:
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_dpiPure : 1; // DPI import pure (vs. virtual pure)
bool m_pureVirtual : 1; // Pure virtual
bool m_recursive : 1; // Recursive or part of recursion
bool m_static : 1; // Static method in class
bool m_underGenerate : 1; // Under generate (for warning)
bool m_virtual : 1; // Virtual method in class
bool m_needProcess : 1; // Implements part of a process that allocates std::process
VLifetime m_lifetime; // Lifetime
bool m_needProcess : 1; // Needs access to VlProcess of the caller
VLifetime m_lifetime; // Default lifetime of local vars
VIsCached m_purity; // Pure state
protected:
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
: AstNode{t, fl}
@@ -107,9 +110,10 @@ protected:
, m_isConstructor{false}
, m_isHideLocal{false}
, m_isHideProtected{false}
, m_pure{false}
, m_dpiPure{false}
, m_pureVirtual{false}
, m_recursive{false}
, m_static{false}
, m_underGenerate{false}
, m_virtual{false}
, m_needProcess{false} {
@@ -119,10 +123,13 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeFTask;
virtual AstNodeFTask* cloneType(const string& name) = 0;
void dump(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool maybePointedTo() const override { return true; }
bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); }
bool isGateOptimizable() const override {
return !((m_dpiExport || m_dpiImport) && !m_dpiPure);
}
// {AstFunc only} op1 = Range output variable
void name(const string& name) override { m_name = name; }
string cname() const { return m_cname; }
@@ -162,12 +169,14 @@ public:
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 dpiPure(bool flag) { m_dpiPure = flag; }
bool dpiPure() const { return m_dpiPure; }
void pureVirtual(bool flag) { m_pureVirtual = flag; }
bool pureVirtual() const { return m_pureVirtual; }
void recursive(bool flag) { m_recursive = flag; }
bool recursive() const { return m_recursive; }
void isStatic(bool flag) { m_static = flag; }
bool isStatic() const { return m_static; }
void underGenerate(bool flag) { m_underGenerate = flag; }
bool underGenerate() const { return m_underGenerate; }
void isVirtual(bool flag) { m_virtual = flag; }
@@ -177,6 +186,20 @@ public:
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
bool isPure() override;
const char* broken() const override;
void propagateAttrFrom(const AstNodeFTask* fromp) {
// Creating a wrapper with e.g. cloneType(); preserve some attributes
classMethod(fromp->classMethod());
isHideLocal(fromp->isHideLocal());
isHideProtected(fromp->isHideProtected());
isVirtual(fromp->isVirtual());
lifetime(fromp->lifetime());
underGenerate(fromp->underGenerate());
}
private:
bool getPurityRecurse() const;
};
class AstNodeFile VL_NOT_FINAL : public AstNode {
// Emitted Output file
@@ -215,6 +238,7 @@ private:
bool m_inLibrary : 1; // From a library, no error if not used, never top level
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
bool m_hasGParam : 1; // Has global parameter (for link)
bool m_hasParameterList : 1; // Has #() for parameter declaration
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
bool m_internal : 1; // Internally created
bool m_recursive : 1; // Recursive module
@@ -229,6 +253,7 @@ protected:
, m_inLibrary{false}
, m_dead{false}
, m_hasGParam{false}
, m_hasParameterList{false}
, m_hierBlock{false}
, m_internal{false}
, m_recursive{false}
@@ -258,6 +283,8 @@ public:
bool dead() const { return m_dead; }
void hasGParam(bool flag) { m_hasGParam = flag; }
bool hasGParam() const { return m_hasGParam; }
void hasParameterList(bool flag) { m_hasParameterList = flag; }
bool hasParameterList() const { return m_hasParameterList; }
void hierBlock(bool flag) { m_hierBlock = flag; }
bool hierBlock() const { return m_hierBlock; }
void internal(bool flag) { m_internal = flag; }
@@ -277,7 +304,7 @@ class AstNodeProcedure VL_NOT_FINAL : public AstNode {
// IEEE procedure: initial, final, always
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only
bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc.
bool m_needProcess : 1; // Implements part of a process that allocates std::process
bool m_needProcess : 1; // Uses VlProcess
protected:
AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp)
: AstNode{t, fl} {
@@ -457,11 +484,11 @@ public:
ASTGEN_MEMBERS_AstNodeReadWriteMem;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* samep) const override {
return isHex() == static_cast<const AstNodeReadWriteMem*>(samep)->isHex();
return isHex() == VN_DBG_AS(samep, NodeReadWriteMem)->isHex();
}
bool isHex() const { return m_isHex; }
virtual const char* cFuncPrefixp() const = 0;
@@ -480,7 +507,7 @@ public:
ASTGEN_MEMBERS_AstNodeText;
void dump(std::ostream& str = std::cout) const override;
bool same(const AstNode* samep) const override {
const AstNodeText* asamep = static_cast<const AstNodeText*>(samep);
const AstNodeText* asamep = VN_DBG_AS(samep, NodeText);
return text() == asamep->text();
}
const string& text() const VL_MT_SAFE { return m_text; }
@@ -578,14 +605,15 @@ private:
bool m_isInline : 1; // Inline function
bool m_isVirtual : 1; // Virtual function
bool m_entryPoint : 1; // User may call into this top level function
bool m_pure : 1; // Pure function
bool m_dpiPure : 1; // Pure DPI function
bool m_dpiContext : 1; // Declared as 'context' DPI import/export function
bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user)
bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup)
bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user)
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
bool m_dpiTraceInit : 1; // DPI trace_init
bool m_needProcess : 1; // Implements part of a process that allocates std::process
bool m_needProcess : 1; // Needs access to VlProcess of the caller
bool m_recursive : 1; // Recursive or part of recursion
public:
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
: ASTGEN_SUPER_CFunc(fl) {
@@ -607,13 +635,14 @@ public:
m_isVirtual = false;
m_needProcess = false;
m_entryPoint = false;
m_pure = false;
m_dpiPure = false;
m_dpiContext = false;
m_dpiExportDispatcher = false;
m_dpiExportImpl = false;
m_dpiImportPrototype = false;
m_dpiImportWrapper = false;
m_dpiTraceInit = false;
m_recursive = false;
}
ASTGEN_MEMBERS_AstCFunc;
string name() const override VL_MT_STABLE { return m_name; }
@@ -622,7 +651,7 @@ public:
bool maybePointedTo() const override { return true; }
void dump(std::ostream& str = std::cout) const override;
bool same(const AstNode* samep) const override {
const AstCFunc* const asamep = static_cast<const AstCFunc*>(samep);
const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc);
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
&& (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors())
&& isLoose() == asamep->isLoose()
@@ -678,8 +707,8 @@ public:
void setNeedProcess() { m_needProcess = true; }
bool entryPoint() const { return m_entryPoint; }
void entryPoint(bool flag) { m_entryPoint = flag; }
bool pure() const { return m_pure; }
void pure(bool flag) { m_pure = flag; }
bool dpiPure() const { return m_dpiPure; }
void dpiPure(bool flag) { m_dpiPure = flag; }
bool dpiContext() const { return m_dpiContext; }
void dpiContext(bool flag) { m_dpiContext = flag; }
bool dpiExportDispatcher() const VL_MT_SAFE { return m_dpiExportDispatcher; }
@@ -693,12 +722,24 @@ public:
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
bool dpiTraceInit() const { return m_dpiTraceInit; }
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
void recursive(bool flag) { m_recursive = flag; }
bool recursive() const { return m_recursive; }
// Special methods
bool emptyBody() const {
return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
&& finalsp() == nullptr;
}
};
class AstCLocalScope final : public AstNode {
// Pack statements into an unnamed scope when generating C++
// @astgen op1 := stmtsp : List[AstNode]
public:
AstCLocalScope(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_CLocalScope(fl) {
this->addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCLocalScope;
};
class AstCUse final : public AstNode {
// C++ use of a class or #include; indicates need of forward declaration
// Parents: NODEMODULE
@@ -736,13 +777,14 @@ class AstCell final : public AstNode {
// @astgen op1 := pinsp : List[AstPin] // List of port assignments
// @astgen op2 := paramsp : List[AstPin] // List of parameter assignments
// @astgen op3 := rangep : Optional[AstRange] // Range for arrayed instances
// @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references
// @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references, for tracing
FileLine* m_modNameFileline; // Where module the cell instances token was
string m_name; // Cell name
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced
bool m_hasIfaceVar : 1; // True if a Var has been created for this cell
bool m_hasNoParens : 1; // Instantiation has no parenthesis
bool m_recursive : 1; // Self-recursive module
bool m_trace : 1; // Trace this cell
public:
@@ -754,6 +796,7 @@ public:
, m_origName{instName}
, m_modName{modName}
, m_hasIfaceVar{false}
, m_hasNoParens{false}
, m_recursive{false}
, m_trace{true} {
this->addPinsp(pinsp);
@@ -777,6 +820,8 @@ public:
void modp(AstNodeModule* nodep) { m_modp = nodep; }
bool hasIfaceVar() const { return m_hasIfaceVar; }
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
bool hasNoParens() const { return m_hasNoParens; }
void hasNoParens(bool flag) { m_hasNoParens = flag; }
void trace(bool flag) { m_trace = flag; }
bool isTrace() const { return m_trace; }
void recursive(bool flag) { m_recursive = flag; }
@@ -972,11 +1017,11 @@ public:
string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
bool same(const AstNode* samep) const override {
return displayType() == static_cast<const AstElabDisplay*>(samep)->displayType();
return displayType() == VN_DBG_AS(samep, ElabDisplay)->displayType();
}
int instrCount() const override { return INSTR_COUNT_PLI; }
VDisplayType displayType() const { return m_displayType; }
@@ -1005,7 +1050,7 @@ class AstExecGraph final : public AstNode {
const string m_name; // Name of this AstExecGraph (for uniqueness at code generation)
public:
explicit AstExecGraph(FileLine* fl, const string& name);
explicit AstExecGraph(FileLine* fl, const string& name) VL_MT_DISABLED;
ASTGEN_MEMBERS_AstExecGraph;
~AstExecGraph() override;
const char* broken() const override {
@@ -1154,6 +1199,8 @@ class AstNetlist final : public AstNode {
AstCFunc* m_evalNbap = nullptr; // The '_eval__nba' function
AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable
AstVar* m_delaySchedulerp = nullptr; // The delay scheduler variable
AstVarScope* m_nbaEventp = nullptr; // The NBA event variable
AstVarScope* m_nbaEventTriggerp = nullptr; // If set to 1, the NBA event should get triggered
AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module
VTimescale m_timeunit; // Global time unit
VTimescale m_timeprecision; // Global time precision
@@ -1183,6 +1230,10 @@ public:
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; }
AstVarScope* nbaEventp() const { return m_nbaEventp; }
void nbaEventp(AstVarScope* const varScopep) { m_nbaEventp = varScopep; }
AstVarScope* nbaEventTriggerp() const { return m_nbaEventTriggerp; }
void nbaEventTriggerp(AstVarScope* const varScopep) { m_nbaEventTriggerp = varScopep; }
void stdPackagep(AstPackage* const packagep) { m_stdPackagep = packagep; }
AstPackage* stdPackagep() const { return m_stdPackagep; }
AstTopScope* topScopep() const { return m_topScopep; }
@@ -1310,7 +1361,7 @@ public:
VPragmaType pragType() const { return m_pragType; } // *=type of the pragma
bool isPredictOptimizable() const override { return false; }
bool same(const AstNode* samep) const override {
return pragType() == static_cast<const AstPragma*>(samep)->pragType();
return pragType() == VN_DBG_AS(samep, Pragma)->pragType();
}
};
class AstPropSpec final : public AstNode {
@@ -1345,7 +1396,7 @@ public:
}
ASTGEN_MEMBERS_AstPull;
bool same(const AstNode* samep) const override {
return direction() == static_cast<const AstPull*>(samep)->direction();
return direction() == VN_DBG_AS(samep, Pull)->direction();
}
uint32_t direction() const { return (uint32_t)m_direction; }
};
@@ -1378,7 +1429,6 @@ public:
void dump(std::ostream& str) const override;
bool same(const AstNode* samep) const override;
string nameDotless() const;
string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); }
AstNodeModule* modp() const { return m_modp; }
//
AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; }
@@ -1426,7 +1476,7 @@ public:
ASTGEN_MEMBERS_AstSenItem;
void dump(std::ostream& str) const override;
bool same(const AstNode* samep) const override {
return edgeType() == static_cast<const AstSenItem*>(samep)->edgeType();
return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType();
}
VEdgeType edgeType() const { return m_edgeType; }
void edgeType(VEdgeType type) {
@@ -1627,12 +1677,11 @@ class AstVar final : public AstNode {
VVarType m_varType; // Type of variable
VDirection m_direction; // Direction input/output etc
VDirection m_declDirection; // Declared direction input/output etc
VBasicDTypeKwd m_declKwd; // Keyword at declaration time
VLifetime m_lifetime; // Lifetime
VVarAttrClocker m_attrClocker;
MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var
int m_pinNum = 0; // For XML, if non-zero the connection pin number
bool m_ansi : 1; // ANSI port list variable (for dedup check)
bool m_ansi : 1; // Params or pins declared in the module header, rather than the body
bool m_declTyped : 1; // Declared as type (for dedup check)
bool m_tristate : 1; // Inout or triwire or trireg
bool m_primaryIO : 1; // In/out to top level (or directly assigned from same)
@@ -1656,6 +1705,7 @@ class AstVar final : public AstNode {
bool m_attrSplitVar : 1; // declared with split_var metacomment
bool m_fileDescr : 1; // File descriptor
bool m_isRand : 1; // Random variable
bool m_isRandC : 1; // Random cyclic variable (isRand also set)
bool m_isConst : 1; // Table contains constant data
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
@@ -1663,6 +1713,7 @@ class AstVar final : public AstNode {
bool m_isPulldown : 1; // Tri0
bool m_isPullup : 1; // Tri1
bool m_isIfaceParent : 1; // dtype is reference to interface present in this module
bool m_isInternal : 1; // Internal state, don't add to method pinter
bool m_isDpiOpenArray : 1; // DPI import open array
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
@@ -1700,6 +1751,7 @@ class AstVar final : public AstNode {
m_attrSplitVar = false;
m_fileDescr = false;
m_isRand = false;
m_isRandC = false;
m_isConst = false;
m_isContinuously = false;
m_hasStrengthAssignment = false;
@@ -1707,6 +1759,7 @@ class AstVar final : public AstNode {
m_isPulldown = false;
m_isPullup = false;
m_isIfaceParent = false;
m_isInternal = false;
m_isDpiOpenArray = false;
m_isHideLocal = false;
m_isHideProtected = false;
@@ -1730,11 +1783,6 @@ public:
combineType(type);
childDTypep(dtp); // Only for parser
dtypep(nullptr); // V3Width will resolve
if (dtp->basicp()) {
m_declKwd = dtp->basicp()->keyword();
} else {
m_declKwd = VBasicDTypeKwd::LOGIC;
}
}
AstVar(FileLine* fl, VVarType type, const string& name, AstNodeDType* dtp)
: ASTGEN_SUPER_Var(fl)
@@ -1744,11 +1792,6 @@ public:
combineType(type);
UASSERT(dtp, "AstVar created with no dtype");
dtypep(dtp);
if (dtp->basicp()) {
m_declKwd = dtp->basicp()->keyword();
} else {
m_declKwd = VBasicDTypeKwd::LOGIC;
}
}
AstVar(FileLine* fl, VVarType type, const string& name, VFlagLogicPacked, int wantwidth)
: ASTGEN_SUPER_Var(fl)
@@ -1757,7 +1800,6 @@ public:
init();
combineType(type);
dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED);
m_declKwd = VBasicDTypeKwd::LOGIC;
}
AstVar(FileLine* fl, VVarType type, const string& name, VFlagBitPacked, int wantwidth)
: ASTGEN_SUPER_Var(fl)
@@ -1766,7 +1808,6 @@ public:
init();
combineType(type);
dtypeSetBitSized(wantwidth, VSigning::UNSIGNED);
m_declKwd = VBasicDTypeKwd::BIT;
}
AstVar(FileLine* fl, VVarType type, const string& name, AstVar* examplep)
: ASTGEN_SUPER_Var(fl)
@@ -1776,7 +1817,6 @@ public:
combineType(type);
if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true));
dtypeFrom(examplep);
m_declKwd = examplep->declKwd();
}
ASTGEN_MEMBERS_AstVar;
void dump(std::ostream& str) const override;
@@ -1804,7 +1844,6 @@ public:
m_tristate = false;
m_direction = VDirection::INPUT;
}
VBasicDTypeKwd declKwd() const { return m_declKwd; }
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
// Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
string cPubArgType(bool named, bool forReturn) const;
@@ -1852,10 +1891,15 @@ public:
void scSensitive(bool flag) { m_scSensitive = flag; }
void primaryIO(bool flag) { m_primaryIO = flag; }
void isRand(bool flag) { m_isRand = flag; }
void isRandC(bool flag) {
m_isRandC = flag;
if (flag) isRand(true);
}
void isConst(bool flag) { m_isConst = flag; }
void isContinuously(bool flag) { m_isContinuously = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void isInternal(bool flag) { m_isInternal = flag; }
void funcLocal(bool flag) {
m_funcLocal = flag;
if (flag) m_funcLocalSticky = true;
@@ -1894,12 +1938,15 @@ public:
bool isInoutish() const { return m_direction.isInoutish(); }
bool isNonOutput() const { return m_direction.isNonOutput(); }
bool isReadOnly() const VL_MT_SAFE { return m_direction.isReadOnly(); }
bool isConstRef() const VL_MT_SAFE { return m_direction.isConstRef(); }
bool isRef() const VL_MT_SAFE { return m_direction.isRef(); }
bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); }
bool isTristate() const { return m_tristate; }
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); }
bool isIfaceParent() const { return m_isIfaceParent; }
bool isInternal() const { return m_isInternal; }
bool isSignal() const { return varType().isSignal(); }
bool isNet() const { return varType().isNet(); }
bool isTemp() const { return varType().isTemp(); }
@@ -1912,9 +1959,7 @@ public:
bool isClassMember() const { return varType() == VVarType::MEMBER; }
bool isStatementTemp() const { return (varType() == VVarType::STMTTEMP); }
bool isXTemp() const { return (varType() == VVarType::XTEMP); }
bool isParam() const VL_MT_SAFE {
return (varType() == VVarType::LPARAM || varType() == VVarType::GPARAM);
}
bool isParam() const { return varType().isParam(); }
bool isGParam() const { return (varType() == VVarType::GPARAM); }
bool isGenVar() const { return (varType() == VVarType::GENVAR); }
bool isBitLogic() const {
@@ -1937,6 +1982,7 @@ public:
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
bool isTrace() const { return m_trace; }
bool isRand() const { return m_isRand; }
bool isRandC() const { return m_isRandC; }
bool isConst() const VL_MT_SAFE { return m_isConst; }
bool isStatic() const VL_MT_SAFE { return m_isStatic; }
bool isLatched() const { return m_isLatched; }
@@ -1955,18 +2001,25 @@ public:
string verilogKwd() const override;
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
void propagateAttrFrom(AstVar* fromp) {
void propagateAttrFrom(const AstVar* fromp) {
// This is getting connected to fromp; keep attributes
// Note the method below too
if (fromp->attrFileDescr()) attrFileDescr(true);
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
if (fromp->isContinuously()) isContinuously(true);
}
void propagateWrapAttrFrom(const AstVar* fromp) {
// Creating a function wrapper; keep attributes
propagateAttrFrom(fromp);
direction(fromp->direction());
declDirection(fromp->declDirection());
lifetime(fromp->lifetime());
}
bool gateMultiInputOptimizable() const {
// Ok to gate optimize; must return false if propagateAttrFrom would do anything
return !isUsedClock();
}
void combineType(AstVar* typevarp) {
void combineType(const AstVar* typevarp) {
// This is same as typevarp (for combining input & reg decls)
// "this" is the input var. typevarp is the reg var.
propagateAttrFrom(typevarp);
@@ -2040,25 +2093,30 @@ public:
class AstBegin final : public AstNodeBlock {
// A Begin/end named block, only exists shortly after parsing until linking
// Parents: statement
// @astgen op2 := genforp : Optional[AstNode]
// @astgen op1 := genforp : Optional[AstNode]
bool m_generate; // Underneath a generate
const bool m_implied; // Not inserted by user
bool m_generate : 1; // Underneath a generate
bool m_needProcess : 1; // Uses VlProcess
const bool m_implied : 1; // Not inserted by user
public:
// Node that puts name into the output stream
AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false,
bool implied = false)
: ASTGEN_SUPER_Begin(fl, name, stmtsp)
, m_generate{generate}
, m_needProcess{false}
, m_implied{implied} {}
ASTGEN_MEMBERS_AstBegin;
void dump(std::ostream& str) const override;
void generate(bool flag) { m_generate = flag; }
bool generate() const { return m_generate; }
void setNeedProcess() { m_needProcess = true; }
bool needProcess() const { return m_needProcess; }
bool implied() const { return m_implied; }
};
class AstFork final : public AstNodeBlock {
// A fork named block
// @astgen op1 := initsp : List[AstNode]
// Parents: statement
// Children: statements
private:
@@ -2084,6 +2142,24 @@ public:
}
ASTGEN_MEMBERS_AstFunc;
bool hasDType() const override { return true; }
AstNodeFTask* cloneType(const string& name) override {
return new AstFunc{fileline(), name, nullptr, nullptr};
}
};
class AstLet final : public AstNodeFTask {
// Verilog "let" statement
// Parents: MODULE
// stmtp is always a StmtExpr as Let always returns AstNodeExpr
public:
AstLet(FileLine* fl, const string& name)
: ASTGEN_SUPER_Let(fl, name, nullptr) {}
ASTGEN_MEMBERS_AstLet;
bool hasDType() const override { return true; }
const char* broken() const override {
BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr));
return nullptr;
}
AstNodeFTask* cloneType(const string& name) override { return new AstLet{fileline(), name}; }
};
class AstProperty final : public AstNodeFTask {
// A property inside a module
@@ -2092,6 +2168,9 @@ public:
: ASTGEN_SUPER_Property(fl, name, stmtp) {}
ASTGEN_MEMBERS_AstProperty;
bool hasDType() const override { return true; }
AstNodeFTask* cloneType(const string& name) override {
return new AstProperty{fileline(), name, nullptr};
}
};
class AstTask final : public AstNodeFTask {
// A task inside a module
@@ -2099,6 +2178,9 @@ public:
AstTask(FileLine* fl, const string& name, AstNode* stmtp)
: ASTGEN_SUPER_Task(fl, name, stmtp) {}
ASTGEN_MEMBERS_AstTask;
AstNodeFTask* cloneType(const string& name) override {
return new AstTask{fileline(), name, nullptr};
}
};
// === AstNodeFile ===
@@ -2532,7 +2614,7 @@ public:
void hier(const string& flag) { m_hier = flag; }
void comment(const string& flag) { m_text = flag; }
bool same(const AstNode* samep) const override {
const AstCoverDecl* const asamep = static_cast<const AstCoverDecl*>(samep);
const AstCoverDecl* const asamep = VN_DBG_AS(samep, CoverDecl);
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
&& hier() == asamep->hier() && comment() == asamep->comment());
}
@@ -2561,11 +2643,11 @@ public:
void dump(std::ostream& str) const override;
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
bool same(const AstNode* samep) const override {
return declp() == static_cast<const AstCoverInc*>(samep)->declp();
return declp() == VN_DBG_AS(samep, CoverInc)->declp();
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isOutputter() const override { return true; }
bool isOutputter() override { return true; }
// but isPure() true
AstCoverDecl* declp() const { return m_declp; } // Where defined
};
@@ -2587,7 +2669,7 @@ public:
bool same(const AstNode* /*samep*/) const override { return true; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return true; }
bool isOutputter() const override {
bool isOutputter() override {
return false; // Though the AstCoverInc under this is an outputter
}
// but isPure() true
@@ -2664,11 +2746,11 @@ public:
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
bool same(const AstNode* samep) const override {
return displayType() == static_cast<const AstDisplay*>(samep)->displayType();
return displayType() == VN_DBG_AS(samep, Display)->displayType();
}
int instrCount() const override { return INSTR_COUNT_PLI; }
VDisplayType displayType() const { return m_displayType; }
@@ -2707,7 +2789,7 @@ public:
string verilogKwd() const override { return ctlType().ascii(); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isOutputter() const override { return true; }
bool isOutputter() override { return true; }
virtual bool cleanOut() const { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
VDumpCtlType ctlType() const { return m_ctlType; }
@@ -2739,8 +2821,8 @@ public:
string verilogKwd() const override { return "$fclose"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -2756,8 +2838,8 @@ public:
string verilogKwd() const override { return "$fflush"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -2768,8 +2850,8 @@ public:
ASTGEN_MEMBERS_AstFinish;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
int instrCount() const override { return 0; } // Rarely executes
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
@@ -2845,7 +2927,7 @@ public:
void dump(std::ostream& str) const override;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* samep) const override {
return labelp() == static_cast<const AstJumpGo*>(samep)->labelp();
return labelp() == VN_DBG_AS(samep, JumpGo)->labelp();
}
bool isGateOptimizable() const override { return false; }
bool isBrancher() const override {
@@ -2876,7 +2958,7 @@ public:
void dump(std::ostream& str) const override;
int instrCount() const override { return 0; }
bool same(const AstNode* samep) const override {
return blockp() == static_cast<const AstJumpLabel*>(samep)->blockp();
return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp();
}
AstJumpBlock* blockp() const { return m_blockp; }
};
@@ -2891,11 +2973,11 @@ public:
string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; }
bool isGateOptimizable() const override { return false; } // Though deleted before opt
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
bool isPure() const override { return false; } // Though deleted before opt
bool isOutputter() const override { return true; } // Though deleted before opt
bool isPure() override { return false; } // Though deleted before opt
bool isOutputter() override { return true; } // Though deleted before opt
int instrCount() const override { return INSTR_COUNT_PLI; }
bool same(const AstNode* samep) const override {
return m_off == static_cast<const AstMonitorOff*>(samep)->m_off;
return m_off == VN_DBG_AS(samep, MonitorOff)->m_off;
}
bool off() const { return m_off; }
};
@@ -2913,8 +2995,8 @@ public:
string verilogKwd() const override { return "$printtimescale"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
@@ -2991,8 +3073,8 @@ public:
string verilogKwd() const override { return "$sformat"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return true; }
bool isPure() const override { return true; }
bool isOutputter() const override { return false; }
bool isPure() override { return true; }
bool isOutputter() override { return false; }
virtual bool cleanOut() const { return false; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -3006,8 +3088,8 @@ public:
string verilogKwd() const override { return "$stacktrace"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -3028,8 +3110,8 @@ public:
ASTGEN_MEMBERS_AstStop;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
int instrCount() const override { return 0; } // Rarely executes
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
@@ -3047,8 +3129,8 @@ public:
string verilogKwd() const override { return ""; }
bool isGateOptimizable() const override { return true; }
bool isPredictOptimizable() const override { return true; }
bool isPure() const override { return true; }
bool isOutputter() const override { return false; }
bool isPure() override { return true; }
bool isOutputter() override { return false; }
int instrCount() const override { return 0; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -3064,8 +3146,8 @@ public:
string verilogKwd() const override { return "$system"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
@@ -3088,8 +3170,8 @@ public:
string verilogKwd() const override { return "$timeformat"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
};
class AstTraceDecl final : public AstNodeStmt {
@@ -3099,13 +3181,13 @@ class AstTraceDecl final : public AstNodeStmt {
// Expression being traced - Moved to AstTraceInc by V3Trace
// @astgen op1 := valuep : Optional[AstNodeExpr]
private:
uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines
uint32_t m_code{0}; // Trace identifier code
uint32_t m_fidx{0}; // Trace function index
const string m_showname; // Name of variable
const VNumRange m_bitRange; // Property of var the trace details
const VNumRange m_arrayRange; // Property of var the trace details
const uint32_t m_codeInc; // Code increment
const VVarType m_varType; // Type of variable (for localparam vs. param)
const VBasicDTypeKwd m_declKwd; // Keyword at declaration time
const VDirection m_declDirection; // Declared direction input/output etc
public:
AstTraceDecl(FileLine* fl, const string& showname,
@@ -3119,7 +3201,6 @@ public:
((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
* (VL_EDATASIZE / 32))) // A code is always 32-bits
, m_varType{varp->varType()}
, m_declKwd{varp->declKwd()}
, m_declDirection{varp->declDirection()} {
dtypeFrom(valuep);
this->valuep(valuep);
@@ -3135,11 +3216,12 @@ public:
// Details on what we're tracing
uint32_t code() const { return m_code; }
void code(uint32_t code) { m_code = code; }
uint32_t fidx() const { return m_fidx; }
void fidx(uint32_t fidx) { m_fidx = fidx; }
uint32_t codeInc() const { return m_codeInc; }
const VNumRange& bitRange() const { return m_bitRange; }
const VNumRange& arrayRange() const { return m_arrayRange; }
VVarType varType() const { return m_varType; }
VBasicDTypeKwd declKwd() const { return m_declKwd; }
VDirection declDirection() const { return m_declDirection; }
};
class AstTraceInc final : public AstNodeStmt {
@@ -3150,14 +3232,14 @@ class AstTraceInc final : public AstNodeStmt {
private:
AstTraceDecl* m_declp; // Pointer to declaration
const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc
const bool m_full; // Is this a full vs incremental dump
const VTraceType m_traceType; // Is this a const/full/incremental dump
public:
AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0)
AstTraceInc(FileLine* fl, AstTraceDecl* declp, VTraceType traceType, uint32_t baseCode = 0)
: ASTGEN_SUPER_TraceInc(fl)
, m_declp{declp}
, m_baseCode{baseCode}
, m_full{full} {
, m_traceType{traceType} {
dtypeFrom(declp);
this->valuep(
declp->valuep()->cloneTree(true)); // TODO: maybe use reference to TraceDecl instead?
@@ -3174,35 +3256,35 @@ public:
int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; }
bool hasDType() const override { return true; }
bool same(const AstNode* samep) const override {
return declp() == static_cast<const AstTraceInc*>(samep)->declp();
return declp() == VN_DBG_AS(samep, TraceInc)->declp();
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isOutputter() const override { return true; }
bool isOutputter() override { return true; }
// but isPure() true
AstTraceDecl* declp() const { return m_declp; }
bool full() const { return m_full; }
VTraceType traceType() const { return m_traceType; }
uint32_t baseCode() const { return m_baseCode; }
};
class AstTracePopNamePrefix final : public AstNodeStmt {
const unsigned m_count; // How many levels to pop
class AstTracePopPrefix final : public AstNodeStmt {
public:
AstTracePopNamePrefix(FileLine* fl, unsigned count)
: ASTGEN_SUPER_TracePopNamePrefix(fl)
, m_count{count} {}
ASTGEN_MEMBERS_AstTracePopNamePrefix;
AstTracePopPrefix(FileLine* fl)
: ASTGEN_SUPER_TracePopPrefix(fl) {}
ASTGEN_MEMBERS_AstTracePopPrefix;
bool same(const AstNode* samep) const override { return false; }
unsigned count() const { return m_count; }
};
class AstTracePushNamePrefix final : public AstNodeStmt {
class AstTracePushPrefix final : public AstNodeStmt {
const string m_prefix; // Prefix to add to signal names
const VTracePrefixType m_prefixType; // Type of prefix being pushed
public:
AstTracePushNamePrefix(FileLine* fl, const string& prefix)
: ASTGEN_SUPER_TracePushNamePrefix(fl)
, m_prefix{prefix} {}
ASTGEN_MEMBERS_AstTracePushNamePrefix;
AstTracePushPrefix(FileLine* fl, const string& prefix, VTracePrefixType prefixType)
: ASTGEN_SUPER_TracePushPrefix(fl)
, m_prefix{prefix}
, m_prefixType{prefixType} {}
ASTGEN_MEMBERS_AstTracePushPrefix;
bool same(const AstNode* samep) const override { return false; }
string prefix() const { return m_prefix; }
VTracePrefixType prefixType() const { return m_prefixType; }
};
class AstUCStmt final : public AstNodeStmt {
// User $c statement
@@ -3215,8 +3297,8 @@ public:
ASTGEN_MEMBERS_AstUCStmt;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; }
bool isOutputter() const override { return true; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstWait final : public AstNodeStmt {
@@ -3238,6 +3320,7 @@ public:
explicit AstWaitFork(FileLine* fl)
: ASTGEN_SUPER_WaitFork(fl) {}
ASTGEN_MEMBERS_AstWaitFork;
bool isTimingControl() const override { return true; }
};
class AstWhile final : public AstNodeStmt {
// @astgen op1 := precondsp : List[AstNode]
@@ -3384,7 +3467,7 @@ public:
ASTGEN_MEMBERS_AstCase;
string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; }
bool same(const AstNode* samep) const override {
return m_casex == static_cast<const AstCase*>(samep)->m_casex;
return m_casex == VN_DBG_AS(samep, Case)->m_casex;
}
bool casex() const { return m_casex == VCaseType::CT_CASEX; }
bool casez() const { return m_casex == VCaseType::CT_CASEZ; }
@@ -3506,48 +3589,48 @@ public:
AstScCtor(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScCtor(fl, textp) {}
ASTGEN_MEMBERS_AstScCtor;
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScDtor final : public AstNodeText {
public:
AstScDtor(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScDtor(fl, textp) {}
ASTGEN_MEMBERS_AstScDtor;
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScHdr final : public AstNodeText {
public:
AstScHdr(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScHdr(fl, textp) {}
ASTGEN_MEMBERS_AstScHdr;
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScImp final : public AstNodeText {
public:
AstScImp(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScImp(fl, textp) {}
ASTGEN_MEMBERS_AstScImp;
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScImpHdr final : public AstNodeText {
public:
AstScImpHdr(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScImpHdr(fl, textp) {}
ASTGEN_MEMBERS_AstScImpHdr;
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScInt final : public AstNodeText {
public:
AstScInt(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScInt(fl, textp) {}
ASTGEN_MEMBERS_AstScInt;
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() const override { return true; }
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
// === AstNodeSimpleText ===
+242 -77
View File
@@ -14,13 +14,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstMT.h"
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include "V3File.h"
#include "V3Global.h"
#include "V3Graph.h"
#include "V3Hasher.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
@@ -50,6 +47,7 @@ AstIface* AstIfaceRefDType::ifaceViaCellp() const {
const char* AstNodeFTaskRef::broken() const {
BROKEN_RTN(m_taskp && !m_taskp->brokeExists());
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
@@ -60,12 +58,29 @@ void AstNodeFTaskRef::cloneRelink() {
}
}
bool AstNodeFTaskRef::isPure() const {
// TODO: For non-DPI functions we could traverse the AST of function's body to determine
// pureness.
return this->taskp() && this->taskp()->dpiImport() && this->taskp()->pure();
bool AstNodeFTaskRef::isPure() {
if (!this->taskp()) {
// The task isn't linked yet, so it's assumed that it is impure, but the value shouldn't be
// cached.
return false;
} else {
if (!m_purity.isCached()) m_purity.set(this->getPurityRecurse());
return m_purity.get();
}
}
bool AstNodeFTaskRef::getPurityRecurse() const {
AstNodeFTask* const taskp = this->taskp();
// Unlinked yet, so treat as impure
if (!taskp) return false;
// First compute the purity of arguments
for (AstNode* pinp = this->pinsp(); pinp; pinp = pinp->nextp()) {
if (!pinp->isPure()) return false;
}
return taskp->isPure();
}
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
const char* AstNodeVarRef::broken() const {
@@ -83,12 +98,6 @@ void AstNodeVarRef::cloneRelink() {
}
}
string AstNodeVarRef::selfPointerProtect(bool useSelfForThis) const {
const string& sp
= useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer();
return VIdProtect::protectWordsIf(sp, protect());
}
void AstAddrOfCFunc::cloneRelink() {
if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep();
}
@@ -126,14 +135,65 @@ const char* AstNodeCCall::broken() const {
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
return nullptr;
}
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
string AstCCall::selfPointerProtect(bool useSelfForThis) const {
const string& sp
= useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer();
return VIdProtect::protectWordsIf(sp, protect());
bool AstNodeCCall::isPure() { return funcp()->dpiPure(); }
bool AstNodeUniop::isPure() {
if (!m_purity.isCached()) m_purity.set(lhsp()->isPure());
return m_purity.get();
}
const char* AstNodeUniop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != lhsp()->isPure());
return nullptr;
}
bool AstNodeBiop::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
}
const char* AstNodeBiop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
bool AstNodeTriop::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
}
const char* AstNodeTriop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
bool AstNodePreSel::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
}
const char* AstNodePreSel::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
bool AstNodeQuadop::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
}
const char* AstNodeQuadop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
AstNodeExpr* elsep)
: AstNodeTriop{t, fl, condp, thenp, elsep} {
UASSERT_OBJ(thenp, this, "No thenp expression");
UASSERT_OBJ(elsep, this, "No elsep expression");
if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) {
// Get the most-deriving class type that both arguments can be casted to.
AstNodeDType* const commonClassTypep = getCommonClassTypep(thenp, elsep);
UASSERT_OBJ(commonClassTypep, this, "No common base class exists");
dtypep(commonClassTypep);
} else {
dtypeFrom(thenp);
}
}
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
if (lhs.isNeqZero()) {
@@ -213,12 +273,10 @@ int AstBasicDType::widthTotalBytes() const {
}
bool AstBasicDType::same(const AstNode* samep) const {
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
if (!rangep() && !sp->rangep() && m == sp->m) {
return true;
} else {
return m == sp->m && rangep() && rangep()->sameTree(sp->rangep());
}
const AstBasicDType* const sp = VN_DBG_AS(samep, BasicDType);
if (!(m == sp->m) || numeric() != sp->numeric()) return false;
if (!rangep() && !sp->rangep()) return true;
return rangep() && rangep()->sameTree(sp->rangep());
}
int AstNodeUOrStructDType::widthTotalBytes() const {
@@ -267,17 +325,17 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* r
}
}
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name)
: ASTGEN_SUPER_ExecGraph(fileline)
, m_depGraphp{new V3Graph}
, m_name{name} {}
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name) VL_MT_DISABLED
: ASTGEN_SUPER_ExecGraph(fileline),
m_depGraphp{new V3Graph},
m_name{name} {}
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp,
AstNodeExpr* rhsp) {
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp};
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp};
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTreePure(true), lhsp};
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTreePure(true), rhsp};
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
return new AstAnd{fileline(), ap, bp};
@@ -385,7 +443,8 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
if (isStatic() && namespc.empty()) ostatic = "static ";
const bool isRef = isDpiOpenArray()
|| (forFunc && (isWritable() || direction().isRefOrConstRef())) || asRef;
|| (forFunc && (isWritable() || this->isRef() || this->isConstRef()))
|| asRef;
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
@@ -407,6 +466,8 @@ string AstVar::vlEnumType() const {
return "VLVT_PTR";
} else if (strtype) {
arg += "VLVT_STRING";
} else if (isDouble()) {
arg += "VLVT_REAL";
} else if (widthMin() <= 8) {
arg += "VLVT_UINT8";
} else if (widthMin() <= 16) {
@@ -499,7 +560,7 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
if (forReturn) named = false;
string arg;
if (isWide() && isReadOnly()) arg += "const ";
const bool isRef = !forReturn && (isWritable() || direction().isRefOrConstRef());
const bool isRef = !forReturn && (isWritable() || this->isRef() || this->isConstRef());
if (VN_IS(dtypeSkipRefp(), BasicDType) && !dtypeSkipRefp()->isDouble()
&& !dtypeSkipRefp()->isString()) {
// Backward compatible type declaration
@@ -627,13 +688,14 @@ string AstVar::dpiTmpVarType(const string& varName) const {
string AstVar::scType() const {
if (isScBigUint()) {
return (string{"sc_biguint<"} + cvtToStr(widthMin())
return (string{"sc_dt::sc_biguint<"} + cvtToStr(widthMin())
+ "> "); // Keep the space so don't get >>
} else if (isScUint()) {
return (string{"sc_uint<"} + cvtToStr(widthMin())
return (string{"sc_dt::sc_uint<"} + cvtToStr(widthMin())
+ "> "); // Keep the space so don't get >>
} else if (isScBv()) {
return (string{"sc_bv<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
return (string{"sc_dt::sc_bv<"} + cvtToStr(widthMin())
+ "> "); // Keep the space so don't get >>
} else if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_IDATASIZE) {
@@ -709,6 +771,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
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* const adtypep = VN_CAST(dtypep, CDType)) {
info.m_type = adtypep->name();
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlAssocArray<std::string, " + sub.m_type + ">";
@@ -766,7 +830,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
} else if (bdtypep->isProcessRef()) {
info.m_type = "VlProcessRef";
} else if (bdtypep->isEvent()) {
info.m_type = "VlEvent";
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
@@ -1114,13 +1178,10 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange()};
DetailedMap& mapr = m_detailedMap;
const auto it = mapr.find(key);
if (it != mapr.end()) return it->second;
mapr.emplace(key, nodep);
nodep->generic(true);
auto pair = m_detailedMap.emplace(key, nodep);
if (pair.second) nodep->generic(true);
// No addTypesp; the upper function that called new() is responsible for adding
return nodep;
return pair.first->second;
}
AstConstPool::AstConstPool(FileLine* fl)
@@ -1318,7 +1379,6 @@ void AstNode::dump(std::ostream& str) const {
if (user2p()) str << " u2=" << nodeAddr(user2p());
if (user3p()) str << " u3=" << nodeAddr(user3p());
if (user4p()) str << " u4=" << nodeAddr(user4p());
if (user5p()) str << " u5=" << nodeAddr(user5p());
if (hasDType()) {
// Final @ so less likely to by accident read it as a nodep
if (dtypep() == this) {
@@ -1392,7 +1452,7 @@ const char* AstCell::broken() const {
void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << origModName();
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
str << " [scopep=" << nodeAddr(scopep()) << "]";
}
const char* AstCellInline::broken() const {
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
@@ -1522,6 +1582,12 @@ const char* AstEnumItemRef::broken() const {
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
return nullptr;
}
void AstEnumItemRef::cloneRelink() {
if (m_itemp->clonep()) m_itemp = m_itemp->clonep();
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
m_classOrPackagep = m_classOrPackagep->clonep();
}
}
void AstIfaceRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (cellName() != "") str << " cell=" << cellName();
@@ -1555,7 +1621,7 @@ void AstInitArray::dump(std::ostream& str) const {
str << " ...";
break;
}
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
str << " [" << itr.first << "]=" << nodeAddr(itr.second);
}
}
const char* AstInitArray::broken() const {
@@ -1571,13 +1637,13 @@ void AstInitArray::cloneRelink() {
}
}
void AstInitArray::addIndexValuep(uint64_t index, AstNodeExpr* newp) {
const auto it = m_map.find(index);
if (it != m_map.end()) {
it->second->valuep(newp);
} else {
const auto pair = m_map.emplace(index, nullptr);
if (pair.second) {
AstInitItem* const itemp = new AstInitItem{fileline(), newp};
m_map.emplace(index, itemp);
pair.first->second = itemp;
addInitsp(itemp);
} else {
pair.first->second->valuep(newp);
}
}
AstNodeExpr* AstInitArray::getIndexValuep(uint64_t index) const {
@@ -1619,10 +1685,6 @@ void AstJumpLabel::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstLogOr::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (sideEffect()) str << " [SIDE]";
}
void AstMemberDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
@@ -1637,8 +1699,8 @@ AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
}
bool AstMemberSel::same(const AstNode* samep) const {
const AstMemberSel* const sp = static_cast<const AstMemberSel*>(samep);
return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp())
const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
return sp != nullptr && access() == sp->access() && fromp()->isSame(sp->fromp())
&& name() == sp->name() && varp()->same(sp->varp());
}
@@ -1873,6 +1935,8 @@ const char* AstNetlist::broken() const {
BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists());
BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists());
BROKEN_RTN(m_delaySchedulerp && !m_delaySchedulerp->brokeExists());
BROKEN_RTN(m_nbaEventp && !m_nbaEventp->brokeExists());
BROKEN_RTN(m_nbaEventTriggerp && !m_nbaEventTriggerp->brokeExists());
return nullptr;
}
AstPackage* AstNetlist::dollarUnitPkgAddp() {
@@ -1971,7 +2035,7 @@ void AstTypeTable::dump(std::ostream& str) const {
}
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
str << "[assoc-" << nodeAddr(keyDTypep()) << "]";
}
string AstAssocArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
@@ -1995,13 +2059,14 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
str << "[*]";
}
bool AstWildcardArrayDType::same(const AstNode* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstWildcardArrayDType::similarDType(const AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
if (type() != samep->type()) return false;
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
return asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
void AstSampleQueueDType::dumpSmall(std::ostream& str) const {
@@ -2013,13 +2078,14 @@ void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
str << "[]";
}
bool AstUnsizedArrayDType::same(const AstNode* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstUnsizedArrayDType::similarDType(const AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
if (type() != samep->type()) return false;
const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType);
return asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
}
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
@@ -2037,7 +2103,7 @@ void AstStreamDType::dumpSmall(std::ostream& str) const {
void AstVarScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isTrace()) str << " [T]";
if (scopep()) str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
if (scopep()) str << " [scopep=" << nodeAddr(scopep()) << "]";
if (varp()) {
str << " -> ";
varp()->dump(str);
@@ -2046,7 +2112,7 @@ void AstVarScope::dump(std::ostream& str) const {
}
}
bool AstVarScope::same(const AstNode* samep) const {
const AstVarScope* const asamep = static_cast<const AstVarScope*>(samep);
const AstVarScope* const asamep = VN_DBG_AS(samep, VarScope);
return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep());
}
void AstNodeVarRef::dump(std::ostream& str) const {
@@ -2080,9 +2146,7 @@ const char* AstVarRef::broken() const {
BROKEN_RTN(!varp());
return AstNodeVarRef::broken();
}
bool AstVarRef::same(const AstNode* samep) const {
return same(static_cast<const AstVarRef*>(samep));
}
bool AstVarRef::same(const AstNode* samep) const { return same(VN_DBG_AS(samep, VarRef)); }
int AstVarRef::instrCount() const {
// Account for the target of hard-coded method calls as just an address computation
if (const AstCMethodHard* const callp = VN_CAST(backp(), CMethodHard)) {
@@ -2101,8 +2165,14 @@ void AstVar::dump(std::ostream& str) const {
if (isPulldown()) str << " [PULLDOWN]";
if (isUsedClock()) str << " [CLK]";
if (isSigPublic()) str << " [P]";
if (isInternal()) str << " [INTERNAL]";
if (isLatched()) str << " [LATCHED]";
if (isUsedLoopIdx()) str << " [LOOP]";
if (isRandC()) {
str << " [RANDC]";
} else if (isRand()) {
str << " [RAND]";
}
if (noReset()) str << " [!RST]";
if (attrIsolateAssign()) str << " [aISO]";
if (attrFileDescr()) str << " [aFD]";
@@ -2117,17 +2187,17 @@ void AstVar::dump(std::ostream& str) const {
str << " " << varType();
}
bool AstVar::same(const AstNode* samep) const {
const AstVar* const asamep = static_cast<const AstVar*>(samep);
const AstVar* const asamep = VN_DBG_AS(samep, Var);
return name() == asamep->name() && varType() == asamep->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()) << "]";
str << " [abovep=" << nodeAddr(aboveScopep()) << "]";
str << " [cellp=" << nodeAddr(aboveCellp()) << "]";
str << " [modp=" << nodeAddr(modp()) << "]";
}
bool AstScope::same(const AstNode* samep) const {
const AstScope* const asamep = static_cast<const AstScope*>(samep);
const AstScope* const asamep = VN_DBG_AS(samep, Scope);
return name() == asamep->name()
&& ((!aboveScopep() && !asamep->aboveScopep())
|| (aboveScopep() && asamep->aboveScopep()
@@ -2215,6 +2285,31 @@ void AstNodeFTask::dump(std::ostream& str) const {
if (taskPublic()) str << " [PUBLIC]";
if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]";
}
bool AstNodeFTask::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
}
const char* AstNodeFTask::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
bool AstNodeFTask::getPurityRecurse() const {
if (this->dpiImport()) return this->dpiPure();
// Check the list of statements if it contains any impure statement
// or any write reference to a variable that isn't an automatic function local.
for (AstNode* stmtp = this->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (const AstVar* const varp = VN_CAST(stmtp, Var)) {
if (varp->isInoutish() || varp->isRef()) return false;
}
if (!stmtp->isPure()) return false;
if (stmtp->exists([](const AstNodeVarRef* const varrefp) {
return (!varrefp->varp()->isFuncLocal() || varrefp->varp()->lifetime().isStatic())
&& varrefp->access().isWriteOrRW();
}))
return false;
}
return true;
}
void AstNodeBlock::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (unnamed()) str << " [UNNAMED]";
@@ -2224,6 +2319,7 @@ void AstBegin::dump(std::ostream& str) const {
if (generate()) str << " [GEN]";
if (genforp()) str << " [GENFOR]";
if (implied()) str << " [IMPLIED]";
if (needProcess()) str << " [NPRC]";
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
@@ -2284,7 +2380,7 @@ void AstCFile::dump(std::ostream& str) const {
void AstCFunc::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (slow()) str << " [SLOW]";
if (pure()) str << " [PURE]";
if (dpiPure()) str << " [DPIPURE]";
if (isStatic()) str << " [STATIC]";
if (dpiExportDispatcher()) str << " [DPIED]";
if (dpiExportImpl()) str << " [DPIEI]";
@@ -2314,7 +2410,7 @@ void AstCAwait::dump(std::ostream& str) const {
int AstCMethodHard::instrCount() const {
if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) {
// TODO: add a more structured description of library methods, rather than using string
// matching. See #3715.
// matching. See issue #3715.
if (basicp->isTriggerVec() && m_name == "word") {
// This is an important special case for scheduling so we compute it precisely,
// it is simply a load.
@@ -2323,6 +2419,75 @@ int AstCMethodHard::instrCount() const {
}
return 0;
}
void AstCMethodHard::setPurity() {
static const std::map<std::string, bool> isPureMethod{{"andNot", false},
{"any", true},
{"anyTriggered", false},
{"assign", false},
{"at", true},
{"atBack", true},
{"awaitingCurrentTime", true},
{"clear", false},
{"clearFired", false},
{"commit", false},
{"delay", false},
{"done", false},
{"erase", false},
{"evaluate", false},
{"evaluation", false},
{"exists", true},
{"find", true},
{"find_first", true},
{"find_first_index", true},
{"find_index", true},
{"find_last", true},
{"find_last_index", true},
{"fire", false},
{"first", false},
{"init", false},
{"insert", false},
{"isFired", true},
{"isTriggered", true},
{"join", false},
{"last", false},
{"max", true},
{"min", true},
{"neq", true},
{"next", false},
{"pop", false},
{"pop_back", false},
{"pop_front", false},
{"prev", false},
{"push", false},
{"push_back", false},
{"push_front", false},
{"r_and", true},
{"r_or", true},
{"r_product", true},
{"r_sum", true},
{"r_xor", true},
{"renew", false},
{"renew_copy", false},
{"resume", false},
{"reverse", false},
{"rsort", false},
{"set", false},
{"shuffle", false},
{"size", true},
{"slice", true},
{"sliceBackBack", true},
{"sliceFrontBack", true},
{"sort", false},
{"thisOr", false},
{"trigger", false},
{"unique", true},
{"unique_index", true},
{"word", true}};
auto isPureIt = isPureMethod.find(name());
UASSERT_OBJ(isPureIt != isPureMethod.end(), this, "Unknown purity of method " + name());
m_pure = isPureIt->second;
}
const char* AstCFunc::broken() const {
BROKEN_RTN((m_scopep && !m_scopep->brokeExists()));
return nullptr;
+9 -21
View File
@@ -29,11 +29,11 @@
template <class T_Node, class T_Data, int T_UserN>
class AstUserAllocatorBase VL_NOT_FINAL {
static_assert(1 <= T_UserN && T_UserN <= 5, "Wrong user pointer number");
static_assert(1 <= T_UserN && T_UserN <= 4, "Wrong user pointer number");
static_assert(std::is_base_of<AstNode, T_Node>::value, "T_Node must be an AstNode type");
private:
std::vector<T_Data*> m_allocated;
std::deque<T_Data> m_allocated;
T_Data* getUserp(const T_Node* nodep) const {
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
@@ -45,11 +45,8 @@ private:
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
const VNUser user = nodep->user3u();
return user.to<T_Data*>();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
const VNUser user = nodep->user4u();
return user.to<T_Data*>();
} else {
const VNUser user = nodep->user5u();
const VNUser user = nodep->user4u();
return user.to<T_Data*>();
}
}
@@ -61,10 +58,8 @@ private:
nodep->user2u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
nodep->user3u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
nodep->user4u(VNUser{userp});
} else {
nodep->user5u(VNUser{userp});
nodep->user4u(VNUser{userp});
}
}
@@ -76,18 +71,11 @@ protected:
VNUser2InUse::check();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
VNUser3InUse::check();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
VNUser4InUse::check();
} else {
VNUser5InUse::check();
VNUser4InUse::check();
}
}
virtual ~AstUserAllocatorBase() {
// Delete all allocated data structures
for (T_Data* const p : m_allocated) { delete p; }
}
VL_UNCOPYABLE(AstUserAllocatorBase);
public:
@@ -96,8 +84,8 @@ public:
T_Data& operator()(T_Node* nodep, Args&&... args) {
T_Data* userp = getUserp(nodep);
if (!userp) {
userp = new T_Data{std::forward<Args>(args)...};
m_allocated.push_back(userp);
m_allocated.emplace_back(std::forward<Args>(args)...);
userp = &m_allocated.back();
setUserp(nodep, userp);
}
return *userp;
@@ -112,6 +100,8 @@ public:
// Get a pointer to the user data if exists, otherwise nullptr
T_Data* tryGet(const T_Node* nodep) { return getUserp(nodep); }
void clear() { m_allocated.clear(); }
};
// User pointer allocator classes. T_Node is the type of node the allocator should be applied to
@@ -125,7 +115,5 @@ template <class T_Node, class T_Data>
class AstUser3Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 3> {};
template <class T_Node, class T_Data>
class AstUser4Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 4> {};
template <class T_Node, class T_Data>
class AstUser5Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 5> {};
#endif // Guard
+1 -7
View File
@@ -26,16 +26,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Begin.h"
#include "V3Ast.h"
#include "V3Global.h"
#include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Begin final {
public:
static void debeginAll(AstNetlist* nodep);
static void debeginAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+1 -7
View File
@@ -23,16 +23,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Branch.h"
#include "V3Ast.h"
#include "V3Global.h"
#include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
+3 -1
View File
@@ -20,6 +20,8 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
@@ -27,7 +29,7 @@ class AstNetlist;
class V3Branch final {
public:
// CONSTRUCTORS
static void branchAll(AstNetlist* nodep);
static void branchAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+32 -21
View File
@@ -22,18 +22,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstMT.h"
#include "V3Broken.h"
#include "V3Ast.h"
#include "V3Global.h"
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
#include "V3AstConstOnly.h"
#include <unordered_map>
#include <unordered_set>
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -147,22 +139,25 @@ bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinka
// Check every node in tree
class BrokenCheckVisitor final : public VNVisitorConst {
bool m_inScope = false; // Under AstScope
// Constants for marking we are under/not under a node
const uint8_t m_brokenCntCurrentNotUnder = s_brokenCntGlobal.get(); // Top bit is clear
const uint8_t m_brokenCntCurrentUnder = m_brokenCntCurrentNotUnder | 0x80; // Top bit is set
// Current CFunc, if any
const AstCFunc* m_cfuncp = nullptr;
// STATE - across all visitors
// All local variables declared in current function
std::unordered_set<const AstVar*> m_localVars;
std::set<const AstVar*> m_localVars;
// Variable references in current function that do not reference an in-scope local
std::unordered_map<const AstVar*, const AstNodeVarRef*> m_suspectRefs;
std::map<const AstVar*, const AstNodeVarRef*> m_suspectRefs;
// Local variables declared in the scope of the current statement
std::vector<std::unordered_set<const AstVar*>> m_localsStack;
// STATE - for current visit position (use VL_RESTORER)
const AstCFunc* m_cfuncp = nullptr; // Current CFunc, if any
bool m_inScope = false; // Under AstScope
std::set<std::string> m_cFuncNames; // CFunc by name in current class/module
private:
// METHODS
static void checkWidthMin(const AstNode* nodep) {
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
@@ -220,6 +215,7 @@ private:
}
return false;
}
// VISITORS
void visit(AstNodeAssign* nodep) override {
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
@@ -235,10 +231,20 @@ private:
}
void visit(AstScope* nodep) override {
VL_RESTORER(m_inScope);
{
m_inScope = true;
processAndIterate(nodep);
}
m_inScope = true;
VL_RESTORER(m_cFuncNames);
m_cFuncNames.clear();
processAndIterate(nodep);
}
void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_cFuncNames);
m_cFuncNames.clear();
processAndIterate(nodep);
}
void visit(AstNodeUOrStructDType* nodep) override {
VL_RESTORER(m_cFuncNames);
m_cFuncNames.clear();
processAndIterate(nodep);
}
void visit(AstNodeVarRef* nodep) override {
processAndIterate(nodep);
@@ -260,12 +266,19 @@ private:
}
void visit(AstCFunc* nodep) override {
UASSERT_OBJ(!m_cfuncp, nodep, "Nested AstCFunc");
VL_RESTORER(m_cfuncp);
m_cfuncp = nodep;
m_localVars.clear();
m_suspectRefs.clear();
m_localsStack.clear();
pushLocalScope();
// Check for duplicate names, otherwise linker might just ignore them
string nameArgs = nodep->name();
if (!nodep->argTypes().empty()) nameArgs += "(" + nodep->argTypes() + ")";
UASSERT_OBJ(m_cFuncNames.emplace(nameArgs).second, nodep,
"Duplicate cfunc name: '" << nameArgs << "'");
processAndIterate(nodep);
// Check suspect references are all to non-locals
@@ -273,8 +286,6 @@ private:
UASSERT_OBJ(m_localVars.count(pair.first) == 0, pair.second,
"Local variable not in scope where referenced: " << pair.first);
}
m_cfuncp = nullptr;
}
void visit(AstNodeIf* nodep) override {
// Each branch is a separate local variable scope
+3 -6
View File
@@ -24,15 +24,12 @@
// This transformation honors outputSplitCFuncs.
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3CCtors.h"
#include "V3EmitCBase.h"
#include "V3Global.h"
#include <algorithm>
#include <list>
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -117,7 +114,7 @@ public:
callp->argTypes("vlSymsp");
} else {
if (m_type.isCoverage()) callp->argTypes("first");
callp->selfPointer("this");
callp->selfPointer(VSelfPointerText{VSelfPointerText::This()});
}
rootFuncp->addStmtsp(callp->makeStmt());
}
@@ -229,7 +226,7 @@ void V3CCtors::evalAsserts() {
// if (signal & CONST(upper_non_clean_mask)) { fail; }
AstVarRef* const vrefp
= new AstVarRef{varp->fileline(), varp, VAccess::READ};
vrefp->selfPointer("this");
vrefp->selfPointer(VSelfPointerText{VSelfPointerText::This()});
AstNodeExpr* newp = vrefp;
if (varp->isWide()) {
newp = new AstWordSel{
+4 -2
View File
@@ -20,14 +20,16 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
//============================================================================
class V3CCtors final {
public:
static void cctorsAll();
static void cctorsAll() VL_MT_DISABLED;
private:
static void evalAsserts();
static void evalAsserts() VL_MT_DISABLED;
};
#endif // Guard
+17 -38
View File
@@ -22,16 +22,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3CUse.h"
#include "V3Ast.h"
#include "V3Global.h"
#include <set>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
@@ -46,52 +40,31 @@ class CUseVisitor final : public VNVisitor {
// MEMBERS
AstNodeModule* const m_modp; // Current module
std::set<std::pair<VUseType, std::string>> m_didUse; // What we already used
bool m_dtypesImplOnly = false;
std::map<std::string, std::pair<FileLine*, VUseType>> m_didUse; // What we already used
// METHODS
void addNewUse(AstNode* nodep, VUseType useType, const string& name) {
if (m_dtypesImplOnly
&& (useType == VUseType::INT_INCLUDE || useType == VUseType::INT_FWD_CLASS))
return;
if (m_didUse.emplace(useType, name).second) {
AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name};
m_modp->addStmtsp(newp);
UINFO(8, "Insert " << newp << endl);
auto e = m_didUse.emplace(name, std::make_pair(nodep->fileline(), useType));
if (e.second || ((e.first->second.second & useType) != useType)) {
e.first->second.second = e.first->second.second | useType;
}
}
// VISITORS
void visit(AstClassRefDType* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
}
void visit(AstCFunc* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (nodep->user1SetOnce()) return;
iterateAndNextNull(nodep->argsp());
{
VL_RESTORER(m_dtypesImplOnly);
m_dtypesImplOnly = true;
iterateAndNextNull(nodep->initsp());
iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->finalsp());
}
iterateAndNextNull(nodep->stmtsp());
}
void visit(AstCCall* nodep) override { return; }
void visit(AstCReturn* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (m_dtypesImplOnly) {
for (AstNode* exprp = nodep->op1p(); exprp; exprp = exprp->nextp()) {
if (exprp->dtypep()) iterate(exprp->dtypep());
}
} else {
iterateChildren(nodep);
}
UASSERT(!nodep->user1SetOnce(), "Visited same return twice.");
iterate(nodep->lhsp()->dtypep());
}
void visit(AstNodeDType* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep());
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
@@ -106,7 +79,7 @@ class CUseVisitor final : public VNVisitor {
}
void visit(AstNode* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
if (nodep->dtypep() && !nodep->dtypep()->user1()) iterate(nodep->dtypep());
if (nodep->dtypep()) iterate(nodep->dtypep());
iterateChildren(nodep);
}
void visit(AstCell* nodep) override {
@@ -121,6 +94,12 @@ public:
explicit CUseVisitor(AstNodeModule* modp)
: m_modp(modp) {
iterate(modp);
for (auto& used : m_didUse) {
AstCUse* const newp = new AstCUse{used.second.first, used.second.second, used.first};
m_modp->addStmtsp(newp);
UINFO(8, "Insert " << newp << endl);
}
}
~CUseVisitor() override = default;
VL_UNCOPYABLE(CUseVisitor);
+3 -1
View File
@@ -20,11 +20,13 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
//============================================================================
class V3CUse final {
public:
static void cUseAll();
static void cUseAll() VL_MT_DISABLED;
};
#endif // Guard
+90 -52
View File
@@ -34,17 +34,12 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Case.h"
#include "V3Ast.h"
#include "V3Global.h"
#include "V3Stats.h"
#include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
@@ -139,32 +134,42 @@ private:
std::array<AstNode*, 1 << CASE_OVERLAP_WIDTH> m_valueItem;
// METHODS
bool caseIsEnumComplete(AstCase* nodep, uint32_t numCases) {
// Return true if case is across an enum, and every value in the case
// statement corresponds to one of the enum values
if (!nodep->uniquePragma() && !nodep->unique0Pragma()) return false;
AstEnumDType* const enumDtp
//! Determine whether we should check case items are complete
//! @return Enum's dtype if should check, nullptr if shouldn't
const AstEnumDType* getEnumCompletionCheckDType(const AstCase* const nodep) {
if (!nodep->uniquePragma() && !nodep->unique0Pragma()) return nullptr;
const AstEnumDType* const enumDtp
= VN_CAST(nodep->exprp()->dtypep()->skipRefToEnump(), EnumDType);
if (!enumDtp) return false; // Case isn't enum
AstBasicDType* const basicp = enumDtp->subDTypep()->basicp();
if (!basicp) return false; // Not simple type (perhaps IEEE illegal)
if (basicp->width() > 32) return false;
// Find all case values into a set
std::set<uint32_t> caseSet;
for (uint32_t i = 0; i < numCases; ++i) { // All case items
if (m_valueItem[i]) caseSet.emplace(i);
}
// Find all enum values into a set
std::set<uint32_t> enumSet;
for (AstEnumItem* itemp = enumDtp->itemsp(); itemp;
if (!enumDtp) return nullptr; // Case isn't enum
const AstBasicDType* const basicp = enumDtp->subDTypep()->basicp();
if (!basicp) return nullptr; // Not simple type (perhaps IEEE illegal)
if (basicp->width() > 32) return nullptr;
return enumDtp;
}
//! @return True if case items are complete, false if there are uncovered enums
bool checkCaseEnumComplete(const AstCase* const nodep, const AstEnumDType* const dtype) {
const uint32_t numCases = 1UL << m_caseWidth;
for (AstEnumItem* itemp = dtype->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), EnumItem)) {
AstConst* const econstp = VN_AS(itemp->valuep(), Const);
const uint32_t val = econstp->toUInt();
// UINFO(9, "Complete enum item " << val << ": " << itemp << endl);
enumSet.emplace(val);
V3Number nummask{itemp, econstp->width()};
nummask.opBitsNonX(econstp->num());
const uint32_t mask = nummask.toUInt();
V3Number numval{itemp, econstp->width()};
numval.opBitsOne(econstp->num());
const uint32_t val = numval.toUInt();
for (uint32_t i = 0; i < numCases; ++i) {
if ((i & mask) == val) {
if (!m_valueItem[i]) {
nodep->v3warn(CASEINCOMPLETE, "Enum item " << itemp->prettyNameQ()
<< " not covered by case\n");
return false; // enum has uncovered value by case items
}
}
}
}
// If sets match, all covered
return (caseSet == enumSet);
return true; // enum is fully covered
}
bool isCaseTreeFast(AstCase* nodep) {
int width = 0;
@@ -193,6 +198,8 @@ private:
// We can cheat and use uint32_t's because we only support narrow case's
bool reportedOverlap = false;
bool reportedSubcase = false;
bool hasDefaultCase = false;
std::map<AstNode*, AstCaseItem*> caseItemMap; // case condition -> case item
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
@@ -202,6 +209,7 @@ private:
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
const bool isCondWildcard = iconstp->num().isAnyXZ();
V3Number nummask{itemp, iconstp->width()};
nummask.opBitsNonX(iconstp->num());
const uint32_t mask = nummask.toUInt();
@@ -210,16 +218,17 @@ private:
const uint32_t val = numval.toUInt();
uint32_t firstOverlap = 0;
bool foundOverlap = false;
AstNode* overlappedCondp = nullptr;
bool foundHit = false;
for (uint32_t i = 0; i < numCases; ++i) {
if ((i & mask) == val) {
if (!m_valueItem[i]) {
m_valueItem[i] = itemp;
m_valueItem[i] = icondp;
caseItemMap[icondp] = itemp;
foundHit = true;
} else if (!foundOverlap) {
} else if (!overlappedCondp) {
firstOverlap = i;
foundOverlap = true;
overlappedCondp = m_valueItem[i];
m_caseNoOverlapsAllCovered = false;
}
}
@@ -227,9 +236,19 @@ private:
if (!nodep->priorityPragma()) {
// If this case statement doesn't have the priority
// keyword, we want to warn on any overlap.
if (!reportedOverlap && foundOverlap) {
icondp->v3warn(CASEOVERLAP, "Case values overlap (example pattern 0x"
<< std::hex << firstOverlap << ")");
if (!reportedOverlap && overlappedCondp) {
std::ostringstream examplePattern;
if (isCondWildcard) {
examplePattern << " (example pattern 0x" << std::hex
<< firstOverlap << ")";
}
icondp->v3warn(CASEOVERLAP,
"Case conditions overlap"
<< examplePattern.str() << "\n"
<< icondp->warnContextPrimary() << '\n'
<< overlappedCondp->warnOther()
<< "... Location of overlapping condition\n"
<< overlappedCondp->warnContextSecondary());
reportedOverlap = true;
}
} else {
@@ -240,7 +259,11 @@ private:
if (!reportedSubcase && !foundHit) {
icondp->v3warn(CASEOVERLAP,
"Case item ignored: every matching value is covered "
"by an earlier item");
"by an earlier condition\n"
<< icondp->warnContextPrimary() << '\n'
<< overlappedCondp->warnOther()
<< "... Location of previous condition\n"
<< overlappedCondp->warnContextPrimary());
reportedSubcase = true;
}
}
@@ -251,17 +274,28 @@ private:
for (uint32_t i = 0; i < numCases; ++i) {
if (!m_valueItem[i]) m_valueItem[i] = itemp;
}
caseItemMap[itemp] = itemp;
hasDefaultCase = true;
}
}
if (!caseIsEnumComplete(nodep, numCases)) {
for (uint32_t i = 0; i < numCases; ++i) {
if (!m_valueItem[i]) {
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered "
"(example pattern 0x"
<< std::hex << i << ")");
if (!hasDefaultCase) {
const AstEnumDType* const dtype = getEnumCompletionCheckDType(nodep);
if (dtype) {
if (!checkCaseEnumComplete(nodep, dtype)) {
// checkCaseEnumComplete has already warned of incompletion
m_caseNoOverlapsAllCovered = false;
return false;
}
} else {
for (uint32_t i = 0; i < numCases; ++i) {
if (!m_valueItem[i]) { // has uncovered case
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered "
"(example pattern 0x"
<< std::hex << i << ")");
m_caseNoOverlapsAllCovered = false;
return false;
}
}
}
}
@@ -274,8 +308,10 @@ private:
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch
for (uint32_t i = 0; i < numCases; ++i) {
if (AstCaseItem* const itemp = VN_AS(m_valueItem[i], CaseItem)) {
m_valueItem[i] = itemp->stmtsp();
if (AstNode* const condp = m_valueItem[i]) {
AstCaseItem* caseItemp = caseItemMap[condp];
UASSERT(caseItemp, "caseItemp should exist");
m_valueItem[i] = caseItemp->stmtsp();
}
}
return true; // All is fine
@@ -321,10 +357,10 @@ private:
// Alternate scheme if we ever do multiple bits at a time:
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTreePure(false),
// new AstConst(cexprp->fileline(), nummask));
AstNodeExpr* const and1p
= new AstSel{cexprp->fileline(), cexprp->cloneTree(false), msb, 1};
= new AstSel{cexprp->fileline(), cexprp->cloneTreePure(false), msb, 1};
AstNodeExpr* const eqp
= new AstNeq{cexprp->fileline(), new AstConst{cexprp->fileline(), 0}, and1p};
AstIf* const ifp = new AstIf{cexprp->fileline(), eqp, tree1p, tree0p};
@@ -409,7 +445,7 @@ private:
V3Number numval{itemp, iconstp->width()};
numval.opBitsOne(iconstp->num());
AstNodeExpr* const and1p
= new AstAnd{itemp->fileline(), cexprp->cloneTree(false),
= new AstAnd{itemp->fileline(), cexprp->cloneTreePure(false),
new AstConst{itemp->fileline(), nummask}};
AstNodeExpr* const and2p = new AstAnd{
itemp->fileline(), new AstConst{itemp->fileline(), numval},
@@ -419,7 +455,7 @@ private:
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can build CASEEQ(cexpr icond)
AstNodeExpr* const and1p = cexprp->cloneTree(false);
AstNodeExpr* const and1p = cexprp->cloneTreePure(false);
AstNodeExpr* const and2p = icondp;
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
}
@@ -461,7 +497,7 @@ private:
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = nullptr;
AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTree(true)};
AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTreePure(true)};
if (groupnextp) {
groupnextp->addElsesp(newp);
} else {
@@ -471,7 +507,7 @@ private:
} else { // Continue group, modify if condition to OR in this new condition
AstNodeExpr* const condp = groupnextp->condp()->unlinkFrBack();
groupnextp->condp(
new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTree(true)});
new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTreePure(true)});
}
}
{ // Make the new lower IF and attach in the tree
@@ -543,10 +579,12 @@ private:
}
}
//--------------------
void visit(AstNode* nodep) override {
if (VN_IS(nodep, Always)) m_alwaysp = nodep;
void visit(AstAlways* nodep) override {
VL_RESTORER(m_alwaysp)
m_alwaysp = nodep;
iterateChildren(nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
+4 -2
View File
@@ -20,6 +20,8 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
class AstNodeCase;
@@ -27,8 +29,8 @@ class AstNodeCase;
class V3Case final {
public:
static void caseAll(AstNetlist* nodep);
static void caseLint(AstNodeCase* nodep);
static void caseAll(AstNetlist* nodep) VL_MT_DISABLED;
static void caseLint(AstNodeCase* nodep) VL_MT_DISABLED;
};
#endif // Guard
+13 -10
View File
@@ -37,16 +37,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Cast.h"
#include "V3Ast.h"
#include "V3Global.h"
#include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
@@ -56,7 +50,7 @@ class CastVisitor final : public VNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstNode::user() // bool. Indicates node is of known size
// AstNode::user1() // bool. Indicates node is of known size
const VNUser1InUse m_inuser1;
// STATE
@@ -64,12 +58,12 @@ private:
// METHODS
void insertCast(AstNodeExpr* nodep, int needsize) { // We'll insert ABOVE passed node
UINFO(4, " NeedCast " << nodep << endl);
VNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
//
AstCCast* const castp
= new AstCCast{nodep->fileline(), nodep, needsize, nodep->widthMin()};
UINFO(4, " MadeCast " << static_cast<void*>(castp) << " for " << nodep << endl);
relinkHandle.relink(castp);
// if (debug() > 8) castp->dumpTree("- castins: ");
//
@@ -168,6 +162,15 @@ private:
ensureLower32Cast(nodep);
nodep->user1(1);
}
void visit(AstConsPackMember* nodep) override {
iterateChildren(nodep);
if (VN_IS(nodep->rhsp()->dtypep()->skipRefp(), BasicDType)) ensureCast(nodep->rhsp());
nodep->user1(1);
}
void visit(AstExprStmt* nodep) override {
iterateChildren(nodep);
nodep->user1(1);
}
void visit(AstNegate* nodep) override {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
@@ -187,7 +190,7 @@ private:
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, StructSel) && !VN_IS(backp, RedXor)
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()
&& !nodep->varp()->basicp()->isForkSync()
&& !nodep->varp()->basicp()->isProcessRef())
&& !nodep->varp()->basicp()->isProcessRef() && !nodep->varp()->basicp()->isEvent())
&& backp->width() && castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Cast final {
public:
static void castAll(AstNetlist* nodep);
static void castAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+10 -17
View File
@@ -20,13 +20,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Class.h"
#include "V3Ast.h"
#include "V3Global.h"
#include "V3UniqueNames.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -121,17 +118,17 @@ private:
void visit(AstVar* nodep) override {
iterateChildren(nodep);
if (m_packageScopep) {
if (m_ftaskp && m_ftaskp->lifetime().isStatic()) {
if (m_ftaskp && m_ftaskp->isStatic()) {
// Move later, or we wouldn't keep iterating the class
// We're really moving the VarScope but we might not
// have a pointer to it yet
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
m_toScopeMoves.emplace_back(nodep, m_packageScopep);
}
if (!m_ftaskp && nodep->lifetime().isStatic()) {
m_toPackageMoves.emplace_back(std::make_pair(nodep, m_classPackagep));
m_toPackageMoves.emplace_back(nodep, m_classPackagep);
// We're really moving the VarScope but we might not
// have a pointer to it yet
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
m_toScopeMoves.emplace_back(nodep, m_packageScopep);
}
}
}
@@ -146,8 +143,8 @@ private:
{
m_ftaskp = nodep;
iterateChildren(nodep);
if (m_packageScopep && nodep->lifetime().isStatic()) {
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
if (m_packageScopep && nodep->isStatic()) {
m_toScopeMoves.emplace_back(nodep, m_packageScopep);
}
}
}
@@ -156,7 +153,7 @@ private:
// Don't move now, or wouldn't keep iterating the class
// TODO move function statics only
// if (m_classScopep) {
// m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep));
// m_toScopeMoves.emplace_back(nodep, m_classScopep);
//}
}
void visit(AstCoverDecl* nodep) override {
@@ -167,16 +164,12 @@ private:
void visit(AstInitial* nodep) override {
// But not AstInitialAutomatic, which remains under the class
iterateChildren(nodep);
if (m_packageScopep) {
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
}
if (m_packageScopep) { m_toScopeMoves.emplace_back(nodep, m_packageScopep); }
}
void visit(AstInitialStatic* nodep) override {
// But not AstInitialAutomatic, which remains under the class
iterateChildren(nodep);
if (m_packageScopep) {
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
}
if (m_packageScopep) { m_toScopeMoves.emplace_back(nodep, m_packageScopep); }
}
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Class final {
public:
static void classAll(AstNetlist* nodep);
static void classAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+1 -7
View File
@@ -23,16 +23,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Clean.h"
#include "V3Ast.h"
#include "V3Global.h"
#include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Clean final {
public:
static void cleanAll(AstNetlist* nodep);
static void cleanAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+1 -6
View File
@@ -27,17 +27,12 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Clock.h"
#include "V3Ast.h"
#include "V3Global.h"
#include "V3Sched.h"
#include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Clock final {
public:
static void clockAll(AstNetlist* nodep);
static void clockAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+1 -4
View File
@@ -19,15 +19,12 @@
// Also drop empty CFuncs
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Combine.h"
#include "V3Ast.h"
#include "V3AstUserAllocator.h"
#include "V3DupFinder.h"
#include "V3Global.h"
#include "V3Stats.h"
#include <list>
+3 -1
View File
@@ -20,13 +20,15 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================
class V3Combine final {
public:
static void combineAll(AstNetlist* nodep);
static void combineAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+2 -5
View File
@@ -20,14 +20,11 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Common.h"
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include "V3Global.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -116,7 +113,7 @@ static void makeToStringMiddle(AstClass* nodep) {
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (const auto* const varp = VN_CAST(itemp, Var)) {
if (!varp->isParam()) {
if (!varp->isParam() && !varp->isInternal()) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";

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