Compare commits

...
477 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
Wilson Snyder f79749e7b2 Version bump 2023-08-06 10:39:35 -04:00
Krzysztof Bieganski 1a77030c9b Internals: Speedup to only typecheck node child getters in debug builds (#4394) 2023-08-05 03:24:00 -04:00
Wilson Snyder 817ade27fb Commentary: Changes update 2023-08-05 03:18:00 -04:00
Aleksander Kiryk 4afa14b612 Internals: Remove m_pkgp and m_classp from WidthVisitor (#4402) 2023-08-05 03:07:23 -04:00
Krzysztof Bieganski 9caa79a7ea Internals: Remove the name field from AstVarRef (#4395) 2023-08-03 02:52:52 -04:00
Wilson Snyder 446f21d2a0 Tests: Fix more missing internal code coverage 2023-07-27 06:53:43 -04:00
Wilson Snyder 06521f6cf1 Tests: Fix some missing coverage, and cleanup some error messages 2023-07-27 06:53:43 -04:00
github action 75336670d7 Apply 'make format' 2023-07-27 09:44:05 +00:00
Andrew Miloradovsky 106a9fe67f Fix config_build.h issues (#4380) (#4381) 2023-07-27 05:42:35 -04:00
Wilson Snyder a5eccc199b Commentary: Changes update 2023-07-27 04:01:28 -04:00
Vito Gamberini 837d9f9d77 Require CMake config minimum version 3.13 (#4389) (#4390) 2023-07-26 17:54:18 -04:00
Anthony Donlon 959387b69f Support property declaration with empty parentheses (#4313) (#4317) 2023-07-26 05:18:21 -04:00
Ryszard Rozak fd0703b8c8 Fix selects on unpacked structs (#4359) 2023-07-25 12:50:24 +02:00
Ryszard Rozak 3ff608b9cb Fix non-public methods with wide output (#4364) 2023-07-25 04:55:58 -04:00
Aleksander Kiryk edc0a0e982 Optimize V3Number::opAdd (#4385) 2023-07-24 17:09:27 -04:00
Aleksander Kiryk 1549ff9185 Support more types in wait (#4374) 2023-07-24 08:14:01 -04:00
Wilson Snyder 3454641244 Commentary: Add website badge 2023-07-21 04:11:15 -04:00
Wilson Snyder 5dedf25e3b Commentary: Add website badge 2023-07-21 04:07:29 -04:00
Wilson Snyder 7214c180ae Commentary: Add website badge 2023-07-21 04:06:22 -04:00
Ryszard Rozak aa0ef554b3 Fix order of evaluation of function calls in statements (#4375) 2023-07-21 03:29:11 -04:00
Ryszard Rozak a6015863d8 Support for static method calls as default values of function arguments (#4378) 2023-07-21 03:27:00 -04:00
Aleksander Kiryk 5a694ccb8a Fix assign to input var in methods (#4367) 2023-07-17 09:52:37 -04:00
Aleksander Kiryk f7d09c671a Fix VlProcess not found (#4368) 2023-07-17 09:52:07 -04:00
Ryszard Rozak 4de1b22672 Fix handling of super.new calls (#4366) 2023-07-17 13:30:42 +02:00
Krzysztof Boroński 4bdda3f240 Improve propagation of process requirement and decouple it from suspendability (#4321) 2023-07-14 17:12:02 +02:00
Ryszard Rozak ced1dfeffd Fix select operation on assoc array with wide keys (#4360) 2023-07-12 18:48:24 +02:00
Krzysztof Boroński 0774f825cf Internals: Use pointer to const nodes in V3MemberMap (#4353) 2023-07-12 11:36:24 -04:00
Ryszard Rozak 23fe5c1b93 Fix string concatenations (#4354) 2023-07-10 12:58:54 -04:00
Wilson Snyder bd4afeea69 Tests: Fix removing line numbers (#4352) 2023-07-10 08:17:49 -04:00
Julian Daube 3ee9b33f8a Fix cmake astgen for Rocky Linux 8.7 (#4343) 2023-07-09 06:02:21 +05:00
Wilson Snyder 5be0813893 Explicity reference std:: in header files (#4338). No functional change intended. 2023-07-08 13:20:40 -04:00
Wilson Snyder f94c1b32e5 Internals: Make V3MemberMap to remove member cache (#4350) 2023-07-08 12:40:27 -04:00
Wilson Snyder ff4923cf67 Internals: Make V3MemberMap towards removing member cache (#4350) 2023-07-08 12:27:50 -04:00
Krzysztof Bieganski 5788bc8048 Propagate class timescale to class package (#4348)
Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-07-07 17:27:33 +02:00
Wilson SnyderandAhmed El-Mahmoudy 5749662194 Documentation: Drop analytics_id unless VERILATOR_ANALYTICS_ID set (#4333)
Co-authored-by: Ahmed El-Mahmoudy <[email protected]>
2023-07-07 10:44:33 -04:00
Krzysztof Bieganski d5d1cc47e0 Fix multiple edge timing controls in class methods (#4318) (#4320) (#4344)
Multiple edge timing controls in class methods would cause compilation errors on
the generated C++ code. This is because the `SenExprBuilder` used for these
would get recreated per timing control, resulting in duplicate variable names.
The fix is to have a single `SenExprBuilder` per scope.
2023-07-07 08:19:49 -04:00
Ryszard Rozak da043ca16d Fix comparison of class objects (#4346) 2023-07-07 16:20:23 +05:00
Aleksander Kiryk 9aa90569bf Support string replication with variable (#4341) 2023-07-07 13:05:06 +05:00
Wilson Snyder 294d78e0e2 Backout unstable dbb35ab8 (#4318) (#4320) 2023-07-05 14:26:28 -04:00
Wilson Snyder 8182c3fe2c Tests: Fix t_vpi_unimpl exiting early with missed error 2023-07-05 14:12:22 -04:00
Wilson Snyder 6f7bc38088 Tests: Improve specparam verilog.y coverage 2023-07-05 14:11:55 -04:00
Wilson Snyder dcbc0ccfdc Commentary: Revert lost name. 2023-07-05 13:55:47 -04:00
Aleksander Kiryk 399319dc1c Fix wildcard referring types (#4336) (#4342) 2023-07-05 13:08:00 -04:00
Krzysztof Bieganski 35d6da391b Fix multiple edge timing controls in class methods (#4318) (#4320)
Multiple edge timing controls in class methods would cause compilation errors on the generated C++ code. This is because the `SenExprBuilder` used for these would get recreated per timing control, resulting in duplicate variable names. The fix is to have a single `SenExprBuilder` per scope.
2023-07-05 10:36:10 +00:00
Aleksander Kiryk fcbd7c87af Fix unexpected RefDType on assoc arrays (#4337) 2023-07-04 18:13:22 +05:00
Ryszard Rozak 97feba6898 Support locator methods with "with" on assoc arrays (#4335) 2023-07-04 18:11:15 +05:00
Aleksander Kiryk 9249ffdb84 Fix queue slicing (#4329) 2023-07-03 13:55:24 -04:00
أحمد المحمودي 71df9e3381 Commentary: Fix typo of concurrent (#4332) 2023-07-02 16:12:09 -04:00
Wilson Snyder 3c964147be Add MISINDENT lint warning for misleading indentation. 2023-07-01 10:45:25 -04:00
Wilson Snyder 54b4b6b378 Internals: Fix missing calls to cleanFileline. 2023-07-01 08:59:26 -04:00
Wilson Snyder cff37f0775 Add GENUNNAMED lint warning.
Also fix generate-for blocks with empty statements getting lost.
2023-07-01 08:31:53 -04:00
Wilson Snyder 8b1cc3b303 Commentary: Changes update 2023-07-01 07:35:58 -04:00
Mariusz Glebocki 65b6121186 Revert .gdbinit modified by accident. (#4330)
`test_regress/.gdbinit` has been modified in
d42f9c095b most likely by accident.
Restore its previous content.
2023-06-30 16:57:31 -04:00
Ryszard Rozak 3d30527860 Fix unique..with method on queues of class objects (#4328) 2023-06-30 17:04:09 +02:00
Ryszard Rozak 24a9f7c650 Fix references to members of results of static methods (#4327) 2023-06-30 13:23:34 +02:00
Ryszard Rozak 242f661644 Fix selects of static members (#4326) 2023-06-30 09:12:22 +02:00
Aleksander Kiryk 32019d2bc4 Fix state update for always processes (#4311) 2023-06-29 09:21:49 -04:00
Krzysztof Boroński b252bb048f Fix unhandled overloads in V3InstrCount (#4324) 2023-06-28 08:49:56 -04:00
Ryszard Rozak ba47c01a01 Fix implicit calls of base class constructors with optional arguments (#4319) 2023-06-27 16:08:38 +02:00
Ryszard Rozak 51266898ec Fix comparison of string parameters (#4308) 2023-06-27 10:40:45 +02:00
Wilson Snyder f9164ab0d2 Internals: Assert dtype comparison. No functional change intended. 2023-06-25 07:40:00 -04:00
Wilson Snyder c43e707f43 Internals: refactor sameTreeIter. No functional change. 2023-06-25 07:26:45 -04:00
Mariusz Glebocki 85b7f828b3 Internals: Use std::packaged_task as a job wrapper; add and use V3ThreadPool::ScopedExclusiveAccess (#4310).
* Add VL_ASSERT_CAPABILITY; add assumeLocked and pretendUnlock to V3Mutex.

* Pass jobs as template-arguments and use std::packaged_task.

* Add and use V3ThreadPool::ScopedExclusiveAccess.
2023-06-23 18:25:12 -04:00
Wilson Snyder 7005a65d32 Tests: Attempt 20.04 fix for (#b1aec9b) (#4307) 2023-06-23 07:09:07 -04:00
Wilson Snyder 776d4e6ac2 CI: Build 20.04 on pull requests 2023-06-23 07:08:04 -04:00
Jiamin Zhu 1c88c3083c Fix splitting coroutines (#4297) (#4307) 2023-06-23 06:01:38 -04:00
Ryszard Rozak 4522834f7a Fix duplicate fork names (#4295) 2023-06-22 06:51:53 -04:00
Ryszard Rozak 9ee5fd0585 Fix handling of ref types in initial values of type parameters (#4304) 2023-06-20 14:10:07 -04:00
Wilson Snyder 63b2dbb827 Fix error when multiple duplicate DPI exports (#4301). 2023-06-20 06:26:46 -04:00
Wilson Snyder 5bee8ef15b Remove long deprecated verilated_heavy.h 2023-06-17 08:45:13 -04:00
Wilson Snyder e7de3d368f Commentary: Deprecation planned for 32-bit pointer -m32 mode (#4268). 2023-06-17 08:44:13 -04:00
Wilson Snyder d45deccc0a Internals: Favot std::array. No functional change intended. 2023-06-16 19:44:40 -04:00
Wilson Snyder d5b03ab721 Tests (#3806) (#3807) 2023-06-16 18:30:25 -04:00
Ryszard Rozak d1ff81a41c Fix class reference assignment checking (#4296) 2023-06-15 14:00:47 +02:00
Krzysztof Bieganski 43fa6858f6 Fix VlForkSync redeclaration (#4277)
Given nested forks, if the inner fork had a `join` or `join_any` at the end,
`V3Sched::transformForks()` would decide that the fork's `VlForkSync` variable
should be passed in from the outside. This resulted in the `VlForkSync` getting
redeclared as a function argument. Ultimately, it led to C++ compilation errors
due to variable redeclaration.

Fixed by rearranging the `if`s that decide whether a variable should be passed
in or left as-is.
2023-06-15 07:49:50 -04:00
Wilson Snyder db7eb45433 Contributors: Add Krzysztof Boronski and re-sort 2023-06-14 18:53:44 -04:00
Krzysztof Boronski 21c01ba97b V3Fork - transform processes that can outlive their parents into separate tasks (#4253)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-06-14 20:44:53 +02:00
Ryszard Rozak b517fb5ee3 Support some stream operations on queues (#4292) 2023-06-13 22:46:42 -04:00
Wilson Snyder 9dbc669199 devel release 2023-06-13 19:39:50 -04:00
Wilson Snyder 7d2d32420a Version bump 2023-06-13 19:31:57 -04:00
Wilson Snyder 48e98ea2bd Internals: Sort some error codes (#4253). No functional change intended. 2023-06-13 08:52:13 -04:00
Wilson Snyder 01d0f0327b Commentary (#4254) 2023-06-13 08:22:57 -04:00
Wilson Snyder 0dc887720d Tests: Fix tests, broke in commit 3a9eeabd 2023-06-12 22:38:45 -04:00
Wilson Snyder e08bbcdb07 Commentary 2023-06-12 21:59:52 -04:00
Wilson Snyder 70d26ec123 Commentary (#4211) (#4254) 2023-06-12 21:59:33 -04:00
Wilson Snyder a06f260f42 Fix C++11 compiler error with C++14 rbegin 2023-06-12 21:46:32 -04:00
Wilson Snyder d42f76c346 Tests: Fix tests, broke in commit 3a9eeabd 2023-06-12 21:36:23 -04:00
Wilson Snyder 66c3d6d2d1 Commentary 2023-06-12 20:52:29 -04:00
Wilson Snyder 81affad2dc Tests: Fix test, broke in previous commit 2023-06-12 20:41:33 -04:00
Wilson Snyder 2488af9066 Commentary: Changes update 2023-06-12 20:38:33 -04:00
Wilson Snyder 5cf9d78516 Commentary 2023-06-12 20:28:32 -04:00
Wilson Snyder 3a9eeabdb2 Tests: Auto detect and exit --timing with no coroutines 2023-06-12 20:09:12 -04:00
Julien Margetts ac4315e145 Fix LATCH warning on function local variables (#4221) (#4284) 2023-06-12 09:24:46 -04:00
John Wehle 5094e94df1 Fix tracing undefined alignment (#4201) (#4288) 2023-06-12 07:13:00 -04:00
Àlex Torregrosa 4b7b185d05 Fix VCD scope types (#4227) (#4282) 2023-06-08 11:43:04 -04:00
Aleksander Kiryk 6cb0335d28 Support array max (#4275) 2023-06-07 07:44:21 -04:00
Aleksander Kiryk c248318958 Fix struct redefinition (#4276) 2023-06-06 18:28:35 -04:00
Ryszard Rozak c3e5db5f04 Fix names of foreach blocks (#4264) 2023-06-06 16:24:42 +02:00
Krzysztof Bieganski 058233fc87 Set the global usesTiming flag if forks exist (#4274) 2023-06-06 09:35:12 -04:00
Mariusz Glebocki 186c851695 Internals: Avoid pessimistic mutex locking in waitIfStopRequested() (#4272). No functional change intended.
`stopRequested()` reads only atomic variables. It doesn't need a mutex
to do this.

This function is called in `waitIfStopRequested()`, which in turn
is called before execution of every job, and inside some jobs. With this
change the mutex inside `waitIfStopRequested` needs to be locked only in
very rare cases instead of every time.
2023-06-05 19:40:36 -04:00
Mariusz Glebocki 5aa36357f6 Internals: Use auto instead of SFINAE in return type (#4271). No functional change intended. 2023-06-05 18:53:19 -04:00
Wilson Snyder 191d30cf1c Update gtkwave from upstream (#4141) 2023-06-03 12:10:07 -04:00
Andrei Kostovski d8c2ecaaf8 Commentary: Update install.rst for help2man (#4260) (#4261) 2023-06-03 10:31:17 -04:00
github action a7b0551d23 Apply 'make format' 2023-06-03 14:11:23 +00:00
John Wehle dc34968fe7 Add class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250) 2023-06-03 10:07:39 -04:00
Jiamin Zhu 45f064f7cb Fix missing assignment for wide class members. (#4267) 2023-06-03 06:40:23 -07:00
Krzysztof Boroński 545caba720 Give iterated variables in foreach loops VAUTOM lifetimes (#4265)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-06-02 17:16:42 +02:00
Krzysztof Boroński 0e24f36fef Use STATIC lifetime for variables created from clocking items (#4262)
Signed-off-by: Krzysztof Boronski <[email protected]>
2023-06-01 17:49:27 +02:00
Aleksander Kiryk db7935faf3 Add std::process class (#4212) 2023-06-01 10:02:08 -04:00
Adrien Le Masle 9cc218db3e Fix incorrect multi-driven lint warning (#4231) (#4248) 2023-06-01 08:43:17 -04:00
Ryszard Rozak 15f8ebc562 Fix static methods with prototypes (#4220) 2023-05-31 21:18:32 -04:00
github action 205cae963b Apply 'make format' 2023-05-31 16:03:33 +00:00
Don Williamson df2746de71 Add --main-top-name option for C main TOP name (#4235) (#4249) 2023-05-31 09:02:26 -07:00
Risto Pejašinović 7f471d862e Fix operator == for unpacked struct, if elements are VlUnpacked arrays (#4247) 2023-05-31 08:34:34 -04:00
Risto Pejašinović 338acabe2b Fix AstStructSel clean when data type is structure (#4241) (#4244) 2023-05-30 23:44:48 -04:00
Ryszard Rozak 4f1f487ae4 Fix function calls in with statements (#4245) 2023-05-30 09:02:59 -04:00
Krzysztof Bieganski 77502aeb97 Add warning that timing controls in DPI exports are unsupported (#4238)
Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-05-30 09:00:10 -04:00
Ryszard Rozak ba82d43ca1 Support for condition operator on class objects (#4214) 2023-05-30 08:59:00 -04:00
Wilson Snyder e9135598b3 Fix method calls on function return values. 2023-05-29 18:51:27 -04:00
Risto Pejašinović 1c0739db10 Fix unpacked struct == and != operators (#4234) (#4240) 2023-05-29 12:08:39 -04:00
Ryszard Rozak dfd3907787 Mark AstMemberSel as clean (#4236) 2023-05-29 09:35:53 +02:00
Wilson Snyder 1069652701 Fix some AstExprStmt handling issues, towards side effect fixes. 2023-05-27 12:43:40 -04:00
Wilson Snyder 70b82f1aec Internals: V3Dead cleanups. No functional change. 2023-05-27 11:46:25 -04:00
Wilson Snyder 5573bdb219 Internals: Cleanup V3SplitAs VL_RESTORED. No functional change intended. 2023-05-27 10:43:04 -04:00
Wilson Snyder cf68578261 Internals: Cleanup V3SplitAs VL_RESTORED. No functional change intended. 2023-05-27 10:17:51 -04:00
Wilson Snyder f407d442d4 Commentary 2023-05-27 09:43:23 -04:00
Wilson Snyder 7f12ad9d91 Commentary: Changes update 2023-05-27 07:17:37 -04:00
Wilson Snyder 5efe9367d2 Fix SystemC signal copy macro use (#4135). 2023-05-27 07:00:26 -04:00
Wilson Snyder cfce92645f Tests: Check equality of complex types. 2023-05-26 18:01:11 -04:00
Krzysztof Bieganski 519792d02b Fix to commit coroutines immediately on wait statements (#4229)
Event-triggered coroutines live in two stages: 'uncommitted' and 'ready'. First
they land in 'uncommitted', meaning they can't be resumed yet. Only after
coroutines from the 'ready' queue are resumed, the 'uncommitted' ones are moved
to the 'ready' queue, and can be resumed. This is to avoid self-triggering in
situations like waiting for an event immediately after triggering it.

However, there is an issue with `wait` statements. If you have a `wait(b)`, it's
being translated into a loop that awaits a change in `b` as long as `b` is
false. If `b` is false at first, the coroutine is put into the `uncommitted`
queue. If `b` is set to true before it's committed, the coroutine won't get
resumed.

This patch fixes that by immediately committing event controls created from
`wait` statements. That means the coroutine from the example above will get
resumed from now on.
2023-05-25 20:20:44 -04:00
Jiamin Zhu bfa1f2d7ce Fix missing assignment for wide unpacked structs (#4233) 2023-05-25 20:13:02 -04:00
Aleksander Kiryk 42beaf467c Tests: Add incomplete type definition test (#4230) 2023-05-25 14:06:37 -04:00
Mariusz Glebocki 8303938d0e Internals: Make mutex classes uncopyable. (#4223) 2023-05-25 07:35:14 -04:00
Mariusz Glebocki 0ece155418 Internals: Move some includes to .cpp files. (#4224) 2023-05-24 18:53:14 -04:00
Ryszard Rozak 4f7e155e59 Fix class parameters of enum types (#4219) 2023-05-24 15:51:03 +02:00
Wilson Snyder ff324625e4 CI: Disable m32 on g++ 2023-05-23 23:04:24 -04:00
Wilson Snyder fd7515b046 Tests: Cleanup scenarios lines. No test run change. 2023-05-23 22:40:19 -04:00
Wilson Snyder 607f853bc7 CI: Disable m32 on g++ 2023-05-23 22:35:07 -04:00
Wilson Snyder 09fb1174f1 CI: Disable m32 on g++ 2023-05-23 22:34:27 -04:00
Wilson Snyder 542eaab3dd CI: Disable m32 on g++ 2023-05-23 22:28:40 -04:00
Wilson Snyder a301a498f5 CI: Disable m32 on g++ 2023-05-23 22:27:10 -04:00
Wilson Snyder d66e749ec8 CI: Fix mold build 2023-05-23 22:25:03 -04:00
Wilson Snyder c8ca54ea31 CI: Disable m32 on g++ 2023-05-23 22:24:47 -04:00
Wilson Snyder 5704552053 Fix ci for mold 2023-05-23 21:30:39 -04:00
Wilson Snyder 426069a4dd Configure for faster C++ linking using 'mold', if it is installed. 2023-05-23 21:26:29 -04:00
Wilson Snyder 19d0aabe7a Internals: Fix extra cast on ExprStmt. 2023-05-23 20:52:30 -04:00
Krzysztof Boroński fb0d735f68 Tests: Skip t_suspendable_deep if coroutines are not supported by CXX toolchain (#4217) 2023-05-23 14:02:40 -04:00
Krzysztof Boroński 167a30be1c Fix deep traversal of class inheritance timing (#4216) 2023-05-23 09:01:57 -04:00
Wilson Snyder 5982528274 Fix duplicate std:: declaration with -I (#4215). 2023-05-22 20:32:20 -04:00
Krzysztof Boroński de3095e3b4 Fix missing class forward declarations (#4151) 2023-05-22 08:29:01 -04:00
Wilson Snyder 8e0682f442 Fix V3Expand ignoring side effects 2023-05-21 21:02:39 -04:00
Wilson Snyder 140994d2c4 Internals: Cleanup more VL_RESTORER. No functional change intended. 2023-05-21 14:06:39 -04:00
Wilson Snyder 950e29d56e Internals: Cleanup some missing VL_RESTORER in V3Gate. No functional change intended. 2023-05-21 12:49:07 -04:00
Wilson Snyder 65667356b6 wip 2023-05-21 12:24:00 -04:00
Wilson Snyder 6b393e9d7c Internals: Allow statement-in-statement recursion in V3Premit 2023-05-21 12:03:13 -04:00
Wilson Snyder 4818130e4f Internals: Remove dead code, addBeforeStmt 2023-05-20 22:37:28 -04:00
Ryszard Rozak 9da3aacd08 Fix bit selections under parameterized classes (#4210) 2023-05-18 20:01:36 -04:00
Krzysztof Bieganski 729f8b9334 Move suspendable detection to a separate visitor (#4208)
This makes the implementation of the detection and propagation of the
suspendable property simpler and easier to read. More importantly, there are no
more jumps around the AST with the `visit` functions, which in some cases could
result in incorrect visitor context while in the `visit` function. See the added
test, which would cause Verilator to segfault before this patch.

In testing, verilation performance was not shown to be affected by this change.
Though there is a slight performance improvement from this patch, due to adding
one more check before refreshing class member cache.

Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-05-17 17:09:33 +00:00
Ryszard Rozak 279216048b Fix dotted references in parameterized classes (#4206) 2023-05-16 07:40:02 -04:00
Ryszard Rozak 2ce7a348df Fix references to members of parameterized base classes (#4196) 2023-05-15 19:50:04 -04:00
Wilson Snyder 46f719ceaa Tests: Fix some coverage holes 2023-05-13 20:15:03 -04:00
Mariusz Glebocki 949be301de Internals: Fix unbalanced V3LockGuard locking (#4193) 2023-05-13 10:32:33 -04:00
Mariusz Glebocki be429a5800 Internals: Lock the same mutex reference as specified in VL_ACQUIRE. (#4194) 2023-05-13 10:28:34 -04:00
Mariusz Glebocki e7714e0902 Internals: Add additional clang's thread safety analysis annotations (#4195)
* Simplify some Clang-specific attribute defines.

* Add `VL_RETURN_CAPABILITY` and `VL_PT_GUARDED_BY`.
2023-05-12 09:06:36 -04:00
Krzysztof Bieganski 4835ed6967 Fix forced assignments that override non-continuous assignments (#4183) (#4192)
Only assign forced value on release if it was forced in the first place.
2023-05-12 06:57:12 -04:00
Ryszard Rozak 0198a3fc52 Use unchanged copy of parameterized class for instantation (#4179) 2023-05-11 09:56:15 +02:00
Krzysztof Boroński e095bf1af0 Support inside expressions with strings and doubles (#4138) (#4139) 2023-05-10 20:36:41 -04:00
Aylon Chaim Porat d5de67c6dc Fix wide structure VL_TOSTRING_W generation (#4188) (#4189)
* V3Common.cpp::makeVlToString: fix `VL_TOSTRING_W` statement generation to include width argument

* fix contribution name

* add testcase for long struct `VL_TO_STRING_W` bug
2023-05-10 20:34:44 -04:00
Ryszard Rozak 2267db093f Fix hashes of instances of parameterized classes (#4182) 2023-05-10 18:34:29 -04:00
Ryszard Rozak 5aecfa98a1 Internals: Add param value string to hash in V3Param.cpp (#4186) 2023-05-10 17:52:17 -04:00
Wilson Snyder 485e230dd8 Commentary (#4187) 2023-05-10 17:51:22 -04:00
Wilson Snyder befb415f27 Fix mod/div/round argument side effects 2023-05-07 22:31:31 -04:00
Wilson Snyder c0490627bf Tests: Update historical 2023-05-07 22:00:52 -04:00
Wilson Snyder d269fbb446 Add creating __inputs.vpp file with --debug (#4177). 2023-05-07 17:58:14 -04:00
Wilson Snyder 444020f7c7 Fix super.new missing data type (#4147). 2023-05-07 16:47:34 -04:00
Wilson Snyder 6188083baa Tests: Improve randc tests 2023-05-07 15:08:44 -04:00
Wilson Snyder c2a524d80b Commentary (#4175) 2023-05-07 08:36:03 -04:00
Wilson Snyder e6f5a0495f Fix $fscanf of decimals overflowing variables (#4174). 2023-05-07 08:25:10 -04:00
Wilson Snyder 0606a29f13 Fix arrays of unpacked structs (#4173). 2023-05-06 21:41:17 -04:00
Wilson Snyder c6052830e1 Fix C++17 requirement on previous commit. 2023-05-06 20:23:35 -04:00
Wilson Snyder 4bb876aee5 Fix false IMPLICITSTATIC on package functions. 2023-05-06 19:48:22 -04:00
Wilson Snyder a3640c1767 Support get_randstate/set_randstate class method function. 2023-05-06 19:09:19 -04:00
Wilson Snyder 250c6950cf Fix randomize missing simple class rand members. 2023-05-06 18:33:08 -04:00
Wilson Snyder 76f5de6e54 Replace flake8 with ruff for Python linting 2023-05-06 06:08:32 -04:00
Wilson Snyder 1a1c5c5d44 Internals: Fix pylint warning 2023-05-06 06:05:11 -04:00
Wilson Snyder 4ae80f9a9f Commentary 2023-05-05 22:50:28 -04:00
github action 8a3cb8daa8 Apply 'make format' 2023-05-06 02:37:42 +00:00
Ethan Sifferman 64ab537b68 Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). 2023-05-05 22:36:51 -04:00
Wilson Snyder fdea386727 Fix false WIDTHEXPAND on array declarations (#3959). 2023-05-05 22:05:19 -04:00
Wilson Snyder 28944ed862 Fix crash on duplicate imported modules (#3231). 2023-05-05 20:31:48 -04:00
Wilson Snyder 3250ee5707 Commentary: Changes update 2023-05-05 20:24:45 -04:00
Wilson Snyder d308a561e4 Fix detection of wire/reg duplicates 2023-05-05 20:16:27 -04:00
Wilson Snyder 584f8cc9e7 Internal: With --xml-only support --debug-exit-uvm 2023-05-05 13:47:34 -04:00
Kamil Rakoczy 61e1483b74 Add multi-threaded Verilating at emit stage (#3608) 2023-05-05 08:36:20 -04:00
Wilson Snyder 3bb4e34044 Commentary 2023-05-04 19:04:38 -04:00
Kamil Rakoczy 832b17d4d2 clang_check_attributes: fix mt-safe checks for global objects in constructor context (#4171) 2023-05-04 14:00:30 -04:00
Krzysztof Bieganski 76c5875912 Fix marking overridden methods as coroutines (#4120) (#4169)
This patch fixes two cases where methods in base classes were not being marked
as coroutines, even though they were being overridden by coroutines.
- One case is the class member cache not getting refreshed for searched classes.
- The other is when the overriding methods are not declared as `virtual`. In
  that case, the `isVirtual()` getter on such a method returns false, which led
  to `V3Timing` skipping the step of searching for overridden methods.

Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-05-04 15:27:45 +02:00
Ryszard Rozak 266dc7679a Don't link AstRefDType if it has parameterized class ref (#4164) (#4170) 2023-05-04 15:09:01 +02:00
Jose Loyola d693dc85e4 Add Github action to build and push docker images (#4163) 2023-05-04 07:44:55 -04:00
Wilson Snyder add68130b8 Internals: Rename to dumpLevel(), to avoid confusion with make-a-dump() 2023-05-03 18:04:10 -04:00
Tudor Timi d9b5680a45 Fix crash caused by $display() optimization (#4165) (#4166) 2023-05-03 17:04:18 -04:00
Wilson Snyder dc25be536c Internals: Deprecate VL_ATTR_ALIGNED, use alignas instead. 2023-05-02 21:21:10 -04:00
Stefan Wallentowitz 7708c88e32 Fix duplicate static names in blocks in functions (#4144) (#4160)
Static variables of functions are created in the function. When blocks
in a function use identical names for static variables, we need to name
those variables properly.
2023-05-02 20:24:44 -04:00
february cozzocrea 707f230353 Commentary: Update install.rst help2man dependency (#4161) 2023-05-02 14:32:24 -04:00
Kamil Rakoczy 49d2eb9a08 Fix initialization order of initial static after function/task (#4159) 2023-05-02 11:50:57 -04:00
github action 128186ea68 Apply 'make format' 2023-05-02 11:29:45 +00:00
Hennadii ChernyshchykandOleh Maks 949be9d0a1 Optimize VPI callValueCbs (#4155)
Co-authored-by: Oleh Maks <[email protected]>
2023-05-02 07:28:56 -04:00
Wilson Snyder 3e986517c3 devel release 2023-04-30 07:10:14 -04:00
1356 changed files with 134566 additions and 40989 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
+20 -11
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,15 +37,18 @@ 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' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
# - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04 clang++
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
- compiler: { cc: gcc, cxx: g++ }
m32: 1
include:
# Build GCC 10 on ubuntu-20.04
- os: ubuntu-20.04
@@ -56,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:
@@ -101,16 +108,18 @@ 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
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
# - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-22.04
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
- compiler: { cc: gcc, cxx: g++ }
m32: 1
include:
# Test with GCC 10 on ubuntu-20.04 without m32
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0}
@@ -127,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:
+85
View File
@@ -0,0 +1,85 @@
# Build and push verilator docker image when tags are pushed to the 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
on:
push:
tags: [ 'v*' ]
workflow_dispatch:
inputs:
manual_tag:
description: 'Git tag to use for image build'
required: true
type: string
add_latest_tag:
description: 'Tag workflow_dispatch docker image as "latest"'
required: true
type: boolean
default: false
jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
contexts:
- "ci/docker/run:verilator"
# - "ci/docker/buildenv:verilator-buildenv"
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Extract context variables
run: |
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
- name: Use manual tag
if: ${{ inputs.manual_tag }}
run: |
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v4
with:
images: |
${{ 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 != '' }}
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
buildkitd-flags: --debug
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and Push to Docker
uses: docker/build-push-action@v4
if: startsWith(github.ref, 'refs/tags/v')
with:
context: ${{ env.build_context }}
build-args: SOURCE_COMMIT=${{ env.git_tag }}
platforms: linux/arm64,linux/amd64
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
+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.010
VERSION 5.018
HOMEPAGE_URL https://verilator.org
LANGUAGES CXX
)
+240
View File
@@ -8,6 +8,246 @@ 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
==========================
**Minor:**
* Deprecation planned for 32-bit pointer -m32 mode (#4268).
* Deprecate CMake config below version 3.13 (#4389) (#4390). [Vito Gamberini]
* Support some stream operations on queues (#4292). [Ryszard Rozak, Antmicro Ltd]
* Support property declaration with empty parentheses (#4313) (#4317). [Anthony Donlon]
* Support locator methods with "with" on assoc arrays (#4335). [Ryszard Rozak, Antmicro Ltd]
* Support string replication with variable (#4341). [Aleksander Kiryk, Antmicro Ltd]
* Support more types in wait (#4374). [Aleksander Kiryk, Antmicro Ltd]
* Support static method calls as default values of function arguments (#4378). [Ryszard Rozak, Antmicro Ltd]
* Add GENUNNAMED lint warning. [Srinivasan Venkataramanan, Deepa Palaniappan]
* Add MISINDENT lint warning for misleading indentation.
* Fix 'VlForkSync' redeclaration (#4277). [Krzysztof Bieganski, Antmicro Ltd]
* Fix processes that can outlive their parents (#4253). [Krzysztof Boronski, Antmicro Ltd]
* Fix duplicate fork names (#4295). [Ryszard Rozak, Antmicro Ltd]
* Fix splitting coroutines (#4297) (#4307). [Jiamin Zhu]
* Fix error when multiple duplicate DPI exports (#4301).
* Fix class reference assignment checking (#4296). [Ryszard Rozak, Antmicro Ltd]
* Fix handling of ref types in initial values of type parameters (#4304). [Ryszard Rozak, Antmicro Ltd]
* Fix comparison of string parameters (#4308). [Ryszard Rozak, Antmicro Ltd]
* Fix state update for always processes (#4311). [Aleksander Kiryk, Antmicro Ltd]
* Fix multiple edge timing controls in class methods (#4318) (#4320) (#4344). [Krzysztof Bieganski, Antmicro Ltd]
* Fix implicit calls of base class constructors with optional arguments (#4319). [Ryszard Rozak, Antmicro Ltd]
* Fix propagation of process requirement (#4321). [Krzysztof Boroński]
* Fix unhandled overloads in V3InstrCount (#4324). [Krzysztof Boroński]
* Fix selects of static members (#4326). [Ryszard Rozak, Antmicro Ltd]
* Fix references to members of results of static methods (#4327). [Ryszard Rozak, Antmicro Ltd]
* Fix unique..with method on queues of class objects (#4328). [Ryszard Rozak, Antmicro Ltd]
* Fix queue slicing (#4329). [Aleksander Kiryk, Antmicro Ltd]
* Fix wildcard referring types (#4336) (#4342). [Aleksander Kiryk, Antmicro Ltd]
* Fix comparison of class objects (#4346). [Ryszard Rozak, Antmicro Ltd]
* Fix unexpected RefDType on assoc arrays (#4337). [Aleksander Kiryk, Antmicro Ltd]
* Fix cmake astgen for Rocky Linux 8.7 (#4343). [Julian Daube]
* Fix class timescale in class packages (#4348). [Krzysztof Bieganski, Antmicro Ltd]
* Fix string concatenations (#4354). [Ryszard Rozak, Antmicro Ltd]
* Fix unlinked task error from broken context (#4355) (#4402). [Aleksander Kiryk, Antmicro Ltd]
* Fix selects on unpacked structs (#4359). [Ryszard Rozak, Antmicro Ltd]
* Fix select operation on assoc array with wide keys (#4360). [Ryszard Rozak, Antmicro Ltd]
* Fix non-public methods with wide output (#4364). [Ryszard Rozak, Antmicro Ltd]
* Fix handling of super.new calls (#4366). [Ryszard Rozak, Antmicro Ltd]
* Fix assign to input var in methods (#4367). [Aleksander Kiryk, Antmicro Ltd]
* Fix VlProcess not found (#4368). [Aleksander Kiryk, Antmicro Ltd]
* Fix order of evaluation of function calls in statements (#4375). [Ryszard Rozak, Antmicro Ltd]
* Fix config_build.h issues (#4380) (#4381). [Andrew Miloradovsky]
Verilator 5.012 2023-06-13
==========================
**Major:**
* With -j or --build-jobs, multithread Verilator's emit phase of Verilation. [Kamil Rakoczy, Antmicro Ltd]
Additional Verilator-internal stages will become multithreaded over time.
**Minor:**
* Add --main-top-name option for C main TOP name (#4235) (#4249). [Don Williamson]
* Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi]
* Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). [Ethan Sifferman]
* Add warning that timing controls in DPI exports are unsupported (#4238). [Krzysztof Bieganski, Antmicro Ltd]
* Support std::process class (#4212). [Aleksander Kiryk, Antmicro Ltd]
* Support inside expressions with strings and doubles (#4138) (#4139). [Krzysztof Boroński]
* Support get_randstate/set_randstate class method functions.
* Support for condition operator on class objects (#4214). [Ryszard Rozak, Antmicro Ltd]
* Support array max (#4275). [Aleksander Kiryk, Antmicro Ltd]
* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk]
* Configure for faster C++ linking using 'mold', if it is installed.
* Fix crash on duplicate imported modules (#3231). [Robert Balas]
* Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO]
* Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd]
* Fix SystemC signal copy macro use (#4135). [Josep Sans]
* Fix duplicate static names in blocks in functions (#4144) (#4160). [Stefan Wallentowitz]
* Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd]
* Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd]
* Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi]
* Fix arrays of unpacked structs (#4173). [Risto Pejašinović]
* Fix $fscanf of decimals overflowing variables (#4174). [Ahmed El-Mahmoudy]
* Fix super.new missing data type (#4147). [Tudor Timi]
* Fix missing class forward declarations (#4151). [Krzysztof Boroński]
* Fix hashes of instances of parameterized classes (#4182). [Ryszard Rozak, Antmicro Ltd]
* Fix forced assignments that override non-continuous assignments (#4183) (#4192). [Krzysztof Bieganski, Antmicro Ltd]
* Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat]
* Fix references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd]
* Fix tracing undefined alignment (#4201) (#4288) [John Wehle]
* Fix class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle]
* Fix dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd]
* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd]
* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl]
* Fix deep traversal of class inheritance timing (#4216). [Krzysztof Boroński]
* Fix class parameters of enum types (#4219). [Ryszard Rozak, Antmicro Ltd]
* Fix static methods with prototypes (#4220). [Ryszard Rozak, Antmicro Ltd]
* Fix LATCH warning on function local variables (#4221) (#4284) [Julien Margetts]
* Fix VCD scope types (#4227) (#4282). [Àlex Torregrosa]
* Fix incorrect multi-driven lint warning (#4231) (#4248). [Adrien Le Masle]
* Fix missing assignment for wide unpacked structs (#4233). [Jiamin Zhu]
* Fix unpacked struct == and != operators (#4234) (#4240). [Risto Pejašinović]
* Fix AstStructSel clean when data type is structure (#4241) (#4244). [Risto Pejašinović]
* Fix function calls in with statements (#4245). [Ryszard Rozak, Antmicro Ltd]
* Fix operator == for unpacked struct, if elements are VlUnpacked arrays (#4247). [Risto Pejašinović]
* Fix STATIC lifetime for variables created from clocking items (#4262). [Krzysztof Boroński]
* Fix names of foreach blocks (#4264). [Ryszard Rozak, Antmicro Ltd]
* Fix iterated variables in foreach loops to have VAUTOM lifetimes (#4265). [Krzysztof Boroński]
* Fix missing assignment for wide class members (#4267). [Jiamin Zhu]
* Fix the global uses timing flag when forks exist (#4274). [Krzysztof Bieganski, Antmicro Ltd]
* Fix struct redefinition (#4276). [Aleksander Kiryk, Antmicro Ltd]
* Fix detection of wire/reg duplicates.
* Fix false IMPLICITSTATIC on package functions.
* Fix method calls on function return values.
Verilator 5.010 2023-04-30
==========================
+17 -9
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; \
@@ -424,17 +428,21 @@ YAPF_FLAGS = -i
yapf:
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
FLAKE8 = flake8
FLAKE8_FLAGS = \
--extend-exclude=fastcov.py \
--ignore=E123,E129,E251,E402,E501,W503,W504,E701
PYLINT = pylint
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:
-$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS)
-$(PYLINT) $(PYLINT_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
@@ -451,8 +459,8 @@ install-msg:
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
# autoheader might not change config_build.h.in, so touch it
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
# autoheader might not change config_package.h.in, so touch it
${srcdir}/config_package.h: ${srcdir}/config_package.h.in configure
cd ${srcdir} && autoheader
touch $@
Makefile: Makefile.in config.status $(IN_WILD)
+12 -9
View File
@@ -1,12 +1,16 @@
.. Github doesn't render images unless absolute URL
.. Do not know of a conditional tag, "only: github" nor "github display" works
.. image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
:target: https://verilator.org
.. image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
:target: https://www.gnu.org/licenses/lgpl-3.0]
:target: https://www.gnu.org/licenses/lgpl-3.0
.. image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
:target: https://opensource.org/licenses/Artistic-2.0
.. image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
:target: https://repology.org/project/verilator/versions
.. image:: https://img.shields.io/docker/pulls/verilator/verilator
:target: https://hub.docker.com/r/verilator/verilator
.. image:: https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f
:target: https://www.codacy.com/gh/verilator/verilator
.. image:: https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg
@@ -57,17 +61,16 @@ files, the "Verilated" code.
These Verilated C++/SystemC files are then compiled by a C++ compiler
(gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper
file to instantiate the Verilated model. Executing the resulting executable
performs the design simulation. Verilator also supports linking Verilated
generated libraries, optionally encrypted, into other simulators.
file, to instantiate the Verilated model. Executing the resulting
executable performs the design simulation. Verilator also supports linking
Verilated generated libraries, optionally encrypted, into other simulators.
Verilator may not be the best choice if you are expecting a full-featured
replacement for a closed-source Verilog simulator, needs SDF annotation,
mixed-signal simulation, or are doing a quick class project (we recommend
`Icarus Verilog`_ for classwork.) However, if you are looking for a path
to migrate SystemVerilog to C++/SystemC, or want high-speed simulation of
synthesizable designs containing limited verification constructs, Verilator
is the tool for you.
designs, Verilator is the tool for you.
Performance
@@ -83,11 +86,11 @@ as `Icarus Verilog`_. Another 2-10x speedup might be gained from
multithreading (yielding 200-1000x total over interpreted simulators).
Verilator has typically similar or better performance versus the
closed-source Verilog simulators (Carbon Design Systems Carbonator,
closed-source Verilog simulators (e.g., Carbon Design Systems Carbonator,
Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
computes rather than licenses. Thus, Verilator gives you the best
cycles/dollar.
simulation cycles/dollar.
Installation & Documentation
@@ -147,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
+2
View File
@@ -372,6 +372,7 @@ detailed descriptions of these arguments.
--make <build-tool> Generate scripts for specified build tool
-MAKEFLAGS <flags> Arguments to pass to make during --build
--main Generate C++ main() file
--main-top-name Specify top name passed to Verilated model in generated C++ main
--max-num-width <value> Maximum number width (default: 64K)
--Mdir <directory> Name of output object directory
--MMD Create .d dependency files
@@ -439,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
+7 -3
View File
@@ -61,7 +61,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
sudo apt-get update
sudo apt-get install ccache help2man libfl-dev ||
sudo apt-get install ccache help2man libfl-dev
if [ "$CI_RUNS_ON" != "ubuntu-22.04" ]; then
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ]; then
# Some conflict of libunwind verison on 22.04, can live without it for now
sudo apt-get install libgoogle-perftools-dev ||
sudo apt-get install libgoogle-perftools-dev
@@ -70,6 +70,10 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
sudo apt-get install libsystemc libsystemc-dev ||
sudo apt-get install libsystemc libsystemc-dev
fi
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
sudo apt-get install bear mold ||
sudo apt-get install bear mold
fi
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Parallel::Forker
fi
@@ -102,8 +106,8 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
sudo apt-get install gdb gtkwave lcov libfl-dev ccache
# Required for test_regress/t/t_dist_attributes.pl
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
sudo apt-get install libclang-dev ||
sudo apt-get install libclang-dev
sudo apt-get install libclang-dev mold ||
sudo apt-get install libclang-dev mold
pip3 install clang==14.0
fi
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
+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
+7 -1
View File
@@ -19,10 +19,16 @@ RUN apt-get update \
ccache \
flex \
git \
help2man \
libfl2 \
libfl-dev \
libgoogle-perftools-dev \
numactl \
perl \
perl-doc \
python3 \
zlib1g \
zlib1g-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@@ -39,7 +45,7 @@ RUN git clone "${REPO}" verilator && \
git checkout "${SOURCE_COMMIT}" && \
autoconf && \
./configure && \
make -j "$(nproc)" && \
make && \
make install && \
cd .. && \
rm -r verilator
+39 -11
View File
@@ -5,16 +5,16 @@
# General Public License Version 3 or the Perl Artistic License Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# When releasing, also update header of Changes file,
# When releasing, also update header of Changes file, and CmakeLists.txt,
# and commit using "devel release" or "Version bump" message
# Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[5.010 2023-04-30],
AC_INIT([Verilator],[5.018 2023-10-30],
[https://verilator.org],
[verilator],[https://verilator.org])
AC_CONFIG_HEADERS(src/config_build.h)
AC_CONFIG_HEADERS(src/config_package.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
# Version
@@ -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"
@@ -470,6 +478,10 @@ m4_foreach([ldflag], [
AC_SUBST(CFG_LDLIBS_THREADS)
AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE)
# If 'mold' is installed, use it to link for faster buildtimes
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -fuse-ld=mold)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_VERILATED, -fuse-ld=mold)
# When linking partially statically
if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc)
@@ -480,6 +492,7 @@ else
LTCMALLOC=-ltcmalloc_minimal
fi
AC_SUBST(CFG_LDFLAGS_SRC)
AC_SUBST(CFG_LDFLAGS_VERILATED)
# The pthread library is required by tcmalloc, so add it if it exists. If it
# does not, the tcmalloc check below will fail anyway, and linking against
@@ -554,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])],
@@ -568,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])],
+30 -4
View File
@@ -12,9 +12,14 @@ Alex Chadwick
Aliaksei Chapyzhenka
Ameya Vikram Singh
Andreas Kuster
Andrei Kostovski
Andrew Miloradovsky
Andrew Nolte
Anthony Donlon
Arkadiusz Kozdra
Aylon Chaim Porat
Cameron Kirk
Chih-Mao Chen
Chris Randall
Chuxuan Wang
Conor McCullough
@@ -24,15 +29,20 @@ David Horton
David Metz
David Stanford
David Turner
Don Williamson
Drew Ranck
Drew Taussig
Driss Hafdi
Edgar E. Iglesias
Eric Rippey
Ethan Sifferman
Eyck Jentzsch
Fan Shupei
february cozzocrea
Felix Neumärker
Felix Yan
Frans Skarman
G-A. Kamendje
Garrett Smith
Geza Lore
Gianfranco Costamagna
@@ -40,17 +50,19 @@ Glen Gibb
Gökçe Aydos
Graham Rushton
Guokai Chen
Gus Smith
Gustav Svensk
G-A. Kamendje
Harald Heckmann
Hennadii Chernyshchyk
Howard Su
Huang Rui
Huanghuang Zhou
HungMingWu
HyungKi Jeong
Ícaro Lima
Ilya Barkov
Iru Cai
Ivan Vnučec
Ilya Barkov
Iztok Jeras
Jake Merdich
James Hanlon
@@ -65,16 +77,21 @@ Jeremy Bennett
Jesse Taube
Jevin Sweval
Jiacheng Qian
Jiamin Zhu
Jiuyang Liu
Joey Liu
John Coiner
John Demme
John Wehle
Jonathan Drolet
Joseph Nwabueze
Jose Loyola
Josep Sans
Joseph Nwabueze
Josh Redford
Julian Daube
Julie Schwartz
Julien Margetts
Justin Thiel
Kaleb Barrett
Kamil Rakoczy
Kanad Kanhere
@@ -82,6 +99,7 @@ Keith Colbert
Kevin Kiningham
Kritik Bhimani
Krzysztof Bieganski
Krzysztof Boronski
Krzysztof Boroński
Kuba Ober
Larry Doolittle
@@ -100,6 +118,7 @@ Martin Stadler
Matthew Ballance
Michael Killough
Michaël Lefebvre
Michal Czyz
Mike Popoloski
Miodrag Milanović
Mladen Slijepcevic
@@ -108,6 +127,7 @@ Mostafa Gamal
Nandu Raj
Nathan Kohagen
Nathan Myers
Oleh Maksymenko
Patrick Stewart
Paul Wright
Pawel Sagan
@@ -119,6 +139,7 @@ Pierre-Henri Horrein
Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Quentin Corradi
Rafal Kapuscik
Raynard Qiao
Richard Myers
@@ -136,6 +157,7 @@ Stephen Henry
Steven Hugg
Sören Tempel
Teng Huang
Tim Hutt
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
@@ -143,6 +165,7 @@ Todd Strader
Tomasz Gorochowik
Topa Topino
Toru Niina
Tudor Timi
Tymoteusz Blazejczyk
Udi Finkelstein
Unai Martinez-Corral
@@ -150,15 +173,18 @@ Varun Koyyalagunta
Vassilis Papaefstathiou
Veripool API Bot
Victor Besyakov
Vito Gamberini
William D. Jones
Wilson Snyder
Xi Zhang
Yinan Xu
Yoda Lee
Yossi Nivin
Yu-Sheng Lin
Yuri Victorovich
Yutetsu TAKATSUKASA
Yu-Sheng Lin
Yves Mathieu
Zhanglei Wang
Zhou Shen
Zixi Li
أحمد المحمودي
+5 -1
View File
@@ -18,12 +18,16 @@
RST2HTML = rst2html
PYTHON3 = python3
DOXYGEN = doxygen
SPHINXOPTS ?= -c guide
SPHINXBUILD ?= sphinx-build
SOURCEDIR = guide
BUILDDIR = _build
SPHINXOPTS ?= -c guide
ifneq ($(VERILATOR_ANALYTICS_ID),)
SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID)
endif
######################################################################
.SUFFIXES:
+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
######################################################################
+2 -3
View File
@@ -31,7 +31,7 @@ def get_vlt_version():
if match:
try:
data = os.popen('git log -n 1 --pretty=%cs').read()
except Exception:
except Exception: # pylint: disable=broad-except
data = "" # fallback, and Sphinx will fill in today's date
return "Devel " + match.group(1), data
return "unknown", "unknown"
@@ -115,7 +115,6 @@ html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_theme_options = {
'analytics_id': 'G-D27B0C9QEB',
'logo_only': True,
'style_nav_header_background': "#45acf8", # Default is #2980B9
# 'canonical_url':
@@ -231,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)
==================================
+4 -4
View File
@@ -17,10 +17,10 @@ C++11 compiler support
Verilator will require C++20 or newer compilers for both compiling
Verilator and compiling all Verilated models no sooner than January 2025.
Verilated_heavy.h
The legacy "verilated_heavy.h" include was replaced with just including
"verilated.h". Verilated_heavy.h is planned for removal no sooner than
July 2022.
32-bit compiler support
Verilator currently regresses both 64-bit and 32-bit pointer modes (GCC's
`-m64` and `-m32`). Support for 32-bit `-m32` mode will be deprecated no
sooner than January 2024.
Option `-O<letter>`
The debug `-O<letter>` options have been replaced with
+47 -6
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
@@ -91,9 +112,29 @@ associated programs.
.. option:: VERILATOR_ROOT
Specifies the directory containing the distribution kit. This is used
to find the executable, Perl library, and include files. If not
specified, it will come from a default optionally specified at configure
time (before Verilator was compiled). It should not be specified if
using a pre-compiled Verilator package as the hard-coded value should be
correct. See :ref:`Installation`.
The ``VERILATOR_ROOT`` environment variable is used in several places:
* At ``./configure`` time: If set, it is embedded into the binary, and
at runtime if ``VERILATOR_ROOT`` is not set, the embedded value is
used for the runtime default.
* When ``verilator`` is run: If ``VERILATOR_ROOT`` is set it will be
used to find the ``verilator_bin`` executable (this is the actual
Verilator binary; ``verilator`` is a Perl wrapper). If not set, the
``verilator`` script uses other methods to find ``verilator_bin``
(looking in the same directory and falling back to ``$PATH``).
* When ``make`` is run on the Makefile generated by ``verilator``: The
value of ``VERILATOR_ROOT`` (falling back to the value embedded in the
binary if not set) is used to find the include files
(``include/verilated.mk``).
If you are using a pre-compiled Verilator package, you should not need
to set ``VERILATOR_ROOT`` - the value embedded in the binary should be
correct. In fact this option *does not work* with Verilator packages
that have been installed with ``make install``. If a Verilator package
has been installed using ``./configure --prefix=/some/path && make
install`` and then moved to another location, you cannot use
``VERILATOR_ROOT`` to point to the new version.
See :ref:`Installation` for more details.
+59 -25
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
@@ -808,6 +811,13 @@ Summary:
See also :vlopt:`--binary`.
.. option:: --main-top-name <string>
Specify the name passed to the Verilated model being constructed, in the
generated C++ main() function.
If the string ``"-"`` is used, no top level scope is added.
.. option:: --max-num-width <value>
Set the maximum number literal width (e.g., in 1024'd22 this
@@ -1307,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
@@ -1385,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
@@ -1467,8 +1489,11 @@ Summary:
them systematically.
The generated file is in the Verilator Configuration format, see
:ref:`Configuration Files`, and can directly be consumed by
Verilator. The standard file extension is ".vlt".
:ref:`Configuration Files`. The standard file extension is ".vlt".
These files can directly be consumed by Verilator, typically by placing
the filename as part of the Verilator command line options. Waiver files
need to be listed on the command line before listing the files they are
waiving.
.. option:: -Wall
@@ -1513,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
@@ -1527,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-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
@@ -1550,19 +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-BSSPACE -Wwarn-CASEINCOMPLETE
-Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CASEWITHX -Wwarn-CMPCONST
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-ASCRANGE
-Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``.
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-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
+3 -3
View File
@@ -356,8 +356,8 @@ Why do I get "undefined reference to \`VL_RAND_RESET_I' or \`Verilated::...'"?
You need to link your compiled Verilated code against the
:code:`verilated.cpp` file found in the include directory of the Verilator
kit. This is one target in the ``$(VK_GLOBAL_OBJS)`` make variable, which
should be part of your Makefile's link rule. If you use :vlopt:`--exe`,
this is done for you.
should be part of your Makefile's link rule. If you use :vlopt:`--exe` or
:vlopt:`--binary`, this is done for you.
Is the PLI supported?
@@ -486,7 +486,7 @@ From the sc_main.cpp file, you'd then:
#include "Vour.h"
#include "Vour_our.h"
cout << "clock is " << top->our->clk << endl;
std::cout << "clock is " << top->our->clk << std::endl;
In this example, clk is a bool you can read or set as any other variable.
+4 -2
View File
@@ -126,8 +126,10 @@ In specific debug and other modes, it also creates:
- Debugging graph files (from --debug)
* - *{prefix}{misc}*\ .tree
- Debugging files (from --debug)
* - {mod_prefix}_{each_verilog_base_filename}*\ .vpp
- Pre-processed verilog (from --debug)
* - *{prefix}*\ __inputs\ .vpp
- Pre-processed verilog for all files (from --debug)
* - *{prefix}*\ _ *{each_verilog_base_filename}*\ .vpp
- Pre-processed verilog for each file (from --debug)
After running Make, the C++ compiler may produce the following:
+22 -34
View File
@@ -39,7 +39,7 @@ In brief, to install from git:
::
# Prerequisites:
#sudo apt-get install git perl python3 make autoconf g++ flex bison ccache
#sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache
#sudo apt-get install libgoogle-perftools-dev numactl perl-doc
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
@@ -104,6 +104,7 @@ for good performance:
::
sudo apt-get install ccache # If present at build, needed for run
sudo apt-get install mold # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl
The following is optional but is recommended for nicely rendered command line
@@ -124,9 +125,9 @@ Those developing Verilator itself may also want these (see internals.rst):
::
sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov
sudo apt-get install libclang-dev yapf3
sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov
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
@@ -201,8 +202,9 @@ These are the installation options:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Our personal favorite is to always run Verilator in-place from its Git
directory. This allows the easiest experimentation and upgrading, and
allows many versions of Verilator to co-exist on a system.
directory (don't run ``make install``). This allows the easiest
experimentation and upgrading, and allows many versions of Verilator to
co-exist on a system.
::
@@ -211,17 +213,18 @@ allows many versions of Verilator to co-exist on a system.
./configure
# Running will use files from $VERILATOR_ROOT, so no install needed
Note after installing (below steps), a calling program or shell must set
the environment variable :option:`VERILATOR_ROOT` to point to this Git
directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will find
the path to all needed files.
Note after installing (see `Installation`_), a calling program or shell
must set the environment variable :option:`VERILATOR_ROOT` to point to this
Git directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will
find the path to all needed files.
2. Install into a specific location
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2. Install into a Specific Prefix
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may eventually be installing onto a project/company-wide "CAD" tools
disk that may support multiple versions of every tool. Tell configure the
You may be an OS package maintainer building a Verilator package, or you
may eventually be installing onto a project/company-wide "CAD" tools disk
that may support multiple versions of every tool. Tell configure the
eventual destination directory name. We recommend that the destination
location include the Verilator version name:
@@ -232,7 +235,8 @@ location include the Verilator version name:
# For the tarball, use the version number instead of git describe
./configure --prefix /CAD_DISK/verilator/`git describe | sed "s/verilator_//"`
Note after installing (below steps), if you use `modulecmd
Note after installing (see `Installation`_), you need to add the path to
the ``bin`` directory to your ``PATH``. Or, if you use `modulecmd
<http://modules.sourceforge.net/>`__, you'll want a module file like the
following:
@@ -245,23 +249,7 @@ following:
prepend-path PKG_CONFIG_PATH $install_root/share/pkgconfig
3. Install into a Specific Path
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may eventually install Verilator into a specific installation prefix,
as most GNU tools support:
::
unset VERILATOR_ROOT # if your shell is bash
unsetenv VERILATOR_ROOT # if your shell is csh
./configure --prefix /opt/verilator-VERSION
Then after installing (below steps), you will need to add
``/opt/verilator-VERSION/bin`` to your ``$PATH`` environment variable.
4. Install System Globally
3. Install System Globally
^^^^^^^^^^^^^^^^^^^^^^^^^^
The final option is to eventually install Verilator globally, using
@@ -273,8 +261,8 @@ configure's default system paths:
unsetenv VERILATOR_ROOT # if your shell is csh
./configure
Then after installing (below), the binaries should be in a location
already in your ``$PATH`` environment variable.
Then after installing (see `Installation`_), the binaries should be in a
location already in your ``$PATH`` environment variable.
Configure
+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
+2 -2
View File
@@ -143,7 +143,7 @@ Functional Coverage
-------------------
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
translate functional coverage points the user has inserted manually win
translate functional coverage points the user has inserted manually in
SystemVerilog code through into the Verilated model.
Currently, all functional coverage points are specified using SystemVerilog
@@ -500,7 +500,7 @@ feedback-directed optimization. See the appropriate compiler
documentation.
.. _Runtime Debugging
.. _Runtime Debugging:
Runtime Debugging
=================
+1 -1
View File
@@ -165,7 +165,7 @@ compiled on the different target system.
To support this, none of the files that Verilator produces will reference
any configure-generated build-system-specific files, such as
:file:`config.h` (which is renamed in Verilator to :file:`config_build.h`
:file:`config.h` (which is renamed in Verilator to :file:`config_package.h`
to reduce confusion.) The disadvantage of this approach is that
:file:`include/verilatedos.h` must self-detect the requirements of the
target system, rather than using configure.
+273 -19
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
========================
@@ -670,6 +678,52 @@ List Of Warnings
used as a clock.
.. option:: GENUNNAMED
Warns that a generate block was unnamed and "genblk" will be used per
IEEE.
The potential issue is that adding additional generate blocks will
renumber the assigned names, which may cause eventual problems with
synthesis constraints or other tools that depend on hierarchical paths
remaining consistent.
Blocks that are empty may not be reported with this warning, as no
scopes are created for empty blocks, so there is no harm in having them
unnamed.
Disabled by default as this is a code-style warning; it will simulate
correctly.
.. code-block:: sv
:linenos:
:emphasize-lines: 2
generate
if (PARAM == 1) begin //<--- Warning
end
Results in:
.. code-block::
%Warning-GENUNNAMED: example.v:2:9: Unnamed generate block (IEEE 1800-2017 27.6)
To fix this assign a label (often with the naming convention prefix of
:code:`gen_` or :code:`g_`), for example:
.. code-block:: sv
:linenos:
:emphasize-lines: 2
generate
if (PARAM == 1) begin : gen_param_1 //<--- Repaired
end
Other tools with similar warnings: Verible's generate-label, "All
generate block statements must have a label."
.. option:: HIERBLOCK
Warns that the top module is marked as a hierarchy block by the
@@ -769,11 +823,14 @@ List Of Warnings
then automatic as static prevents the function from being reentrant,
which may be a source of bugs, and/or performance issues.
If the function does not require static behavior, change it to "function
automatic".
If the function is in a module, and does not require static behavior,
change it to "function automatic".
If the function requires static behavior, change it to "function
static".
If the function is in a module, and requires static behavior, change it
to "function static".
If the function is in a package, it defaults to static, and label the
function's variables as static.
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
@@ -873,6 +930,102 @@ List Of Warnings
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: LIFETIME
Error when a variable is referenced in a process that can outlive the process
in which it was declared. This can happen when using 'fork..join_none' or
'fork..join_any' blocks, which spawn process that can outlive their parents.
This error occurs only when Verilator can't replace the reference with a
reference to copy of this variable, local to the forked process. For example:
.. code-block:: sv
:linenos:
:emphasize-lines: 3
task foo(int local_var);
fork
#10 local_var++;
#20 $display("local_var = %d", local_var);
join_none
endtask
In the example above 'local_var' exists only within scope of 'foo', once foo
finishes, the stack frame containing 'i' gets removed. However, the process
forked from foo continues, as it contains a delay. After 10 units of time
pass, this process attempts to modify 'local_var'. However, this variable no
longer exits. It can't be made local to the forked process upon spawning, because
it's modified and can be referenced somewhere else, for example in the other
forked process, that was delayed by 20 units of time in this example. Thus,
there's no viable stack allocation for it.
In order to fix it, if the intent is not to share the variable's state outside
of the process, then create a local copy of the variable.
For example:
.. code-block:: sv
:linenos:
:emphasize-lines: 4
task foo(int local_var);
fork
#10 begin
int forked_var = local_var;
forked_var++;
end
#20 begin
// Note that we are going to print the original value here,
// as `forked_var`is a local copy that was initialized while
// `foo` was still alive.
int forked_var = local_var;
$display("forked_var = %d", forked_var)
end
join_none
endtask
If you need to share its state, another strategy is to ensure it's allocated
statically:
.. code-block:: sv
:linenos:
:emphasize-lines: 1
int static_var;
task foo();
fork
#10 static_var++;
#20 $display("static_var = %d", static_var);
join_none
endtask
However, if you need to be able to instantiate at runtime, the solution would be to
wrap it in an object, since the forked process can hold a reference to that object
and ensure that the variable stays alive this way:
.. code-block:: sv
:linenos:
:emphasize-lines: 2
class Wrapper;
int m_var;
// Here we implicitly hold a reference to `this`
task foo();
fork
#10 m_var++;
#20 $display("this.m_var = %d", m_var);
join_none
endtask
endclass
// Here we explicitly hold a handle to an object
task bar(Wrapper wrapper);
fork
#10 wrapper.m_var++;
#20 $display("wrapper.m_var = %d", wrapper.m_var);
join_none
endtask
.. option:: LITENDIAN
@@ -894,6 +1047,51 @@ List Of Warnings
unsupported. Verilator uses only the typical delay value.
.. option:: MISINDENT
Warns that the indentation of a statement is misleading, suggesting the
statement is part of a previous :code:`if` or :code:`while` block while
it is not.
Verilator suppresses this check when there is an inconsistent mix of
spaces and tabs, as it cannot ensure the width of tabs. Verilator also
ignores blocks with :code:`begin`/:code:`end`, as the :code:`end`
visually indicates the earlier statement's end.
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
For example
.. code-block:: sv
:linenos:
:emphasize-lines: 3
if (something)
statement_in_if;
statement_not_in_if; //<--- Warning
Results in:
.. code-block::
%Warning-MISINDENT: example.v:3:9: Misleading indentation
To fix this repair the indentation to match the correct earlier
statement, for example:
.. code-block:: sv
:linenos:
:emphasize-lines: 3
if (something)
statement_in_if;
statement_not_in_if; //<--- Repaired
Other tools with similar warnings: GCC -Wmisleading-indentation,
clang-tidy readability-misleading-indentation.
.. option:: MODDUP
.. TODO better example
@@ -972,6 +1170,21 @@ List Of Warnings
(neither :vlopt:`--timing` nor :vlopt:`--no-timing` option was provided).
.. option:: NEWERSTD
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 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
syntax that is supported by the Verilog/SystemVerilog standard specified
by the :vlopt:`--language` option.
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: NOLATCH
.. TODO better example
@@ -1155,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`.
@@ -1298,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*/`
@@ -1785,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
@@ -1834,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
+51 -17
View File
@@ -638,7 +638,22 @@ condition. See the `Timing Pass` section for more details.
Timing Pass
~~~~~~~~~~~
The visitor in ``V3Timing.cpp`` transforms each timing control into a ``co_await``.
There are two visitors in ``V3Timing.cpp``.
The first one, ``TimingSuspendableVisitor``, does not perform any AST
transformations. It is responsible for marking processes and C++ functions that
contain timing controls as suspendable. Processes that call suspendable
functions are also marked as suspendable. Functions that call, are overridden
by, or override suspendable functions are marked as suspendable as well.
The visitor keeps a dependency graph of functions and processes to handle such
cases. A function or process is dependent on a function if it calls it. A
virtual class method is dependent on another class method if it calls it,
overrides it, or is overriden by it.
The second visitor in ``V3Timing.cpp``, ``TimingControlVisitor``, uses the
information provided by ``TimingSuspendableVisitor`` and transforms each timing
control into a ``co_await``.
* event controls are turned into ``co_await`` on a trigger scheduler's
``trigger`` method. The awaited trigger scheduler is the one corresponding to
@@ -670,14 +685,9 @@ Each sub-statement of a ``fork`` is put in an ``AstBegin`` node for easier
grouping. In a later step, each of these gets transformed into a new, separate
function. See the `Forks` section for more detail.
Processes that use awaits are marked as suspendable. Later, during ``V3Sched``,
they are transformed into coroutines. Functions that use awaits get the return
type of ``VlCoroutine``. This immediately makes them coroutines. Note that if a
process calls a function that is a coroutine, the call gets wrapped in an
await, which means the process itself will be marked as suspendable. A virtual
function is a coroutine if any of its overriding or overridden functions are
coroutines. The visitor keeps a dependency graph of functions and processes to
handle such cases.
Suspendable functions get the return type of ``VlCoroutine``, which makes them
coroutines. Later, during ``V3Sched``, suspendable processes are also
transformed into coroutines.
Scheduling with timing
~~~~~~~~~~~~~~~~~~~~~~
@@ -1212,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
@@ -1390,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`.
@@ -1422,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.
::
@@ -1452,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
----------------------
@@ -1503,8 +1526,19 @@ debug level 5, with the V3Width.cpp file at level 9.
--debug
-------
When you run with ``--debug``, there are two primary output file types
placed into the obj_dir, .tree and .dot files.
When you run with ``--debug``, there are three primary output file types
placed into the obj_dir, .vpp, .tree and .dot files.
.vpp Output
-----------
Verilator creates a *{mod_prefix}*\ __inputs\ .vpp file containing all the
files that were read, filtered by preprocessing. This file can be fed back
into Verilator, replacing on the command line all of the previous input
files, to enable simplification of test cases.
Verilator also creates .vpp files for each individual file passed on the
command line.
.dot Output
@@ -1619,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
@@ -2102,7 +2136,7 @@ Or in a hand-written C++ wrapper:
::
#ifdef TEST_VERBOSE
cout << "Read a=" << a << endl;
std::cout << "Read a=" << a << std::endl;
#endif
A filename that should be used to check the output results is given with
+29
View File
@@ -35,11 +35,13 @@ Briquet
Brownlee
Buckenmaier
Bybell
CLang
CMake
Cai
Cavium
Cfuncs
Chandan
Chih
Chitlesh
Christophe
Cochrane
@@ -56,6 +58,7 @@ Das
Dcache
Deadman
Debacker
Deepa
Defparams
Denio
Deprecations
@@ -88,6 +91,7 @@ Engstrom
Enzo
Eugen
Fabrizio
Faucher
Fekete
Ferrandi
Flachs
@@ -213,6 +217,7 @@ Maupin
Mdir
Mednick
Menküc
Michail
Michiels
Microsystems
Milanovic
@@ -228,6 +233,7 @@ Mong
Muhlestein
Multithreaded
Multithreading
Mykyta
NOUNOPTFLAT
NaN
Nalbantis
@@ -246,6 +252,7 @@ Olof
Olofsson
Oyvind
PLI
Palaniappan
Patricio
Petr
Piechotka
@@ -260,6 +267,8 @@ Prateek
Pre
Preprocess
Pretet
Pretl
Pringlemeir
Priyadharshini
Pullup
Pulver
@@ -274,6 +283,7 @@ Renga
Requin
Rodionov
Rolfe
Rontionov
Roodselaar
Runtime
Ruud
@@ -375,6 +385,7 @@ Wfuture
Whatson
Wildman
Wim
Wmisleading
Wno
Wojciech
Wolfel
@@ -409,7 +420,9 @@ architected
args
arrarys
assertOn
astgen
async
atClone
ato
atoi
autoconf
@@ -472,10 +485,12 @@ constexpr
constpool
coredump
coroutine
coroutines
countbits
countones
cout
cpp
cppstyle
cpu
ctor
ctrace
@@ -510,6 +525,7 @@ doxygen
dpiGetContext
dpic
dsvf
dt
dtor
dumpall
dumpfile
@@ -602,6 +618,7 @@ genvar
genvars
getenv
getline
ggdb
gmake
gmon
gotFinish
@@ -646,6 +663,7 @@ ish
isunbounded
isunknown
jobserver
jwoutersymatra
killua
lang
lcov
@@ -709,6 +727,7 @@ multithreading
musl
mutexes
mux
muzafferkal
myftptoyman
mysignal
namespace
@@ -747,6 +766,7 @@ pdf
perf
perftools
pgo
phelter
picoChip
pinIndex
pinout
@@ -764,7 +784,9 @@ pragma
pragmas
pre
precisions
precompiled
predefines
prepareClone
prepend
prepended
preprocess
@@ -791,6 +813,8 @@ qrq
radix
randc
randcase
randstate
raphmaster
rarr
rdtsc
reStructuredText
@@ -800,6 +824,7 @@ readmemb
readmemh
realpath
realtime
realtobits
recoding
recrem
redeclaring
@@ -896,10 +921,12 @@ typedefs
typename
uint
un
unbased
undef
undefineall
undriven
ungetc
unhandled
uniquified
unistd
unlink
@@ -920,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")
#######################################################################
+26 -22
View File
@@ -2052,7 +2052,8 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
int zfd;
int fourpack_duo = 0;
#ifndef __MINGW32__
char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1);
int fnam_len = strlen(xc->filename) + 5 + 1;
char *fnam = (char *)malloc(fnam_len);
#endif
fixup_offs = ftello(xc->handle);
@@ -2142,7 +2143,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
fflush(xc->handle);
#ifndef __MINGW32__
sprintf(fnam, "%s.hier", xc->filename);
snprintf(fnam, fnam_len, "%s.hier", xc->filename);
unlink(fnam);
free(fnam);
#endif
@@ -2821,7 +2822,7 @@ if(ctx && name && literal_arr && val_arr && (elem_count != 0))
uint32_t i;
name_len = strlen(name);
elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count);
elem_count_len = snprintf(elem_count_buf, 16, "%" PRIu32, elem_count);
literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
@@ -3909,7 +3910,8 @@ int pass_status = 1;
if(!xc->fh)
{
fst_off_t offs_cache = ftello(xc->f);
char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1);
int fnam_len = strlen(xc->filename) + 6 + 16 + 32 + 1;
char *fnam = (char *)malloc(fnam_len);
unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
fst_off_t hl, uclen;
fst_off_t clen = 0;
@@ -3928,7 +3930,7 @@ if(!xc->fh)
htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4;
}
sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
snprintf(fnam, fnam_len, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
uclen = fstReaderUint64(xc->f);
#ifndef __MINGW32__
@@ -4179,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;
@@ -4585,15 +4587,17 @@ if(sectype == FST_BL_ZWRAPPER)
int zfd;
int flen = strlen(xc->filename);
char *hf;
int hf_len;
seclen = fstReaderUint64(xc->f);
uclen = fstReaderUint64(xc->f);
if(!seclen) return(0); /* not finished compressing, this is a failed read */
hf = (char *)calloc(1, flen + 16 + 32 + 1);
hf_len = flen + 16 + 32 + 1;
hf = (char *)calloc(1, hf_len);
sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
snprintf(hf, hf_len, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
fcomp = fopen(hf, "w+b");
if(!fcomp)
{
@@ -5189,16 +5193,16 @@ for(;;)
if(beg_tim)
{
if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim);
if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", beg_tim);
fstWritex(xc, wx_buf, wx_len);
if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
}
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
{
if(beg_tim == xc->blackout_times[cur_blackout])
{
wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
wx_len = snprintf(wx_buf, 32, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -5332,7 +5336,7 @@ for(;;)
clone_d[j] = srcdata[7-j];
}
}
sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.16g", d);
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
}
}
@@ -5360,7 +5364,7 @@ for(;;)
}
fstVcdID(vcdid_buf, idx+1);
wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf);
wx_len = snprintf(wx_buf, 64, "r%.16g %s\n", d, vcdid_buf);
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -5625,16 +5629,16 @@ for(;;)
}
}
if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]);
if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", time_table[i]);
fstWritex(xc, wx_buf, wx_len);
if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
{
if(time_table[i] == xc->blackout_times[cur_blackout])
{
wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
wx_len = snprintf(wx_buf, 32, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -5884,7 +5888,7 @@ for(;;)
clone_d[j] = srcdata[7-j];
}
}
sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.16g", d);
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
}
}
@@ -5910,7 +5914,7 @@ for(;;)
}
}
wx_len = sprintf(wx_buf, "r%.16g", d);
wx_len = snprintf(wx_buf, 32, "r%.16g", d);
fstWritex(xc, wx_buf, wx_len);
}
}
@@ -6016,7 +6020,7 @@ if(xc->signal_lens[facidx] == 1)
}
}
sprintf((char *)buf, "%.16g", d);
snprintf((char *)buf, 32, "%.16g", d); /* this will write 18 bytes */
}
}
@@ -6608,7 +6612,7 @@ if(xc->signal_lens[facidx] == 1)
}
}
sprintf(buf, "r%.16g", d);
snprintf(buf, 32, "r%.16g", d); /* this will write 19 bytes */
return(buf);
}
}
+53 -20
View File
@@ -315,15 +315,28 @@ void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE {
if (VL_COUNTONES_I(m_state[0]) < 10) m_state[0] = ~m_state[0];
if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1];
}
// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) {
// Unused: memcpy(m_state, state.data(), sizeof(m_state));
// Unused: }
// Unused: }
// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
// Unused: std::string result{reinterpret_cast<const char *>(&m_state), sizeof(m_state)};
// Unused: return result;
// Unused: }
std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
// Though not stated in IEEE, assumption is the string must be printable
const char* const stateCharsp = reinterpret_cast<const char*>(&m_state);
static_assert(sizeof(m_state) == 16, "");
std::string result{"R00112233445566770011223344556677"};
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);
}
return result;
}
void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
if (VL_UNLIKELY((state.length() != 1 + 2 * sizeof(m_state)) || (state[0] != 'R'))) {
VL_PRINTF_MT("%%Warning: set_randstate ignored as state string not from get_randstate\n");
return;
}
char* const stateCharsp = reinterpret_cast<char*>(&m_state);
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);
}
}
static uint32_t vl_sys_rand32() VL_MT_SAFE {
// Return random 32-bits using system library.
@@ -1360,16 +1373,18 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
*p = t_tmp;
} else if (obits <= VL_BYTESIZE) {
CData* const p = va_arg(ap, CData*);
*p = owp[0];
*p = VL_CLEAN_II(obits, obits, owp[0]);
} else if (obits <= VL_SHORTSIZE) {
SData* const p = va_arg(ap, SData*);
*p = owp[0];
*p = VL_CLEAN_II(obits, obits, owp[0]);
} else if (obits <= VL_IDATASIZE) {
IData* const p = va_arg(ap, IData*);
*p = owp[0];
*p = VL_CLEAN_II(obits, obits, owp[0]);
} else if (obits <= VL_QUADSIZE) {
QData* const p = va_arg(ap, QData*);
*p = VL_SET_QW(owp);
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
} else {
_vl_clean_inplace_w(obits, owp);
}
}
} // switch
@@ -1881,6 +1896,12 @@ std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
return std::string{destout, len};
}
std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE {
std::string output;
for (const std::string& s : q) output += s;
return output;
}
std::string VL_PUTC_N(const std::string& lhs, IData rhs, CData ths) VL_PURE {
std::string lstring = lhs;
const int32_t rhs_s = rhs; // To signed value
@@ -2073,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
@@ -2587,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));
@@ -2995,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();
}
@@ -3213,15 +3243,18 @@ void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
//===========================================================================
// VlDeleter:: Methods
void VlDeleter::deleteAll() {
void VlDeleter::deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_MT_SAFE {
while (true) {
VerilatedLockGuard lock{m_mutex};
if (m_newGarbage.empty()) break;
VerilatedLockGuard deleteLock{m_deleteMutex};
std::swap(m_newGarbage, m_toDelete);
lock.unlock(); // So destructors can enqueue new objects
{
VerilatedLockGuard lock{m_mutex};
if (m_newGarbage.empty()) break;
m_deleteMutex.lock();
std::swap(m_newGarbage, m_toDelete);
// m_mutex is unlocked here, so destructors can enqueue new objects
}
for (VlDeletable* const objp : m_toDelete) delete objp;
m_toDelete.clear();
m_deleteMutex.unlock();
}
}
+9 -15
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 {
@@ -175,6 +178,7 @@ public:
/// Construct mutex (without locking it)
VerilatedMutex() = default;
~VerilatedMutex() = default;
VL_UNCOPYABLE(VerilatedMutex);
const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety
/// Acquire/lock mutex
void lock() VL_ACQUIRE() VL_MT_SAFE {
@@ -218,23 +222,10 @@ public:
/// Construct and hold given mutex lock until destruction or unlock()
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
m_mutexr.lock();
mutexr.lock();
}
/// Destruct and unlock the mutex
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
/// Lock the mutex
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
/// Unlock the mutex
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
/// Acquire/lock mutex and check for stop request.
/// It tries to lock the mutex and if it fails, it check if stop request was send.
/// It returns after locking mutex.
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
/// limitations it needs to be placed here.
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
VL_ACQUIRE() VL_MT_SAFE {
m_mutexr.lockCheckStopRequest(checkStopRequestFunction);
}
};
// Internals: Remember the calling thread at construction time, and make
@@ -580,6 +571,8 @@ public:
void addModel(VerilatedModel*);
VerilatedVirtualBase* threadPoolp();
void prepareClone();
VerilatedVirtualBase* threadPoolpOnClone();
VerilatedVirtualBase*
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
@@ -929,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
+56 -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,14 @@ 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
CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@
@@ -41,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
@@ -77,6 +95,8 @@ VPATH += ..
VPATH += $(VERILATOR_ROOT)/include
VPATH += $(VERILATOR_ROOT)/include/vltstd
LDFLAGS += $(CFG_LDFLAGS_VERILATED)
#OPT = -ggdb -DPRINTINITSTR -DDETECTCHANGE
#OPT = -ggdb -DPRINTINITSTR
CPPFLAGS += $(OPT)
@@ -158,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))
@@ -189,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
@@ -233,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:
@@ -292,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
######################################################################
+4 -4
View File
@@ -210,8 +210,8 @@ private:
std::string result = prefix + "*" + suffix;
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
// <<"\ncho="<<result<<endl;
// std::cout << "\nch pre=" << prefix << " s=" << suffix << "\nch a="
// << old << "\nch b=" << add << "\ncho=" << result << std::endl;
return result;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
@@ -316,7 +316,7 @@ public:
valps[2] = page_default.c_str();
// Keys -> strings
std::string keys[VerilatedCovConst::MAX_KEYS];
std::array<std::string, VerilatedCovConst::MAX_KEYS> keys;
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) keys[i] = ckeyps[i];
}
@@ -337,7 +337,7 @@ public:
const std::string key = keys[i];
if (!keys[i].empty()) {
const std::string val = valps[i];
// cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
// std::cout << " " << __FUNCTION__ << " " << key << " = " << val << std::endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
++addKeynum;
+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);
+116 -67
View File
@@ -152,9 +152,11 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE; // PLIi
// Base macros
// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
// Arguments must not have side effects
#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit))
// Shift appropriate word by bit. Does not account for wrapping between two words
// Argument 'bit' must not have side effects
#define VL_BITRSHIFT_W(data, bit) ((data)[VL_BITWORD_E(bit)] >> VL_BITBIT_E(bit))
// Create two 32-bit words from quadword
@@ -342,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))
@@ -447,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) { \
@@ -473,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); \
}
@@ -502,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)) { \
@@ -758,6 +760,7 @@ static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_PURE {
static inline IData VL_CLOG2_I(IData lhs) VL_PURE {
// There are faster algorithms, or fls GCC4 builtins, but rarely used
// In C++20 there will be std::bit_width(lhs) - 1
if (VL_UNLIKELY(!lhs)) return 0;
--lhs;
int shifts = 0;
@@ -953,11 +956,19 @@ static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE
// EMIT_RULE: VL_MUL: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_DIV: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_MODDIV: oclean=dirty; lclean==clean; rclean==clean;
#define VL_DIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs))
#define VL_DIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs))
static inline IData VL_DIV_III(int lbits, IData lhs, IData rhs) {
return (rhs == 0) ? 0 : lhs / rhs;
}
static inline QData VL_DIV_QQQ(int lbits, QData lhs, QData rhs) {
return (rhs == 0) ? 0 : lhs / rhs;
}
#define VL_DIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 0))
#define VL_MODDIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs))
#define VL_MODDIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs))
static inline IData VL_MODDIV_III(int lbits, IData lhs, IData rhs) {
return (rhs == 0) ? 0 : lhs % rhs;
}
static inline QData VL_MODDIV_QQQ(int lbits, QData lhs, QData rhs) {
return (rhs == 0) ? 0 : lhs % rhs;
}
#define VL_MODDIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 1))
static inline WDataOutP VL_ADD_W(int words, WDataOutP owp, WDataInP const lwp,
@@ -1426,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) {
@@ -1515,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.
@@ -1614,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);
@@ -1651,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 {
@@ -1665,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
@@ -1718,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;
@@ -1750,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));
}
@@ -2078,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);
}
@@ -2185,6 +2233,7 @@ extern IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE;
// Conversion functions
extern std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE;
extern std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE;
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
VlWide<VL_WQ_WORDS_E> lw;
VL_SET_WQ(lw, lhs);
-31
View File
@@ -1,31 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2010-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 old string and data-type header
///
/// This file is deprecated, and provided for backwards compatibility.
/// Include verilated.h instead.
///
//*************************************************************************
#ifndef VERILATOR_VERILATED_HEAVY_H_
#define VERILATOR_VERILATED_HEAVY_H_
#ifdef VL_NO_LEGACY
#error "Include <verilated.h> instead of <verilated_heavy.h>"
#endif
#include "verilated.h"
#endif // Guard
+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,
+58 -25
View File
@@ -26,10 +26,6 @@
// verilator lint_off TIMESCALEMOD
// verilator lint_off UNUSEDSIGNAL
package std;
// The process class is not implemented, but it's predeclared here,
// so the linter accepts references to it.
typedef class process;
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
@@ -45,13 +41,13 @@ package std;
task put(T message);
`ifdef VERILATOR_TIMING
if (m_bound != 0)
wait (m_queue.size() < m_bound);
wait (m_queue.size() < m_bound);
m_queue.push_back(message);
`endif
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
@@ -117,43 +113,80 @@ package std;
endclass
class process;
typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state;
static process _s_global_process;
typedef enum {
FINISHED = 0,
RUNNING = 1,
WAITING = 2,
SUSPENDED = 3,
KILLED = 4
} state;
`ifdef VERILATOR_TIMING
// Width visitor changes it to VlProcessRef
protected chandle m_process;
`endif
static function process self();
// Unsupported, emulating with single process' state
if (!_s_global_process) _s_global_process = new;
return _s_global_process;
process p = new;
`ifdef VERILATOR_TIMING
$c(p.m_process, " = vlProcess;");
`endif
return p;
endfunction
protected function void set_status(state s);
`ifdef VERILATOR_TIMING
$c(m_process, "->state(", s, ");");
`endif
endfunction
function state status();
// Unsupported, emulating with single process' state
`ifdef VERILATOR_TIMING
return state'($c(m_process, "->state()"));
`else
return RUNNING;
`endif
endfunction
function void kill();
$error("std::process::kill() not supported");
set_status(KILLED);
endfunction
task await();
$error("std::process::await() not supported");
endtask
function void suspend();
$error("std::process::suspend() not supported");
endfunction
function void resume();
$error("std::process::resume() not supported");
set_status(RUNNING);
endfunction
// When really implemented, srandom must operates on the process, but for
task await();
`ifdef VERILATOR_TIMING
wait (status() == FINISHED || status() == KILLED);
`endif
endtask
// When really implemented, srandom must operate on the process, but for
// now rely on the srandom() that is automatically generated for all
// classes.
//
// function void srandom(int seed);
// endfunction
// The methods below work only if set_randstate is never applied to
// a state string created before another such string. Full support
// could use VlRNG class to store the state per process in VlProcess
// objects.
function string get_randstate();
// Could operate on all proceses for now
// No error, as harmless until set_randstate is called
return "NOT_SUPPORTED";
string s;
s.itoa($random); // Get a random number
set_randstate(s); // Pretend it's the state of RNG
return s;
endfunction
function void set_randstate(string randstate);
$error("std::process::set_randstate() not supported");
// Could operate on all proceses for now
function void set_randstate(string s);
$urandom(s.atoi()); // Set the seed using a string
endfunction
endclass
endpackage
+1 -1
View File
@@ -173,7 +173,7 @@ public:
VerilatedLockGuard lock{m_mutex};
while (m_ready.empty()) {
m_waiting = true;
m_cv.wait(lock);
m_cv.wait(m_mutex);
}
m_waiting = false;
// As noted above this is inefficient if our ready list is ever
+15 -4
View File
@@ -30,7 +30,16 @@ void VlCoroutineHandle::resume() {
// main process
if (VL_LIKELY(m_coro)) {
VL_DEBUG_IF(VL_DBG_MSGF(" Resuming: "); dump(););
m_coro();
if (m_process) { // If process state is managed with std::process
if (m_process->state() == VlProcess::KILLED) {
m_coro.destroy();
} else {
m_process->state(VlProcess::RUNNING);
m_coro();
}
} else {
m_coro();
}
m_coro = nullptr;
}
}
@@ -95,8 +104,9 @@ void VlTriggerScheduler::resume(const char* eventDescription) {
VL_DEBUG_IF(dump(eventDescription);
VL_DBG_MSGF(" Resuming processes waiting for %s\n", eventDescription););
#endif
for (auto& susp : m_ready) susp.resume();
m_ready.clear();
std::swap(m_ready, m_resumeQueue);
for (VlCoroutineHandle& coro : m_resumeQueue) coro.resume();
m_resumeQueue.clear();
commit(eventDescription);
}
@@ -143,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() {
+65 -26
View File
@@ -96,33 +96,52 @@ class VlCoroutineHandle final {
// MEMBERS
std::coroutine_handle<> m_coro; // The wrapped coroutine handle
VlProcessRef m_process; // Data of the suspended process, null if not needed
VlFileLineDebug m_fileline;
public:
// CONSTRUCTORS
// Construct
VlCoroutineHandle()
: m_coro{nullptr} {}
VlCoroutineHandle(std::coroutine_handle<> coro, VlFileLineDebug fileline)
// non-explicit:
// cppcheck-suppress noExplicitConstructor
VlCoroutineHandle(VlProcessRef process)
: m_coro{nullptr}
, m_process{process} {
if (m_process) m_process->state(VlProcess::WAITING);
}
VlCoroutineHandle(std::coroutine_handle<> coro, VlProcessRef process, VlFileLineDebug fileline)
: m_coro{coro}
, m_fileline{fileline} {}
, m_process{process}
, m_fileline{fileline} {
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{std::exchange(moved.m_process, nullptr)}
, m_fileline{moved.m_fileline} {}
// Destroy if the handle isn't null
~VlCoroutineHandle() {
// Usually these coroutines should get resumed; we only need to clean up if we destroy a
// model with some coroutines suspended
if (VL_UNLIKELY(m_coro)) m_coro.destroy();
if (VL_UNLIKELY(m_coro)) {
m_coro.destroy();
if (m_process && m_process->state() != VlProcess::KILLED) {
m_process->state(VlProcess::FINISHED);
}
}
}
// METHODS
// 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
// Resume the coroutine if the handle isn't null and the process isn't killed
void resume();
#ifdef VL_DEBUG
void dump() const;
@@ -173,21 +192,24 @@ public:
void dump() const;
#endif
// Used by coroutines for co_awaiting a certain simulation time
auto delay(uint64_t delay, const char* filename = VL_UNKNOWN, int lineno = 0) {
auto delay(uint64_t delay, VlProcessRef process, const char* filename = VL_UNKNOWN,
int lineno = 0) {
struct Awaitable {
VlProcessRef process; // Data of the suspended process, null if not needed
VlDelayedCoroutineQueue& queue;
uint64_t delay;
VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) {
queue.push_back({delay, VlCoroutineHandle{coro, fileline}});
queue.push_back({delay, VlCoroutineHandle{coro, process, fileline}});
// Move last element to the proper place in the max-heap
std::push_heap(queue.begin(), queue.end());
}
void await_resume() const {}
};
return Awaitable{m_queue, m_context.time() + delay, VlFileLineDebug{filename, lineno}};
return Awaitable{process, m_queue, m_context.time() + delay,
VlFileLineDebug{filename, lineno}};
}
};
@@ -207,6 +229,10 @@ class VlTriggerScheduler final {
// (not resumable)
VlCoroutineVec m_ready; // Coroutines that can be resumed (all coros from m_uncommitted are
// moved here in commit())
VlCoroutineVec m_resumeQueue; // Coroutines being resumed by resume(); kept as a field to
// avoid reallocation. Resumed coroutines are moved to
// m_resumeQueue to allow adding coroutines to m_ready
// during resume(). Outside of resume() should always be empty.
public:
// METHODS
@@ -220,21 +246,23 @@ public:
void dump(const char* eventDescription) const;
#endif
// Used by coroutines for co_awaiting a certain trigger
auto trigger(const char* eventDescription = VL_UNKNOWN, const char* filename = VL_UNKNOWN,
int lineno = 0) {
auto trigger(bool commit, VlProcessRef process, const char* eventDescription = VL_UNKNOWN,
const char* filename = VL_UNKNOWN, int lineno = 0) {
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
eventDescription, filename, lineno););
struct Awaitable {
VlCoroutineVec& suspended; // Coros waiting on trigger
VlProcessRef process; // Data of the suspended process, null if not needed
VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) {
suspended.emplace_back(coro, fileline);
suspended.emplace_back(coro, process, fileline);
}
void await_resume() const {}
};
return Awaitable{m_uncommitted, VlFileLineDebug{filename, lineno}};
return Awaitable{commit ? m_ready : m_uncommitted, process,
VlFileLineDebug{filename, lineno}};
}
};
@@ -247,6 +275,7 @@ public:
// co_await __VdynSched.evaluation();
// <pre updates>;
// __Vtrigger = <trigger eval>;
// __VdynShed.anyTriggered(__Vtrigger);
// [optionally] co_await __VdynSched.postUpdate();
// <post updates>;
// }
@@ -260,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
@@ -267,23 +297,26 @@ class VlDynamicTriggerScheduler final {
// with destructive post updates, e.g. named events)
// METHODS
auto awaitable(VlCoroutineVec& queue, const char* filename, int lineno) {
auto awaitable(VlProcessRef process, VlCoroutineVec& queue, const char* filename, int lineno) {
struct Awaitable {
VlProcessRef process; // Data of the suspended process, null if not needed
VlCoroutineVec& suspended; // Coros waiting on trigger
VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) {
suspended.emplace_back(coro, fileline);
suspended.emplace_back(coro, process, fileline);
}
void await_resume() const {}
};
return Awaitable{queue, VlFileLineDebug{filename, lineno}};
return Awaitable{process, queue, VlFileLineDebug{filename, lineno}};
}
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())
@@ -292,23 +325,26 @@ public:
void dump() const;
#endif
// Used by coroutines for co_awaiting trigger evaluation
auto evaluation(const char* eventDescription, const char* filename, int lineno) {
auto evaluation(VlProcessRef process, const char* eventDescription, const char* filename,
int lineno) {
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
eventDescription, filename, lineno););
return awaitable(m_suspended, filename, lineno);
return awaitable(process, m_suspended, filename, lineno);
}
// Used by coroutines for co_awaiting the trigger post update step
auto postUpdate(const char* eventDescription, const char* filename, int lineno) {
auto postUpdate(VlProcessRef process, const char* eventDescription, const char* filename,
int lineno) {
VL_DEBUG_IF(
VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting the post update step\n",
eventDescription, filename, lineno););
return awaitable(m_post, filename, lineno);
return awaitable(process, m_post, filename, lineno);
}
// Used by coroutines for co_awaiting the resumption step (in 'act' eval)
auto resumption(const char* eventDescription, const char* filename, int lineno) {
auto resumption(VlProcessRef process, const char* eventDescription, const char* filename,
int lineno) {
VL_DEBUG_IF(VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting resumption\n",
eventDescription, filename, lineno););
return awaitable(m_triggered, filename, lineno);
return awaitable(process, m_triggered, filename, lineno);
}
};
@@ -338,24 +374,27 @@ class VlForkSync final {
public:
// Create the join object and set the counter to the specified number
void init(size_t count) { m_join.reset(new VlJoin{count, {}}); }
void init(size_t count, VlProcessRef process) { m_join.reset(new VlJoin{count, {process}}); }
// Called whenever any of the forked processes finishes. If the join counter reaches 0, the
// main process gets resumed
void done(const char* filename = VL_UNKNOWN, int lineno = 0);
// Used by coroutines for co_awaiting a join
auto join(const char* filename = VL_UNKNOWN, int lineno = 0) {
auto join(VlProcessRef process, const char* filename = VL_UNKNOWN, int lineno = 0) {
assert(m_join);
VL_DEBUG_IF(
VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno););
struct Awaitable {
VlProcessRef process; // Data of the suspended process, null if not needed
const std::shared_ptr<VlJoin> join; // Join to await on
VlFileLineDebug fileline;
bool await_ready() { return join->m_counter == 0; } // Suspend if join still exists
void await_suspend(std::coroutine_handle<> coro) { join->m_susp = {coro, fileline}; }
void await_suspend(std::coroutine_handle<> coro) {
join->m_susp = {coro, process, fileline};
}
void await_resume() const {}
};
return Awaitable{m_join, VlFileLineDebug{filename, lineno}};
return Awaitable{process, m_join, VlFileLineDebug{filename, lineno}};
}
};
+89 -32
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
@@ -75,7 +122,7 @@ public:
// Get an element from the front of the queue. Blocks if none available
T get() VL_MT_SAFE_EXCLUDES(m_mutex) {
VerilatedLockGuard lock{m_mutex};
m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
m_cv.wait(m_mutex, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
assert(!m_queue.empty());
T value = m_queue.front();
m_queue.pop_front();
@@ -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
@@ -447,7 +499,9 @@ public:
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
}
VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) {
const uint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval;
QData old;
std::memcpy(&old, oldp, sizeof(old));
const uint64_t diff = old ^ newval;
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
}
VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WData* newvalp, int bits) {
@@ -458,10 +512,13 @@ 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) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
double old;
std::memcpy(&old, oldp, sizeof(old));
if (VL_UNLIKELY(old != newval)) fullDouble(oldp, newval);
}
};
@@ -536,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
+44 -37
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);
}
}
@@ -482,7 +478,7 @@ VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWorkerData::wa
// We have been spinning for a while, so yield the thread
VerilatedLockGuard lock{m_mutex};
m_waiting = true;
m_cv.wait(lock, [this] { return m_ready.load(std::memory_order_relaxed); });
m_cv.wait(m_mutex, [this] { return m_ready.load(std::memory_order_relaxed); });
m_waiting = false;
}
@@ -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);
@@ -872,7 +879,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
*reinterpret_cast<QData*>(oldp) = newval;
std::memcpy(oldp, &newval, sizeof(newval));
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitQData(code, newval, bits);
}
@@ -888,7 +895,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullWData(uint32_t* oldp, const WData* newv
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) {
const uint32_t code = oldp - m_sigs_oldvalp;
*reinterpret_cast<double*>(oldp) = newval;
std::memcpy(oldp, &newval, sizeof(newval));
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
// cppcheck-suppress invalidPointerCast
emitDouble(code, newval);
+423 -20
View File
@@ -33,6 +33,7 @@
#include <atomic>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
@@ -69,10 +70,76 @@ 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
//===================================================================
// 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
enum : int { // Type int for compatibility with $c
FINISHED = 0,
RUNNING = 1,
WAITING = 2,
SUSPENDED = 3,
KILLED = 4,
};
// 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);
}
~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;
}
};
inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); }
//===================================================================
// Activity trigger vector
@@ -125,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
@@ -133,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
@@ -161,8 +269,8 @@ public:
VlRNG() VL_MT_SAFE;
explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {}
void srandom(uint64_t n) VL_MT_UNSAFE;
// Unused: std::string get_randstate() const VL_MT_UNSAFE;
// Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE;
std::string get_randstate() const VL_MT_UNSAFE;
void set_randstate(const std::string& state) VL_MT_UNSAFE;
uint64_t rand64() VL_MT_UNSAFE;
// Threadsafe, but requires use on vl_thread_rng
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
@@ -180,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(); }
@@ -427,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);
}
@@ -487,7 +647,7 @@ public:
template <typename Func>
VlQueue unique(Func with_func) const {
VlQueue out;
std::set<T_Value> saw;
std::set<decltype(with_func(0, m_deque[0]))> saw;
for (const auto& i : m_deque) {
const auto i_mapped = with_func(0, i);
const auto it = saw.find(i_mapped);
@@ -516,7 +676,7 @@ public:
VlQueue<IData> unique_index(Func with_func) const {
VlQueue<IData> out;
IData index = 0;
std::unordered_set<T_Value> saw;
std::set<decltype(with_func(0, m_deque[0]))> saw;
for (const auto& i : m_deque) {
const auto i_mapped = with_func(index, i);
auto it = saw.find(i_mapped);
@@ -830,6 +990,22 @@ public:
}
return out;
}
template <typename Func>
VlQueue<T_Value> unique(Func with_func) const {
VlQueue<T_Value> out;
T_Key default_key;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw;
for (const auto& i : m_map) {
const auto i_mapped = with_func(default_key, i.second);
const auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i.second);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
std::set<T_Key> saw;
@@ -843,6 +1019,21 @@ public:
return out;
}
template <typename Func>
VlQueue<T_Key> unique_index(Func with_func) const {
VlQueue<T_Key> out;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw;
for (const auto& i : m_map) {
const auto i_mapped = with_func(i.first, i.second);
auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i.first);
}
}
return out;
}
template <typename Func>
VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
for (const auto& i : m_map)
@@ -903,6 +1094,16 @@ public:
});
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element(
m_map.begin(), m_map.end(),
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
@@ -912,6 +1113,16 @@ public:
});
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
m_map.begin(), m_map.end(),
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
@@ -1040,9 +1251,15 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
template <class T_Value, std::size_t T_Depth>
struct VlUnpacked final {
private:
// TYPES
using T_Key = IData; // Index type, for uniformity with other containers
using Unpacked = T_Value[T_Depth];
public:
// MEMBERS
// This should be the only data member, otherwise generated static initializers need updating
T_Value m_storage[T_Depth]; // Contents of the unpacked array
Unpacked m_storage; // Contents of the unpacked array
// CONSTRUCTORS
// Default constructors and destructor are used. Note however that C++20 requires that
@@ -1053,6 +1270,7 @@ struct VlUnpacked final {
// Default copy assignment operators are used.
// METHODS
public:
// Raw access
WData* data() { return &m_storage[0]; }
const WData* data() const { return &m_storage[0]; }
@@ -1065,6 +1283,170 @@ struct VlUnpacked final {
bool neq(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(*this, that); }
// Similar to 'neq' above, *this = that used for change detection
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); }
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) { return neq(that); }
void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); }
template <typename Func>
void sort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(std::begin(m_storage), std::end(m_storage),
[=](const T_Value& a, const T_Value& b) {
// index number is meaningless with sort, as it changes
return with_func(0, a) < with_func(0, b);
});
}
// std::rbegin/std::rend not available until C++14
void rsort() {
std::sort(std::begin(m_storage), std::end(m_storage), std::greater<T_Value>());
}
template <typename Func>
void rsort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
// std::rbegin/std::rend not available until C++14, so using > below
std::sort(std::begin(m_storage), std::end(m_storage),
[=](const T_Value& a, const T_Value& b) {
// index number is meaningless with sort, as it changes
return with_func(0, a) > with_func(0, b);
});
}
void reverse() { std::reverse(std::begin(m_storage), std::end(m_storage)); }
void shuffle() { std::shuffle(std::begin(m_storage), std::end(m_storage), VlURNG{}); }
VlQueue<T_Value> unique() const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_storage) {
const auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(i);
}
}
return out;
}
template <typename Func>
VlQueue<T_Value> unique(Func with_func) const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_storage) {
const auto i_mapped = with_func(0, i);
const auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
IData index = 0;
std::set<T_Value> saw;
for (const auto& i : m_storage) {
const auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Key> unique_index(Func with_func) const {
VlQueue<T_Key> out;
IData index = 0;
std::unordered_set<T_Value> saw;
for (const auto& i : m_storage) {
const auto i_mapped = with_func(index, i);
auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) out.push_back(i);
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> out;
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) out.push_back(index);
++index;
}
return out;
}
template <typename Func>
VlQueue<T_Value> find_first(Func with_func) const {
// Can't use std::find_if as need index number
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<T_Value>::cons(i);
++index;
}
return VlQueue<T_Value>{};
}
template <typename Func>
VlQueue<T_Key> find_first_index(Func with_func) const {
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
++index;
}
return VlQueue<T_Key>{};
}
template <typename Func>
VlQueue<T_Value> find_last(Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::cons(m_storage[i]);
}
return VlQueue<T_Value>{};
}
template <typename Func>
VlQueue<T_Key> find_last_index(Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<IData>::cons(i);
}
return VlQueue<T_Key>{};
}
// Reduction operators
VlQueue<T_Value> min() const {
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::cons(*it);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage),
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue<T_Value>::cons(*it);
}
VlQueue<T_Value> max() const {
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::cons(*it);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage),
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue<T_Value>::cons(*it);
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
@@ -1138,7 +1520,7 @@ public:
}
// Deletes all queued garbage objects.
void deleteAll() VL_MT_SAFE;
void deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_MT_SAFE;
};
//===================================================================
@@ -1166,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;
};
@@ -1215,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)
@@ -1286,12 +1669,26 @@ public:
// For 'if (ptr)...'
operator bool() const { return m_objp; }
// In SV A == B iff both are handles to the same object (IEEE 1800-2017 8.4)
bool operator==(const VlClassRef& rhs) const { return m_objp == rhs.m_objp; };
bool operator!=(const VlClassRef& 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_OtherClass>
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;
@@ -1301,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 -233
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,141 +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);
// Find character after name end
const char* sp = np;
while (*sp && *sp != ' ' && *sp != '\t' && !(*sp & '\x80')) sp++;
printStr("$scope ");
if (*sp & '\x80') {
switch (*sp & 0x7f) {
case VLT_TRACE_SCOPE_STRUCT: printStr("struct "); break;
case VLT_TRACE_SCOPE_INTERFACE: printStr("interface "); break;
case VLT_TRACE_SCOPE_UNION: printStr("union "); break;
default: printStr("module ");
}
} else {
printStr("module ");
}
for (; *np && *np != ' ' && *np != '\t'; np++) {
if (*np == '[') {
printStr("[");
} else if (*np == ']') {
printStr("]");
} else if (!(*np & '\x80')) {
*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);
@@ -472,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
@@ -683,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);
+274 -40
View File
@@ -165,6 +165,7 @@ class VerilatedVpioVarBase VL_NOT_FINAL : public VerilatedVpio {
protected:
const VerilatedVar* m_varp = nullptr;
const VerilatedScope* m_scopep = nullptr;
std::string m_fullname;
const VerilatedRange& get_range() const {
// Determine number of dimensions and return outermost
return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed();
@@ -173,11 +174,13 @@ protected:
public:
VerilatedVpioVarBase(const VerilatedVar* varp, const VerilatedScope* scopep)
: m_varp{varp}
, m_scopep{scopep} {}
, m_scopep{scopep}
, m_fullname{std::string{m_scopep->name()} + '.' + m_varp->name()} {}
explicit VerilatedVpioVarBase(const VerilatedVpioVarBase* varp) {
if (varp) {
m_varp = varp->m_varp;
m_scopep = varp->m_scopep;
m_fullname = varp->m_fullname;
}
}
static VerilatedVpioVarBase* castp(vpiHandle h) {
@@ -188,11 +191,7 @@ public:
uint32_t size() const override { return get_range().elements(); }
const VerilatedRange* rangep() const override { return &get_range(); }
const char* name() const override { return m_varp->name(); }
const char* fullname() const override {
static thread_local std::string t_out;
t_out = std::string{m_scopep->name()} + "." + name();
return t_out.c_str();
}
const char* fullname() const override { return m_fullname.c_str(); }
};
class VerilatedVpioParam final : public VerilatedVpioVarBase {
@@ -304,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; }
@@ -537,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) {
@@ -546,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) {
@@ -646,23 +649,21 @@ public:
continue;
}
VerilatedVpiCbHolder& ho = *it++;
if (VerilatedVpioVar* const varop = VerilatedVpioVar::castp(ho.cb_datap()->obj)) {
void* const newDatap = varop->varDatap();
void* const prevDatap
= varop->prevDatap(); // Was malloced when we added the callback
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n",
varop->fullname(), *(static_cast<CData*>(newDatap)),
*(static_cast<CData*>(prevDatap)), newDatap,
prevDatap););
if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n",
ho.id(), varop->fullname(),
*(static_cast<CData*>(newDatap))););
update.insert(varop);
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
(ho.cb_rtnp())(ho.cb_datap());
called = true;
}
VerilatedVpioVar* const varop
= reinterpret_cast<VerilatedVpioVar*>(ho.cb_datap()->obj);
void* const newDatap = varop->varDatap();
void* const prevDatap = varop->prevDatap(); // Was malloced when we added the callback
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n",
varop->fullname(), *(static_cast<CData*>(newDatap)),
*(static_cast<CData*>(prevDatap)), newDatap, prevDatap););
if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n",
ho.id(), varop->fullname(),
*(static_cast<CData*>(newDatap))););
update.insert(varop);
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
(ho.cb_rtnp())(ho.cb_datap());
called = true;
}
if (was_last) break;
}
@@ -988,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
@@ -1316,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);
@@ -1737,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;
@@ -1752,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 {
@@ -1769,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) {
@@ -1921,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());
@@ -1957,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;
}
@@ -2174,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) {
@@ -2193,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());
@@ -2310,7 +2544,7 @@ PLI_INT32 vpi_flush(void) {
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
Verilated::runFlushCallbacks();
return 0;
return 0; // Gcc coverage bug // LCOV_EXCL_LINE
}
PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
+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"
//======================================================================
+99 -74
View File
@@ -37,8 +37,13 @@
//=========================================================================
// Compiler pragma abstraction
#if defined(__clang__)
# define VL_CLANG_ATTR(attr) __attribute__(( attr ))
#else
# define VL_CLANG_ATTR(attr)
#endif
#ifdef __GNUC__
# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment)))
# define VL_ATTR_ALWINLINE __attribute__((always_inline)) inline
# define VL_ATTR_NOINLINE __attribute__((noinline))
# define VL_ATTR_COLD __attribute__((cold))
@@ -57,19 +62,6 @@
// All VL_ATTR_WEAK symbols must be marked with the macOS -U linker flag in verilated.mk.in
# define VL_ATTR_WEAK __attribute__((weak))
# endif
# if defined(__clang__)
# define VL_ACQUIRE(...) __attribute__((annotate("ACQUIRE"))) __attribute__((acquire_capability(__VA_ARGS__)))
# define VL_ACQUIRE_SHARED(...) __attribute__((annotate("ACQUIRE_SHARED"))) __attribute__((acquire_shared_capability(__VA_ARGS__)))
# define VL_RELEASE(...) __attribute__((annotate("RELEASE"))) __attribute__((release_capability(__VA_ARGS__)))
# define VL_RELEASE_SHARED(...) __attribute__((annotate("RELEASE_SHARED"))) __attribute__((release_shared_capability(__VA_ARGS__)))
# define VL_TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__)))
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
# define VL_CAPABILITY(x) __attribute__((capability(x)))
# define VL_REQUIRES(x) __attribute__((annotate("REQUIRES"))) __attribute__((requires_capability(x)))
# define VL_GUARDED_BY(x) __attribute__((annotate("GUARDED_BY"))) __attribute__((guarded_by(x)))
# define VL_EXCLUDES(x) __attribute__((annotate("EXCLUDES"))) __attribute__((locks_excluded(x)))
# define VL_SCOPED_CAPABILITY __attribute__((scoped_lockable))
# endif
# define VL_LIKELY(x) __builtin_expect(!!(x), 1) // Prefer over C++20 [[likely]]
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0) // Prefer over C++20 [[unlikely]]
# define VL_UNREACHABLE __builtin_unreachable() // C++23 std::unreachable()
@@ -77,10 +69,74 @@
# define VL_PREFETCH_RW(p) __builtin_prefetch((p), 1)
#endif
// Defaults for unsupported compiler features
#ifndef VL_ATTR_ALIGNED
# define VL_ATTR_ALIGNED(alignment) ///< Attribute to align structure to byte alignment
// Function acquires a capability/lock (-fthread-safety)
#define VL_ACQUIRE(...) \
VL_CLANG_ATTR(annotate("ACQUIRE")) \
VL_CLANG_ATTR(acquire_capability(__VA_ARGS__))
// Function acquires a shared capability/lock (-fthread-safety)
#define VL_ACQUIRE_SHARED(...) \
VL_CLANG_ATTR(annotate("ACQUIRE_SHARED")) \
VL_CLANG_ATTR(acquire_shared_capability(__VA_ARGS__))
// Function releases a capability/lock (-fthread-safety)
#define VL_RELEASE(...) \
VL_CLANG_ATTR(annotate("RELEASE")) \
VL_CLANG_ATTR(release_capability(__VA_ARGS__))
// Function releases a shared capability/lock (-fthread-safety)
#define VL_RELEASE_SHARED(...) \
VL_CLANG_ATTR(annotate("RELEASE_SHARED")) \
VL_CLANG_ATTR(release_shared_capability(__VA_ARGS__))
// Function returns bool if acquired a capability (-fthread-safety)
#define VL_TRY_ACQUIRE(...) \
VL_CLANG_ATTR(try_acquire_capability(__VA_ARGS__))
// Function returns bool if acquired shared (-fthread-safety)
#define VL_TRY_ACQUIRE_SHARED(...) \
VL_CLANG_ATTR(try_acquire_shared_capability(__VA_ARGS__))
// Function requires a capability inbound (-fthread-safety)
#define VL_CAPABILITY(x) \
VL_CLANG_ATTR(capability(x))
// Name of mutex protecting this variable (-fthread-safety)
#define VL_EXCLUDES(x) \
VL_CLANG_ATTR(annotate("EXCLUDES")) \
VL_CLANG_ATTR(locks_excluded(x))
// Scoped threaded capability/lock (-fthread-safety)
#define VL_SCOPED_CAPABILITY \
VL_CLANG_ATTR(scoped_lockable)
// Annotated function returns reference to the given capability.
// Allowed on: function, method. (-fthread-safety)
#define VL_RETURN_CAPABILITY(x) \
VL_CLANG_ATTR(lock_returned(x))
// Assert that capability is already held.
// Allowed on: function, method. (-fthread-safety)
#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
#endif
@@ -111,19 +167,6 @@
#ifndef VL_ATTR_WEAK
# define VL_ATTR_WEAK ///< Attribute that function external that is optionally defined
#endif
#ifndef VL_CAPABILITY
# define VL_ACQUIRE(...) ///< Function acquires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function acquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if acquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if acquired shared (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
#endif
#ifndef VL_LIKELY
# define VL_LIKELY(x) (!!(x)) ///< Return boolean expression that is more often true
# define VL_UNLIKELY(x) (!!(x)) ///< Return boolean expression that is more often false
@@ -142,6 +185,7 @@
#ifndef VL_NO_LEGACY
# define VL_ATTR_ALIGNED(alignment) // Deprecated
# define VL_FUNC __func__ // Deprecated
# define VL_THREAD // Deprecated
# define VL_THREAD_LOCAL thread_local // Deprecated
@@ -149,56 +193,24 @@
#endif
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
#if defined(__clang__)
# define VL_PURE __attribute__((annotate("PURE")))
#else
# define VL_PURE
#endif
#define VL_PURE VL_CLANG_ATTR(annotate("PURE"))
// Comment tag that function is threadsafe
#if defined(__clang__)
# define VL_MT_SAFE __attribute__((annotate("MT_SAFE")))
#else
# define VL_MT_SAFE
#endif
#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE"))
// Comment tag that function is threadsafe, only if
// other threads doesn't change tree topology
#if defined(__clang__)
# define VL_MT_STABLE __attribute__((annotate("MT_STABLE")))
#else
# define VL_MT_STABLE
#endif
#define VL_MT_STABLE VL_CLANG_ATTR(annotate("MT_STABLE"))
// Comment tag that function is threadsafe, only
// during normal operation (post-init)
#if defined(__clang__)
# define VL_MT_SAFE_POSTINIT __attribute__((annotate("MT_SAFE_POSTINIT")))
#else
# define VL_MT_SAFE_POSTINIT
#endif
#define VL_MT_SAFE_POSTINIT VL_CLANG_ATTR(annotate("MT_SAFE_POSTINIT"))
// Attribute that function is clang threadsafe and uses given mutex
#if defined(__clang__)
# define VL_MT_SAFE_EXCLUDES(mutex) __attribute__((annotate("MT_SAFE_EXCLUDES"))) VL_EXCLUDES(mutex)
#else
# define VL_MT_SAFE_EXCLUDES(mutex) VL_EXCLUDES(mutex)
#endif
#define VL_MT_SAFE_EXCLUDES(mutex) VL_CLANG_ATTR(annotate("MT_SAFE_EXCLUDES")) VL_EXCLUDES(mutex)
// Comment tag that function is not threadsafe
#if defined(__clang__)
# define VL_MT_UNSAFE __attribute__((annotate("MT_UNSAFE")))
#else
# define VL_MT_UNSAFE
#endif
#define VL_MT_UNSAFE VL_CLANG_ATTR(annotate("MT_UNSAFE"))
// Comment tag that function is not threadsafe
// protected to make sure single-caller
#if defined(__clang__)
# define VL_MT_UNSAFE_ONE __attribute__((annotate("MT_UNSAFE_ONE")))
#else
# define VL_MT_UNSAFE_ONE
#endif
#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE"))
// Comment tag that function is entry point of parallelization
#if defined(__clang__)
# define VL_MT_START __attribute__((annotate("MT_START")))
#else
# define VL_MT_START
#endif
#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START"))
#ifndef VL_NO_LEGACY
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated)
@@ -324,6 +336,7 @@ extern "C" void __gcov_dump();
// Now that C++ requires these standard types the vl types are deprecated
#include <cstdint>
#include <cinttypes>
#include <cmath>
#ifndef VL_NO_LEGACY
using vluint8_t = uint8_t; ///< 8-bit unsigned type (backward compatibility)
@@ -429,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
@@ -448,11 +466,14 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
#define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad
/// Return mask for words with 1's where relevant bits are (0=all bits)
/// Arguments must not have side effects
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
/// Return mask for quads with 1's where relevant bits are (0=all bits)
/// Arguments must not have side effects
#define VL_MASK_Q(nbits) \
(((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL)
/// Return mask for EData with 1's where relevant bits are (0=all bits)
/// Arguments must not have side effects
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
#define VL_EUL(n) VL_UL(n) // Make constant number EData sized
@@ -474,8 +495,12 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
// #defines, to avoid requiring math.h on all compile runs
#ifdef _MSC_VER
# define VL_TRUNC(n) (((n) < 0) ? std::ceil((n)) : std::floor((n)))
# define VL_ROUND(n) (((n) < 0) ? std::ceil((n)-0.5) : std::floor((n) + 0.5))
static inline double VL_TRUNC(double n) {
return (n < 0) ? std::ceil(n) : std::floor(n);
}
static inline double VL_ROUND(double n) {
return (n < 0) ? std::ceil(n-0.5) : std::floor(n + 0.5);
}
#else
# define VL_TRUNC(n) std::trunc(n)
# define VL_ROUND(n) std::round(n)
@@ -569,8 +594,8 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
//=========================================================================
// 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
+331 -66
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):
@@ -33,6 +53,26 @@ def fully_qualified_name(node):
return [node.displayname] if node.displayname else []
# Returns True, if `class_node` contains node
# that matches `member` spelling
def check_class_member_exists(class_node, member):
for child in class_node.get_children():
if member.spelling == child.spelling:
return True
return False
# Returns Base class (if found) of `class_node`
# that is of type `base_type`
def get_base_class(class_node, base_type):
for child in class_node.get_children():
if child.kind is CursorKind.CXX_BASE_SPECIFIER:
base_class = child.type
if base_type.spelling == base_class.spelling:
return base_class
return None
@dataclass
class VlAnnotations:
mt_start: bool = False
@@ -40,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
@@ -61,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()
@@ -111,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"]:
@@ -183,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,
@@ -208,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
@@ -245,13 +302,109 @@ 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._constructor_context: list[clang.cindex.Cursor] = []
self._level: int = 0
self._constructor_context: 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],
@@ -259,18 +412,32 @@ class CallAnnotationsValidator:
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)
@@ -341,7 +508,7 @@ class CallAnnotationsValidator:
return None
refn = find_object_ref(node)
if self._constructor_context and not refn:
if self.is_constructor_context() and not refn:
# we are in constructor and no object reference means
# we are calling local method. It is MT safe
# only if this method is also only calling local methods or
@@ -353,20 +520,44 @@ class CallAnnotationsValidator:
elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
refn = refn.referenced
refna = VlAnnotations.from_nodes_list(refn.get_children())
if refna.guarded or self._constructor_context:
if refna.guarded:
is_mt_safe = True
if self.is_constructor_context() and refn.semantic_parent:
# we are in constructor, so calling local members is MT_SAFE,
# make sure object that we are calling is local to the constructor
constructor_class = self._constructor_context[
-1].semantic_parent
if refn.semantic_parent.spelling == constructor_class.spelling:
if check_class_member_exists(constructor_class, refn):
is_mt_safe = True
else:
# check if this class inherits from some base class
base_class = get_base_class(constructor_class,
refn.semantic_parent)
if base_class:
if check_class_member_exists(
base_class.get_declaration(), refn):
is_mt_safe = True
# variable
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
# This is probably a local or an argument.
# Calling methods on local pointers or references is MT-safe,
# but on argument pointers or references is not.
if "*" not in refn.type.spelling and "&" not in refn.type.spelling:
is_mt_safe = True
# local variable
if refn.referenced.kind == CursorKind.VAR_DECL:
is_mt_safe = True
if refn.get_definition():
if refn.referenced.semantic_parent:
if refn.referenced.semantic_parent.kind in [
CursorKind.FUNCTION_DECL, CursorKind.CXX_METHOD
]:
# This is a local or an argument.
# Calling methods on local pointers or references is MT-safe,
# but on argument pointers or references is not.
if "*" not in refn.type.spelling and "&" not in refn.type.spelling:
is_mt_safe = True
# local variable
if refn.referenced.kind == CursorKind.VAR_DECL:
is_mt_safe = True
else:
# Global variable in different translation unit, unsafe
pass
elif refn and refn.kind == CursorKind.CALL_EXPR:
if self._constructor_context:
if self.is_constructor_context():
# call to local function from constructor context
# safe if this function also calling local methods or
# MT-safe methods
@@ -442,18 +633,18 @@ class CallAnnotationsValidator:
# Constructors are OK in MT-safe context
# only if they call local methods or MT-safe functions.
if ctx.is_mt_safe_context() or self._constructor_context:
self._constructor_context += 1
if ctx.is_mt_safe_context() or self.is_constructor_context():
self._constructor_context.append(refd)
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
self._constructor_context -= 1
self._constructor_context.pop()
# stable tree context
if ctx.is_stabe_tree_context():
self._constructor_context += 1
self._constructor_context.append(refd)
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
self._constructor_context -= 1
self._constructor_context.pop()
# pure context
if ctx.is_pure_context():
@@ -516,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):
@@ -546,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
@@ -558,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)
@@ -575,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()
])
@@ -664,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 ""
@@ -714,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)
@@ -834,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)"
@@ -900,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,
@@ -928,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")
#######################################################################
+1 -1
View File
@@ -1,6 +1,6 @@
*~
*.old
config_build.h
config_package.h
Makefile
Makefile_obj
.objcache*
+23 -8
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
@@ -82,6 +81,7 @@ set(HEADERS
V3File.h
V3FileLine.h
V3Force.h
V3Fork.h
V3FunctionTraits.h
V3Gate.h
V3Global.h
@@ -95,6 +95,7 @@ set(HEADERS
V3Inline.h
V3Inst.h
V3InstrCount.h
V3Interface.h
V3LangCode.h
V3LanguageWords.h
V3Life.h
@@ -103,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
@@ -125,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
@@ -147,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
@@ -163,6 +171,7 @@ set(HEADERS
V3Waiver.h
V3Width.h
V3WidthCommit.h
V3WidthRemove.h
VlcBucket.h
VlcOptions.h
VlcPoint.h
@@ -218,6 +227,7 @@ set(COMMON_SOURCES
V3EmitCMain.cpp
V3EmitCMake.cpp
V3EmitCModel.cpp
V3EmitCPch.cpp
V3EmitCSyms.cpp
V3EmitMk.cpp
V3EmitV.cpp
@@ -227,6 +237,7 @@ set(COMMON_SOURCES
V3File.cpp
V3FileLine.cpp
V3Force.cpp
V3Fork.cpp
V3Gate.cpp
V3Global.cpp
V3Graph.cpp
@@ -240,6 +251,7 @@ set(COMMON_SOURCES
V3Inline.cpp
V3Inst.cpp
V3InstrCount.cpp
V3Interface.cpp
V3Life.cpp
V3LifePost.cpp
V3LinkCells.cpp
@@ -293,6 +305,7 @@ set(COMMON_SOURCES
V3VariableOrder.cpp
V3Waiver.cpp
V3Width.cpp
V3WidthCommit.cpp
V3WidthSel.cpp
V3ParseImp.cpp
V3ParseGrammar.cpp
@@ -322,7 +335,7 @@ file(TO_NATIVE_PATH ${srcdir}/../bin/verilator_includer VERILATOR_INCLUDER)
file(TO_NATIVE_PATH ${srcdir}/vlcovgen VLCOVGEN)
file(TO_NATIVE_PATH ${srcdir}/config_rev CONFIG_REV)
configure_file(config_build.h.in config_build.h @ONLY)
configure_file(config_package.h.in config_package.h @ONLY)
add_custom_command(
OUTPUT V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h
@@ -414,7 +427,7 @@ foreach(astgen_name ${ASTGENERATED_NAMES})
MAIN_DEPENDENCY ${astgen_name}.cpp
DEPENDS ${ASTGEN} V3Ast.h
COMMAND ${PYTHON3} ARGS
${ASTGEN} -I"${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp
)
list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp)
endforeach()
@@ -488,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})
+24 -5
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
@@ -95,7 +114,7 @@ clean mostlyclean distclean maintainer-clean::
-rm -f .objcache*
distclean maintainer-clean::
-rm -f Makefile Makefile_obj config_build.h
-rm -f Makefile Makefile_obj config_package.h
maintainer-clean::
-rm -f config_rev.h
+86 -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,37 +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 \
@@ -231,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 \
@@ -258,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 \
@@ -274,8 +292,8 @@ RAW_OBJS = \
V3Unknown.o \
V3Unroll.o \
V3VariableOrder.o \
V3Waiver.o \
V3Width.o \
V3WidthCommit.o \
V3WidthSel.o \
# verilator_coverage
@@ -283,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
@@ -308,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)
@@ -328,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
@@ -345,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
@@ -387,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:
+8 -7
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 };
@@ -183,7 +181,7 @@ public:
<< " (not all control paths of combinational always assign a value)\n"
<< nodep->warnMore()
<< "... Suggest use of always_latch for intentional latches");
if (dumpGraph() >= 9) dumpDotFilePrefixed("latch_" + vrp->name());
if (dumpGraphLevel() >= 9) dumpDotFilePrefixed("latch_" + vrp->name());
}
vertp->user(false); // Clear again (see above)
vrp->varp()->isLatched(latch_detected);
@@ -320,7 +318,8 @@ private:
// VISITORS
void visit(AstVarRef* nodep) override {
const AstVar* const varp = nodep->varp();
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) {
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()
&& !varp->isFuncLocalSticky()) {
m_graph.addAssignment(nodep);
}
}
@@ -333,6 +332,8 @@ private:
m_graph.addPathVertex(branchp, "ELSE");
iterateAndNextConstNull(nodep->elsesp());
m_graph.currentp(parentp);
} else {
iterateChildrenConst(nodep);
}
}
//--------------------
@@ -652,5 +653,5 @@ public:
void V3Active::activeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("active", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeLevel() >= 3);
}
+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
+2 -5
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;
@@ -145,5 +142,5 @@ public:
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveTopVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeLevel() >= 3);
}
+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
+13 -16
View File
@@ -14,13 +14,10 @@
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Assert.h"
#include "V3Ast.h"
#include "V3Global.h"
#include "V3Stats.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@@ -156,8 +153,8 @@ private:
sentreep->unlinkFrBack();
if (m_procedurep) {
// To support this need queue of asserts to activate
nodep->v3error("Unsupported: Procedural concurent assertion with"
" clocking event inside always (IEEE 1800-2917 16.14.6)");
nodep->v3error("Unsupported: Procedural concurrent assertion with"
" clocking event inside always (IEEE 1800-2017 16.14.6)");
}
}
//
@@ -242,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 {
@@ -255,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
@@ -311,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};
@@ -544,5 +541,5 @@ public:
void V3Assert::assertAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assert", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeLevel() >= 3);
}
+2 -2
View File
@@ -21,13 +21,13 @@
#include "verilatedos.h"
#include "V3Ast.h"
#include "V3Error.h"
#include "V3ThreadSafety.h"
//============================================================================
class V3Assert final {
public:
static void assertAll(AstNetlist* nodep);
static void assertAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard
+11 -14
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()},
@@ -496,5 +493,5 @@ public:
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertPreVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeLevel() >= 3);
}
+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
+210 -60
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}
@@ -125,9 +136,7 @@ string AstNode::encodeNumber(int64_t num) {
}
}
string AstNode::nameProtect() const VL_MT_STABLE {
return VIdProtect::protectIf(name(), protect());
}
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
string AstNode::shortName() const {
@@ -285,7 +294,7 @@ string AstNode::vpiName(const string& namein) {
return pretty;
}
string AstNode::prettyTypeName() const VL_MT_STABLE {
string AstNode::prettyTypeName() const {
if (name() == "") return typeName();
return std::string{typeName()} + " '" + prettyName() + "'";
}
@@ -358,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);
@@ -785,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;
@@ -816,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;
}
@@ -1081,10 +1098,12 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
// private: Return true if the two trees are identical
if (!node1p && !node2p) return true;
if (!node1p || !node2p) return false;
if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep()
|| !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) {
return false;
}
if (node1p->type() != node2p->type()) return false;
UASSERT_OBJ(
(!node1p->dtypep() && !node2p->dtypep()) || (node1p->dtypep() && node2p->dtypep()), node1p,
"Comparison of a node with dtypep() with a node without dtypep()\n-node2=" << node2p);
if (node1p->dtypep() && !node1p->dtypep()->similarDType(node2p->dtypep())) return false;
if (!node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) return false;
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly)
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly)
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly)
@@ -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
@@ -1217,7 +1283,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
if (logsp->fail()) v3fatal("Can't write " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
if (editCountGbl() == editCountLast() && ::dumpTree() < 9) {
if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) {
*logsp << '\n';
*logsp << "No changes since last dump!\n";
} else {
@@ -1227,7 +1293,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
}
}
if (doDump && v3Global.opt.debugEmitV()) V3EmitV::debugEmitV(filename + ".v");
if (doCheck && (v3Global.opt.debugCheck() || ::dumpTree())) {
if (doCheck && (v3Global.opt.debugCheck() || ::dumpTreeLevel())) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
@@ -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
@@ -1406,6 +1457,105 @@ AstNodeDType* AstNode::findQueueIndexDType() const {
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
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
+432 -146
View File
@@ -82,12 +82,36 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
// Ast<nodetypename>*' is returned.
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
// Same as VN_AS, but only checks the type in debug builds. Type checking is less critical in node
// child getters (the strongly-typed functions that wrap op*p pointers). This is because the op*p
// pointers are usually populated by code that already asserts the correct type. Having fewer type
// assertions yields better performance in release builds.
#ifdef VL_DEBUG
#define VN_DBG_AS(nodep, nodetypename) VN_AS(nodep, nodetypename)
#else
#define VN_DBG_AS(nodep, nodetypename) \
(AstNode::unsafePrivateAs<Ast##nodetypename, decltype(nodep)>(nodep))
#endif
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
#define VN_DELETED(nodep) VL_UNLIKELY((uint64_t)(nodep) == 0x1)
//######################################################################
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:
@@ -100,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 {
@@ -142,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 {
@@ -268,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,
//
@@ -461,6 +517,7 @@ public:
TRIGGER_SCHEDULER,
DYNAMIC_TRIGGER_SCHEDULER,
FORK_SYNC,
PROCESS_REFERENCE,
// Unsigned and two state; fundamental types
UINT32,
UINT64,
@@ -493,6 +550,7 @@ public:
"VlTriggerScheduler",
"VlDynamicTriggerScheduler",
"VlFork",
"VlProcessRef",
"IData",
"QData",
"LOGIC_IMPLICIT",
@@ -500,13 +558,20 @@ public:
return names[m_e];
}
const char* dpiType() const {
static const char* const names[]
= {"%E-unk", "svBit", "char", "void*", "char",
"int", "%E-integer", "svLogic", "long long", "double",
"short", "%E-time", "const char*", "%E-untyped", "dpiScope",
"const char*", "%E-mtaskstate", "%E-triggervec", "%E-dly-sched", "%E-trig-sched",
"%E-dyn-sched", "%E-fork", "IData", "QData", "%E-logic-implct",
" MAX"};
static const char* const names[] = {"%E-unk", "svBit",
"char", "void*",
"char", "int",
"%E-integer", "svLogic",
"long long", "double",
"short", "%E-time",
"const char*", "%E-untyped",
"dpiScope", "const char*",
"%E-mtaskstate", "%E-triggervec",
"%E-dly-sched", "%E-trig-sched",
"%E-dyn-sched", "%E-fork",
"%E-proc-ref", "IData",
"QData", "%E-logic-implct",
" MAX"};
return names[m_e];
}
static void selfTest() {
@@ -545,6 +610,7 @@ public:
case TRIGGER_SCHEDULER: return 0; // opaque
case DYNAMIC_TRIGGER_SCHEDULER: return 0; // opaque
case FORK_SYNC: return 0; // opaque
case PROCESS_REFERENCE: return 0; // opaque
case UINT32: return 32;
case UINT64: return 64;
default: return 0;
@@ -584,7 +650,7 @@ public:
return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|| m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER
|| m_e == TRIGGER_SCHEDULER || m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC
|| m_e == DOUBLE || m_e == UNTYPED);
|| m_e == PROCESS_REFERENCE || m_e == DOUBLE || m_e == UNTYPED);
}
bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; }
bool isEvent() const { return m_e == EVENT; }
@@ -609,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;
@@ -655,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;
@@ -755,7 +855,6 @@ public:
SUPPLY1,
WIRE,
WREAL,
IMPLICITWIRE,
TRIWIRE,
TRI0,
TRI1,
@@ -775,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
@@ -807,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;
@@ -1147,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 {
@@ -1211,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
@@ -1293,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
//######################################################################
@@ -1353,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
@@ -1366,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(); }
};
//######################################################################
@@ -1379,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:
@@ -1397,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
};
@@ -1405,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);
@@ -1416,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(); }
};
//######################################################################
@@ -1542,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) {
@@ -1564,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,
@@ -1618,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; }
@@ -1676,7 +1949,7 @@ public:
static constexpr int INSTR_COUNT_PLI = 20; // PLI routines
// ACCESSORS
virtual string name() const VL_MT_STABLE { return ""; }
virtual string name() const { return ""; }
virtual string origName() const { return ""; }
virtual void name(const string& name) {
this->v3fatalSrc("name() called on object without name() method");
@@ -1684,7 +1957,7 @@ public:
virtual void tag(const string& text) {}
virtual string tag() const { return ""; }
virtual string verilogKwd() const { return ""; }
string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied
string nameProtect() const; // Name with --protect-id applied
string origNameProtect() const; // origName with --protect-id applied
string shortName() const; // Name with __PVT__ removed for concatenating scopes
static string dedotName(const string& namein); // Name with dots removed
@@ -1697,10 +1970,10 @@ public:
static string encodeName(const string& namein);
static string encodeNumber(int64_t num); // Encode number into internal C representation
static string vcdName(const string& namein); // Name for printing out to vcd files
string prettyName() const VL_MT_STABLE { return prettyName(name()); }
string prettyName() const { return prettyName(name()); }
string prettyNameQ() const { return prettyNameQ(name()); }
// "VARREF" for error messages (NOT dtype's pretty name)
string prettyTypeName() const VL_MT_STABLE;
string prettyTypeName() const;
virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
FileLine* fileline() const VL_MT_SAFE { return m_fileline; }
void fileline(FileLine* fl) { m_fileline = fl; }
@@ -1730,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; }
@@ -1817,6 +2078,7 @@ public:
// ACCESSORS for specific types
// Alas these can't be virtual or they break when passed a nullptr
inline bool isClassHandleValue() const;
inline bool isZero() const;
inline bool isOne() const;
inline bool isNeqZero() const;
@@ -1856,6 +2118,7 @@ public:
void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate
void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); }
void dtypeSetVoid() { dtypep(findVoidDType()); }
void dtypeSetStream() { dtypep(findStreamDType()); }
// Data type locators
AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); }
@@ -1867,6 +2130,7 @@ public:
AstNodeDType* findCHandleDType() const { return findBasicDType(VBasicDTypeKwd::CHANDLE); }
AstNodeDType* findEmptyQueueDType() const;
AstNodeDType* findVoidDType() const;
AstNodeDType* findStreamDType() const;
AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
@@ -1876,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();
}
@@ -1915,15 +2183,11 @@ public:
// Iterate and insert - assumes tree format
virtual void addNextStmt(AstNode* newp,
AstNode* belowp); // When calling, "this" is second argument
virtual void addBeforeStmt(AstNode* newp,
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
@@ -1948,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
@@ -1958,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.
@@ -1971,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
@@ -2056,24 +2332,34 @@ public:
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
}
// For use via the VN_AS macro only
// For use via privateAs or the VN_DBG_AS macro only
template <typename T, typename E>
static T* privateAs(AstNode* nodep) VL_PURE {
static T* unsafePrivateAs(AstNode* nodep) VL_PURE {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return reinterpret_cast<T*>(nodep);
}
template <typename T, typename E>
static const T* privateAs(const AstNode* nodep) VL_PURE {
static const T* unsafePrivateAs(const AstNode* nodep) VL_PURE {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
return reinterpret_cast<const T*>(nodep);
}
// For use via the VN_AS macro only
template <typename T, typename E>
static T* privateAs(AstNode* nodep) VL_PURE {
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return reinterpret_cast<const T*>(nodep);
return unsafePrivateAs<T, E>(nodep);
}
template <typename T, typename E>
static const T* privateAs(const AstNode* nodep) VL_PURE {
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return unsafePrivateAs<T, E>(nodep);
}
// Predicate that returns true if the given 'nodep' might have a descendant of type 'T_Node'.
+16 -4
View File
@@ -39,8 +39,16 @@ 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 {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNull())
|| VN_IS(dtypep(), ClassRefDType);
}
bool AstNode::isZero() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
}
@@ -150,12 +158,15 @@ AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool clea
}
AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {}
: ASTGEN_SUPER_VarRef(fl, varp, access) {}
// This form only allowed post-link (see above)
AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) {
: ASTGEN_SUPER_VarRef(fl, varscp->varp(), access) {
varScopep(varscp);
}
string AstVarRef::name() const { return varp() ? varp()->name() : "<null>"; }
bool AstVarRef::same(const AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep() && access() == samep->access());
@@ -169,13 +180,14 @@ 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());
}
}
AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access)
: ASTGEN_SUPER_VarXRef(fl, varp, access)
, m_name{varp->name()}
, m_dotted{dotted} {
dtypeFrom(varp);
}
+108 -38
View File
@@ -126,13 +126,13 @@ public:
const char* charIQWN() const {
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
}
string cType(const string& name, bool forFunc, bool isRef) const VL_MT_STABLE;
string cType(const string& name, bool forFunc, bool isRef) const;
// Represents a C++ LiteralType? (can be constexpr)
bool isLiteralType() const VL_MT_STABLE;
private:
class CTypeRecursed;
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_STABLE;
CTypeRecursed cTypeRecurse(bool compound) const;
};
class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
@@ -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(); }
@@ -199,12 +199,9 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
// A struct or union; common handling
// @astgen op1 := membersp : List[AstMemberDType]
private:
// TYPES
using MemberNameMap = std::map<const std::string, AstMemberDType*>;
// MEMBERS
string m_name; // Name from upper typedef, if any
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
MemberNameMap m_members;
AstNodeModule* m_classOrPackagep = nullptr; // Package it will be emitted with
const int m_uniqueNum;
bool m_packed;
bool m_isFourstate = false; // V3Width computes
@@ -250,12 +247,6 @@ public:
static bool packedUnsup() { return true; }
void isFourstate(bool flag) { m_isFourstate = flag; }
bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; }
void clearCache() { m_members.clear(); }
void repairMemberCache();
AstMemberDType* findMember(const string& name) const {
const auto it = m_members.find(name);
return (it == m_members.end()) ? nullptr : it->second;
}
static int lo() { return 0; }
int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange{hi(), lo()}; }
@@ -323,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;
@@ -438,6 +430,7 @@ public:
bool isEvent() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::EVENT; }
bool isTriggerVec() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::TRIGGERVEC; }
bool isForkSync() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::FORK_SYNC; }
bool isProcessRef() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::PROCESS_REFERENCE; }
bool isDelayScheduler() const VL_MT_SAFE {
return keyword() == VBasicDTypeKwd::DELAY_SCHEDULER;
}
@@ -502,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]
@@ -520,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 {
@@ -569,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 {
@@ -618,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 {
@@ -669,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;
@@ -727,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)
@@ -743,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 {
@@ -753,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; }
@@ -782,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
@@ -887,6 +925,7 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeUOrStructDType* getChildStructp() const;
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
@@ -945,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(); }
@@ -1018,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;
@@ -1060,7 +1100,7 @@ private:
// Post-width typedefs are removed and point to type directly
AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef
string m_name; // Name of an AstTypedef
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Class/package in which it was defined
public:
AstRefDType(FileLine* fl, const string& name)
: ASTGEN_SUPER_RefDType(fl)
@@ -1075,13 +1115,14 @@ public:
AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp)
: ASTGEN_SUPER_RefDType(fl) {
this->typeofp(typeofp);
if (AstNodeDType* const dtp = VN_CAST(typeofp, NodeDType)) refDTypep(dtp);
}
ASTGEN_MEMBERS_AstRefDType;
// METHODS
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);
}
@@ -1159,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;
@@ -1186,6 +1228,34 @@ public:
int widthTotalBytes() const override { return sizeof(std::map<std::string, std::string>); }
bool isCompound() const override { return true; }
};
class AstStreamDType final : public AstNodeDType {
// Stream data type, used only as data type of stream operations
// Should behave like AstPackArrayDType, but it doesn't have a size
public:
explicit AstStreamDType(FileLine* fl)
: ASTGEN_SUPER_StreamDType(fl) {
dtypep(this);
}
ASTGEN_MEMBERS_AstStreamDType;
void dumpSmall(std::ostream& str) const override;
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
bool undead() const override { return true; }
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* virtRefDTypep() const override { return nullptr; }
void virtRefDTypep(AstNodeDType* nodep) override {}
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
int widthAlignBytes() const override { return 1; }
int widthTotalBytes() const override { return 1; }
bool isCompound() const override { return false; }
};
class AstUnsizedArrayDType final : public AstNodeDType {
// Unsized/open-range Array data type, ie "some_dtype var_name []"
// @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width
@@ -1330,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.
+301 -121
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)
@@ -214,11 +224,13 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
// @astgen op3 := pinsp : List[AstNodeExpr]
// @astgen op4 := scopeNamep : Optional[AstScopeName]
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the task
string m_name; // Name of variable
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
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:
@@ -449,21 +489,19 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr {
VAccess m_access; // Left hand side assignment
AstVar* m_varp; // [AfterLink] Pointer to variable itself
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
string m_name; // Name of variable
string m_selfPointer; // Output code object pointer (e.g.: 'this')
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the variable
VSelfPointerText m_selfPointer
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
// pointer (e.g.: 'this')
protected:
AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access)
AstNodeVarRef(VNType t, FileLine* fl, const VAccess& access)
: AstNodeExpr{t, fl}
, m_access{access}
, m_name{name} {
, m_access{access} {
varp(nullptr);
}
AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access)
: AstNodeExpr{t, fl}
, m_access{access}
, m_name{name} {
, m_access{access} {
// May have varp==nullptr
this->varp(varp);
}
@@ -474,8 +512,6 @@ public:
const char* broken() const override;
int instrCount() const override { return widthInstrs(); }
void cloneRelink() override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
@@ -485,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
@@ -582,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; }
};
@@ -593,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
@@ -721,7 +754,7 @@ class AstClassOrPackageRef final : public AstNodeExpr {
private:
string m_name;
// Node not NodeModule to appease some early parser usage
AstNode* m_classOrPackageNodep; // Package hierarchy
AstNode* m_classOrPackageNodep; // Pointer to class/package referenced
public:
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
AstPin* paramsp)
@@ -743,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
@@ -975,6 +1008,20 @@ public:
, m_num(this, 1, on) {
dtypeSetBit();
}
class All0 {};
AstConst(FileLine* fl, All0)
: ASTGEN_SUPER_Const(fl)
, m_num(this, "'0") {
initWithNumber();
fl->warnOff(V3ErrorCode::NEWERSTD, true);
}
class All1 {};
AstConst(FileLine* fl, All1)
: ASTGEN_SUPER_Const(fl)
, m_num(this, "'1") {
initWithNumber();
fl->warnOff(V3ErrorCode::NEWERSTD, true);
}
class Null {};
AstConst(FileLine* fl, Null)
: ASTGEN_SUPER_Const(fl)
@@ -1000,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()); }
@@ -1010,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
@@ -1048,7 +1128,7 @@ public:
};
class AstEnumItemRef final : public AstNodeExpr {
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
AstNodeModule* m_classOrPackagep; // Package hierarchy
AstNodeModule* m_classOrPackagep; // Class/package in which it was defined
public:
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
: ASTGEN_SUPER_EnumItemRef(fl)
@@ -1061,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; }
@@ -1092,7 +1170,11 @@ public:
// METHODS
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
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 {
@@ -1110,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 {
@@ -1129,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; }
};
@@ -1148,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; }
};
@@ -1172,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; }
};
@@ -1190,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; }
@@ -1215,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; }
@@ -1241,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; }
};
@@ -1259,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; }
@@ -1299,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]
@@ -1346,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; }
@@ -1414,6 +1498,7 @@ class AstMemberSel final : public AstNodeExpr {
// @astgen op1 := fromp : AstNodeExpr
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
string m_name;
VAccess m_access; // Read or write, as in AstNodeVarRef
AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection
public:
AstMemberSel(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name)
@@ -1434,10 +1519,12 @@ public:
void dump(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& name) override { m_name = name; }
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool same(const AstNode* samep) const override { return true; } // dtype comparison does it
bool cleanOut() const override { return true; }
bool same(const AstNode* samep) const override;
int instrCount() const override { return widthInstrs(); }
AstVar* varp() const { return m_varp; }
void varp(AstVar* nodep) { m_varp = nodep; }
@@ -1499,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; }
@@ -1694,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
@@ -1732,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; }
@@ -1776,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(""); }
@@ -1890,14 +1977,14 @@ 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; }
};
class AstStructSel final : public AstNodeExpr {
// Unpacked struct member access
// Unpacked struct/union member access
// Parents: math|stmt
// Children: varref, math
// @astgen op1 := fromp : AstNodeExpr
@@ -1915,9 +2002,12 @@ public:
void name(const string& name) override { m_name = name; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanOut() const override {
// Not a union
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(); }
@@ -1933,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(""); }
@@ -1955,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; }
@@ -2039,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; }
@@ -2095,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; }
};
@@ -2108,14 +2198,14 @@ class AstWith final : public AstNodeExpr {
// Children: expression (equation establishing the with)
// @astgen op1 := indexArgRefp : AstLambdaArgRef
// @astgen op2 := valueArgRefp : AstLambdaArgRef
// @astgen op3 := exprp : AstNodeExpr
// @astgen op3 := exprp : List[AstNode]
public:
AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
AstNodeExpr* exprp)
: ASTGEN_SUPER_With(fl) {
this->indexArgRefp(indexArgRefp);
this->valueArgRefp(valueArgRefp);
this->exprp(exprp);
this->addExprp(exprp);
}
ASTGEN_MEMBERS_AstWith;
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -2202,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()
@@ -2426,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(); }
};
@@ -2711,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) {
@@ -2728,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 "||"; }
@@ -2742,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:
@@ -3199,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)
@@ -3224,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
@@ -3250,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)
@@ -4008,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
@@ -4045,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)
@@ -4087,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) {
@@ -4097,6 +4257,8 @@ public:
dtypeSetVoid();
}
ASTGEN_MEMBERS_AstTaskRef;
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
// === AstNodePreSel ===
@@ -4147,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) {}
@@ -4597,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;
//
@@ -4657,7 +4819,7 @@ public:
ASTGEN_MEMBERS_AstCvtPackString;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { return "%f$_CAST(%l)"; }
string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
@@ -4720,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 {
@@ -4737,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 {
@@ -5043,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:
@@ -5335,15 +5512,15 @@ public:
class AstVarRef final : public AstNodeVarRef {
// A reference to a variable (lvalue or rvalue)
public:
AstVarRef(FileLine* fl, const string& name, const VAccess& access)
: ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {}
// This form only allowed post-link because output/wire compression may
// lead to deletion of AstVar's
inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access);
// This form only allowed post-link (see above)
inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access);
ASTGEN_MEMBERS_AstVarRef;
inline string name() const override; // * = Var name
void dump(std::ostream& str) const override;
const char* broken() const override;
bool same(const AstNode* samep) const override;
inline bool same(const AstVarRef* samep) const;
inline bool sameNoLvalue(AstVarRef* samep) const;
@@ -5355,14 +5532,17 @@ public:
class AstVarXRef final : public AstNodeVarRef {
// A VarRef to something in another module before AstScope.
// Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope
string m_name;
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
public:
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, name, nullptr, access)
: ASTGEN_SUPER_VarXRef(fl, nullptr, access)
, m_name{name}
, m_dotted{dotted} {}
inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access);
ASTGEN_MEMBERS_AstVarXRef;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void dump(std::ostream& str) const override;
string dotted() const { return m_dotted; }
void dotted(const string& dotted) { m_dotted = dotted; }
@@ -5373,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());
}
+240 -143
View File
File diff suppressed because it is too large Load Diff
+311 -152
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();
}
@@ -103,29 +112,8 @@ int AstNodeSel::bitConst() const {
return (constp ? constp->toSInt() : 0);
}
void AstNodeUOrStructDType::repairMemberCache() {
clearCache();
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
if (m_members.find(itemp->name()) != m_members.end()) {
itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ());
} else {
m_members.emplace(itemp->name(), itemp);
}
}
}
const char* AstNodeUOrStructDType::broken() const {
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
std::unordered_set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) {
if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: " << it->first);
return "member broken";
}
}
return nullptr;
}
@@ -147,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()) {
@@ -234,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 {
@@ -288,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};
@@ -391,20 +428,23 @@ string AstVar::verilogKwd() const {
return "wreal";
} else if (varType() == VVarType::IFACEREF) {
return "ifaceref";
} else {
} else if (dtypep()) {
return dtypep()->name();
} else {
return "UNKNOWN";
}
}
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
bool asRef) const VL_MT_STABLE {
bool asRef) const {
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string ostatic;
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 ";
@@ -426,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) {
@@ -518,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
@@ -646,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) {
@@ -714,12 +757,12 @@ public:
}
};
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_STABLE {
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const {
const CTypeRecursed info = cTypeRecurse(false);
return info.render(name, isRef);
}
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_MT_STABLE {
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
// Legacy compound argument currently just passed through and unused
CTypeRecursed info;
@@ -728,6 +771,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_M
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 + ">";
@@ -782,8 +827,10 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_M
info.m_type = "VlDynamicTriggerScheduler";
} else if (bdtypep->isForkSync()) {
info.m_type = "VlForkSync";
} 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) {
@@ -1067,6 +1114,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
return m_voidp;
}
AstStreamDType* AstTypeTable::findStreamDType(FileLine* fl) {
if (VL_UNLIKELY(!m_streamp)) {
AstStreamDType* const newp = new AstStreamDType{fl};
addTypesp(newp);
m_streamp = newp;
}
return m_streamp;
}
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* const newp = new AstQueueDType{fl, AstNode::findUInt32DType(), nullptr};
@@ -1122,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)
@@ -1269,44 +1322,17 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
//======================================================================
// Special walking tree inserters
void AstNode::addBeforeStmt(AstNode* newp, AstNode*) {
UASSERT_OBJ(backp(), newp, "Can't find current statement to addBeforeStmt");
// Look up; virtual call will find where to put it
this->backp()->addBeforeStmt(newp, this);
}
void AstNode::addNextStmt(AstNode* newp, AstNode*) {
UASSERT_OBJ(backp(), newp, "Can't find current statement to addNextStmt");
// Look up; virtual call will find where to put it
this->backp()->addNextStmt(newp, this);
}
void AstNodeStmt::addBeforeStmt(AstNode* newp, AstNode*) {
// Insert newp before current node
this->addHereThisAsNext(newp);
}
void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
// Insert newp after current node
this->addNextHere(newp);
}
void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
// Preconditions insert first just before themselves (the normal rule
// for other statement types)
if (belowp == precondsp()) {
// Must have been first statement in precondsp list, so newp is new first statement
belowp->addHereThisAsNext(newp);
} else if (belowp == condp()) {
// Goes before condition, IE in preconditions
addPrecondsp(newp);
} else if (belowp == stmtsp()) {
// Was first statement in body, so new front
belowp->addHereThisAsNext(newp);
} else {
belowp->v3fatalSrc("Doesn't look like this was really under the while");
}
}
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
@@ -1353,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) {
@@ -1377,6 +1402,7 @@ void AstNode::dump(std::ostream& str) const {
void AstNodeProcedure::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isSuspendable()) str << " [SUSP]";
if (needProcess()) str << " [NPRC]";
}
void AstAlways::dump(std::ostream& str) const {
@@ -1426,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());
@@ -1440,29 +1466,10 @@ const char* AstClassPackage::broken() const {
void AstClassPackage::cloneRelink() {
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
}
void AstClass::insertCache(AstNode* nodep) {
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|| VN_IS(nodep, CFunc));
if (doit) {
if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
} else {
m_members.emplace(nodep->name(), nodep);
}
}
}
void AstClass::repairCache() {
clearCache();
for (auto* itemp = membersp(); itemp; itemp = itemp->nextp()) {
if (const auto* const scopep = VN_CAST(itemp, Scope)) {
for (auto* blockp = scopep->blocksp(); blockp; blockp = blockp->nextp()) {
insertCache(blockp);
}
} else {
insertCache(itemp);
}
}
bool AstClass::isCacheableChild(const AstNode* nodep) {
return (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|| VN_IS(nodep, CFunc));
}
AstClass* AstClass::baseMostClassp() {
AstClass* basep = this;
@@ -1499,13 +1506,20 @@ void AstClassExtends::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isImplements()) str << " [IMPLEMENTS]";
}
AstClass* AstClassExtends::classp() const {
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
refp = VN_AS(childDTypep(), ClassRefDType);
AstClass* AstClassExtends::classOrNullp() const {
const AstNodeDType* const dtp = dtypep() ? dtypep() : childDTypep();
const AstClassRefDType* const refp = VN_CAST(dtp, ClassRefDType);
if (refp && !refp->paramsp()) {
// Class already resolved
return refp->classp();
} else {
return nullptr;
}
UASSERT_OBJ(refp, this, "class extends non-ref");
return refp->classp();
}
AstClass* AstClassExtends::classp() const {
AstClass* const clsp = classOrNullp();
UASSERT_OBJ(clsp, this, "Extended class is unresolved");
return clsp;
}
void AstClassRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
@@ -1568,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();
@@ -1601,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 {
@@ -1617,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 {
@@ -1665,14 +1685,25 @@ 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);
str << "member";
}
AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
AstNodeDType* subdtp = skipRefp();
while (AstNodeArrayDType* const asubdtp = VN_CAST(subdtp, NodeArrayDType)) {
subdtp = asubdtp->subDTypep();
}
return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr
}
bool AstMemberSel::same(const AstNode* samep) const {
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());
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
str << " -> ";
@@ -1829,6 +1860,7 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (packed()) str << " [PACKED]";
if (isFourstate()) str << " [4STATE]";
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
}
void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
@@ -1903,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() {
@@ -2001,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() + "]";
@@ -2025,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 {
@@ -2043,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 {
@@ -2060,10 +2096,14 @@ void AstVoidDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "void";
}
void AstStreamDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "stream";
}
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);
@@ -2071,6 +2111,10 @@ void AstVarScope::dump(std::ostream& str) const {
str << " ->UNLINKED";
}
}
bool AstVarScope::same(const AstNode* samep) const {
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 {
this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
@@ -2098,9 +2142,11 @@ void AstVarRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
bool AstVarRef::same(const AstNode* samep) const {
return same(static_cast<const AstVarRef*>(samep));
const char* AstVarRef::broken() const {
BROKEN_RTN(!varp());
return AstNodeVarRef::broken();
}
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)) {
@@ -2119,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]";
@@ -2134,11 +2186,22 @@ void AstVar::dump(std::ostream& str) const {
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
}
bool AstVar::same(const AstNode* samep) const {
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 = VN_DBG_AS(samep, Scope);
return name() == asamep->name()
&& ((!aboveScopep() && !asamep->aboveScopep())
|| (aboveScopep() && asamep->aboveScopep()
&& aboveScopep()->name() == asamep->aboveScopep()->name()));
}
void AstScopeName::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
@@ -2222,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]";
@@ -2231,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);
@@ -2291,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]";
@@ -2302,6 +2391,7 @@ void AstCFunc::dump(std::ostream& str) const {
if (isDestructor()) str << " [DTOR]";
if (isVirtual()) str << " [VIRT]";
if (isCoroutine()) str << " [CORO]";
if (needProcess()) str << " [NPRC]";
}
const char* AstCAwait::broken() const {
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
@@ -2320,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.
@@ -2329,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
+9 -33
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;
//######################################################################
@@ -72,12 +66,12 @@ private:
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth = 0; // Current if depth
bool m_keepBegins = false; // True if begins should not be inlined
std::set<AstVar*> m_staticFuncVars; // Static variables from m_ftaskp
// METHODS
string dot(const string& a, const string& b) {
if (a == "") return b;
if (b == "") return a;
return a + "__DOT__" + b;
}
@@ -123,25 +117,6 @@ private:
}
}
void renameAndStaticsRecurse(AstNode* const nodep) {
// Rename references and move InitialStatic items
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
const auto it = m_staticFuncVars.find(varrefp->varp());
if (it != m_staticFuncVars.end()) varrefp->name((*it)->name());
}
if (nodep->op1p()) renameAndStaticsRecurse(nodep->op1p());
if (nodep->op2p()) renameAndStaticsRecurse(nodep->op2p());
if (nodep->op3p()) renameAndStaticsRecurse(nodep->op3p());
if (nodep->op4p()) renameAndStaticsRecurse(nodep->op4p());
if (nodep->nextp()) renameAndStaticsRecurse(nodep->nextp());
if (VN_IS(nodep, InitialStatic)) {
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
}
}
// VISITORS
void visit(AstFork* nodep) override {
// Keep begins in forks to group their statements together
@@ -197,7 +172,10 @@ private:
m_ftaskp = nodep;
m_liftedp = nullptr;
iterateChildren(nodep);
renameAndStaticsRecurse(nodep);
nodep->foreach([&](AstInitialStatic* const initp) {
initp->unlinkFrBack();
m_ftaskp->addHereThisAsNext(initp);
});
if (m_liftedp) {
// Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced
if (AstNode* const stmtsp = nodep->stmtsp()) {
@@ -207,7 +185,6 @@ private:
nodep->addStmtsp(m_liftedp);
m_liftedp = nullptr;
}
m_staticFuncVars.clear();
m_ftaskp = nullptr;
}
}
@@ -246,11 +223,11 @@ private:
void visit(AstVar* nodep) override {
// If static variable, move it outside a function.
if (nodep->lifetime().isStatic() && m_ftaskp) {
const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name();
const std::string newName
= m_ftaskp->name() + "__Vstatic__" + dot(m_unnamedScope, nodep->name());
nodep->name(newName);
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
m_staticFuncVars.insert(nodep);
nodep->funcLocal(false);
} else if (m_unnamedScope != "") {
// Rename it
@@ -361,7 +338,6 @@ private:
void visit(AstVarRef* nodep) override {
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef " << nodep << endl);
nodep->name(nodep->varp()->name());
}
iterateChildren(nodep);
}
@@ -392,5 +368,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
{ BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeLevel() >= 3);
}
+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
+5 -9
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;
//######################################################################
@@ -45,10 +39,12 @@ private:
// AstFTask::user1() -> int. Number of references
const VNUser1InUse m_inuser1;
// STATE
// STATE - across all visitors
std::vector<AstCFunc*> m_cfuncsp; // List of all tasks
// STATE - for current visit position (use VL_RESTORER)
int m_likely = false; // Excuses for branch likely taken
int m_unlikely = false; // Excuses for branch likely not taken
std::vector<AstCFunc*> m_cfuncsp; // List of all tasks
// METHODS
+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
+4 -7
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{
@@ -257,5 +254,5 @@ void V3CCtors::cctorsAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
evalAsserts();
{ CCtorsVisitor{v3Global.rootp()}; }
V3Global::dumpCheckGlobalTree("cctors", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeLevel() >= 3);
}
+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
+26 -24
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;
//######################################################################
@@ -45,32 +39,32 @@ class CUseVisitor final : public VNVisitor {
const VNUser1InUse m_inuser1;
// MEMBERS
bool m_impOnly = false; // In details needed only for implementation
AstNodeModule* const m_modp; // Current module
std::set<std::pair<VUseType, std::string>> m_didUse; // What we already used
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_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
if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
// Need to include extends() when we implement, but no need for pointers to know
VL_RESTORER(m_impOnly);
{
m_impOnly = true;
iterateChildren(nodep->classp()); // This also gets all extend classes
}
addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
}
void visit(AstCFunc* nodep) override {
if (nodep->user1SetOnce()) return;
iterateAndNextNull(nodep->argsp());
iterateAndNextNull(nodep->stmtsp());
}
void visit(AstCCall* nodep) override { return; }
void visit(AstCReturn* nodep) override {
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());
@@ -79,11 +73,13 @@ class CUseVisitor final : public VNVisitor {
if (stypep && stypep->classOrPackagep()) {
addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name());
iterateChildren(stypep);
} else if (AstClassRefDType* const classp = VN_CAST(nodep->skipRefp(), ClassRefDType)) {
addNewUse(nodep, VUseType::INT_FWD_CLASS, classp->name());
}
}
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 {
@@ -98,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);
@@ -115,5 +117,5 @@ void V3CUse::cUseAll() {
// for each output file and put under that
CUseVisitor{modp};
}
V3Global::dumpCheckGlobalTree("cuse", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeLevel() >= 3);
}
+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
+91 -53
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
@@ -566,7 +604,7 @@ public:
void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, dumpTree() >= 3);
V3Global::dumpCheckGlobalTree("case", 0, dumpTreeLevel() >= 3);
}
void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
+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

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