Compare commits

..
291 Commits
Author SHA1 Message Date
Wilson Snyder 5d3a9eec7f Version bump 2023-04-30 07:08:27 -04:00
Wilson Snyder 3d21a79148 Fix pylint warning 2023-04-29 22:22:38 -04:00
Wilson Snyder e15f5266a3 Commentary: Changes update 2023-04-29 22:16:53 -04:00
Toru Niina 9130eb8b99 Fix DPI function type alias (#4148) (#4149) 2023-04-28 07:21:09 -04:00
Ryszard Rozak 09e856d2f3 Fix deleting unused parameterized classes (#4150) 2023-04-28 07:20:25 -04:00
Ryszard Rozak ee5c0a2902 Support parameterized class references in extends statement (#4146) 2023-04-24 17:25:53 -04:00
Ryszard Rozak 621b7e63cf Print the type of provided RHS in class type check (#4145) 2023-04-24 17:24:04 -04:00
github action c6bf9fb89e Apply 'make format' 2023-04-24 11:29:33 +00:00
Risto PejašinovićandRisto Pejasinovic f794180865 Fix hier attribute of --xml-only cell section to respect begin blocks (#4129) (#4133)
Co-authored-by: Risto Pejasinovic <[email protected]>
2023-04-24 07:28:29 -04:00
Geza Lore 0e769d42a1 Optimize trigger evaluation
Pack the elements of VlTriggerVec as dense bits (instead of a 1 byte
bool per bit), and check whether they are set on a word granularity.
This effectively transforms conditions of the form `if (trig.at(0) |
trig.at(2) | trig.at(64))` into `if (trig.word(0) & 0x5 | trig.word(1) &
0x1)`. This improves OpenTitan ST by about 1%, worth more on some other
designs.
2023-04-24 09:09:36 +02:00
Wilson Snyder cbeb9d39ff Fix -CFLAGS to allow overriding optimization levels (#4140). 2023-04-23 10:18:48 -04:00
Wilson Snyder 5a98c1a3b1 Commentary 2023-04-23 10:10:05 -04:00
Geza Lore cac634d39b Fix DfgToAst conversion of CountBits (#4101) (#4143) 2023-04-23 08:49:44 -04:00
Peter Monsson 08330bad0b Fix variables in class methods to be automatic (#4111) (#4137) 2023-04-21 08:07:22 -04:00
Ryszard Rozak 84a46939b3 Fix class extend param references (#4136)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-04-20 07:11:35 -04:00
Kamil Rakoczy 65a484e00b Internal: Update clang_check_annotations conditions (#4134) 2023-04-20 07:02:31 -04:00
Krzysztof Boroński 843fdd3e57 Resolve class lvalues after parameterization (#4131) 2023-04-19 18:05:37 -04:00
Ryszard Rozak a10b51705f Fix class param extends A=B (#4128)
Visit global class params even if a class extends a param
2023-04-17 09:08:57 -03:00
Eyck Jentzsch df86e39845 Fix systemc namespace issues (#4126) (#4127)
* replaces use of "systemc.h" with <systemc> to avoid default namespace import
2023-04-17 06:57:29 -03:00
Wilson Snyder 7f49b6c102 Parse 'let' as unsupported 2023-04-16 17:23:16 -04:00
Krzysztof Boroński 754a0b8320 Fix to use parallel build for projects with a lot of files (#4116) 2023-04-14 18:52:05 -04:00
Krzysztof Boroński 7d3b3761b2 Fix including __Syms header in generated C++ files (#4123) 2023-04-14 11:53:27 -04:00
Ryszard Rozak d1b80ffa29 Support parameterized return types of methods (#4122) 2023-04-14 08:52:43 -04:00
Ryszard Rozak f95ce886f1 Fix duplicating parameter class types (#4115) 2023-04-14 06:51:33 -04:00
Wilson Snyder fa16eff003 Commentary (#4118) 2023-04-14 06:46:53 -04:00
Geza Lore 23f90b13f3 Do not create unnecessary DPI AstSenTrees
No functional change
2023-04-13 14:01:45 +01:00
Geza Lore 37e7b5dfc7 Fix unused/hard-coded argument
No functional change.
2023-04-13 14:01:37 +01:00
Kamil Rakoczy e1683afb31 Internals: V3ThreadPool: add function waiting for list of futures (#4112) 2023-04-12 08:49:48 -04:00
Kamil Rakoczy e38b359d75 Internals: Refactor for better clang thread-safety analysis (#4092) 2023-04-11 07:25:10 -04:00
Kamil Rakoczy b6dcec2710 Internals: Split Mutex class used in verilated code and verilator (#4048) 2023-04-11 07:23:24 -04:00
Wilson Snyder 0307d59c1f Fix unpacked structs under classes (#4102). 2023-04-10 19:40:34 -04:00
Wilson Snyder 3aa013c8db Tests: Remove old file 2023-04-10 19:40:34 -04:00
github action fc70876aa9 Apply 'make format' 2023-04-10 23:38:20 +00:00
Srinivasan Venkataramanan 722ab9306a Support class method calls without parenthesis (#3902) (#4082) 2023-04-10 19:37:24 -04:00
Wilson Snyder 2ab34b5eeb Fix false error on new const assignment (#4098). 2023-04-09 19:46:47 -04:00
Wilson Snyder e3bdae77a0 Tests: Add randsequence test 2023-04-09 17:08:04 -04:00
Wilson Snyder 663d6a1c8d Commentary 2023-04-09 10:23:35 -04:00
Wilson Snyder bf5cbb512e Add UNSUPPORTED on dotted disable instead of syntax error 2023-04-09 10:11:47 -04:00
Wilson Snyder d4bb58630e Support 'for' initialization with comma 2023-04-09 09:56:39 -04:00
Wilson Snyder fff0eb5d88 Internals: Use standard 'result' name for return variable. No functional change. 2023-04-08 22:11:28 -04:00
Wilson Snyder 7ae0c5d546 Internals: cppcheck fixes. No functional change intended 2023-04-08 21:36:32 -04:00
Wilson Snyder 114d93b212 Internals: Move -debug-exit-uvm to post V3LinkDot, just before V3Param (#1538) 2023-04-08 15:11:26 -04:00
Wilson Snyder 13a87e5514 Parse process class, and report runtime errors (#3612) 2023-04-08 15:04:42 -04:00
Wilson Snyder d67d75282c Support ++/-- on dotted member variables. 2023-04-07 20:57:17 -04:00
Kamil Rakoczy 827cbf22c9 Fix sense expression variable naming (#4081) 2023-04-07 07:23:37 -04:00
Wilson Snyder 2530cda507 Fix debug crash when no std:: used 2023-04-06 21:43:39 -04:00
Wilson Snyder 38000a3da0 Fix unnecessary verilated_std.sv waivers in --waiver-output. 2023-04-06 21:43:23 -04:00
Wilson Snyder 6c21b21ecc Internals: Indent verilated_std.sv with Verilog-mode. No functional change. 2023-04-06 21:27:16 -04:00
Wilson Snyder 8caf9be3e6 Internals: Favor {} constructor syntax. No functional change intended. 2023-04-06 21:04:26 -04:00
Krzysztof Bieganski cdb61842d6 Internals: Remove VlNow (#4089)
`VlNow{}` is completely unnecessary, as coroutines are always on the
heap (unless optimized out). Also fix access of var ref passed to forked processes.
2023-04-06 10:31:52 -04:00
Wilson Snyder 05660d1118 Add CONSTRAINTIGN warning when constraint ignored. Likewise ignore constraint_mode, rand_mode. 2023-04-05 21:27:37 -04:00
Ryszard Rozak a3f9221a67 Fix importing symbols from base class (#4084) 2023-04-04 20:56:18 -04:00
Wilson Snyder 7e1980af7a Tests: Avoid t_dist failures on deleted files. 2023-04-02 15:10:45 -04:00
Wilson Snyder 921fd919b5 Tests: Improve short circuit test 2023-04-01 23:10:05 -04:00
Robert BalasandRobert Balas fc5a5ea53d Commentary: Fix spelling mistakes (#4080)
Co-authored-by: Robert Balas <[email protected]>
2023-04-01 20:45:28 -04:00
Wilson Snyder 86156dd05b Revert false-positive static error (#4072) (#4077) 2023-04-01 18:54:37 -04:00
Wilson Snyder 3219ffddd4 Tests: Ignore commented out messages 2023-04-01 18:17:45 -04:00
Wilson Snyder 3a01c32bf9 Revert false-positive static error (#4072) (#4077) 2023-04-01 15:45:34 -04:00
Wilson Snyder 9ffd0a4e70 Support queue[$-1] selects. 2023-04-01 15:23:39 -04:00
Wilson Snyder 90e049c674 Internals: Remove unneeded variable. No functional change. 2023-04-01 11:46:43 -04:00
Wilson Snyder 69121633cf Support class srandom and class random stability. 2023-04-01 10:50:27 -04:00
Wilson Snyder 28eadded87 Update include/gtkwave from upstream 2023-04-01 10:38:47 -04:00
Wilson Snyder 93c598dd19 Commentary 2023-04-01 10:38:33 -04:00
Krzysztof Bieganski d012563ab1 Fix tracing with awaits at end of block (#4075) (#4076)
Given an await at the end of a block, e.g. at the end of a loop body, a trace
activity setter was not inserted, as there were no following statements. This
patch makes the activity update unconditional.
2023-03-31 13:51:31 -04:00
Krzysztof Bieganski 0b96789e65 Add error on static access to non-static class member (#4072)
Before this patch, it was possible to access non-static class members using
static access, which resulted in C++ compilation errors. This adds
verilation-time checks for such situations.
2023-03-27 10:46:51 -04:00
Wilson Snyder 947402bc57 Fix interface generate begin (#4065). 2023-03-26 08:49:38 -04:00
Yutetsu TAKATSUKASA d4107dce52 Improve xor tree optimization (#4071)
* AstNot does not have to be frozen in an xor tree during BitOp tree optimization.

* Tests: Update stats.
2023-03-26 20:36:32 +09:00
Yutetsu TAKATSUKASA 990b19e048 Fix incorrect optimization of bit op tree (#4059) (#4070) 2023-03-26 03:29:10 -04:00
Srinivasan Venkataramanan 2290e6ccf2 Fix info message prints under --assert (#4036) (#4053) 2023-03-24 19:22:48 -04:00
Wilson Snyder 14c8f072f1 Commentary 2023-03-24 19:06:07 -04:00
Krzysztof Bieganski c55df02b1a Fix C++ compile errors when passing class refs as task arg (#4063)
1. Fixes passing a null reference as a task argument. Before this patch it would
   cause a C++ compile error like `cannot convert ‘VlNull’ to ‘VlClassRef<...>’`.

2. Fixes passing a class reference as a task argument when the argument is a
   reference to a base class. Before the patch it would cause a C++ compile
   error like `cannot convert ‘VlClassRef<{DERIVED_CLASS}>’ to ‘VlClassRef<{BASE_CLASS}>`.
2023-03-24 13:18:59 -04:00
Ryszard Rozak 5b86248b54 Add error if class types don't match (#4064) 2023-03-24 13:18:20 -04:00
Josep Sans 449ac44131 Fix _Vilp used before declaration (#4057) (#4062) 2023-03-24 11:51:02 +01:00
Ryszard Rozak f439a7927f Fix parameters in a class body to be localparam (#4061) 2023-03-23 10:20:35 +01:00
Aleksander Kiryk 277bd67f72 Fix NBAs inside fork-joins (#4050) 2023-03-21 10:39:29 -04:00
Krzysztof Bieganski 5de8ccbf32 Fix task calls as fork statements (#4055)
Before this patch, calling tasks directly under forks would result in each
statement of these tasks being executed concurrently. This was due to Verilator
inlining tasks most of the time. Such inlined tasks' statements would simply
replace the original call, and there would be no indication that these used to
be grouped together. Ultimately resulting in `V3Timing` treating each statement
as a separate process.

The solution is simply to wrap each fork sub-statement in a begin in `V3Begin`
(except for the ones that are begins, as that would be pointless). `V3Begin` is
already aware of forks, and is supposed to avoid issues like this one, so it
seems like a natural fit. This also protects us from similar bugs, i.e. if some
statement gets replaced or expanded into multiple statements.

Signed-off-by: Krzysztof Bieganski <[email protected]>
2023-03-21 13:50:53 +01:00
Wilson Snyder 577e0700ba Commentary: Changes update 2023-03-21 04:52:12 -04:00
github action 71a37484f5 Apply 'make format' 2023-03-21 08:43:31 +00:00
Jesse Taube daf157e6c0 Fix false LATCH warning on --assert 'unique else if' (#4033) (#4054). 2023-03-21 04:42:19 -04:00
Iztok Jeras 2aa6a229ca Change range order warning from LITENDIAN to ASCRANGE (#4010) 2023-03-20 20:44:11 -04:00
Wilson Snyder 9b869edd90 Internals: Fix cppcheck warnings. No functional change. 2023-03-18 19:28:48 -04:00
Wilson Snyder 2b21697b86 Support class extends of package::class. 2023-03-18 17:26:36 -04:00
Wilson Snyder 895ab8789b Internals: Fix recently added assertion false firing 2023-03-18 17:11:39 -04:00
Wilson Snyder 5f02f95ce6 Commentary (#3906) (#3931) 2023-03-18 15:49:11 -04:00
Wilson Snyder f2aac8c49a Internals: Use VNVisitorConst where possible, for better performance. No functional change indended. 2023-03-18 12:23:17 -04:00
Wilson Snyder 82e653a739 Internals: Avoid emit inheritance in V3EmitCBase. No functional change intended. 2023-03-18 12:23:17 -04:00
Tim Snyder 053f760e2a Fix characters from DEFENV literals for conda (#4035) (#4044)
The baked in DEFENV paths might end up with extra NULL characters
at the end if the binaries are installed by something that patches them
for relocatable installs (e.g. conda).  Avoid this issue by immediately
passing them through std::string::c_str() method to stop at the first NULL
2023-03-18 11:25:27 -04:00
Wilson Snyder ba9e141fae Commentary: Update CONTRIBUTING and internals xrefs (#4043) 2023-03-18 10:23:19 -04:00
Wilson Snyder d60a3e2b66 Fix random internal crashes (#666).
Internally, in V3Broken check m_interpp for null, and make several cleanups
in the addNext/addNextHere/unlinkFr* methods.
2023-03-18 09:48:26 -04:00
Yu-Sheng Lin 70c2d1eded Fix install, standardization in cmake CMakeLists.txt (#3974) 2023-03-18 07:38:09 -04:00
Wilson Snyder 80cbf81b3b Internals: Fix missing relink() and add assert 2023-03-17 22:29:48 -04:00
Kamil Rakoczy 798d7346cf Internals: Add VL_MT_SAFE attribute to functions that requires locking. (#3805) 2023-03-17 20:24:15 -04:00
Wilson Snyder d6c5d40f9b Internals: Add VNVisitorConst class. 2023-03-17 19:59:09 -04:00
Ryszard Rozak 371b8310d9 Support method calls without parenthesis (#4034)
* Support method class without parenthesis

Signed-off-by: Ryszard Rozak <[email protected]>

* Delete replaced nodes

Signed-off-by: Ryszard Rozak <[email protected]>

---------

Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-17 13:25:39 +01:00
Ryszard Rozak 1ac721af8f Add STATICVAR warning and convert to automatic (#4027) (#4030)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-17 07:48:41 -04:00
Wilson Snyder 85fd88ace2 Optimize duplicate JumpBlocks away (#4028) 2023-03-16 22:29:06 -04:00
Wilson Snyder ed1e377bb1 Fix large return blocks with --comp-limit-blocks (#4028). 2023-03-16 21:40:01 -04:00
Wilson Snyder 4240c29f4b Internals: Fix missing broken check 2023-03-16 21:14:49 -04:00
Wilson Snyder 51ba4a1531 Fix clocking block scope internal error (#4032). 2023-03-16 20:48:18 -04:00
Wilson Snyder d1b55cb7aa Fix compile error last commit (#4029) 2023-03-16 20:22:08 -04:00
Kamil Rakoczy bbf53bd5af Add VL_MT_SAFE attribute to several functions. (#3729) 2023-03-16 19:48:56 -04:00
Wilson Snyder b2ced6ff1d Add more debug info to --report-unoptflat graph (#4039) 2023-03-16 19:47:13 -04:00
Wilson Snyder a9b07fe7d7 Tests: Remove unintended t_0 test 2023-03-16 18:44:28 -04:00
Kamil Rakoczy 66e4656a8e Fix event controls reusing same variable (#4014) 2023-03-16 07:12:54 -04:00
Wilson Snyder 8f4d4f07a4 Commentary 2023-03-16 07:09:16 -04:00
Wilson Snyder 8e55580cde Update include/gtkwave from upstream 2023-03-15 22:11:06 -04:00
Wilson Snyder 8ae79066a2 Fix false ENUMVALUE on expressions and arrays. 2023-03-15 21:56:35 -04:00
Wilson Snyder 36da6a3563 Fix parsing #1_2 delays 2023-03-15 21:22:28 -04:00
Wilson Snyder 45690faea7 Parse defparam = as unsupported 2023-03-15 21:04:10 -04:00
Wilson Snyder 046fecbb35 Fix fclose(0). 2023-03-15 20:49:59 -04:00
Ryszard Rozak 0f6024ef3c Fix rand fields in base classes (#4025) 2023-03-15 11:48:18 -04:00
Wilson Snyder 2488b5a97f Fix pullup/pulldown to create implicit wires. 2023-03-14 21:14:27 -04:00
Wilson Snyder 56de6f1a9f Fix min/typ/max internal error 2023-03-14 20:40:58 -04:00
Wilson Snyder 0fc5d37901 Fix bounded queues with parameter bounds 2023-03-14 20:29:47 -04:00
Wilson Snyder ea4cc4e076 Parse nettype with package, still unsupported 2023-03-14 19:52:01 -04:00
Wilson Snyder 9e25c21fed Fix unpacked struct clocking 2023-03-14 19:35:40 -04:00
Ryszard Rozak fc3fdcc71c Tests: Fix randomize_method test (#4024) 2023-03-14 13:47:43 -04:00
Ryszard Rozak 80b7b8bbdb Don't call randomize on null field (#4023)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-14 14:48:06 +01:00
Wilson Snyder a8ce272e4a Commentary: spelling 2023-03-14 08:39:54 -04:00
Wilson Snyder 72963c4e20 Commentary (#4020) 2023-03-14 08:29:39 -04:00
Ryszard Rozak 4e5bd361e0 Internal: Fix dumping of AstMethodCall (#4021) 2023-03-14 06:54:45 -04:00
Ryszard Rozak ed1a9309d4 Throw warning if static variable is declared in a loop (#4018)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-03-14 10:03:08 +01:00
Ryszard Rozak 1d0a06438c Assign unique names for blocks in do..while loop (#4019) 2023-03-14 09:54:43 +01:00
Wilson Snyder 2c62714a30 Fix push to dynamic queue in struct (#4015). 2023-03-13 22:03:53 -04:00
Wilson Snyder f13e753b52 Change ZERODLY to a warning. 2023-03-12 21:28:14 -04:00
Wilson Snyder 39a5bce8a6 Parse covergroup, still unsupported. 2023-03-12 14:11:11 -04:00
Wilson Snyder ba953bfa94 Commentary: Changes update 2023-03-12 10:49:19 -04:00
Wilson Snyder 1debd0405b Support complicated IEEE 'for' assignments. 2023-03-12 10:46:40 -04:00
Wilson Snyder 1f1d9312d2 Parse event 'iff', still unsupported. 2023-03-11 22:39:59 -05:00
Wilson Snyder 259201b352 Support $fopen as an expression 2023-03-11 18:11:01 -05:00
Wilson Snyder bb45bd048e Commentary 2023-03-11 11:27:40 -05:00
Wilson Snyder 5489ec6eff Parse 'first_match', and still unsupported. 2023-03-11 11:08:37 -05:00
Wilson Snyder e55e81bcd0 Parse sequence 'local input', still unsupported. 2023-03-11 10:53:10 -05:00
Wilson Snyder 5c5c758718 Parse 'wait_order' and test, still unsupported. 2023-03-11 10:47:08 -05:00
Wilson Snyder b87669039e Commentary 2023-03-10 22:25:47 -05:00
Wilson Snyder 60a6ed2a20 Support assert property statement-else-statement 2023-03-10 22:13:17 -05:00
Wilson Snyder 81e8388c3f Parse 'expect', still unsupported. 2023-03-10 21:48:56 -05:00
Wilson Snyder 4532680e5f Internals: Cleanup assert/assume. No functional change. 2023-03-10 21:17:54 -05:00
Andrew Nolte fc17ab280a Add --public-depth to force public to a certain instance depth (#3952) 2023-03-09 21:48:05 -05:00
Wilson Snyder 621cd0f008 Internals: Framework for renaming warnings (#4010 partial) 2023-03-08 21:32:37 -05:00
Andrew Nolte 13c9877099 Add --public-params flag (#3990) 2023-03-08 19:38:26 -05:00
Wilson Snyder ff889fde18 Add debug comment when trace disabled (#4004). 2023-03-06 18:22:46 -05:00
Krzysztof Boroński f68c16a5e6 Fix symbol entries when inheriting classes (#3995) (#3996) 2023-03-06 07:43:58 -05:00
Ryszard Rozak cc45f64280 Add __PVT__ prefix to selects nodes (#4001) 2023-03-06 13:18:48 +01:00
Wilson Snyder 725ec088ea Parse 'sequence' declarations, property case/if, still unsupported. 2023-03-06 05:12:09 -05:00
Wilson Snyder 87c3de5aab Parse 'matches', still unsupported. 2023-03-05 23:58:54 -05:00
Wilson Snyder 6d7c04a3de Parse cycle delays and boolean abbrev, still unsupported. 2023-03-05 23:22:41 -05:00
Wilson Snyder d0f5ce0cc4 Parse intersect/throughout/within, still unsupported. 2023-03-05 19:57:09 -05:00
Wilson Snyder cb89ef9885 Parse more property expression syntax, as still unsupported 2023-03-05 19:42:21 -05:00
Wilson Snyder 90360d40fd Change property expression handling towards eventual more general expressions. 2023-03-05 18:52:55 -05:00
Wilson Snyder 15dcd326f8 Internals: Parse weak/strong but do not lex 2023-03-05 18:30:43 -05:00
Wilson Snyder ae1eb56695 Internals: Parser commentary 2023-03-05 17:59:17 -05:00
Wilson Snyder a47fd07585 Internals: Standard grammar for property_expression |-> |=>. 2023-03-05 16:59:24 -05:00
Wilson Snyder 19bc257002 Internals: UNSUPPORTED commentary 2023-03-05 16:45:07 -05:00
Wilson Snyder a1d4cd658e devel release 2023-03-04 11:31:58 -05:00
Wilson Snyder 21093fd1bd Version bump 2023-03-04 11:19:44 -05:00
Wilson Snyder 329a933efd Internals: Parse nettype as unsupported 2023-03-04 10:50:28 -05:00
Wilson Snyder e21198cb2d Add warning on missing class reference #() 2023-03-03 21:06:52 -05:00
Wilson Snyder ab502c5196 Fix coverage of class methods (#3998). 2023-03-03 19:26:15 -05:00
Felix Neumärker 12728bc478 Fix UNDRIVEN warning seg fault (#3989) 2023-03-03 18:54:38 -05:00
Wilson Snyder 3fc684359a Fix prettyName in structure dumps, partial (#4001) 2023-03-03 18:49:26 -05:00
Wilson Snyder 1e28387541 Tests: Add nettype test 2023-03-02 20:29:42 -05:00
Wilson Snyder dd917d50eb Internals: Parse interconnect then say unsupported 2023-03-02 20:02:14 -05:00
Kamil Rakoczy 0130c2bceb Internals: update clang attributes check report conditions (#3997) 2023-03-02 18:37:07 -05:00
Wilson Snyder 8a5804fc3a Tests: Add tagged union test 2023-03-02 08:11:11 -05:00
Wilson Snyder 3df29085c8 Fix end label fileline reporting. 2023-03-02 07:50:16 -05:00
Wilson Snyder 976af0068b Support parsing min:typ:max parameters 2023-03-01 23:11:48 -05:00
Wilson Snyder a85e6a9d8c Commentary: Changes update 2023-03-01 22:43:39 -05:00
Wilson Snyder 463ea57b0a Add error (vs previous warning) on enum value overflow. 2023-03-01 22:36:42 -05:00
Wilson Snyder 326a60d307 Add error on mixing .name and by-port instantiations. 2023-03-01 21:19:21 -05:00
Ryszard Rozak 2c60c5f816 Support recursive methods (#3987) 2023-03-01 21:07:37 -05:00
Cameron Kirk faf3804b9a Fix LITENDIAN warning is backwards (#3966) (#3967). 2023-03-01 11:46:44 -05:00
github action 08a433260c Apply 'make format' 2023-03-01 05:44:35 +00:00
Wilson Snyder 7fc278f6db Fix import of extends typedefs 2023-03-01 00:30:45 -05:00
Wilson Snyder b1a95f642f Support cast to numbers from strings. 2023-02-28 23:34:33 -05:00
Wilson Snyder c6a569df49 Commentary 2023-02-28 18:38:52 -05:00
Krzysztof Boroński 06661ab676 Disallow ++/-- over expressions with potential side effects (#3976). 2023-02-28 15:21:58 -05:00
Wilson Snyder d9a0e69597 Commentary, fix copyright 2023-02-28 01:09:09 -05:00
Wilson Snyder a0997d0b98 Fix internal error with UNSUPPORTED of procedural clocked assertions 2023-02-28 00:35:58 -05:00
Felix Neumärker a3ff375ce7 Fix timing delays to not truncate below 64 bits (#3973) (#3982) 2023-02-27 21:42:22 -05:00
Wilson Snyder c03affa544 Fix enum.next(0) and enum.prev(0). 2023-02-26 15:24:24 -05:00
Wilson Snyder 4703fc39be Add error to avoid @* fatal 2023-02-26 13:13:02 -05:00
Wilson Snyder 9bf0e54937 Internals: add const 2023-02-26 12:21:17 -05:00
Wilson Snyder b039f246df Lint check posedge of nonintegral 2023-02-26 12:08:10 -05:00
Wilson Snyder a93b344096 Tests: use standard lower case for Perl vm_prefix 2023-02-26 10:18:40 -05:00
Peter DebackerandPeter Debacker 191c71edea Fix cmake on macOS to mark weak symbols with -U linker flag (#3978) (#3979)
Co-authored-by: Peter Debacker <[email protected]>
2023-02-23 17:27:29 -05:00
Wilson Snyder b4dd398af6 Tests: Cleanup some C++ new calls. No functional change. 2023-02-23 06:14:54 -05:00
Wilson Snyder cfe0fdd5cc Untabify 2023-02-23 05:47:56 -05:00
Adam Bagley 003a8cfe75 Add lint warning on always_comb multidriven (#3888) (#3939) 2023-02-23 05:36:28 -05:00
Wilson Snyder 7559af5879 Fix missing error on negative replicate (#3963). 2023-02-22 19:11:02 -05:00
Ryszard Rozak 47a7e75841 Fix subsequent parameter declarations (#3969) 2023-02-22 11:26:25 +01:00
Wilson Snyder adf1de45de With -Wpedantic change ASSIGNIN to a warning 2023-02-21 16:45:35 -05:00
Ryszard Rozak 45f955f175 Fix self references to parameterized classes (#3962) 2023-02-17 11:17:35 -05:00
Ryszard Rozak 063f9a7a4c Fix dicts declared with ref type (#3960) 2023-02-16 12:49:45 -05:00
Wilson Snyder c82a098f2e Internals: Parse class extends :: 2023-02-14 21:23:55 -05:00
Wilson Snyder 393b7714c4 Convert some mis-syntax errors to UNSUPPORTED 2023-02-14 20:48:52 -05:00
Wilson Snyder 43d8de4f80 Support property var decls. 2023-02-14 20:44:14 -05:00
Wilson Snyder 026bbc306b Removed deprecated --cdc option. 2023-02-13 22:49:51 -05:00
Wilson Snyder f8b0e359b9 Support class parameters without initial values. 2023-02-13 22:06:52 -05:00
Wilson Snyder 94ef1b76d0 Fix error text on packed struct init. 2023-02-13 20:58:49 -05:00
Wilson Snyder 50929e5d43 Fix packed array structure replication. 2023-02-13 07:49:08 -05:00
github action 3f4b7af8a1 Apply 'make format' 2023-02-13 04:21:52 +00:00
Larry Doolittle bc6a7787ed Fix date on the front page of verilator.pdf (#3956) (#3957) 2023-02-12 23:21:03 -05:00
Wilson Snyder 5064ec2806 Support type case and type equality comparisons. 2023-02-12 20:09:10 -05:00
Wilson Snyder 4f19eeaffa Fix type(typedef) operation core dump 2023-02-12 19:57:52 -05:00
Wilson Snyder 10d0088f73 Fix generate case with empty body statements. 2023-02-12 18:14:18 -05:00
Wilson Snyder 15d0ec317d Fix lint for non-integral types in packed structs. 2023-02-12 16:32:36 -05:00
Wilson Snyder 260d58e47e Tests: Add struct tests 2023-02-12 13:30:52 -05:00
Wilson Snyder d9c4d9316f Parse checkers as UNSUPPORTED. 2023-02-11 14:31:28 -05:00
Wilson Snyder e9441cff50 Parse external constraints as UNSUPPORTED. 2023-02-11 13:29:52 -05:00
Wilson Snyder daa545774e Parse randsequence as UNSUPPORTED. 2023-02-11 13:03:10 -05:00
Wilson Snyder dee2e45e27 Tests: Add defparam not resolved test 2023-02-11 11:00:07 -05:00
Wilson Snyder 4d29487e75 Fix -Wpedantic on std::process. 2023-02-11 10:55:06 -05:00
Wilson Snyder 2bb2935924 Commentary: Changes update 2023-02-11 10:38:00 -05:00
Larry Doolittle aff3f7c4f6 Fix build on hppa (#3954)
As supplied by John David Anglin in Debian bug #1030913
2023-02-11 04:23:26 -05:00
Wilson Snyder 5aa4f46101 Internals: Add some std::. No functional change intended. 2023-02-10 20:32:39 -05:00
Zixi Li 8f87022496 Fix CMake bad C identifiers (#3948) (#3951) 2023-02-10 20:06:05 -05:00
Ryszard Rozak d34aa10faf Fix class field linking when a super classes is a param (#3949) 2023-02-10 07:44:14 -05:00
Kamil Rakoczy 93d50c4499 Internals: Add mutex to V3Error (#3680) 2023-02-09 22:15:37 -05:00
Todd Strader 4eb280601e handle constant format field widths (#3946) 2023-02-09 10:09:00 -05:00
Wilson Snyder b778784333 Add --annotate-points option, change multipoint on line reporting (#3876). 2023-02-08 20:22:54 -05:00
Todd Strader 9121a81a74 Fix constant enum methods (#3621) 2023-02-08 18:50:27 -05:00
Todd Strader d3cbb1e53f Fix constant string function assignment (#3945) 2023-02-08 18:48:07 -05:00
Wilson Snyder cf88700fc2 Fix virus detection false positive (#3944). 2023-02-08 18:44:07 -05:00
Ryszard Rozak 072d76fe8e Use VAR_BASE as attr type if a select's base is a ref (#3943)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-02-07 15:10:19 +01:00
Aleksander Kiryk 3436d1780f Fix namespace fallback resolution (#3863) (#3942) 2023-02-07 07:13:55 -05:00
Wilson Snyder 1607225063 Fix VPI upper interface scopes not found (#3937). 2023-02-05 16:16:39 -05:00
Wilson Snyder 807e5b22a0 Fix verilator_difftree header flush 2023-02-05 15:20:56 -05:00
Wilson Snyder 2c64b83c19 Internals: Fix constructor syntax 2023-02-05 14:29:49 -05:00
Wilson Snyder dfc98e77c0 Commentary 2023-02-05 14:12:27 -05:00
Wilson Snyder 936bb7b1ed Add error on size with unsized number 2023-02-05 14:06:03 -05:00
Wilson Snyder 88e5017564 Internals: Directly assign dtype instead of using dtype's dtype 2023-02-05 13:50:29 -05:00
Wilson Snyder 508f6f7e5a Fix core dump with initial variable delays 2023-02-05 13:17:35 -05:00
Wilson Snyder 70eceae3d8 Fix core dump on bad dotted reference. 2023-02-05 12:45:14 -05:00
Wilson Snyder eb5aad94f1 Support to packed array 2023-02-05 10:18:03 -05:00
Wilson Snyder 2d89c458f6 Fix force/release of real. 2023-02-04 20:37:36 -05:00
Wilson Snyder d33ded22f9 Internals: Remove unused variable 2023-02-04 19:50:04 -05:00
github action edc32ca82d Apply 'make format' 2023-02-04 13:20:41 +00:00
Kritik Bhimani dc9c81256d Fix MsWin missing directory exception, and ::std (#3928) (#3933) (#3935) 2023-02-04 08:19:49 -05:00
Wilson Snyder 6908e471e7 Revert: e3558d9e: Support vpiDefName (#3906) (#3931) 2023-02-03 21:26:21 -05:00
Andrew Nolte e3558d9e1b Support vpiDefName (#3906) (#3931) 2023-02-03 19:14:41 -05:00
Wilson Snyder 11043aeb9b Work around mswin crash with --std (#3933) 2023-02-03 19:01:20 -05:00
Wilson Snyder 15c163c12e github: msbuild compile with -j 3 2023-02-03 18:47:54 -05:00
Wilson Snyder c7ed73e249 Fix MSVC++ compile warning 2023-02-03 18:47:37 -05:00
Wilson Snyder 4aa3e72509 Fix cmake 3.12+ warnings on MSWIN. 2023-02-03 17:16:39 -05:00
Aleksander Kiryk 31130c4b4a Fix std:: to be parsed first (#3864) (#3928) 2023-02-03 09:04:16 -05:00
github action 00f0027c80 Apply 'make format' 2023-02-03 13:48:46 +00:00
Joseph Nwabueze c8be50d40b Add /*verilator public[flat|flat_rd|flat_rw| ]*/ metacomments (#3894) 2023-02-03 08:47:55 -05:00
Wilson Snyder e16e9b89cd Commentary (#3932). 2023-02-03 07:27:23 -05:00
Yoda Lee 80b291407b Add cmake warning if multiple SOURCES w/o PREFIX (#3916) (#3927) 2023-02-02 22:08:13 -05:00
David Stanford d2aff13402 Commentary: Add some more details to the vpi example (#3925) 2023-02-02 21:51:23 -05:00
github action 82f450d838 Apply 'make format' 2023-02-03 00:11:37 +00:00
Wilson Snyder f6d4f1ad02 Fix very long VPI signal names (#3929). 2023-02-02 19:10:23 -05:00
Wilson Snyder 645e1387e0 Tests: Fix merge conflict failure 2023-02-02 19:10:20 -05:00
Andrew Nolte d3c14cc1ac Split WIDTH warning into WIDTHEXPAND and WIDTHTRUNC (#3900) 2023-02-02 18:25:25 -05:00
Ryszard Rozak 33468fa0e7 Fix class extend parameter dot case (#3926) 2023-02-02 17:59:47 -05:00
Ryszard Rozak 0e955d503e Handle references of static members of type aliases of a parametrized class (#3922)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-02-02 08:36:11 +01:00
Andrew Nolte 18e317fb78 Fix inconsistent naming of generate scope arrays (#3840) 2023-02-01 17:30:02 -05:00
Wilson Snyder ef9f443532 Fix single-element replication to dynarray/unpacked/queue (#3548). 2023-01-31 22:43:41 -05:00
Wilson Snyder 6e3b957b30 Tests: Add iterate check (#3919) 2023-01-31 19:34:27 -05:00
Wilson Snyder aea1834ed8 Commentary (#3920) 2023-01-31 12:11:35 -05:00
Ryszard Rozak 7f3e178b68 Fix paramaterized class function linkage (#3917)
* Visit function arguments even if the function is unlinkable
* Don't use m_unlinedScopep in AstLambdaArgRef handling
2023-01-30 22:20:56 -05:00
Larry Doolittle 87a7881d46 Add SOURCE_DATE_EPOCH for docs/guide/conf.py (#3918) 2023-01-30 22:14:33 -05:00
Larry Doolittle 29f4821d78 Tests: Check Makefiles for stray tabs (#3914) 2023-01-30 07:31:39 -05:00
Larry Doolittle 9f9c84aa64 Internals: Avoid using <tab> in the middle of lines (#3913) 2023-01-29 22:39:22 -05:00
Larry Doolittle d80e0523cc Fix nonsensical permissions of some files in test_regress/t (#3912)
chmod a-x *.out *.v *.vlt
2023-01-29 20:32:19 -05:00
Wilson Snyder 164aa96953 Fix GCC warning (fixes recent #3510) 2023-01-29 17:34:48 -05:00
Wilson Snyder 6a12c4d02a Commentary: Changes update 2023-01-29 16:57:30 -05:00
Wilson Snyder 6a7dfb7696 Fix pattern assignment to unpacked structs (#3510). 2023-01-29 16:50:10 -05:00
Wilson Snyder 4208db7811 Support multiple-output buf/not gate primitives 2023-01-28 23:20:48 -05:00
Wilson Snyder a19dddf05e Fix real parameters of infinity and NaN. 2023-01-28 22:11:09 -05:00
Wilson Snyder 7855a78a0f Support %p of union with real 2023-01-28 21:41:50 -05:00
Wilson Snyder 248bd173d3 Support interface classes and class implements. 2023-01-28 18:06:37 -05:00
Wilson Snyder 8d2be855f5 Internals: Parsing and tests for class interfaces 2023-01-28 16:30:47 -05:00
Wilson Snyder ba8700f99d Support $changed_gclk, $fell_gclk, $rose_gclk, $stable_gclk 2023-01-28 14:05:26 -05:00
Wilson Snyder f20997a2f0 Support global clocking and $global_clock. 2023-01-28 12:31:52 -05:00
Wilson Snyder bea225e191 Fix duplicate name check on extern symbols 2023-01-28 11:55:44 -05:00
Wilson Snyder 93517b8378 Support unpacked unions. 2023-01-27 22:41:12 -05:00
Kamil Rakoczy a39c7f7dac Internals: Add V3ThreadPool class (#3898)
The thread pool is self tested, but not otherwise used by the code yet.
2023-01-27 10:43:50 -05:00
Wilson Snyder 5125b94fd8 Commentary (#3908) 2023-01-26 18:27:00 -05:00
Ilya Barkov d118a739dc Fix cinlude check (#3907) 2023-01-26 06:35:59 -05:00
Wilson Snyder c2a8810eb1 Tests: Check for new .pl file copyrights 2023-01-25 22:14:43 -05:00
Ryszard Rozak 91c44d7830 Support class extending its parameter (#3904) 2023-01-25 20:33:18 -05:00
Wilson Snyder 21aafe8f50 Tests: Fix file length issue (cousin of #3905) 2023-01-25 19:42:28 -05:00
Ryszard Rozak 4a8cfe367d Support function calls without parenthesis (#3903) (#3902)
Signed-off-by: Ryszard Rozak <[email protected]>
2023-01-24 15:36:30 +01:00
Ryszard Rozak b56e7f6910 Support static function variables (#3830) 2023-01-23 08:35:10 -05:00
Wilson Snyder 8a85cedaf5 Tests: Update test, part of (#3378) (#3892) 2023-01-23 07:23:42 -05:00
Varun Koyyalagunta be26e8da1b Support struct I/O in --lib-create (#3378) (#3892) 2023-01-22 22:24:36 -05:00
Wilson Snyder b2dd5de860 Tests: Fix some unusual check_finished cases. 2023-01-22 22:21:36 -05:00
Kamil Rakoczy 6ea725f479 Add --verilate-jobs option (#3889)
Currently this option isn't used, but in the future it will be used to specify parallelization of Verilation step.
2023-01-22 21:52:52 -05:00
Wilson Snyder 665758a68b devel release 2023-01-22 11:55:22 -05:00
844 changed files with 20632 additions and 7530 deletions
+6 -11
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.003
VERSION 5.010
HOMEPAGE_URL https://verilator.org
LANGUAGES CXX
)
@@ -23,7 +23,8 @@ project(Verilator
option(DEBUG_AND_RELEASE_AND_COVERAGE
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.")
set(PYTHON3 python)
find_package(Python3 COMPONENTS Interpreter)
set(PYTHON3 Python3::Interpreter)
set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX})
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
@@ -44,15 +45,7 @@ if (MSVC)
if (NOT WIN_FLEX_BISON)
message(FATAL_ERROR "Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build.")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++20")
else()
if (NOT DEFINED ENV{FLEX_INCLUDE})
message(FATAL_ERROR "Please set environment variable FLEX_INCLUDE to the directory containing FlexLexer.h")
endif()
set(WIN_FLEX_BISON "$ENV{FLEX_INCLUDE}")
if (WIN32 AND NOT MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
endif()
set(CMAKE_CXX_STANDARD 20)
endif()
find_package(BISON)
@@ -99,6 +92,7 @@ configure_package_config_file(verilator-config-version.cmake.in verilator-config
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
foreach (program
verilator
verilator_gantt
verilator_ccache_report
verilator_difftree
@@ -118,6 +112,7 @@ install(DIRECTORY include TYPE DATA FILES_MATCHING
PATTERN "include/verilated.mk"
PATTERN "include/*.[chv]"
PATTERN "include/*.cpp"
PATTERN "include/*.sv"
PATTERN "include/gtkwave/*.[chv]*"
PATTERN "include/vltstd/*.[chv]*"
)
+130 -3
View File
@@ -8,7 +8,131 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 5.006 2022-01-22
Verilator 5.010 2023-04-30
==========================
**Minor:**
* Add --public-depth to force public to a certain instance depth (#3952). [Andrew Nolte]
* Add --public-params flag (#3990). [Andrew Nolte]
* Add CONSTRAINTIGN warning when constraint ignored.
* Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd]
* Add error if class types don't match (#4064). [Ryszard Rozak, Antmicro Ltd]
* Support class extends of package::class.
* Support class srandom and class random stability.
* Support class method calls without parenthesis (#3902) (#4082). [Srinivasan Venkataramanan]
* Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd]
* Support parameterized return types of methods (#4122). [Ryszard Rozak, Antmicro Ltd]
* Support parameterized class references in extends statement (#4146). [Ryszard Rozak, Antmicro Ltd]
* Support complicated IEEE 'for' assignments.
* Support $fopen as an expression.
* Support ++/-- on dotted member variables.
* Optimize static trigger evaluation (#4142). [Geza Lore, X-EPIC]
* Optimize more xor trees (#4071). [Yutetsu TAKATSUKASA]
* Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras]
* Change ZERODLY to a warning.
* Fix random internal crashes (#666). [Dag Lem]
* Fix install, standardization in cmake CMakeLists.txt (#3974). [Yu-Sheng Lin]
* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker]
* Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński]
* Fix event controls reusing same variable (#4014). Kamil Rakoczy <[email protected]>
* Fix push to dynamic queue in struct (#4015). [ezchi]
* Fix names for blocks in do..while loop (#4019). [Ryszard Rozak, Antmicro Ltd]
* Fix randomize on null field (#4023). [Ryszard Rozak, Antmicro Ltd]
* Fix rand fields in base classes (#4025). [Ryszard Rozak, Antmicro Ltd]
* Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt]
* Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan]
* Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube]
* Fix characters from DEFENV literals for Conda (#4035) (#4044). [Tim Snyder]
* Fix info message prints under --assert (#4036) (#4053). [Srinivasan Venkataramanan]
* Fix C++ compile errors when passing class refs as task argument (#4063). [Krzysztof Bieganski, Antmicro Ltd]
* Fix NBAs inside fork-joins (#4050). [Aleksander Kiryk, Antmicro Ltd]
* Fix task calls as fork statements (#4055). [Krzysztof Bieganski, Antmicro Ltd]
* Fix _Vilp used before declaration (#4057) (#4062). [Josep Sans]
* Fix incorrect optimization of bit op tree (#4059) (#4070). [Yutetsu TAKATSUKASA]
* Fix parameters in a class body to be localparam (#4061). [Ryszard Rozak, Antmicro Ltd]
* Fix interface generate begin (#4065). [Srinivasan Venkataramanan]
* Fix tracing with awaits at end of block (#4075) (#4076). [Krzysztof Bieganski, Antmicro Ltd]
* Fix sense expression variable naming (#4081). [Kamil Rakoczy]
* Fix importing symbols from base class (#4084). [Ryszard Rozak, Antmicro Ltd]
* Fix false error on new const assignment (#4098). [Tudor Timi]
* Fix unpacked structs under classes (#4102). [Tudor Timi]
* Fix variables in class methods to be automatic (#4111) (#4137). [Peter Monsson]
* Fix to use parallel build for projects with a lot of files (#4116). [Krzysztof Boroński]
* Fix including __Syms header in generated C++ files (#4123). [Krzysztof Boroński]
* Fix systemc namespace issues (#4126) (#4127). [Eyck Jentzsch]
* Fix class param extends A=B (#4128). [Ryszard Rozak, Antmicro Ltd]
* Fix missing begin block hierarchy in --xml-only cells section (#4129) (#4133). [Risto Pejašinović]
* Fix resolution of class lvalues after parameterization (#4131). [Krzysztof Boroński]
* Fix DFG error on $countbits (#4101) (#4143). [Paul Donahue]
* Fix duplicating parameter class types (#4115). [Ryszard Rozak, Antmicro Ltd]
* Fix class extend param references (#4136). [Ryszard Rozak, Antmicro Ltd]
* Fix -CFLAGS to allow overriding optimization levels (#4140). [Peter Monsson]
* Fix DPI function type alias (#4148) (#4149). [Toru Niina]
* Fix deleting unused parameterized classes (#4150). [Ryszard Rozak, Antmicro Ltd]
* Fix false ENUMVALUE on expressions and arrays.
* Fix unnecessary verilated_std.sv waivers in --waiver-output.
Verilator 5.008 2023-03-04
==========================
**Minor:**
* Add --annotate-points option, change multipoint on line reporting (#3876). [Nassim Corteggiani]
* Add --verilate-jobs option (#3889). [Kamil Rakoczy, Antmicro Ltd]
* Add WIDTHEXPAND and WIDTHTRUNC warnings to replace WIDTH (#3900). [Andrew Nolte]
* Add SOURCE_DATE_EPOCH for docs/guide/conf.py (#3918). [Larry Doolittle]
* Add /*verilator public[flat|flat_rd|flat_rw| ]*/ metacomments (#3894). [Joseph Nwabueze]
* Add lint warning on always_comb multidriven (#3888) (#3939). [Adam Bagley]
* Add warning on ++/-- over expressions with potential side effects (#3976). [Krzysztof Boroński]
* Add error on mixing .name and by-port instantiations.
* Removed deprecated --cdc option.
* Support unpacked unions.
* Support interface classes and class implements.
* Support global clocking and $global_clock.
* Support class parameters without initial values.
* Support cast to numbers from strings.
* Support struct I/O in --lib-create (#3378) (#3892). [Varun Koyyalagunta]
* Support function calls without parenthesis (#3903) (#3902). [Ryszard Rozak, Antmicro Ltd]
* Support class extending its parameter (#3904). [Ryszard Rozak, Antmicro Ltd]
* Support static function variables (#3830). [Ryszard Rozak, Antmicro Ltd]
* Support recursive methods (#3987). [Ryszard Rozak, Antmicro Ltd]
* Fix real parameters of infinity and NaN.
* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal]
* Fix single-element replication to dynarray/unpacked/queue (#3548). [Gustav Svensk]
* Fix constant enum methods (#3621). [Todd Strader]
* Fix inconsistent naming of generate scope arrays (#3840). [Andrew Nolte]
* Fix namespace fallback resolution (#3863) (#3942). [Aleksander Kiryk, Antmicro Ltd]
* Fix std:: to be parsed first (#3864) (#3928). [Aleksander Kiryk, Antmicro Ltd]
* Fix cmake warning if multiple SOURCES w/o PREFIX (#3916) (#3927). [Yoda Lee]
* Fix parameterized class function linkage (#3917). [Ryszard Rozak]
* Fix static members of type aliases of a parameterized class (#3922). [Ryszard Rozak, Antmicro Ltd]
* Fix class extend parameter dot case (#3926). [Ryszard Rozak, Antmicro Ltd]
* Fix MsWin missing directory exception, and ::std (#3928) (#3933) (#3935). [Kritik Bhimani]
* Fix very long VPI signal names (#3929). [Marlon James]
* Fix VPI upper interface scopes not found (#3937). [David Stanford]
* Fix virus detection false positive (#3944). [Stuart Morris]
* Fix constant string function assignment (#3945). [Todd Strader]
* Fix constant format field widths (#3946). [Todd Strader]
* Fix class field linking when a super classes is a param (#3949). [Ryszard Rozak, Antmicro Ltd]
* Fix CMake bad C identifiers (#3948) (#3951). [Zixi Li]
* Fix build on HP PA architecture (#3954). [John David Anglin]
* Fix date on the front page of verilator.pdf (#3956) (#3957). [Larry Doolittle]
* Fix associative arrays declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd]
* Fix missing error on negative replicate (#3963). [Benjamin Menküc]
* Fix self references to parameterized classes (#3962). [Ryszard Rozak, Antmicro Ltd]
* Fix LITENDIAN warning is backwards (#3966) (#3967). [Cameron Kirk]
* Fix subsequent parameter declarations (#3969). [Ryszard Rozak, Antmicro Ltd]
* Fix timing delays to not truncate below 64 bits (#3973) (#3982). [Felix Neumärker]
* Fix cmake on MacOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker]
* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker]
* Fix coverage of class methods (#3998). [Tim Paine]
* Fix packed array structure replication.
* Fix enum.next(0) and enum.prev(0).
Verilator 5.006 2023-01-22
==========================
**Minor:**
@@ -20,7 +144,8 @@ Verilator 5.006 2022-01-22
* Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd]
* Support import/export lists in modport (#3886). [Gökçe Aydos]
* Support class queue equality (#3895). [Ilya Barkov]
* Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
* Support type case and type equality comparisons.
* Add IMPLICITSTATIC warning when a task/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
* Add VL_VALUE_STRING_MAX_WORDS override (#3869). [Andrew Nolte]
* Optimize expansion of extend operators.
* Internal multithreading tests. [Mariusz Glebocki, et al, Antmicro Ltd]
@@ -34,7 +159,7 @@ Verilator 5.006 2022-01-22
* Fix self references when param class instantiated (#3833). [Ryszard Rozak, Antmicro Ltd]
* Fix memory leak in V3Sched, etc. (#3834). [Geza Lore]
* Fix compatibility with musl libc / Alpine Linux (#3845). [Sören Tempel]
* Fix empty case items crash (#3851). [rporter]
* Fix empty case items crash (#3851). [Rich Porter]
* Fix VL_CPU_RELAX on MIPS/Armel/s390/sparc (#3843) (#3891). [Kamil Rakoczy]
* Fix module parameter name collision (#3854) (#3855). [James Shi]
* Fix unpacked array expansion (#3861). [Joey Liu]
@@ -44,6 +169,8 @@ Verilator 5.006 2022-01-22
* Fix foreach unnamedblk duplicate error (#3885). [Ilya Barkov]
* Fix elaboration of member selected classes (#3890). [Ilya Barkov]
* Fix mismatched widths in DFG (#3872). [Geza Lore, Yike Zhou]
* Fix lint for non-integral types in packed structs.
* Fix generate case with empty body statements.
Verilator 5.004 2022-12-14
+7 -7
View File
@@ -15,13 +15,13 @@
#
#****************************************************************************/
#
# make all to compile and build Verilator.
# make install to install it.
# make TAGS to update tags tables.
# make all to compile and build Verilator.
# make install to install it.
# make TAGS to update tags tables.
#
# make clean or make mostlyclean
# Delete all files from the current directory that are normally
# created by building the program. Don't delete the files that
# created by building the program. Don't delete the files that
# record the configuration. Also preserve files that could be made
# by building, but normally aren't because the distribution comes
# with them.
@@ -153,7 +153,7 @@ msg_test: all_nomsg
@echo
.PHONY: test
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
test: smoke-test test_regress
# examples is part of test_regress's test_regress/t/t_a2_examples.pl
# (because that allows it to run in parallel with other test_regress's)
@@ -462,7 +462,7 @@ config.status: configure
./config.status --recheck
configure: configure.ac
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
autoconf --warnings=all
else
autoconf
@@ -501,7 +501,7 @@ distclean maintainer-clean::
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
${srcdir}/*.in ${srcdir}/*.pod
TAGS: $(TAGFILES)
TAGS: $(TAGFILES)
etags $(TAGFILES)
.PHONY: doxygen
+4 -1
View File
@@ -362,7 +362,7 @@ detailed descriptions of these arguments.
+incdir+<dir> Directory to search for includes
--inline-mult <value> Tune module inlining
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
-j <jobs> Parallelism for --build (alias to --build-jobs)
-j <jobs> Parallelism for --build-jobs/--verilate-jobs
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
-LDFLAGS <flags> Linker pre-object arguments for makefile
@@ -404,6 +404,7 @@ detailed descriptions of these arguments.
--protect-key <key> Key for symbol protection
--protect-lib <name> Create a DPI protected library
--public Debugging; see docs
--public-params Mark all parameters as public_flat
--public-flat-rw Mark all variables, etc as public_flat_rw
-pvalue+<name>=<value> Overwrite toplevel parameter
--quiet-exit Don't print the command on failure
@@ -416,6 +417,7 @@ detailed descriptions of these arguments.
--no-skip-identical Disable skipping identical output
--stats Create statistics file
--stats-vars Provide statistics on variables
--no-std Prevent parsing standard library
--structs-packed Convert all unpacked structures to packed structures
-sv Enable SystemVerilog parsing
+systemverilogext+<ext> Synonym for +1800-2017ext+<ext>
@@ -445,6 +447,7 @@ detailed descriptions of these arguments.
--unused-regexp <regexp> Tune UNUSED lint signals
-V Verbose version and config
-v <filename> Verilog library
--verilate-jobs Job threads for Verilation stage
--no-verilate Skip Verilation and just compile previously Verilated code
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
+1
View File
@@ -169,6 +169,7 @@ L<https://verilator.org/guide/latest/exe_verilator_coverage.html>.
--annotate <output_dir> Directory name for source annotation.
--annotate-all All files should be shown.
--annotate-min <count> Minimum occurrence count for uncovered.
--annotate-points Annotates info from each coverage point.
--help Displays this message and version and exits.
--rank Compute relative importance of tests.
--unlink With --write, unlink all inputs
+2 -2
View File
@@ -42,8 +42,8 @@ def diff_dir(a, b):
continue
a = files[base]['a']
b = files[base]['b']
print("=" * 70)
print("= %s <-> %s" % (a, b))
print("=" * 70, flush=True)
print("= %s <-> %s" % (a, b), flush=True)
diff_file(a, b)
anyfile = True
if not anyfile:
+2 -2
View File
@@ -4,12 +4,12 @@ if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
mkdir build
cd build
cmake .. --install-prefix $PWD/../../../.ccache
cmake --build . --config Release
cmake --build . --config Release -j 3
cmake --install . --prefix $PWD/../../../.ccache
cd ../..
}
mkdir build
cd build
cmake .. --install-prefix $PWD/../install
cmake --build . --config Release
cmake --build . --config Release -j 3
cmake --install . --prefix $PWD/../install
+1 -1
View File
@@ -4,7 +4,7 @@ cd examples/cmake_tracing_c
mkdir build
cd build
cmake ..
cmake --build . --config Release
cmake --build . --config Release -j 3
Release/example.exe
cd ..
Remove-Item -path build -recurse
+3 -3
View File
@@ -5,12 +5,12 @@
# 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 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.006 2023-01-22],
AC_INIT([Verilator],[5.010 2023-04-30],
[https://verilator.org],
[verilator],[https://verilator.org])
@@ -68,7 +68,7 @@ AC_MSG_CHECKING(whether to use -m32)
AC_ARG_ENABLE([m32],
[AS_HELP_STRING([--enable-m32],
[Use -m32 for all compilation and link,
including Verialtor and generated models.])],
including Verilator and generated models.])],
[case "${enableval}" in
yes) CFG_ENABLE_M32=yes ;;
no) CFG_ENABLE_M32=no ;;
+21 -14
View File
@@ -10,9 +10,12 @@ contributions flow more efficiently.
Did you find a bug?
-------------------
- Please **Ensure the bug was not already reported** by searching
- Please **ensure the bug was not already reported** by searching
`Verilator Issues <https://verilator.org/issues>`__.
- Please **download the latest development GitHub version**, build, and see
if the issue has been fixed.
- If you're unable to find an open issue addressing the problem, `open a
new Verilator issue <https://verilator.org/issues/new>`__.
@@ -20,21 +23,28 @@ Did you find a bug?
demonstrating the bug and expected behavior that is not occurring.
- The ideal example works against other simulators, and is in the
test_regress/t test format, as described in `docs/internals
<internals.rst>`__.
test_regress/t test format, as described in
`Verilator Internals Documentation
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
Did you write a patch that fixes a bug?
---------------------------------------
- Please `Open a new issue <https://verilator.org/issues/new>`__.
- Please `Open a new Verilator issue <https://verilator.org/issues/new>`__
if there is not one already describing the bug.
- You may attach a patch to the issue, or (preferred) may request a
GitHub pull request.
- Please `Open a Verilator pull request
<https://github.com/verilator/verilator/pulls>`__.
- Verilator uses GitHub Actions to provide continuous integration. You
may want to enable Actions on your GitHub branch to ensure your changes
keep the tests passing. See `docs/internals <internals.rst>`__.
- See the coding conventions, and other developer information in
``docs/internals.rst`` in the distribution, or as rendered at
`Verilator Internals Documentation
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
- Verilator uses GitHub Actions to provide continuous integration. You
may want to enable Actions on your GitHub branch to ensure your changes
keep the tests passing.
- Your source-code contributions must be certified as open source,
under the `Developer Certificate of
@@ -56,13 +66,10 @@ Did you write a patch that fixes a bug?
contribution.
- Your test contributions are generally considered released into the
Creative Commons Public Domain (CC0), unless you request otherwise or
Creative Commons Public Domain (CC0), unless you request otherwise, or
put a GNU/Artistic license on your file.
- Most important is we get your patch. If you'd like to clean up
indentation and related issues ahead of our feedback, that is
appreciated; please see the coding conventions in `docs/internals
<internals.rst>`__.
- Most important is we get your patch.
Do you have questions?
+14
View File
@@ -3,6 +3,7 @@ under the Developer Certificate of Origin (https://developercertificate.org/).
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
Adam Bagley
Adrien Le Masle
Ahmed El-Mahmoudy
Aleksander Kiryk
@@ -13,6 +14,7 @@ Ameya Vikram Singh
Andreas Kuster
Andrew Nolte
Arkadiusz Kozdra
Cameron Kirk
Chris Randall
Chuxuan Wang
Conor McCullough
@@ -27,7 +29,9 @@ Drew Taussig
Driss Hafdi
Edgar E. Iglesias
Eric Rippey
Eyck Jentzsch
Fan Shupei
Felix Neumärker
Felix Yan
Garrett Smith
Geza Lore
@@ -58,6 +62,7 @@ Jamie Iles
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
Jesse Taube
Jevin Sweval
Jiacheng Qian
Jiuyang Liu
@@ -65,6 +70,8 @@ Joey Liu
John Coiner
John Demme
Jonathan Drolet
Joseph Nwabueze
Josep Sans
Josh Redford
Julie Schwartz
Julien Margetts
@@ -75,6 +82,7 @@ Keith Colbert
Kevin Kiningham
Kritik Bhimani
Krzysztof Bieganski
Krzysztof Boroński
Kuba Ober
Larry Doolittle
Ludwig Rogiers
@@ -103,6 +111,7 @@ Nathan Myers
Patrick Stewart
Paul Wright
Pawel Sagan
Peter Debacker
Peter Horvath
Peter Monsson
Philipp Wagner
@@ -113,12 +122,15 @@ Qingyao Sun
Rafal Kapuscik
Raynard Qiao
Richard Myers
Risto Pejašinović
Robert Balas
Rupert Swarbrick
Ryszard Rozak
Samuel Riedel
Sean Cross
Sebastien Van Cauwenberghe
Sergi Granell
Srinivasan Venkataramanan
Stefan Wallentowitz
Stephen Henry
Steven Hugg
@@ -130,6 +142,7 @@ Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Topa Topino
Toru Niina
Tymoteusz Blazejczyk
Udi Finkelstein
Unai Martinez-Corral
@@ -148,3 +161,4 @@ Yutetsu TAKATSUKASA
Yu-Sheng Lin
Yves Mathieu
Zhanglei Wang
Zixi Li
@@ -1,4 +1,4 @@
.. comment: generated by t_lint_width_docs_bad
.. comment: generated by t_lint_widthexpand_docs_bad
.. code-block:: sv
:linenos:
:emphasize-lines: 3
@@ -1,4 +1,4 @@
.. comment: generated by t_lint_width_docs_bad
.. comment: generated by t_lint_widthexpand_docs_bad
.. code-block:: sv
:emphasize-lines: 1
+4
View File
@@ -0,0 +1,4 @@
.. comment: generated by t_lint_widthexpand_docs_bad
.. code-block::
%Warning-WIDTHEXPAND: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
-4
View File
@@ -1,4 +0,0 @@
.. comment: generated by t_lint_width_docs_bad
.. code-block::
%Warning-WIDTH: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
+13 -9
View File
@@ -10,7 +10,6 @@
# ----------------------------------------------------------------------
# -- Path setup
from datetime import datetime
import os
import re
import sys
@@ -24,10 +23,18 @@ def get_vlt_version():
filename = "../../Makefile"
with open(filename, "r", encoding="utf8") as fh:
for line in fh:
match = re.search(r"PACKAGE_VERSION_NUMBER *= *([a-z0-9.]+)", line)
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)",
line)
if match:
return match.group(1)
return "unknown"
return match.group(1), match.group(2)
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line)
if match:
try:
data = os.popen('git log -n 1 --pretty=%cs').read()
except Exception:
data = "" # fallback, and Sphinx will fill in today's date
return "Devel " + match.group(1), data
return "unknown", "unknown"
def setup(app):
@@ -44,8 +51,8 @@ author = 'Wilson Snyder'
# The master toctree document.
master_doc = "index"
version = get_vlt_version()
release = get_vlt_version()
version, today_fmt = get_vlt_version()
release = version
rst_prolog = """
.. role:: vlopt(option)
@@ -89,9 +96,6 @@ source_suffix = [".rst"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# Date format to ISO
today_fmt = datetime.now().strftime("%F")
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
+23 -9
View File
@@ -120,6 +120,15 @@ code. This is a feature, as using the SystemC pin interconnect scheme
everywhere would reduce performance by an order of magnitude.
Verilated API
=============
The API to a Verilated model is the C++ headers in the include/ directory
in the distribution. These headers use Doxygen comments, `///` and `//<`,
to indicate and document those functions that are part of the Verilated
public API.
Direct Programming Interface (DPI)
==================================
@@ -374,9 +383,11 @@ changed on the specified clock edge.
.. code-block:: bash
cat >our.v <<'EOF'
module our (input clk);
reg readme /*verilator public_flat_rd*/;
reg writeme /*verilator public_flat_rw @(posedge clk) */;
module our #(
parameter WIDTH /*verilator public_flat_rd*/ = 32
) (input clk);
reg [WIDTH-1:0] readme /*verilator public_flat_rd*/;
reg [WIDTH-1:0] writeme /*verilator public_flat_rw @(posedge clk) */;
initial $finish;
endmodule
EOF
@@ -398,12 +409,14 @@ accesses the above signal "readme" would be:
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
if (!vh1) vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found");
const char* name = vpi_get_str(vpiName, vh1);
printf("Module name: %s\n", name); // Prints "readme"
const char* type = vpi_get_str(vpiType, vh1);
const int size = vpi_get(vpiSize, vh1);
printf("register name: %s, type: %s, size: %d\n", name, type, size); // Prints "register name: readme, type: vpiReg, size: 32"
s_vpi_value v;
v.format = vpiIntVal;
vpi_get_value(vh1, &v);
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
printf("Value of %s: %d\n", name, v.value.integer); // Prints "Value of readme: 0"
}
int main(int argc, char** argv) {
@@ -479,11 +492,12 @@ distribution.
Verilated and VerilatedContext
==============================
Multiple Verilated models may be part of the same simulation context, that
is share a VPI interface, sense of time, and common settings. This common
simulation context information is stored in a ``VerilatedContext``
Multiple C++ Verilated models may be part of the same simulation context,
that is share a VPI interface, sense of time, and common settings. This
common simulation context information is stored in a ``VerilatedContext``
structure. If a ``VerilatedContext`` is not created prior to creating a
model, a default global one is created automatically.
model, a default global one is created automatically. SystemC requires
using only the single, default VerilatedContext.
The ``Verilated::`` methods, including the ``Verilated::commandArgs`` call
shown above, call VerilatedContext methods using the default global
-4
View File
@@ -22,10 +22,6 @@ Verilated_heavy.h
"verilated.h". Verilated_heavy.h is planned for removal no sooner than
July 2022.
Option `--cdc`
The experimental `--cdc` option is believed to be generally unused and is
planned for removal no sooner than January 2023.
Option `-O<letter>`
The debug `-O<letter>` options have been replaced with
`-fno-<optimization>` debug options to match GCC. The old options are
+36 -20
View File
@@ -155,18 +155,6 @@ Summary:
Specify C++ without SystemC output mode; see also the :vlopt:`--sc`
option.
.. option:: --cdc
Permanently experimental. Perform some clock domain crossing checks and
issue related warnings (CDCRSTLOGIC) and then exit; if warnings other
than CDC warnings are needed, make a second run with
:vlopt:`--lint-only`. Additional warning information is also written to
the file :file:`<prefix>__cdc.txt`.
Currently only checks some items that other CDC tools missed; if you are
interested in adding more traditional CDC checks, please contact the
authors.
.. option:: -CFLAGS <flags>
Add specified C compiler argument to the generated makefiles. For
@@ -434,7 +422,7 @@ Summary:
Preprocess the source code, but do not compile, similar to C++
preprocessing using :command:`gcc -E`. Output is written to standard
out. Beware of enabling debugging messages, as they will also go to
standard out.
standard out. See :vlopt:`--no-std`, which is implied by this.
See also :vlopt:`--dump-defines`, :vlopt:`-P`, and
:vlopt:`--pp-comments` options.
@@ -707,9 +695,10 @@ Summary:
.. option:: -j [<value>]
Specify the level of parallelism for :vlopt:`--build` if
:vlopt:`--build-jobs` isn't provided. If zero, uses the number of threads
in the current hardware. Otherwise, the <value> must be a positive
integer specifying the maximum number of parallel build jobs.
:vlopt:`--build-jobs` isn't provided, and the internal compilation steps
of Verilator if :vlopt:`--verilate-jobs` isn't provided. If zero, uses
the number of threads in the current hardware. Otherwise, must be a
positive integer specifying the maximum number of parallel build jobs.
.. option:: --l2-name <value>
@@ -1112,6 +1101,18 @@ Summary:
marking only those signals that need public_flat_rw is typically
significantly better performing.
.. option:: --public-depth <level>
Enables public as with :vlopt:`--public-flat-rw`, but only to the specified depth of modules.
It operates at the module maximum level, so if a module's cells are A.B.X and A.X, the
a --public-depth 3 must be used to make module X public, and both A.B.X and A.X will be public.
.. option:: --public-params
Declares all parameters public as if they had
:code:`/*verilator public_flat_rd*/`
metacomments.
.. option:: -pvalue+<name>=<value>
Overwrites the given parameter(s) of the top-level module. See
@@ -1201,6 +1202,10 @@ Summary:
by size (plain :vlopt:`--stats` just gives a count). See
:vlopt:`--stats`, which is implied by this.
.. option:: --no-std
Prevents parsing standard library.
.. option:: --structs-packed
Converts all unpacked structures to packed structures, and issues an
@@ -1429,6 +1434,15 @@ Summary:
execute only the build. This can be useful for rebuilding the Verilated code
produced by a previous invocation of Verilator.
.. option:: --verilate-jobs [<value>]
Specify the level of parallelism for the internal compilation steps of
Verilator. If zero, uses the number of threads in the current hardware.
Otherwise, must be a positive integer specifying the maximum number of
parallel build jobs.
See also :vlopt:`-j`.
.. option:: +verilog1995ext+<ext>
Synonym for :vlopt:`+1364-1995ext+\<ext\>`.
@@ -1500,10 +1514,10 @@ Summary:
.. option:: -Wno-lint
Disable all lint-related warning messages, and all style warnings. This is
equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE
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-LITENDIAN -Wno-PINCONNECTEMPTY
-Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
-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.
@@ -1528,6 +1542,8 @@ Summary:
:command:`gcc -Wpedantic`. Rarely used, and intended only for strict
compliance tests.
This option changes :option:`ASSIGNIN` from an error to a warning.
.. option:: -Wwarn-<message>
Enables the specified warning message.
@@ -1538,7 +1554,7 @@ Summary:
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-LITENDIAN
-Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-ASCRANGE
-Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``.
.. option:: -Wwarn-style
+23 -4
View File
@@ -6,10 +6,10 @@ verilator_coverage
Verilator_coverage processes Verilated model-generated coverage reports.
With --annotate, it reads the specified coverage data file and generates
annotated source code with coverage metrics annotated. If multiple
coverage points exist on the same source code line, additional lines will
be inserted to report the additional points.
With `--annotate`, it reads the specified coverage data file and generates
annotated source code with coverage metrics annotated. With
`--annotate-points` the coverage points corresponding to each line are also
shown.
Additional Verilog-XL-style standard arguments specify the search paths
necessary to find the source code on which the coverage analysis was
@@ -58,6 +58,18 @@ to read multiple inputs. If no data file is specified, by default,
Specifies the directory name to which source files with annotated coverage
data should be written.
Converting from the Verilator coverage data format to the info format is
lossy; the info will have all forms of coverage merged line coverage, and
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.
.. option:: --annotate-all
Specifies all files should be shown. By default, only those source files
@@ -70,6 +82,13 @@ 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.
.. 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.
.. option:: --help
Displays a help summary, the program version, and exits.
+27
View File
@@ -446,6 +446,33 @@ or "`ifdef`"'s may break other tools.
Same as :option:`public_flat_rw` configuration file option.
.. option:: /*verilator&32;public_[|flat|flat_rd|flat_rw]_on [@(<edge_list>)]*/ (as scope)
Used to wrap multiple signals and parameters with the respective public attribute.
See attribute above for their respective behavior. Cannot be nested. e.g:
.. code-block:: sv
/*verilator public_flat_rw_on*/
logic clk;
logic rst;
parameter width = 8;
/* verilator public_off*/
logic data;
Is equivalent to:
.. code-block:: sv
logic clk /*verilator public_flat_rw*/;
logic rst /*verilator public_flat_rw*/;
parameter width /*verilator public_flat_rw*/ = 8;
logic data;
.. option:: /*verilator&32;public_off*/
Terminates the previous `/*verilator public*_on*/` directive; see above.
.. option:: /*verilator&32;public_module*/
Used after a module statement to indicate the module should not be
+4
View File
@@ -461,6 +461,10 @@ chandle
Treated as a "longint"; does not yet warn about operations specified as
illegal on chandles.
checker
Treated as a "module"; does not yet warn about many constructs illegal
inside a checker.
disable
Disable statements may be used only if the block being disabled is a
block the disable statement itself is inside. This was commonly used to
+17
View File
@@ -498,3 +498,20 @@ Clang. The process in GCC 10 was as follows:
Clang and GCC also support -fauto-profile, which uses sample-based
feedback-directed optimization. See the appropriate compiler
documentation.
.. _Runtime Debugging
Runtime Debugging
=================
To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a
similar tool. Typically you will want to have debugger symbols inserted by
the compiler, assertions enabled in the C library, and assertions enabled
in the Verilated library. (These options slow down the executable, so do
this only when debugging.) To enable this, Verilate with:
-CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG
The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options pass arguments
directly to the compiler or linker.
+66 -21
View File
@@ -74,7 +74,8 @@ List Of Warnings
.. option:: Unsupported: ....
This error indicates that the code uses a Verilog language construct
that is not yet supported in Verilator. See the Limitations chapter.
that is not yet supported in Verilator. See also :ref:`Language
Limitations`.
.. option:: ALWCOMBORDER
@@ -96,6 +97,24 @@ List Of Warnings
simulate correctly.
.. option:: ASCRANGE
.. TODO better example
Warns that a packed vector is declared with ascending bit range
(i.e. [0:7]). Descending bit range is now the overwhelming standard,
and ascending ranges are now thus often due to simple oversight
instead of intent (a notable exception is the OpenPOWER code base).
It also warns that an instance is declared with ascending range
(i.e. [0:7] or [7]) and is connected to an N-wide signal.
The bits will likely be in the reversed order from what people may expect
(i.e., instance [0] will connect to signal bit [N-1] not bit [0]).
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: ASSIGNDLY
.. TODO better example
@@ -317,9 +336,11 @@ List Of Warnings
.. option:: CDCRSTLOGIC
With :vlopt:`--cdc` only, it warns that asynchronous flop reset terms come
from other than primary inputs or flopped outputs, creating the
potential for reset glitches.
Historical, never issued since version 5.008.
Warned with a no longer supported clock domain crossing option that
asynchronous flop reset terms came from other than primary inputs or
flopped outputs, creating the potential for reset glitches.
.. option:: CLKDATA
@@ -375,6 +396,16 @@ List Of Warnings
simulators.
.. option:: CONSTRAINTIGN
Warns that Verilator does not support :code:`constraint`,
:code:`constraint_mode`, or :code:`rand_mode`, and the construct was are
ignored.
Ignoring this warning may make Verilator randomize() simulations differ
from other simulators.
.. option:: CONTASSREG
.. TODO better example
@@ -735,7 +766,7 @@ List Of Warnings
This is a warning because the static default differs from C++, differs
from class member function/tasks. Static is a more dangerous default
then automatic as static prevents the function from being reinterant,
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
@@ -847,18 +878,10 @@ List Of Warnings
.. TODO better example
Warns that a packed vector is declared with little endian bit numbering
(i.e. [0:7]). Big endian bit numbering is now the overwhelming
standard, and little numbering is now thus often due to simple oversight
instead of intent.
It also warns that an instance is declared with little endian range
(i.e. [0:7] or [7]) and is connected to an N-wide signal. Based on IEEE
the bits will likely be backward from what people may expect
(i.e., instance [0] will connect to signal bit [N-1] not bit [0]).
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
The naming of this warning is in contradiction with the common
interpretation of little endian. It was therefore renamed to
:option:`ASCRANGE`. While :option:`LITENDIAN` remains for
backwards compatibility, new projects should use :option:`ASCRANGE`.
.. option:: MINTYPMAX
@@ -1299,6 +1322,17 @@ List Of Warnings
* The variable is tristate or bidirectional. (e.g., :code:`inout`).
.. option:: STATICVAR
Warns that a static variable declared in a loop with declaration assignment
was converted to automatic. Often such variables were intended to
instead be declared "automatic".
Ignoring this warning may make Verilator differ from other simulators,
which will treat the variable as static. Verilator may in future versions also
treat the variable as static.
.. option:: STMTDLY
Warns that the code has a statement with a delayed time in front of it.
@@ -1790,16 +1824,27 @@ List Of Warnings
For example, this is a missized index:
.. include:: ../../docs/gen/ex_WIDTH_1_faulty.rst
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_faulty.rst
Results in:
Results in a WIDTHEXPAND warning:
.. include:: ../../docs/gen/ex_WIDTH_1_msg.rst
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_msg.rst
One possible fix:
.. include:: ../../docs/gen/ex_WIDTH_1_fixed.rst
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst
.. option:: WIDTHTRUNC
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
.. option:: WIDTHXZEXPAND
A more granular WIDTH warning, for when a value is X/Z expanded
.. option:: WIDTHCONCAT
+6 -14
View File
@@ -628,16 +628,12 @@ coroutines ``co_await`` its ``join`` function, and forked ones call ``done``
when they're finished. Once the required number of coroutines (set using
``setCounter``) finish execution, the forking coroutine is resumed.
Awaitable Utilities
~~~~~~~~~~~~~~~~~~~
``VlForever``
~~~~~~~~~~~~~
There are also two small utility awaitable types:
* ``VlNow`` is an awaitable that suspends and immediately resumes coroutines.
It is used for forcing a coroutine to be moved onto the heap. See the `Forks`
section for more detail.
* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass`
section for more detail.
A small utility awaitable type. It allows for blocking a coroutine forever. It
is currently only used for ``wait`` statements that await a constant false
condition. See the `Timing Pass` section for more details.
Timing Pass
~~~~~~~~~~~
@@ -749,9 +745,7 @@ doesn't suspend the forking process.
In forked processes, references to local variables are only allowed in
``fork..join``, as this is the only case that ensures the lifetime of these
locals are at least as long as the execution of the forked processes. This is
where ``VlNow`` is used, to ensure the locals are moved to the heap before they
are passed by reference to the forked processes.
locals are at least as long as the execution of the forked processes.
Multithreaded Mode
@@ -1807,8 +1801,6 @@ IEEE 1800-2017 6.12 "shortreal"
Little/no tool support, and easily promoted to real.
IEEE 1800-2017 11.11 Min, typ, max
No SDF support, so will always use typical.
IEEE 1800-2017 11.12 "let"
Little/no tool support, makes it difficult to implement parsers.
IEEE 1800-2017 20.16 Stochastic analysis
Little industry use.
IEEE 1800-2017 20.17 PLA modeling
+28 -1
View File
@@ -6,6 +6,7 @@ Alexandre
Ami
Amir
Anastasiadis
Anglin
Anikin
Antmicro
Antonin
@@ -42,6 +43,8 @@ Chandan
Chitlesh
Christophe
Cochrane
Conda
Corteggiani
Cuan
Cygwin
DErrico
@@ -96,6 +99,7 @@ Fredieu
GTKWave
Galbi
Gantt
Garnal
Gartner
Gelinek
Geoff
@@ -188,6 +192,7 @@ Laurens
Lavino
Leber
Leendert
Lem
Lesik
Liland
Liu
@@ -207,6 +212,7 @@ Matveyenko
Maupin
Mdir
Mednick
Menküc
Michiels
Microsystems
Milanovic
@@ -223,8 +229,10 @@ Muhlestein
Multithreaded
Multithreading
NOUNOPTFLAT
NaN
Nalbantis
Narayan
Nassim
Nauticus
Newgard
Nigam
@@ -295,6 +303,7 @@ Solomatnikov
Solt
Southwell
Srini
Srinivasan
Stamness
Stephane
Stoddard
@@ -319,6 +328,7 @@ Thiede
Thierry
Thyer
Tichelaar
Timi
Tomov
Tood
Topa
@@ -343,6 +353,7 @@ Vdeeptemp
Vdly
Vemumtab
Vemuri
Venkataramanan
Veriable
Verialted
Verilate
@@ -353,6 +364,7 @@ Verilator
Verilog
Vighnesh
Viktor
Vilp
Vm
Vukobratovic
Wai
@@ -376,6 +388,7 @@ Xuan
Xuanqi
Yazdanbakhsh
Yi
Yike
Yinan
Yosys
Yu
@@ -452,6 +465,7 @@ commandArgsPlusMatch
compilable
concat
concats
conf
config
const
constexpr
@@ -512,6 +526,7 @@ dumpportson
dumpvars
dut
dx
dynarray
elab
elike
elsif
@@ -520,6 +535,7 @@ endcelldefine
endfunction
endgenerate
endian
endianness
endif
endmodule
endprotect
@@ -541,6 +557,7 @@ exe
executables
expr
extern
ezchi
fanin
fasttrace
fauto
@@ -635,6 +652,7 @@ lcov
ld
leavinel
len
libc
libext
libgoogle
libsystemc
@@ -653,7 +671,9 @@ logicals
longint
lossy
lsb
lubc
lvalue
lvalues
lxt
macromodule
makefile
@@ -678,12 +698,15 @@ mtasks
mulithreaded
mult
multidim
multidriven
multiinterfaces
multiline
multipling
multipoint
multithread
multithreaded
multithreading
musl
mutexes
mux
myftptoyman
@@ -714,6 +737,7 @@ ortegon
oversubscription
parallelized
param
parameterization
parameterized
params
parens
@@ -762,6 +786,7 @@ pulldowns
pullup
pvalue
pwd
py
qrq
radix
randc
@@ -807,6 +832,7 @@ specparam
splitme
spp
sqrt
srandom
src
srcdir
srcfile
@@ -838,6 +864,7 @@ svdpi
swrite
sys
systemc
tenghtt
testbench
threadsafe
threashold
@@ -909,6 +936,7 @@ vlt
vltstd
vluint
vpi
vpiDefName
vpiLeftRange
vpiModule
vpiSize
@@ -938,4 +966,3 @@ ypq
yurivict
zdave
Øyvind
+2 -1
View File
@@ -19,7 +19,8 @@
# cmake ..
# cmake --build .
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0074 NEW)
project(cmake_hello_c)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
+2 -1
View File
@@ -19,7 +19,8 @@
# cmake ..
# cmake --build .
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0074 NEW)
project(cmake_hello_sc CXX)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
+2 -1
View File
@@ -19,7 +19,8 @@
# cmake ..
# cmake --build .
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0074 NEW)
project(cmake_protect_lib)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
+2 -1
View File
@@ -19,7 +19,8 @@
# cmake ..
# cmake --build .
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0074 NEW)
project(cmake_tracing_c)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
+3 -1
View File
@@ -19,7 +19,9 @@
# cmake ..
# cmake --build .
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0074 NEW)
project(cmake_tracing_sc_example CXX)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
+3 -1
View File
@@ -7,7 +7,7 @@
//======================================================================
// SystemC global header
#include <systemc.h>
#include <systemc>
// Include common routines
#include <verilated.h>
@@ -15,6 +15,8 @@
// Include model header, generated from Verilating "top.v"
#include "Vtop.h"
using namespace sc_core;
int sc_main(int argc, char* argv[]) {
// See a similar example walkthrough in the verilator manpage.
+1 -1
View File
@@ -31,7 +31,7 @@ CPPFLAGS += -DVL_DEBUG=1
# Turn on some more compiler lint flags (when configured appropriately)
# For testing inside Verilator, "configure --enable-ccwarn" will do this
# automatically; otherwise you may want this unconditionally enabled
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
USER_CPPFLAGS_WALL += -W -Werror -Wall
endif
+1 -1
View File
@@ -30,7 +30,7 @@ CPPFLAGS += -Wno-deprecated
# Turn on some more flags (when configured appropriately)
# For testing inside Verilator, "configure --enable-ccwarn" will do this
# automatically; otherwise you may want this unconditionally enabled
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
USER_CPPFLAGS_WALL += -W -Werror -Wall
endif
+3 -1
View File
@@ -10,7 +10,7 @@
#include <memory>
// SystemC global header
#include <systemc.h>
#include <systemc>
// Include common routines
#include <verilated.h>
@@ -23,6 +23,8 @@
// Include model header, generated from Verilating "top.v"
#include "Vtop.h"
using namespace sc_core;
int sc_main(int argc, char* argv[]) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
+42 -50
View File
@@ -58,6 +58,7 @@
#endif
#ifdef __MINGW32__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
@@ -131,7 +132,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
#define FST_GZIO_LEN (32768)
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) || defined(__aarch64__)
#define FST_DO_MISALIGNED_OPS
#endif
@@ -334,26 +335,22 @@ return(NULL);
/*
* mmap compatibility
*/
#if defined __CYGWIN__ || defined __MINGW32__
#if defined __MINGW32__
#include <limits.h>
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
#define fstMunmap(__addr,__len) free(__addr)
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
{
(void)__off;
HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL,
PAGE_READWRITE, (DWORD)(__len >> 32),
(DWORD)__len, NULL);
if (!handle) { return NULL; }
unsigned char *pnt = (unsigned char *)malloc(__len);
fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
size_t i;
lseek(__fd, 0, SEEK_SET);
for(i=0;i<__len;i+=SSIZE_MAX)
{
read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
}
lseek(__fd, cur_offs, SEEK_SET);
return(pnt);
void *ptr = MapViewOfFileEx(handle, FILE_MAP_READ | FILE_MAP_WRITE,
0, (DWORD)__off, (SIZE_T)__len, (LPVOID)NULL);
CloseHandle(handle);
return ptr;
}
#else
#include <sys/mman.h>
@@ -984,14 +981,26 @@ fflush(xc->handle);
*/
static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage)
{
#if !defined(__CYGWIN__) && !defined(__MINGW32__)
if(pnt == MAP_FAILED)
if(pnt == NULL
#ifdef MAP_FAILED
|| pnt == MAP_FAILED
#endif
)
{
fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
#if !defined(__MINGW32__)
perror("Why");
#else
LPSTR mbuf = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&mbuf, 0, NULL);
fprintf(stderr, "%s", mbuf);
LocalFree(mbuf);
#endif
pnt = NULL;
}
#endif
}
@@ -1037,34 +1046,11 @@ if(!xc->curval_mem)
static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
{
#if !defined __CYGWIN__ && !defined __MINGW32__
(void)is_closing;
#endif
fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
xc->valpos_mem = NULL;
#if defined __CYGWIN__ || defined __MINGW32__
if(xc->curval_mem)
{
if(!is_closing) /* need to flush out for next emulated mmap() read */
{
unsigned char *pnt = xc->curval_mem;
int __fd = fileno(xc->curval_handle);
fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
size_t i;
size_t __len = xc->maxvalpos;
lseek(__fd, 0, SEEK_SET);
for(i=0;i<__len;i+=SSIZE_MAX)
{
write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
}
lseek(__fd, cur_offs, SEEK_SET);
}
}
#endif
fstMunmap(xc->curval_mem, xc->maxvalpos);
xc->curval_mem = NULL;
}
@@ -3412,6 +3398,7 @@ int flat_hier_alloc_len;
unsigned do_rewind : 1;
char str_scope_nam[FST_ID_NAM_SIZ+1];
char str_scope_comp[FST_ID_NAM_SIZ+1];
char *str_scope_attr;
unsigned fseek_failed : 1;
@@ -4140,7 +4127,7 @@ if(!(isfeof=feof(xc->fh)))
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_SIZ)
if(cl < FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
@@ -4152,7 +4139,7 @@ if(!(isfeof=feof(xc->fh)))
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_SIZ)
if(cl < FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
@@ -4169,15 +4156,19 @@ if(!(isfeof=feof(xc->fh)))
xc->hier.htyp = FST_HT_ATTRBEGIN;
xc->hier.u.attr.typ = fgetc(xc->fh);
xc->hier.u.attr.subtype = fgetc(xc->fh);
xc->hier.u.attr.name = pnt = xc->str_scope_nam;
if(!xc->str_scope_attr)
{
xc->str_scope_attr = (char *)calloc(1, FST_ID_NAM_ATTR_SIZ+1);
}
xc->hier.u.attr.name = pnt = xc->str_scope_attr;
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_SIZ)
if(cl < FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
}; /* scopename */
}; /* attrname */
pnt[cl] = 0;
xc->hier.u.attr.name_length = cl;
@@ -4237,7 +4228,7 @@ if(!(isfeof=feof(xc->fh)))
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_SIZ)
if(cl < FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
@@ -4376,7 +4367,7 @@ while(!feof(xc->fh))
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_ATTR_SIZ)
if(cl < FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
@@ -4398,7 +4389,7 @@ while(!feof(xc->fh))
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_ATTR_SIZ)
if(cl < FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
@@ -4487,7 +4478,7 @@ while(!feof(xc->fh))
cl = 0;
while((ch = fgetc(xc->fh)))
{
if(cl <= FST_ID_NAM_ATTR_SIZ)
if(cl < FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
@@ -4974,6 +4965,7 @@ if(xc)
free(xc->signal_typs); xc->signal_typs = NULL;
free(xc->signal_lens); xc->signal_lens = NULL;
free(xc->filename); xc->filename = NULL;
free(xc->str_scope_attr); xc->str_scope_attr = NULL;
if(xc->fh)
{
+118 -37
View File
@@ -232,9 +232,9 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
char* const bufp = new char[len + 1];
VL_VSNPRINTF(bufp, len + 1, formatp, ap);
std::string out{bufp, len}; // Not const to allow move optimization
std::string result{bufp, len}; // Not const to allow move optimization
delete[] bufp;
return out;
return result;
}
uint64_t _vl_dbg_sequence_number() VL_MT_SAFE {
@@ -255,30 +255,76 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
// includes that otherwise would be required in every Verilated module
va_list ap;
va_start(ap, formatp);
const std::string out = _vl_string_vprintf(formatp, ap);
const std::string result = _vl_string_vprintf(formatp, ap);
va_end(ap);
// printf("-imm-V{t%d,%" PRId64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(),
// out.c_str());
// result.c_str());
// Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF
// from within the guts of the thread execution machinery (and it goes
// to the screen and not into the queues we're debugging)
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), result.c_str());
}
void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
const std::string out = _vl_string_vprintf(formatp, ap);
const std::string result = _vl_string_vprintf(formatp, ap);
va_end(ap);
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
VL_PRINTF("%s", out.c_str());
VL_PRINTF("%s", result.c_str());
}});
}
//===========================================================================
// Random -- Mostly called at init time, so not inline.
VlRNG::VlRNG() VL_MT_SAFE {
// Starting point for this new class comes from the global RNG
VlRNG& fromr = vl_thread_rng();
m_state = fromr.m_state;
// Advance the *source* so it can later generate a new number
// Xoroshiro128+ algorithm
fromr.m_state[1] ^= fromr.m_state[0];
fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1]
^ (fromr.m_state[1] << 14));
fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28);
}
uint64_t VlRNG::rand64() VL_MT_UNSAFE {
// Xoroshiro128+ algorithm
const uint64_t result = m_state[0] + m_state[1];
m_state[1] ^= m_state[0];
m_state[0] = (((m_state[0] << 55) | (m_state[0] >> 9)) ^ m_state[1] ^ (m_state[1] << 14));
m_state[1] = (m_state[1] << 36) | (m_state[1] >> 28);
return result;
}
uint64_t VlRNG::vl_thread_rng_rand64() VL_MT_SAFE {
VlRNG& fromr = vl_thread_rng();
const uint64_t result = fromr.m_state[0] + fromr.m_state[1];
fromr.m_state[1] ^= fromr.m_state[0];
fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1]
^ (fromr.m_state[1] << 14));
fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28);
return result;
}
void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE {
m_state[0] = n;
m_state[1] = m_state[0];
// Fix state as algorithm is slow to randomize if many zeros
// This causes a loss of ~ 1 bit of seed entropy, no big deal
if (VL_COUNTONES_I(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: }
static uint32_t vl_sys_rand32() VL_MT_SAFE {
// Return random 32-bits using system library.
// Used only to construct seed for Verilator's PRNG.
@@ -292,27 +338,23 @@ static uint32_t vl_sys_rand32() VL_MT_SAFE {
#endif
}
uint64_t vl_rand64() VL_MT_SAFE {
static thread_local uint64_t t_state[2];
VlRNG& VlRNG::vl_thread_rng() VL_MT_SAFE {
static thread_local VlRNG t_rng{0};
static thread_local uint32_t t_seedEpoch = 0;
// For speed, we use a thread-local epoch number to know when to reseed
// A thread always belongs to a single context, so this works out ok
if (VL_UNLIKELY(t_seedEpoch != VerilatedContextImp::randSeedEpoch())) {
// Set epoch before state, to avoid race case with new seeding
t_seedEpoch = VerilatedContextImp::randSeedEpoch();
t_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64();
t_state[1] = t_state[0];
// Same as srandom() but here as needs to be VL_MT_SAFE
t_rng.m_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64();
t_rng.m_state[1] = t_rng.m_state[0];
// Fix state as algorithm is slow to randomize if many zeros
// This causes a loss of ~ 1 bit of seed entropy, no big deal
if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0];
if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1];
if (VL_COUNTONES_I(t_rng.m_state[0]) < 10) t_rng.m_state[0] = ~t_rng.m_state[0];
if (VL_COUNTONES_I(t_rng.m_state[1]) < 10) t_rng.m_state[1] = ~t_rng.m_state[1];
}
// Xoroshiro128+ algorithm
const uint64_t result = t_state[0] + t_state[1];
t_state[1] ^= t_state[0];
t_state[0] = (((t_state[0] << 55) | (t_state[0] >> 9)) ^ t_state[1] ^ (t_state[1] << 14));
t_state[1] = (t_state[1] << 36) | (t_state[1] >> 28);
return result;
return t_rng;
}
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
@@ -321,6 +363,12 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
return outwp;
}
WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE {
for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = rngr.rand64();
// Last word is unclean
return outwp;
}
IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE {
// $random - seed is a new seed to apply, then we return new seed
Verilated::threadContextp()->randSeed(static_cast<int>(seedr));
@@ -518,12 +566,12 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE
// Skip check for rhs == 0, as short-circuit doesn't save time
if (VL_UNLIKELY(lhs == 0)) return 0;
QData power = lhs;
QData out = 1ULL;
QData result = 1ULL;
for (int bit = 0; bit < rbits; ++bit) {
if (bit > 0) power = power * power;
if (VL_BITISSET_W(rwp, bit)) out *= power;
if (VL_BITISSET_W(rwp, bit)) result *= power;
}
return out;
return result;
}
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
@@ -645,7 +693,7 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE {
}
template <typename T>
std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) {
std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) VL_MT_SAFE {
const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp();
const std::string suffix = ctxImpp->timeFormatSuffix();
const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15
@@ -1411,6 +1459,12 @@ IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
outputr = std::string{::std::strerror(ret)};
return ret;
}
IData VL_FERROR_IW(IData fpi, int obits, WDataOutP outwp) VL_MT_SAFE {
std::string output;
const IData ret = VL_FERROR_IN(fpi, output /*ref*/);
_vl_string_to_vint(obits, outwp, output.length(), output.c_str());
return ret;
}
IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) {
return Verilated::threadContextp()->impp()->fdNew(filename.c_str(), mode.c_str());
@@ -1645,15 +1699,15 @@ std::string VL_STACKTRACE_N() VL_MT_SAFE {
// cppcheck-suppress knownConditionTrueFalse
if (!strings) return "Unable to backtrace\n";
std::string out = "Backtrace:\n";
for (int j = 0; j < nptrs; j++) out += std::string{strings[j]} + std::string{"\n"};
std::string result = "Backtrace:\n";
for (int j = 0; j < nptrs; j++) result += std::string{strings[j]} + std::string{"\n"};
free(strings);
return out;
return result;
}
void VL_STACKTRACE() VL_MT_SAFE {
const std::string out = VL_STACKTRACE_N();
VL_PRINTF("%s", out.c_str());
const std::string result = VL_STACKTRACE_N();
VL_PRINTF("%s", result.c_str());
}
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
@@ -1793,19 +1847,20 @@ std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_NX("'h%0x", 8, lhs); }
std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_NX("'h%0x", 16, lhs); }
std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_NX("'h%0x", 32, lhs); }
std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_NX("'h%0x", 64, lhs); }
std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_NX("%d", 64, lhs); }
std::string VL_TO_STRING_W(int words, const WDataInP obj) {
return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj);
}
std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE {
std::string out = ld;
for (auto& cr : out) cr = std::tolower(cr);
return out;
std::string result = ld;
for (auto& cr : result) cr = std::tolower(cr);
return result;
}
std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE {
std::string out = ld;
for (auto& cr : out) cr = std::toupper(cr);
return out;
std::string result = ld;
for (auto& cr : result) cr = std::toupper(cr);
return result;
}
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
@@ -1861,6 +1916,32 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
if (errno != 0) v = 0;
return static_cast<IData>(v);
}
IData VL_NTOI_I(int obits, const std::string& str) VL_PURE { return VL_NTOI_Q(obits, str); }
QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE {
QData out = 0;
const char* const datap = str.data();
int pos = static_cast<int>(str.length()) - 1;
int bit = 0;
while (bit < obits && pos >= 0) {
out |= static_cast<QData>(datap[pos]) << VL_BITBIT_Q(bit);
bit += 8;
--pos;
}
return out & VL_MASK_Q(obits);
}
void VL_NTOI_W(int obits, WDataOutP owp, const std::string& str) VL_PURE {
const int words = VL_WORDS_I(obits);
for (int i = 0; i < words; ++i) owp[i] = 0;
const char* const datap = str.data();
int pos = static_cast<int>(str.length()) - 1;
int bit = 0;
while (bit < obits && pos >= 0) {
owp[VL_BITWORD_I(bit)] |= static_cast<EData>(datap[pos]) << VL_BITBIT_I(bit);
bit += 8;
--pos;
}
owp[words - 1] &= VL_MASK_E(obits);
}
//===========================================================================
// Readmem/writemem
@@ -2948,7 +3029,7 @@ VerilatedModule::~VerilatedModule() {
// VerilatedVar:: Methods
// cppcheck-suppress unusedFunction // Used by applications
uint32_t VerilatedVarProps::entSize() const {
uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
uint32_t size = 1;
switch (vltype()) {
case VLVT_PTR: size = sizeof(void*); break;
@@ -2968,7 +3049,7 @@ size_t VerilatedVarProps::totalSize() const {
return size;
}
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
const int indxAdj = indx - low(dim);
@@ -3087,7 +3168,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
return nullptr;
}
void* VerilatedScope::exportFindError(int funcnum) const {
void* VerilatedScope::exportFindError(int funcnum) const VL_MT_SAFE {
// Slowpath - Called only when find has failed
const std::string msg
= (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum)
+50 -10
View File
@@ -30,6 +30,13 @@
#ifndef VERILATOR_VERILATED_H_
#define VERILATOR_VERILATED_H_
#define VERILATOR_VERILATED_H_INTERNAL_
#ifdef VERILATOR_INTERNAL_
// This file contains definition of VerilationMutex that should
// only be used by verilated code. Verilator itself should use
// mutex from V3Mutex.h. Make sure this file isn't included in
// verilator code.
#error "verilated.h should only be included in verilated code"
#endif
// clang-format off
#include "verilatedos.h"
@@ -47,6 +54,7 @@
#include <cstdlib>
#include <cstring>
#include <deque>
#include <functional>
#include <map>
#include <memory>
#include <set>
@@ -141,6 +149,15 @@ enum VerilatedVarFlags {
VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout
};
//=============================================================================
// Utility functions
template <size_t N>
inline constexpr size_t roundUpToMultipleOf(size_t value) {
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
return (value + N - 1) & ~(N - 1);
}
//=========================================================================
// Mutex and threading support
@@ -175,6 +192,19 @@ public:
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
/// Try to acquire mutex. Returns true on success, and false on failure.
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
/// 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 {
while (true) {
checkStopRequestFunction();
if (m_mutex.try_lock()) return;
VL_CPU_RELAX();
}
}
};
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
@@ -192,10 +222,19 @@ public:
}
/// Destruct and unlock the mutex
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
/// Unlock the mutex
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
/// 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
@@ -584,6 +623,7 @@ public: // But for internal use only
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
~VerilatedSyms();
VL_UNCOPYABLE(VerilatedSyms);
};
//===========================================================================
@@ -624,7 +664,7 @@ public: // But internals only - called from VerilatedModule's
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
void scopeDump() const;
void* exportFindError(int funcnum) const;
void* exportFindError(int funcnum) const VL_MT_SAFE;
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
@@ -922,18 +962,18 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_s.m_timeprecision = value;
#if VM_SC
const sc_time sc_res = sc_get_time_resolution();
if (sc_res == sc_time(1, SC_SEC)) {
const sc_core::sc_time sc_res = sc_core::sc_get_time_resolution();
if (sc_res == sc_core::sc_time(1, sc_core::SC_SEC)) {
sc_prec = 0;
} else if (sc_res == sc_time(1, SC_MS)) {
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_MS)) {
sc_prec = 3;
} else if (sc_res == sc_time(1, SC_US)) {
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_US)) {
sc_prec = 6;
} else if (sc_res == sc_time(1, SC_NS)) {
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_NS)) {
sc_prec = 9;
} else if (sc_res == sc_time(1, SC_PS)) {
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_PS)) {
sc_prec = 12;
} else if (sc_res == sc_time(1, SC_FS)) {
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) {
sc_prec = 15;
}
#endif
+6 -4
View File
@@ -67,7 +67,7 @@ VK_CPPFLAGS_ALWAYS += \
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
$(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
VK_CPPFLAGS_WALL += -Wall $(CFG_CXXFLAGS_WEXTRA) -Werror
endif
@@ -235,14 +235,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
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
# allow USER_CPPFLAGS to override them
%.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
$(VK_SLOW_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
$(VK_GLOBAL_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
endif
#Default rule embedded in make:
+3 -3
View File
@@ -208,11 +208,11 @@ private:
// Forward to . so we have a whole word
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
std::string out = prefix + "*" + suffix;
std::string result = prefix + "*" + suffix;
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
// <<"\ncho="<<out<<endl;
return out;
// <<"\ncho="<<result<<endl;
return result;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
VL_REQUIRES(m_mutex) {
+11 -11
View File
@@ -19,8 +19,8 @@
///
//=============================================================================
#ifndef VERILATOR_VERILATED_VCD_SC_H_
#define VERILATOR_VERILATED_VCD_SC_H_
#ifndef VERILATOR_VERILATED_FST_SC_H_
#define VERILATOR_VERILATED_FST_SC_H_
#include "verilatedos.h"
@@ -36,23 +36,23 @@
/// with the SystemC simulation kernel, just like a SystemC-documented
/// trace format.
class VerilatedFstSc final : sc_trace_file, public VerilatedFstC {
class VerilatedFstSc final : sc_core::sc_trace_file, public VerilatedFstC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFstSc);
public:
/// Construct a SC trace object, and register with the SystemC kernel
VerilatedFstSc() {
sc_get_curr_simcontext()->add_trace_file(this);
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
// We want to avoid a depreciated warning, but still be back compatible.
// Turning off the message just for this still results in an
// annoying "to turn off" message.
const sc_time t1sec{1, SC_SEC};
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
if (t1sec.to_default_time_units() != 0) {
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
spTrace()->set_time_unit(tunits.to_string());
}
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
}
/// Destruct, flush, and close the dump
~VerilatedFstSc() override { close(); }
@@ -60,7 +60,7 @@ public:
// METHODS - for SC kernel
// Called by SystemC simulate()
void cycle(bool delta_cycle) override {
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
}
// Override VerilatedFstC. Must be called after starting simulation.
@@ -79,7 +79,7 @@ private:
// Cadence Incisive has these as abstract functions so we must create them
void set_time_unit(int exponent10_seconds) override {} // deprecated
#endif
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
//--------------------------------------------------
// SystemC 2.1.v1
@@ -96,8 +96,8 @@ private:
// Formatting matches that of sc_trace.h
// LCOV_EXCL_START
#if (SYSTEMC_VERSION >= 20171012)
DECL_TRACE_METHOD_A( sc_event )
DECL_TRACE_METHOD_A( sc_time )
DECL_TRACE_METHOD_A( sc_core::sc_event )
DECL_TRACE_METHOD_A( sc_core::sc_time )
#endif
DECL_TRACE_METHOD_A( bool )
+9 -5
View File
@@ -260,7 +260,7 @@ extern void _vl_debug_print_w(int lbits, WDataInP const iwp) VL_MT_SAFE;
#if defined(SYSTEMC_VERSION)
/// Return current simulation time
// Already defined: extern sc_time sc_time_stamp();
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_time_stamp().value(); }
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_core::sc_time_stamp().value(); }
#else // Non-SystemC
# if !defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)
# ifdef VL_TIME_STAMP64
@@ -2164,6 +2164,9 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno
}
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
extern IData VL_NTOI_I(int obits, const std::string& str) VL_PURE;
extern QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE;
extern void VL_NTOI_W(int obits, WDataOutP owp, const std::string& str) VL_PURE;
extern IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE;
@@ -2198,10 +2201,10 @@ inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs
return lhs + rhs;
}
inline std::string VL_REPLICATEN_NNQ(const std::string& lhs, IData rep) VL_PURE {
std::string out;
out.reserve(lhs.length() * rep);
for (unsigned times = 0; times < rep; ++times) out += lhs;
return out;
std::string result;
result.reserve(lhs.length() * rep);
for (unsigned times = 0; times < rep; ++times) result += lhs;
return result;
}
inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE {
return VL_REPLICATEN_NNQ(lhs, rep);
@@ -2212,6 +2215,7 @@ extern std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE;
extern std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE;
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
extern IData VL_FERROR_IW(IData fpi, int obits, WDataOutP outwp) VL_MT_SAFE;
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
+1 -1
View File
@@ -148,7 +148,7 @@ public:
private:
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
// METHODS
static VerilatedThreadMsgQueue& threadton() {
static VerilatedThreadMsgQueue& threadton() VL_MT_SAFE {
static thread_local VerilatedThreadMsgQueue t_s;
return t_s;
}
+3 -3
View File
@@ -29,7 +29,7 @@
#include "verilatedos.h"
#include "systemc.h"
#include <systemc>
//=============================================================================
// For \internal use, get a pointer to m_data in the sc_bv_base class,
@@ -37,9 +37,9 @@
// use cast magic to get at it. Saves patching get_datap in SystemC.
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
// This class is thread safe (though most of SystemC is not).
class VlScBvExposer final : public sc_bv_base {
class VlScBvExposer final : public sc_dt::sc_bv_base {
public:
static const uint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE {
static const uint32_t* sp_datap(const sc_dt::sc_bv_base& base) VL_MT_SAFE {
return static_cast<const VlScBvExposer*>(&base)->sp_datatp();
}
const uint32_t* sp_datatp() const { return reinterpret_cast<uint32_t*>(m_data); }
+113 -71
View File
@@ -26,92 +26,134 @@
// verilator lint_off TIMESCALEMOD
// verilator lint_off UNUSEDSIGNAL
package std;
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
// The process class is not implemented, but it's predeclared here,
// so the linter accepts references to it.
typedef class process;
function new(int bound = 0);
m_bound = bound;
endfunction
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
function int num();
return m_queue.size();
endfunction
function new(int bound = 0);
m_bound = bound;
endfunction
task put(T message);
`ifdef VERILATOR_TIMING
if (m_bound != 0)
wait (m_queue.size() < m_bound);
function int num();
return m_queue.size();
endfunction
task put(T message);
`ifdef VERILATOR_TIMING
if (m_bound != 0)
wait (m_queue.size() < m_bound);
m_queue.push_back(message);
`endif
endtask
function int try_put(T message);
if (num() < m_bound) begin
m_queue.push_back(message);
`endif
endtask
return 1;
end
return 0;
endfunction
function int try_put(T message);
if (num() < m_bound) begin
m_queue.push_back(message);
return 1;
end
return 0;
endfunction
task get(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
message = m_queue.pop_front();
`endif
endtask
task get(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
function int try_get(ref T message);
if (num() > 0) begin
message = m_queue.pop_front();
`endif
endtask
return 1;
end
return 0;
endfunction
function int try_get(ref T message);
if (num() > 0) begin
message = m_queue.pop_front();
return 1;
end
return 0;
endfunction
task peek(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
message = m_queue[0];
`endif
endtask
task peek(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
function int try_peek(ref T message);
if (num() > 0) begin
message = m_queue[0];
`endif
endtask
return 1;
end
return 0;
endfunction
endclass
function int try_peek(ref T message);
if (num() > 0) begin
message = m_queue[0];
return 1;
end
return 0;
endfunction
endclass
class semaphore;
protected int m_keyCount;
class semaphore;
protected int m_keyCount;
function new(int keyCount = 0);
m_keyCount = keyCount;
endfunction
function new(int keyCount = 0);
m_keyCount = keyCount;
endfunction
function void put(int keyCount = 1);
m_keyCount += keyCount;
endfunction
function void put(int keyCount = 1);
m_keyCount += keyCount;
endfunction
task get(int keyCount = 1);
`ifdef VERILATOR_TIMING
wait (m_keyCount >= keyCount);
m_keyCount -= keyCount;
`endif
endtask
task get(int keyCount = 1);
`ifdef VERILATOR_TIMING
wait (m_keyCount >= keyCount);
function int try_get(int keyCount = 1);
if (m_keyCount >= keyCount) begin
m_keyCount -= keyCount;
`endif
endtask
return 1;
end
return 0;
endfunction
endclass
class process;
typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state;
static process _s_global_process;
static function process self();
// Unsupported, emulating with single process' state
if (!_s_global_process) _s_global_process = new;
return _s_global_process;
endfunction
function state status();
// Unsupported, emulating with single process' state
return RUNNING;
endfunction
function void kill();
$error("std::process::kill() not supported");
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");
endfunction
// When really implemented, srandom must operates on the process, but for
// now rely on the srandom() that is automatically generated for all
// classes.
// function void srandom(int seed);
// endfunction
function string get_randstate();
// Could operate on all proceses for now
// No error, as harmless until set_randstate is called
return "NOT_SUPPORTED";
endfunction
function void set_randstate(string randstate);
$error("std::process::set_randstate() not supported");
// Could operate on all proceses for now
endfunction
endclass
function int try_get(int keyCount = 1);
if (m_keyCount >= keyCount) begin
m_keyCount -= keyCount;
return 1;
end
return 0;
endfunction
endclass
endpackage
// verilator lint_off IMPORTSTAR
import std::*;
+15 -15
View File
@@ -137,35 +137,35 @@ public:
~VerilatedVarProps() = default;
// METHODS
bool magicOk() const { return m_magic == MAGIC; }
VerilatedVarType vltype() const { return m_vltype; }
VerilatedVarType vltype() const VL_MT_SAFE { return m_vltype; }
VerilatedVarFlags vldir() const {
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
}
uint32_t entSize() const;
uint32_t entSize() const VL_MT_SAFE;
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
// DPI compatible C standard layout
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
int udims() const { return m_udims; }
int udims() const VL_MT_SAFE { return m_udims; }
int dims() const { return m_pdims + m_udims; }
const VerilatedRange& packed() const { return m_packed; }
const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; }
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
// DPI accessors
int left(int dim) const {
int left(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packed.left()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
: 0;
}
int right(int dim) const {
int right(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packed.right()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
: 0;
}
int low(int dim) const {
int low(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packed.low()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
: 0;
}
int high(int dim) const {
int high(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packed.high()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
: 0;
@@ -175,7 +175,7 @@ public:
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
: 0;
}
int elements(int dim) const {
int elements(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packed.elements()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
: 0;
@@ -183,7 +183,7 @@ public:
// Total size in bytes (note DPI limited to 4GB)
size_t totalSize() const;
// Adjust a data pointer to access a given array element, NULL if something goes bad
void* datapAdjustIndex(void* datap, int dim, int indx) const;
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE;
};
//===========================================================================
@@ -203,22 +203,22 @@ public:
, m_datap{const_cast<void*>(datap)} {}
~VerilatedDpiOpenVar() = default;
// METHODS
void* datap() const { return m_datap; }
void* datap() const VL_MT_SAFE { return m_datap; }
// METHODS - from VerilatedVarProps
bool magicOk() const { return m_propsp->magicOk(); }
VerilatedVarType vltype() const { return m_propsp->vltype(); }
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
const VerilatedRange& packed() const { return m_propsp->packed(); }
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
int udims() const { return m_propsp->udims(); }
int left(int dim) const { return m_propsp->left(dim); }
int right(int dim) const { return m_propsp->right(dim); }
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
int low(int dim) const { return m_propsp->low(dim); }
int high(int dim) const { return m_propsp->high(dim); }
int increment(int dim) const { return m_propsp->increment(dim); }
int elements(int dim) const { return m_propsp->elements(dim); }
size_t totalSize() const { return m_propsp->totalSize(); }
void* datapAdjustIndex(void* datap, int dim, int indx) const {
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
return m_propsp->datapAdjustIndex(datap, dim, indx);
}
};
-10
View File
@@ -312,16 +312,6 @@ public:
}
};
//=============================================================================
// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine.
// Allows forcing the move of coroutine locals to the heap.
struct VlNow {
bool await_ready() const { return false; } // Always suspend
bool await_suspend(std::coroutine_handle<>) const { return false; } // Resume immediately
void await_resume() const {}
};
//=============================================================================
// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant
// wait statements.
+72 -16
View File
@@ -45,6 +45,7 @@ extern std::string VL_TO_STRING(CData lhs);
extern std::string VL_TO_STRING(SData lhs);
extern std::string VL_TO_STRING(IData lhs);
extern std::string VL_TO_STRING(QData lhs);
extern std::string VL_TO_STRING(double lhs);
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
@@ -78,9 +79,9 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
template <std::size_t T_size> //
class VlTriggerVec final {
// TODO: static assert T_size > 0, and don't generate when empty
private:
// MEMBERS
std::array<bool, T_size> m_flags; // State of the assoc array
alignas(16) std::array<uint64_t, roundUpToMultipleOf<64>(T_size) / 64> m_flags; // The flags
public:
// CONSTRUCTOR
@@ -90,10 +91,18 @@ public:
// METHODS
// Set all elements to false
void clear() { m_flags.fill(false); }
void clear() { m_flags.fill(0); }
// Reference to element at 'index'
bool& at(size_t index) { return m_flags.at(index); }
// Word at given 'wordIndex'
uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; }
// Set specified flag to given value
void set(size_t index, bool value) {
uint64_t& w = m_flags[index / 64];
const size_t bitIndex = index % 64;
w &= ~(1ULL << bitIndex);
w |= (static_cast<uint64_t>(value) << bitIndex);
}
// Return true iff at least one element is set
bool any() const {
@@ -103,13 +112,13 @@ public:
}
// Set all elements true in 'this' that are set in 'other'
void set(const VlTriggerVec<T_size>& other) {
void thisOr(const VlTriggerVec<T_size>& other) {
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i];
}
// Set elements of 'this' to 'a & !b' element-wise
void andNot(const VlTriggerVec<T_size>& a, const VlTriggerVec<T_size>& b) {
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] && !b.m_flags[i];
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] & ~b.m_flags[i];
}
};
@@ -135,14 +144,34 @@ public:
};
inline std::string VL_TO_STRING(const VlEvent& e) {
return std::string("triggered=") + (e.isTriggered() ? "true" : "false");
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
}
//===================================================================
// Shuffle RNG
// Random
extern uint64_t vl_rand64() VL_MT_SAFE;
// Random Number Generator with internal state
class VlRNG final {
std::array<uint64_t, 2> m_state;
public:
// The default constructor simply sets state, to avoid vl_rand64()
// having to check for construction at each call
// Alternative: seed with zero and check on rand64() call
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;
uint64_t rand64() VL_MT_UNSAFE;
// Threadsafe, but requires use on vl_thread_rng
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
static VlRNG& vl_thread_rng() VL_MT_SAFE;
};
inline uint64_t vl_rand64() VL_MT_SAFE { return VlRNG::vl_thread_rng_rand64(); }
// RNG for shuffle()
class VlURNG final {
public:
using result_type = size_t;
@@ -151,6 +180,11 @@ public:
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
};
// 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(); }
extern WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE;
//===================================================================
// Readmem/Writemem operation classes
@@ -369,18 +403,17 @@ public:
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(int32_t index) {
static thread_local T_Value s_throwAway;
static thread_local T_Value t_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
t_throwAway = atDefault();
return t_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(int32_t index) const {
static thread_local T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault();
@@ -388,6 +421,10 @@ public:
return m_deque[index];
}
}
// Access with an index counted from end (e.g. q[$])
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
// 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;
@@ -403,6 +440,12 @@ public:
for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
return out;
}
VlQueue sliceFrontBack(int32_t lsb, int32_t msb) const {
return slice(lsb, m_deque.size() - 1 - msb);
}
VlQueue sliceBackBack(int32_t lsb, int32_t msb) const {
return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb);
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
@@ -1165,10 +1208,13 @@ public:
// CONSTRUCTORS
VlClassRef() = default;
// Init with nullptr
explicit VlClassRef(VlNull){};
// cppcheck-suppress noExplicitConstructor
VlClassRef(VlNull){};
template <typename... T_Args>
VlClassRef(VlDeleter& deleter, T_Args&&... args)
: m_objp{new T_Class{std::forward<T_Args>(args)...}} {
// () 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)...)} {
m_objp->m_deleterp = &deleter;
refCountInc();
}
@@ -1185,6 +1231,16 @@ public:
// cppcheck-suppress noExplicitConstructor
VlClassRef(VlClassRef&& moved)
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
// cppcheck-suppress noExplicitConstructor
template <typename T_OtherClass>
VlClassRef(const VlClassRef<T_OtherClass>& copied)
: m_objp{copied.m_objp} {
refCountInc();
}
// cppcheck-suppress noExplicitConstructor
template <typename T_OtherClass>
VlClassRef(VlClassRef<T_OtherClass>&& moved)
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
~VlClassRef() { refCountDec(); }
// METHODS
-10
View File
@@ -61,16 +61,6 @@ constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; // Maximum length of a VCD s
// cache-lines.
constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; // Size of a suffix entry
//=============================================================================
// Utility functions: TODO: put these in a common place and share them.
template <size_t N>
static size_t roundUpToMultipleOf(size_t value) {
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
size_t mask = N - 1;
return (value + mask) & ~mask;
}
//=============================================================================
// Specialization of the generics for this trace format
+9 -9
View File
@@ -36,23 +36,23 @@
/// with the SystemC simulation kernel, just like a SystemC-documented
/// trace format.
class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC {
class VerilatedVcdSc final : sc_core::sc_trace_file, public VerilatedVcdC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedVcdSc);
public:
/// Construct a SC trace object, and register with the SystemC kernel
VerilatedVcdSc() {
sc_get_curr_simcontext()->add_trace_file(this);
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
// We want to avoid a depreciated warning, but still be back compatible.
// Turning off the message just for this still results in an
// annoying "to turn off" message.
const sc_time t1sec{1, SC_SEC};
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
if (t1sec.to_default_time_units() != 0) {
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
spTrace()->set_time_unit(tunits.to_string());
}
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
}
/// Destruct, flush, and close the dump
~VerilatedVcdSc() override { close(); }
@@ -60,7 +60,7 @@ public:
// METHODS - for SC kernel
// Called by SystemC simulate()
void cycle(bool delta_cycle) override {
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
}
// Override VerilatedVcdC. Must be called after starting simulation.
@@ -78,7 +78,7 @@ private:
// Cadence Incisive has these as abstract functions so we must create them
void set_time_unit(int exponent10_seconds) override {} // deprecated
#endif
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
//--------------------------------------------------
// SystemC 2.1.v1
@@ -95,8 +95,8 @@ private:
// Formatting matches that of sc_trace.h
// LCOV_EXCL_START
#if (SYSTEMC_VERSION >= 20171012)
DECL_TRACE_METHOD_A( sc_event )
DECL_TRACE_METHOD_A( sc_time )
DECL_TRACE_METHOD_A( sc_core::sc_event )
DECL_TRACE_METHOD_A( sc_core::sc_time )
#endif
DECL_TRACE_METHOD_A( bool )
-2
View File
@@ -791,7 +791,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE {
}
for (auto& ifuture : s().m_nextCbs) {
const QData time = ifuture.first.first;
const uint64_t id = ifuture.first.second;
VerilatedVpiCbHolder& ho = ifuture.second;
if (VL_UNLIKELY(!ho.invalid())) {
VL_DBG_MSGF("- vpi: time=%" PRId64 "(NEXT) reason=%d=%s id=%" PRId64 "\n", time,
@@ -802,7 +801,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE {
}
for (auto& ifuture : s().m_futureCbs) {
const QData time = ifuture.first.first;
const uint64_t id = ifuture.first.second;
VerilatedVpiCbHolder& ho = ifuture.second;
if (VL_UNLIKELY(!ho.invalid())) {
VL_DBG_MSGF("- vpi: time=%" PRId64 " reason=%d=%s id=%" PRId64 "\n", time,
+14 -1
View File
@@ -160,6 +160,13 @@
#else
# define VL_MT_SAFE
#endif
// 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
// Comment tag that function is threadsafe, only
// during normal operation (post-init)
#if defined(__clang__)
@@ -519,6 +526,8 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory");
#elif defined(__aarch64__) || defined(__arm__)
# define VL_CPU_RELAX() asm volatile("yield" ::: "memory")
#elif defined(__hppa__) // HPPA does not currently have yield/pause
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory")
#elif defined(__loongarch__) // LoongArch does not currently have yield/pause
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory")
#elif defined(__mips64el__) || defined(__mips__) || defined(__mips64__) || defined(__mips64)
@@ -594,8 +603,12 @@ reverse_wrapper<T> reverse_view(const T& v) {
}
// C++17's std::as_const
// `VL_MT_SAFE` annotation only applies to this function.
// Object that is returned by this function is not considered
// as MT_SAFE and any function call on this object still
// needs to be `VL_MT_SAFE`.
template <class T>
T const& as_const(T& v) {
T const& as_const(T& v) VL_MT_SAFE {
return v;
}
+2 -2
View File
@@ -106,7 +106,7 @@ done
if [ x"$src" = x ]
then
echo "install: no input file specified"
echo "install: no input file specified"
exit 1
else
true
@@ -137,7 +137,7 @@ else
if [ x"$dst" = x ]
then
echo "install: no destination specified"
echo "install: no destination specified"
exit 1
else
true
+150 -70
View File
@@ -37,6 +37,7 @@ def fully_qualified_name(node):
class VlAnnotations:
mt_start: bool = False
mt_safe: bool = False
stable_tree: bool = False
mt_safe_postinit: bool = False
mt_unsafe: bool = False
mt_unsafe_one: bool = False
@@ -48,12 +49,17 @@ class VlAnnotations:
release: bool = False
def is_mt_safe_context(self):
return (not (self.mt_unsafe or self.mt_unsafe_one)
and (self.mt_safe or self.mt_start))
return self.mt_safe and not (self.mt_unsafe or self.mt_unsafe_one)
def is_pure_context(self):
return self.pure
def is_stabe_tree_context(self):
# stable tree context requires calls to be marked
# as MT_SAFE or MT_STABLE
# Functions in MT_START needs to be MT_SAFE or MT_STABLE
return self.stable_tree or self.mt_start
def is_mt_unsafe_call(self):
return self.mt_unsafe or self.mt_unsafe_one
@@ -66,6 +72,9 @@ class VlAnnotations:
def is_pure_call(self):
return self.pure
def is_stabe_tree_call(self):
return self.stable_tree
def __or__(self, other: "VlAnnotations"):
result = VlAnnotations()
for key, value in dataclasses.asdict(self).items():
@@ -94,6 +103,8 @@ class VlAnnotations:
result.mt_start = True
elif node.displayname == "MT_SAFE":
result.mt_safe = True
elif node.displayname == "MT_STABLE":
result.stable_tree = True
elif node.displayname == "MT_SAFE_POSTINIT":
result.mt_safe_postinit = True
elif node.displayname == "MT_UNSAFE":
@@ -196,6 +207,7 @@ class DiagnosticKind(Enum):
ANNOTATIONS_DEF_DECL_MISMATCH = enum.auto()
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()
def __lt__(self, other):
return self.value < other.value
@@ -239,6 +251,7 @@ class CallAnnotationsValidator:
self._call_location: Optional[FunctionInfo] = None
self._caller: Optional[FunctionInfo] = None
self._level: int = 0
self._constructor_context: int = 0
def compile_and_analyze_file(self, source_file: str,
compiler_args: list[str],
@@ -300,6 +313,67 @@ class CallAnnotationsValidator:
annotations = VlAnnotations.from_nodes_list(children)
return (True, refd, annotations, children)
def check_mt_safe_call(self, node: clang.cindex.Cursor,
refd: clang.cindex.Cursor,
annotations: VlAnnotations):
is_mt_safe = False
if annotations.is_mt_safe_call():
is_mt_safe = True
elif not annotations.is_mt_unsafe_call():
# Check whether the object the method is called on is mt-safe
def find_object_ref(node):
try:
node = next(node.get_children())
if node.kind == CursorKind.DECL_REF_EXPR:
# Operator on an argument or local object
return node
if node.kind != CursorKind.MEMBER_REF_EXPR:
return None
if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL:
# Operator on a member object
return node
node = next(node.get_children())
if node.kind == CursorKind.UNEXPOSED_EXPR:
node = next(node.get_children())
return node
except StopIteration:
return None
refn = find_object_ref(node)
if self._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
# MT-safe methods
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
is_mt_safe = True
# class/struct member
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:
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
elif refn and refn.kind == CursorKind.CALL_EXPR:
if self._constructor_context:
# call to local function from constructor context
# safe if this function also calling local methods or
# MT-safe methods
self.dispatch_call_node(refn)
is_mt_safe = True
return is_mt_safe
# Call handling
def process_method_call(self, node: clang.cindex.Cursor,
@@ -310,47 +384,22 @@ class CallAnnotationsValidator:
# MT-safe context
if ctx.is_mt_safe_context():
is_mt_safe = False
if annotations.is_mt_safe_call():
is_mt_safe = True
elif not annotations.is_mt_unsafe_call():
# Check whether the object the method is called on is mt-safe
def find_object_ref(node):
try:
node = next(node.get_children())
if node.kind == CursorKind.DECL_REF_EXPR:
# Operator on an argument or local object
return node
if node.kind != CursorKind.MEMBER_REF_EXPR:
return None
if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL:
# Operator on a member object
return node
node = next(node.get_children())
if node.kind == CursorKind.UNEXPOSED_EXPR:
node = next(node.get_children())
return node
except StopIteration:
return None
refn = find_object_ref(node)
# class/struct member
if 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:
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. Assume it's safe.
is_mt_safe = True
if not is_mt_safe:
if not self.check_mt_safe_call(node, refd, annotations):
self.emit_diagnostic(
FunctionInfo.from_node(refd, refd, annotations),
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
# stable tree context
if ctx.is_stabe_tree_context():
if annotations.is_mt_unsafe_call() or not (
annotations.is_stabe_tree_call()
or annotations.is_pure_call()
or self.check_mt_safe_call(node, refd, annotations)):
self.emit_diagnostic(
FunctionInfo.from_node(refd, refd, annotations),
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
# pure context
if ctx.is_pure_context():
if not annotations.is_pure_call():
self.emit_diagnostic(
@@ -368,6 +417,17 @@ class CallAnnotationsValidator:
self.emit_diagnostic(
FunctionInfo.from_node(refd, refd, annotations),
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
# stable tree context
if ctx.is_stabe_tree_context():
if annotations.is_mt_unsafe_call() or not (
annotations.is_pure_call()
or annotations.is_mt_safe_call()
or annotations.is_stabe_tree_call()):
self.emit_diagnostic(
FunctionInfo.from_node(refd, refd, annotations),
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
# pure context
if ctx.is_pure_context():
if not annotations.is_pure_call():
@@ -380,7 +440,20 @@ class CallAnnotationsValidator:
assert self._call_location
ctx = self._call_location.annotations
# Constructors are always OK in MT-safe context.
# 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
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
self._constructor_context -= 1
# stable tree context
if ctx.is_stabe_tree_context():
self._constructor_context += 1
self.iterate_children(refd.get_children(),
self.dispatch_node_inside_definition)
self._constructor_context -= 1
# pure context
if ctx.is_pure_context():
@@ -396,11 +469,19 @@ class CallAnnotationsValidator:
if not supported:
self.iterate_children(node.get_children(),
self.dispatch_node_inside_definition)
return
return True
assert refd is not None
if self._is_ignored_call(refd):
return
return True
if "std::function" in refd.displayname:
# Workaroud for missing support for lambda annotations
# in c++11.
# If function takes std::function as argument,
# assume, that this std::function will be called inside it.
self.process_function_definition(node)
return False
assert self._call_location is not None
node_file = os.path.abspath(node.location.file.name)
@@ -412,37 +493,40 @@ class CallAnnotationsValidator:
or refd.kind == CursorKind.CXX_METHOD
and refd.is_static_method()):
self.process_function_call(refd, annotations)
return
# Function pointer
if refd.kind in [
elif refd.kind in [
CursorKind.VAR_DECL, CursorKind.FIELD_DECL,
CursorKind.PARM_DECL
]:
self.process_function_call(refd, annotations)
return
# Non-static class methods
if refd.kind == CursorKind.CXX_METHOD:
elif refd.kind == CursorKind.CXX_METHOD:
self.process_method_call(node, refd, annotations)
return
# Conversion method (e.g. `operator int()`)
if refd.kind == CursorKind.CONVERSION_FUNCTION:
elif refd.kind == CursorKind.CONVERSION_FUNCTION:
self.process_method_call(node, refd, annotations)
return
# Constructors
if refd.kind == CursorKind.CONSTRUCTOR:
elif refd.kind == CursorKind.CONSTRUCTOR:
self.process_constructor_call(refd, annotations)
return
# Ignore other callables
print(f"{refd.location.file.name}:{refd.location.line}: "
f"{refd.displayname} {refd.kind}\n"
f" from: {node.location.file.name}:{node.location.line}")
else:
# Ignore other callables, but report them
print("Unknown callable: "
f"{refd.location.file.name}:{refd.location.line}: "
f"{refd.displayname} {refd.kind}\n"
f" from: {node.location.file.name}:{node.location.line}")
return True
# Definition handling
def dispatch_node_inside_definition(self, node: clang.cindex.Cursor):
if node.kind == CursorKind.CALL_EXPR:
self.dispatch_call_node(node)
if self.dispatch_call_node(node) is False:
return None
elif node.is_definition() and node.kind in [
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
]:
self.process_function_definition(node)
return None
return self.iterate_children(node.get_children(),
@@ -461,9 +545,6 @@ class CallAnnotationsValidator:
assert refd is not None
prev_caller = self._caller
prev_call_location = self._call_location
def_annotations = VlAnnotations.from_nodes_list(node_children)
if not (def_annotations.is_empty() or def_annotations == annotations):
@@ -480,13 +561,14 @@ class CallAnnotationsValidator:
# for callees validation.
self._caller = FunctionInfo.from_node(node, refd,
def_annotations | annotations)
prev_call_location = self._call_location
self._call_location = self._caller
self.iterate_children(node_children,
self.dispatch_node_inside_definition)
self._call_location = prev_call_location
self._caller = prev_caller
self._caller = prev_call_location
return None
@@ -704,8 +786,7 @@ class TopDownSummaryPrinter():
info: FunctionInfo
calees: set[FunctionInfo]
mismatch: Optional[FunctionInfo] = None
non_mt_safe_call_in_mt_safe: Optional[FunctionInfo] = None
non_pure_call_in_pure: Optional[FunctionInfo] = None
reason: Optional[DiagnosticKind] = None
def __init__(self):
self._is_first_group = True
@@ -727,15 +808,12 @@ class TopDownSummaryPrinter():
if func is None:
func = TopDownSummaryPrinter.FunctionCallees(diag.source, set())
self._funcs[usr] = func
func.reason = diag.kind
if diag.kind == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
func.mismatch = diag.target
else:
func.calees.add(diag.target)
self._unsafe_in_safe.add(diag.target.usr)
if diag.kind == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX:
func.non_mt_safe_call_in_mt_safe = diag.target
elif diag.kind == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
func.non_pure_call_in_pure = diag.target
def print_summary(self, root_dir: str):
row_groups: dict[str, list[list[str]]] = {}
@@ -748,12 +826,14 @@ class TopDownSummaryPrinter():
row_group = []
name = f"\"{func_info.name}\" "
if func.mismatch:
if func.reason == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
name += "declaration does not match definition"
elif func.non_mt_safe_call_in_mt_safe:
elif func.reason == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX:
name += "is mtsafe but calls non-mtsafe function(s)"
elif func.non_pure_call_in_pure:
elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
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"
else:
name += "for unknown reason (please add description)"
+2 -2
View File
@@ -47,7 +47,6 @@ set(HEADERS
V3Case.h
V3Cast.h
V3CCtors.h
V3Cdc.h
V3Class.h
V3Clean.h
V3Clock.h
@@ -150,6 +149,7 @@ set(HEADERS
V3SymTable.h
V3Table.h
V3Task.h
V3ThreadPool.h
V3Timing.h
V3Trace.h
V3TraceDecl.h
@@ -186,7 +186,6 @@ set(COMMON_SOURCES
V3CUse.cpp
V3Case.cpp
V3Cast.cpp
V3Cdc.cpp
V3Class.cpp
V3Clean.cpp
V3Clock.cpp
@@ -283,6 +282,7 @@ set(COMMON_SOURCES
V3Subst.cpp
V3Table.cpp
V3Task.cpp
V3ThreadPool.cpp
V3Trace.cpp
V3TraceDecl.cpp
V3Tristate.cpp
+3 -3
View File
@@ -50,7 +50,7 @@ obj_dbg:
.PHONY: ../bin/verilator_bin$(EXEEXT) ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT)
opt: ../bin/verilator_bin$(EXEEXT)
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
../bin/verilator_bin$(EXEEXT): ../bin/verilator_bin_dbg$(EXEEXT)
-cp -p $< $@.tmp
-mv -f $@.tmp $@
@@ -70,7 +70,7 @@ dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
endif
endif
@@ -78,7 +78,7 @@ endif
prefiles::
prefiles:: config_rev.h
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP)
config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP)
$(PYTHON3) ${srcdir}/config_rev ${srcdir} >$@
# Human convenience
+16 -15
View File
@@ -92,11 +92,12 @@ endif
# -lfl not needed as Flex invoked with %nowrap option
LIBS = $(CFG_LIBS) -lm
CPPFLAGS += -DVERILATOR_INTERNAL_
CPPFLAGS += -MMD
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
CPPFLAGS += -MP # Only works on recent GCC versions
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
#CPPFLAGS += -pedantic-errors
else
@@ -114,7 +115,7 @@ ifeq ($(CFG_WITH_DEFENV),yes)
CPPFLAGS += -DDEFENV_SYSTEMC_ARCH=\"$(SYSTEMC_ARCH)\"
CPPFLAGS += -DDEFENV_SYSTEMC_INCLUDE=\"$(SYSTEMC_INCLUDE)\"
CPPFLAGS += -DDEFENV_SYSTEMC_LIBDIR=\"$(SYSTEMC_LIBDIR)\"
ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit
ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit
CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(pkgdatadir)\"
else
CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(VERILATOR_ROOT)\"
@@ -155,7 +156,7 @@ RAW_OBJS = \
V3ActiveTop.o \
V3Assert.o \
V3AssertPre.o \
V3Ast.o \
V3Ast.o \
V3AstNodes.o \
V3Begin.o \
V3Branch.o \
@@ -164,7 +165,6 @@ RAW_OBJS = \
V3CUse.o \
V3Case.o \
V3Cast.o \
V3Cdc.o \
V3Class.o \
V3Clean.o \
V3Clock.o \
@@ -265,6 +265,7 @@ RAW_OBJS = \
V3TSP.o \
V3Table.o \
V3Task.o \
V3ThreadPool.o \
V3Timing.o \
V3Trace.o \
V3TraceDecl.o \
@@ -322,26 +323,26 @@ V3Number_test: V3Number_test.o
#### Modules
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
$(PYTHON3) $(ASTGEN) $(ASTGENFLAGS) $*.cpp
.SECONDARY:
%.o: %.cpp
%.o: %.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
%.o: %.c
%.o: %.c
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
#### Generated files
@@ -365,14 +366,14 @@ V3ParseBison.c: verilog.y $(BISONPRE)
@echo "If you get errors from verilog.y below, try upgrading bison to version 1.875 or newer."
$(PYTHON3) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $<
V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
${LEX} --version
${LEX} ${LFLAGS} -o$@ $<
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
$(PYTHON3) $(FLEXFIX) V3Lexer <$< >$@
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
${LEX} --version
${LEX} ${LFLAGS} -o$@ $<
+7 -7
View File
@@ -54,7 +54,7 @@ private:
const string m_name; // Only used for .dot file generation
const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
string typestr() const { // "
string typestr() const VL_MT_SAFE { // "
switch (m_type) {
case VT_BLOCK: return "(||)"; // basic block node
case VT_BRANCH: return "(&&)"; // if/else branch mode
@@ -68,7 +68,7 @@ public:
: V3GraphVertex{graphp}
, m_name{name}
, m_type{type} {}
string name() const override { return m_name + " " + typestr(); }
string name() const override VL_MT_STABLE { return m_name + " " + typestr(); }
string dotColor() const override { return user() ? "green" : "black"; }
virtual int type() const { return m_type; }
};
@@ -309,7 +309,7 @@ AstActive*& ActiveNamer::getSpecialActive<AstSenItem::Combo>() {
//######################################################################
// Latch checking visitor
class ActiveLatchCheckVisitor final : public VNVisitor {
class ActiveLatchCheckVisitor final : public VNVisitorConst {
private:
// NODE STATE
// Input:
@@ -329,20 +329,20 @@ private:
LatchDetectGraphVertex* const parentp = m_graph.currentp();
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
m_graph.addPathVertex(branchp, "IF");
iterateAndNextNull(nodep->thensp());
iterateAndNextConstNull(nodep->thensp());
m_graph.addPathVertex(branchp, "ELSE");
iterateAndNextNull(nodep->elsesp());
iterateAndNextConstNull(nodep->elsesp());
m_graph.currentp(parentp);
}
}
//--------------------
void visit(AstNode* nodep) override { iterateChildren(nodep); }
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public:
// CONSTRUCTORS
ActiveLatchCheckVisitor(AstNode* nodep, bool expectLatch) {
m_graph.begin();
iterate(nodep);
iterateConst(nodep);
m_graph.latchCheck(nodep, expectLatch);
}
~ActiveLatchCheckVisitor() override = default;
+29 -10
View File
@@ -43,6 +43,7 @@ private:
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
unsigned m_modPastNum = 0; // Module past numbering
unsigned m_modStrobeNum = 0; // Module $strobe numbering
const AstNodeProcedure* m_procedurep = nullptr; // Current procedure
VDouble0 m_statCover; // Statistic tracking
VDouble0 m_statAsNotImm; // Statistic tracking
VDouble0 m_statAsImm; // Statistic tracking
@@ -50,14 +51,22 @@ private:
bool m_inSampled = false; // True inside a sampled expression
// METHODS
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":"
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
+ ((message != "") ? ": " : "") + message + "\n");
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message,
VDisplayType severity) {
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":"
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
+ ((message != "") ? ": " : "") + message + "\n");
} else {
return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":"
+ cvtToStr(nodep->fileline()->lineno()) + ": %m"
+ ((message != "") ? ": " : "") + message + "\n");
}
}
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
nodep->fmtp()->text(
assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType()));
nodep->displayType(VDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
// cppcheck-suppress nullPointer
AstNodeExpr* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
if (AstNodeExpr* const timesp = nodep->fmtp()->exprsp()) {
@@ -145,6 +154,11 @@ private:
} else {
UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensitivity");
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)");
}
}
//
AstNode* bodysp = nullptr;
@@ -176,7 +190,7 @@ private:
const bool force = VN_IS(nodep, AssertIntrinsic);
if (passsp) passsp = newIfAssertOn(passsp, force);
if (failsp) failsp = newIfAssertOn(failsp, force);
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
if (!passsp && !failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
ifp = new AstIf{nodep->fileline(), propp, passsp, failsp};
ifp->isBoundsCheck(true); // To avoid LATCH warning
// It's more LIKELY that we'll take the nullptr if clause
@@ -350,8 +364,7 @@ private:
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
AstNodeExpr* inp = newSampledExpr(exprp);
AstVar* invarp = nullptr;
AstSenTree* const sentreep = nodep->sentreep();
sentreep->unlinkFrBack();
AstSenTree* const sentreep = nodep->sentreep()->unlinkFrBack();
AstAlways* const alwaysp
= new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr};
m_modp->addStmtsp(alwaysp);
@@ -414,9 +427,10 @@ private:
replaceDisplay(nodep, "-Info");
} else if (nodep->displayType() == VDisplayType::DT_WARNING) {
replaceDisplay(nodep, "%%Warning");
} else if (nodep->displayType() == VDisplayType::DT_ERROR
|| nodep->displayType() == VDisplayType::DT_FATAL) {
} else if (nodep->displayType() == VDisplayType::DT_ERROR) {
replaceDisplay(nodep, "%%Error");
} else if (nodep->displayType() == VDisplayType::DT_FATAL) {
replaceDisplay(nodep, "%%Fatal");
} else if (nodep->displayType() == VDisplayType::DT_MONITOR) {
nodep->displayType(VDisplayType::DT_DISPLAY);
const auto fl = nodep->fileline();
@@ -496,6 +510,11 @@ private:
iterateChildren(nodep);
}
}
void visit(AstNodeProcedure* nodep) override {
VL_RESTORER(m_procedurep);
m_procedurep = nodep;
iterateChildren(nodep);
}
void visit(AstBegin* nodep) override {
// This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin
+16 -9
View File
@@ -63,9 +63,10 @@ private:
// METHODS
AstSenTree* newSenTree(AstNode* nodep) {
AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr) {
// Create sentree based on clocked or default clock
// Return nullptr for always
if (useTreep) return useTreep;
AstSenTree* newp = nullptr;
AstSenItem* senip = m_senip;
if (!senip && m_defaultClockingp) senip = m_defaultClockingp->sensesp();
@@ -228,7 +229,7 @@ private:
// always queue.push(<sampled var>);
AstCMethodHard* const pushp = new AstCMethodHard{
flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push",
new AstTime(nodep->fileline(), m_modp->timeunit())};
new AstTime{nodep->fileline(), m_modp->timeunit()}};
pushp->addPinsp(exprp->cloneTree(false));
pushp->dtypeSetVoid();
m_clockingp->addNextHere(
@@ -237,7 +238,7 @@ private:
// always @<clocking event> queue.pop(<skew>, /*out*/<skewed var>});
AstCMethodHard* const popp = new AstCMethodHard{
flp, new AstVarRef{flp, queueVarp, VAccess::READWRITE}, "pop",
new AstTime(nodep->fileline(), m_modp->timeunit())};
new AstTime{nodep->fileline(), m_modp->timeunit()}};
popp->addPinsp(skewp->unlinkFrBack());
popp->addPinsp(refp);
popp->dtypeSetVoid();
@@ -362,17 +363,19 @@ private:
clearAssertInfo();
}
void visit(AstFell* nodep) override {
if (nodep->sentreep()) return; // Already processed
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
AstSenTree* sentreep = nodep->sentreep();
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->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
nodep->sentreep(newSenTree(nodep, sentreep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstPast* nodep) override {
@@ -381,30 +384,34 @@ private:
nodep->sentreep(newSenTree(nodep));
}
void visit(AstRose* nodep) override {
if (nodep->sentreep()) return; // Already processed
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
AstSenTree* sentreep = nodep->sentreep();
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->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
nodep->sentreep(newSenTree(nodep, sentreep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstStable* nodep) override {
if (nodep->sentreep()) return; // Already processed
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
AstSenTree* sentreep = nodep->sentreep();
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstEq{fl, past, exprp->cloneTree(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
nodep->sentreep(newSenTree(nodep, sentreep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
+147 -42
View File
@@ -87,8 +87,8 @@ string AstNode::encodeName(const string& namein) {
// Encode signal name raw from parser, then not called again on same signal
string out;
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
: isalnum(pos[0])) {
if ((pos == namein.begin()) ? std::isalpha(pos[0]) // digits can't lead identifiers
: std::isalnum(pos[0])) {
out += pos[0];
} else if (pos[0] == '_') {
if (pos[1] == '_') {
@@ -125,7 +125,9 @@ string AstNode::encodeNumber(int64_t num) {
}
}
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
string AstNode::nameProtect() const VL_MT_STABLE {
return VIdProtect::protectIf(name(), protect());
}
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
string AstNode::shortName() const {
@@ -155,10 +157,9 @@ string AstNode::vcdName(const string& namein) {
return prettyName(pretty);
}
string AstNode::prettyName(const string& namein) {
string AstNode::prettyName(const string& namein) VL_PURE {
// This function is somewhat hot, so we short-circuit some compares
string pretty;
pretty = "";
pretty.reserve(namein.length());
for (const char* pos = namein.c_str(); *pos;) {
if (pos[0] == '-' && pos[1] == '>') { // ->
@@ -187,11 +188,14 @@ string AstNode::prettyName(const string& namein) {
pos += 7;
continue;
}
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3])
&& isxdigit(pos[4])) {
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3])
&& std::isxdigit(pos[4])) {
char value = 0;
value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10));
value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10));
value += 16
* (std::isdigit(pos[3]) ? (pos[3] - '0')
: (std::tolower(pos[3]) - 'a' + 10));
value
+= (std::isdigit(pos[4]) ? (pos[4] - '0') : (std::tolower(pos[4]) - 'a' + 10));
pretty += value;
pos += 5;
continue;
@@ -206,7 +210,82 @@ string AstNode::prettyName(const string& namein) {
return pretty;
}
string AstNode::prettyTypeName() const {
string AstNode::vpiName(const string& namein) {
// This is slightly different from prettyName, in that when we encounter escaped characters,
// we change that identifier to an escaped identifier, wrapping it with '\' and ' '
// as specified in LRM 23.6
string pretty;
pretty.reserve(namein.length());
bool inEscapedIdent = false;
int lastIdent = 0;
for (const char* pos = namein.c_str(); *pos;) {
char specialChar = 0;
if (pos[0] == '-' && pos[1] == '>') { // ->
specialChar = '.';
pos += 2;
} else if (pos[0] == '_' && pos[1] == '_') { // __
if (0 == std::strncmp(pos, "__BRA__", 7)) {
specialChar = '[';
pos += 7;
} else if (0 == std::strncmp(pos, "__KET__", 7)) {
specialChar = ']';
pos += 7;
} else if (0 == std::strncmp(pos, "__DOT__", 7)) {
specialChar = '.';
pos += 7;
} else if (0 == std::strncmp(pos, "__PVT__", 7)) {
pos += 7;
continue;
} else if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3])
&& std::isxdigit(pos[4])) {
char value = 0;
value += 16
* (std::isdigit(pos[3]) ? (pos[3] - '0')
: (std::tolower(pos[3]) - 'a' + 10));
value
+= (std::isdigit(pos[4]) ? (pos[4] - '0') : (std::tolower(pos[4]) - 'a' + 10));
// __ doesn't always imply escaped ident
if (value != '_') inEscapedIdent = true;
pretty += value;
pos += 5;
continue;
}
} else if (pos[0] == '.') {
specialChar = '.';
++pos;
}
if (specialChar) {
if (inEscapedIdent && (specialChar == '[' || specialChar == '.')) {
pretty += " ";
pretty.insert(lastIdent, "\\");
inEscapedIdent = false;
}
pretty += specialChar;
if (specialChar == ']' || specialChar == '.') {
lastIdent = pretty.length();
inEscapedIdent = false;
}
} else {
pretty += pos[0];
++pos;
}
}
if (inEscapedIdent) {
pretty += " ";
pretty.insert(lastIdent, "\\");
}
if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
return pretty;
}
string AstNode::prettyTypeName() const VL_MT_STABLE {
if (name() == "") return typeName();
return std::string{typeName()} + " '" + prettyName() + "'";
}
@@ -219,17 +298,19 @@ void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int line
// Called on all major tree changers.
// Only for use for those really nasty bugs relating to internals
// Note this may be null.
// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
// if (debug() && nodep) cout << "-treeChange: V3Ast.cpp:" << lineno
// << " Tree Change for " << prefix << ": "
// << cvtToHex(nodep) << " <e" << AstNode::s_editCntGbl << ">"
// << "m_iterpp=" << (void*)nodep->m_iterpp << endl;
// if (debug()) {
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
// // Commenting out the section below may crash, as the tree state
// // between edits is not always consistent for printing
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
// v3Global.rootp()->dumpTree("- treeChange: ");
// if (next||1) this->dumpTreeAndNext(cout, prefix);
// else this->dumpTree(prefix);
// this->checkTree();
// if (next||1) nodep->dumpTreeAndNext(cout, prefix);
// else nodep->dumpTree(prefix);
// nodep->checkTree();
// v3Global.rootp()->checkTree();
//}
#endif
@@ -268,7 +349,8 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp) {
newtailp->m_headtailp = headp;
headp->m_headtailp = newtailp;
newp->editCountInc();
if (oldtailp->m_iterpp) *(oldtailp->m_iterpp) = newp; // Iterate on new item
// No change of m_iterpp, as only changing m_nextp of current node;
// the current node is still the one at the iteration point
}
debugTreeChange(nodep, "-addNextOut:", __LINE__, true);
return nodep;
@@ -318,7 +400,8 @@ void AstNode::addNextHere(AstNode* newp) {
} // else is head, and we're inserting into the middle, so no other change
}
if (this->m_iterpp) *(this->m_iterpp) = newp; // Iterate on new item
// No change of m_iterpp, as adding after current node;
// the current node is still the one at the iteration point
debugTreeChange(this, "-addHereOut: ", __LINE__, true);
}
@@ -486,8 +569,10 @@ AstNode* AstNode::unlinkFrBackWithNext(VNRelinker* linkerp) {
// Relink
oldp->m_backp = nullptr;
// Iterator fixup
if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr;
oldp->m_iterpp = nullptr;
if (oldp->m_iterpp) {
*(oldp->m_iterpp) = nullptr;
oldp->m_iterpp = nullptr;
}
debugTreeChange(oldp, "-unlinkWNextOut: ", __LINE__, true);
return oldp;
}
@@ -501,7 +586,11 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
linkerp->m_iterpp = oldp->m_iterpp;
if (oldp->m_iterpp) { // Assumes we will always relink() if want to keep iterating
linkerp->m_iterpp = oldp->m_iterpp;
*(oldp->m_iterpp) = nullptr;
oldp->m_iterpp = nullptr;
}
if (backp->m_nextp == oldp) {
linkerp->m_chg = VNRelinker::RELINK_NEXT;
} else if (backp->m_op1p == oldp) {
@@ -546,12 +635,15 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
}
}
// Iterator fixup
if (oldp->m_iterpp) *(oldp->m_iterpp) = oldp->m_nextp;
if (oldp->m_iterpp) { // Only if no linker, point to next in list
if (oldp->m_nextp) oldp->m_nextp->m_iterpp = oldp->m_iterpp;
*(oldp->m_iterpp) = oldp->m_nextp;
oldp->m_iterpp = nullptr;
}
// Relink
oldp->m_nextp = nullptr;
oldp->m_backp = nullptr;
oldp->m_headtailp = this;
oldp->m_iterpp = nullptr;
oldp->m_headtailp = oldp;
debugTreeChange(oldp, "-unlinkFrBkOut: ", __LINE__, true);
return oldp;
}
@@ -589,12 +681,12 @@ void AstNode::relink(VNRelinker* linkerp) {
// Iterator fixup
if (linkerp->m_iterpp) {
// If we're iterating over a next() link, we need to follow links off the
// NEW node. Thus we pass iteration information via a pointer in the node.
// NEW node, which is always assumed to be what we are relinking to.
// This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing
// across every function.
// If anyone has a cleaner way, I'd be grateful.
*(linkerp->m_iterpp) = newp;
newp->m_iterpp = linkerp->m_iterpp;
*(newp->m_iterpp) = newp;
}
// Empty the linker so not used twice accidentally
linkerp->m_backp = nullptr;
@@ -756,6 +848,7 @@ void AstNode::deleteNode() {
this->m_op2p = reinterpret_cast<AstNode*>(0x1);
this->m_op3p = reinterpret_cast<AstNode*>(0x1);
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
this->m_iterpp = reinterpret_cast<AstNode**>(0x1);
if (
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
true
@@ -830,7 +923,7 @@ void AstNode::iterateChildren(VNVisitor& v) {
if (m_op4p) m_op4p->iterateAndNext(v);
}
void AstNode::iterateChildrenConst(VNVisitor& v) {
void AstNode::iterateChildrenConst(VNVisitorConst& v) {
// This is a very hot function
ASTNODE_PREFETCH(m_op1p);
ASTNODE_PREFETCH(m_op2p);
@@ -871,13 +964,13 @@ void AstNode::iterateAndNext(VNVisitor& v) {
niterp->m_iterpp = nullptr;
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
nodep = niterp;
} else { // Unchanged node, just continue loop
} else { // Unchanged node (though maybe updated m_next), just continue loop
nodep = niterp->m_nextp;
}
}
}
void AstNode::iterateListBackwards(VNVisitor& v) {
void AstNode::iterateListBackwardsConst(VNVisitorConst& v) {
AstNode* nodep = this;
while (nodep->m_nextp) nodep = nodep->m_nextp;
while (nodep) {
@@ -891,14 +984,14 @@ void AstNode::iterateListBackwards(VNVisitor& v) {
}
}
void AstNode::iterateChildrenBackwards(VNVisitor& v) {
if (m_op1p) m_op1p->iterateListBackwards(v);
if (m_op2p) m_op2p->iterateListBackwards(v);
if (m_op3p) m_op3p->iterateListBackwards(v);
if (m_op4p) m_op4p->iterateListBackwards(v);
void AstNode::iterateChildrenBackwardsConst(VNVisitorConst& v) {
if (m_op1p) m_op1p->iterateListBackwardsConst(v);
if (m_op2p) m_op2p->iterateListBackwardsConst(v);
if (m_op3p) m_op3p->iterateListBackwardsConst(v);
if (m_op4p) m_op4p->iterateListBackwardsConst(v);
}
void AstNode::iterateAndNextConst(VNVisitor& v) {
void AstNode::iterateAndNextConst(VNVisitorConst& v) {
// Keep following the current list even if edits change it
AstNode* nodep = this;
do {
@@ -1002,7 +1095,7 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
//======================================================================
// Debugging
void AstNode::checkTreeIter(const AstNode* prevBackp) const {
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()) {
@@ -1052,7 +1145,7 @@ void AstNode::checkIter() const {
if (m_iterpp) {
dumpPtrs(cout);
// Perhaps something forgot to clear m_iterpp?
this->v3fatalSrc("Iteration link should be nullptr");
this->v3fatalSrc("Iteration link m_iterpp should be nullptr");
}
}
@@ -1186,7 +1279,17 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump)
}
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_MT_SAFE {
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;
@@ -1216,9 +1319,9 @@ string AstNode::instanceStr() const {
return "";
}
void AstNode::v3errorEnd(std::ostringstream& str) const {
void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
if (!m_fileline) {
V3Error::v3errorEnd(str, instanceStr());
V3Error::s().v3errorEnd(str, instanceStr());
} else {
std::ostringstream nsstr;
nsstr << str.str();
@@ -1231,8 +1334,8 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
// Don't look for instance name when warning is disabled.
// In case of large number of warnings, this can
// take significant amount of time
m_fileline->v3errorEnd(nsstr,
m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr());
m_fileline->v3errorEnd(
nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr());
}
}
@@ -1255,7 +1358,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) {
dtypeSetLogicUnsized(width, widthMin, numeric);
} else {
if (width == dtypep()->width() && widthMin == dtypep()->widthMin()
&& numeric == dtypep()->numeric())
&& numeric == dtypep()->numeric()
// Enums need to become direct sizes to avoid later ENUMVALUE errors
&& !VN_IS(dtypep()->skipRefToEnump(), EnumDType))
return; // Correct already
// FUTURE: We may be pointing at a two state data type, and this may
// convert it to logic. Since the AstVar remains correct, we
+124 -88
View File
@@ -102,11 +102,11 @@ public:
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const VL_MT_SAFE { return m_e; }
};
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_MT_SAFE {
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_PURE {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; }
constexpr bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; }
constexpr bool operator==(const VNType& lhs, VNType::en rhs) VL_PURE { return lhs.m_e == rhs; }
constexpr bool operator==(VNType::en lhs, const VNType& rhs) VL_PURE { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VNType& rhs) { return os << rhs.ascii(); }
// ######################################################################
@@ -371,7 +371,6 @@ public:
//
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
//
ENUM_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
ENUM_FIRST, // V3Width processes
ENUM_LAST, // V3Width processes
ENUM_NUM, // V3Width processes
@@ -380,8 +379,7 @@ public:
ENUM_NAME, // V3Width processes
ENUM_VALID, // V3Width processes
//
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
//
TYPEID, // V3Width processes
TYPENAME, // V3Width processes
//
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
@@ -407,10 +405,9 @@ public:
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
"DT_PUBLIC",
"ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
"ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID",
"MEMBER_BASE",
"TYPENAME",
"TYPEID", "TYPENAME",
"VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
@@ -473,7 +470,7 @@ public:
_ENUM_MAX
};
enum en m_e;
const char* ascii() const {
const char* ascii() const VL_MT_SAFE {
static const char* const names[] = {"%E-unk",
"bit",
"byte",
@@ -570,7 +567,8 @@ public:
}
bool isIntNumeric() const { // Enum increment supported
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64
|| m_e == TIME);
}
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
return (m_e == LOGIC || m_e == BIT);
@@ -805,6 +803,10 @@ public:
bool isTemp() const {
return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP);
}
bool isVPIAccessible() const {
return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == PORT || m_e == WIRE
|| m_e == TRI0 || m_e == TRI1);
}
};
constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) VL_MT_SAFE {
return lhs.m_e == rhs.m_e;
@@ -1095,21 +1097,21 @@ public:
}
//
VNumRange() = default;
VNumRange(int hi, int lo, bool littleEndian) { init(hi, lo, littleEndian); }
VNumRange(int hi, int lo, bool ascending) { init(hi, lo, ascending); }
VNumRange(int left, int right)
: m_left{left}
, m_right{right}
, m_ranged{true} {}
~VNumRange() = default;
// MEMBERS
void init(int hi, int lo, bool littleEndian) {
void init(int hi, int lo, bool ascending) {
if (lo > hi) {
const int t = hi;
hi = lo;
lo = t;
}
m_left = littleEndian ? lo : hi;
m_right = littleEndian ? hi : lo;
m_left = ascending ? lo : hi;
m_right = ascending ? hi : lo;
m_ranged = true;
}
int left() const { return m_left; }
@@ -1120,10 +1122,10 @@ public:
int lo() const VL_MT_SAFE {
return m_left > m_right ? m_right : m_left;
} // How to show a declaration
int leftToRightInc() const { return littleEndian() ? 1 : -1; }
int leftToRightInc() const { return ascending() ? 1 : -1; }
int elements() const VL_MT_SAFE { return hi() - lo() + 1; }
bool ranged() const { return m_ranged; }
bool littleEndian() const { return m_left < m_right; }
bool ascending() const { return m_left < m_right; }
int hiMaxSelect() const {
return (lo() < 0 ? hi() - lo() : hi());
} // Maximum value a [] select may index
@@ -1371,13 +1373,38 @@ public:
virtual ~VNDeleter() { doDeletes(); }
};
//######################################################################
// VNVisitorConst -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
// This only has the constant fuctions for non-modifying visitors.
// For more typical usage see VNVisitor
class VNVisitorConst VL_NOT_FINAL : public VNDeleter {
friend class AstNode;
public:
/// Call visit()s on nodep
inline void iterateConst(AstNode* nodep);
/// Call visit()s on nodep
inline void iterateConstNull(AstNode* nodep);
/// Call visit()s on const nodep's children
inline void iterateChildrenConst(AstNode* nodep);
/// Call visit()s on nodep's children in backp() order
inline void iterateChildrenBackwardsConst(AstNode* nodep);
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
inline void iterateAndNextConstNull(AstNode* nodep);
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
virtual void visit(AstNode* nodep) = 0;
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
};
//######################################################################
// VNVisitor -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
class VNVisitor VL_NOT_FINAL : public VNDeleter {
friend class AstNode;
class VNVisitor VL_NOT_FINAL : public VNVisitorConst {
public:
/// Call visit()s on nodep
inline void iterate(AstNode* nodep);
@@ -1385,21 +1412,10 @@ public:
inline void iterateNull(AstNode* nodep);
/// Call visit()s on nodep's children
inline void iterateChildren(AstNode* nodep);
/// Call visit()s on nodep's children in backp() order
inline void iterateChildrenBackwards(AstNode* nodep);
/// Call visit()s on const nodep's children
inline void iterateChildrenConst(AstNode* nodep);
/// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list
inline void iterateAndNextNull(AstNode* nodep);
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
inline void iterateAndNextConstNull(AstNode* nodep);
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
/// Return edited nodep; see comments in V3Ast.cpp
inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
virtual void visit(AstNode* nodep) = 0;
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
};
//######################################################################
@@ -1424,6 +1440,13 @@ protected:
public:
VNRelinker() = default;
~VNRelinker() {
// Relink is needed so m_iterpp's get restored, e.g. can't have:
// ->unlinkFrBack(relinker);
// if (only_sometimes) relinker.relink(newp);
UDEBUGONLY(
UASSERT_STATIC(!m_backp, "Active linker must be relink()ed before destruction"););
}
inline void relink(AstNode* newp);
AstNode* oldp() const { return m_oldp; }
void dump(std::ostream& str = std::cout) const;
@@ -1543,7 +1566,7 @@ class AstNode VL_NOT_FINAL {
private:
AstNode* cloneTreeIter();
AstNode* cloneTreeIterList();
void checkTreeIter(const AstNode* prevBackp) const VL_MT_SAFE;
void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE;
bool gateTreeIter() const;
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
bool gateOnly);
@@ -1599,14 +1622,14 @@ 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_SAFE { return m_nextp; }
AstNode* backp() const VL_MT_SAFE { return m_backp; }
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* op1p() const VL_MT_SAFE { return m_op1p; }
AstNode* op2p() const VL_MT_SAFE { return m_op2p; }
AstNode* op3p() const VL_MT_SAFE { return m_op3p; }
AstNode* op4p() const VL_MT_SAFE { return m_op4p; }
AstNodeDType* dtypep() const VL_MT_SAFE { return m_dtypep; }
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; }
AstNode* op4p() const VL_MT_STABLE { return m_op4p; }
AstNodeDType* dtypep() const VL_MT_STABLE { return m_dtypep; }
AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : nullptr); }
AstNode* firstAbovep() const { // Returns nullptr when second or later in list
return ((backp() && backp()->nextp() != this) ? backp() : nullptr);
@@ -1653,7 +1676,7 @@ public:
static constexpr int INSTR_COUNT_PLI = 20; // PLI routines
// ACCESSORS
virtual string name() const VL_MT_SAFE { return ""; }
virtual string name() const VL_MT_STABLE { return ""; }
virtual string origName() const { return ""; }
virtual void name(const string& name) {
this->v3fatalSrc("name() called on object without name() method");
@@ -1661,21 +1684,23 @@ public:
virtual void tag(const string& text) {}
virtual string tag() const { return ""; }
virtual string verilogKwd() const { return ""; }
string nameProtect() const VL_MT_SAFE; // Name with --protect-id applied
string nameProtect() const VL_MT_STABLE; // 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
static string prettyName(const string& namein); // Name for printing out to the user
static string prettyName(const string& namein) VL_PURE; // Name for printing out to the user
static string vpiName(const string& namein); // Name for vpi access
static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors)
return std::string{"'"} + prettyName(namein) + "'";
}
static string
encodeName(const string& namein); // Encode user name into internal C representation
// Encode user name into internal C representation
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_SAFE { return prettyName(name()); }
string prettyName() const VL_MT_STABLE { return prettyName(name()); }
string prettyNameQ() const { return prettyNameQ(name()); }
string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name)
// "VARREF" for error messages (NOT dtype's pretty name)
string prettyTypeName() const VL_MT_STABLE;
virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
FileLine* fileline() const VL_MT_SAFE { return m_fileline; }
void fileline(FileLine* fl) { m_fileline = fl; }
@@ -1694,25 +1719,25 @@ public:
void protect(bool flag) { m_flags.protect = flag; }
// TODO stomp these width functions out, and call via dtypep() instead
inline int width() const VL_MT_SAFE;
inline int width() const VL_MT_STABLE;
inline int widthMin() const;
int widthMinV() const {
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
}
int widthWords() const { return VL_WORDS_I(width()); }
bool isQuad() const VL_MT_SAFE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
bool isWide() const VL_MT_SAFE { return (width() > VL_QUADSIZE); }
inline bool isDouble() const;
inline bool isSigned() const;
inline bool isString() const;
bool isQuad() const VL_MT_STABLE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
bool isWide() const VL_MT_STABLE { return (width() > VL_QUADSIZE); }
inline bool isDouble() const VL_MT_STABLE;
inline bool isSigned() const VL_MT_STABLE;
inline bool isString() const VL_MT_STABLE;
// clang-format off
VNUser user1u() const VL_MT_SAFE {
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});
}
AstNode* user1p() const VL_MT_SAFE { return user1u().toNodep(); }
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(); }
@@ -1721,12 +1746,12 @@ public:
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_SAFE {
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});
}
AstNode* user2p() const VL_MT_SAFE { return user2u().toNodep(); }
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(); }
@@ -1735,12 +1760,12 @@ public:
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_SAFE {
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});
}
AstNode* user3p() const VL_MT_SAFE { return user3u().toNodep(); }
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(); }
@@ -1749,12 +1774,12 @@ public:
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_SAFE {
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});
}
AstNode* user4p() const VL_MT_SAFE { return user4u().toNodep(); }
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(); }
@@ -1763,12 +1788,12 @@ public:
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_SAFE {
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_SAFE { return user5u().toNodep(); }
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(); }
@@ -1852,12 +1877,15 @@ public:
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
// METHODS - dump and error
void v3errorEnd(std::ostringstream& str) const VL_MT_SAFE;
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN VL_MT_SAFE;
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex);
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
return fileline()->warnContextPrimary();
}
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
string warnMore() const { return fileline()->warnMore(); }
string warnOther() const { return fileline()->warnOther(); }
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
virtual void dump(std::ostream& str = std::cout) const;
static void dumpGdb(const AstNode* nodep); // For GDB only
@@ -1901,7 +1929,7 @@ public:
// Does tree of this == node2p?, not allowing non-isGateOptimizable
inline bool sameGateTree(const AstNode* node2p) const;
void deleteTree(); // Always deletes the next link
void checkTree() const VL_MT_SAFE {
void checkTree() const VL_MT_STABLE {
if (v3Global.opt.debugCheck()) checkTreeIter(backp());
}
void checkIter() const;
@@ -1920,6 +1948,8 @@ public:
void dumpTreeDot(std::ostream& os = std::cout) const;
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
bool isTreePureRecurse() const;
// METHODS - queries
// Changes control flow, disable some optimizations
virtual bool isBrancher() const { return false; }
@@ -1956,26 +1986,27 @@ public:
virtual const char* broken() const { return nullptr; }
// INVOKERS
virtual void accept(VNVisitor& v) = 0;
virtual void accept(VNVisitorConst& v) = 0;
protected:
// All VNVisitor related functions are called as methods off the visitor
friend class VNVisitor;
friend class VNVisitorConst;
// Use instead VNVisitor::iterateChildren
void iterateChildren(VNVisitor& v);
// Use instead VNVisitor::iterateChildrenBackwards
void iterateChildrenBackwards(VNVisitor& v);
// Use instead VNVisitor::iterateChildrenBackwardsConst
void iterateChildrenBackwardsConst(VNVisitorConst& v);
// Use instead VNVisitor::iterateChildrenConst
void iterateChildrenConst(VNVisitor& v);
void iterateChildrenConst(VNVisitorConst& v);
// Use instead VNVisitor::iterateAndNextNull
void iterateAndNext(VNVisitor& v);
// Use instead VNVisitor::iterateAndNextConstNull
void iterateAndNextConst(VNVisitor& v);
void iterateAndNextConst(VNVisitorConst& v);
// Use instead VNVisitor::iterateSubtreeReturnEdits
AstNode* iterateSubtreeReturnEdits(VNVisitor& v);
private:
void iterateListBackwards(VNVisitor& v);
void iterateListBackwardsConst(VNVisitorConst& v);
// For internal use only.
// Note: specializations for particular node types are provided by 'astgen'
@@ -1984,7 +2015,7 @@ private:
// For internal use only.
template <typename TargetType, typename DeclType>
constexpr static bool uselessCast() {
constexpr static bool uselessCast() VL_PURE {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
@@ -1993,7 +2024,7 @@ private:
// For internal use only.
template <typename TargetType, typename DeclType>
constexpr static bool impossibleCast() {
constexpr static bool impossibleCast() VL_PURE {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
@@ -2027,7 +2058,7 @@ public:
// For use via the VN_AS macro only
template <typename T, typename E>
static T* privateAs(AstNode* nodep) VL_MT_SAFE {
static T* privateAs(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,
@@ -2036,7 +2067,7 @@ public:
return reinterpret_cast<T*>(nodep);
}
template <typename T, typename E>
static const T* privateAs(const AstNode* nodep) VL_MT_SAFE {
static const T* privateAs(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.");
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
@@ -2475,24 +2506,29 @@ struct std::equal_to<VNRef<T_Node>> final {
//######################################################################
// Inline VNVisitor METHODS
void VNVisitorConst::iterateConst(AstNode* nodep) { nodep->accept(*this); }
void VNVisitorConst::iterateConstNull(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->accept(*this);
}
void VNVisitorConst::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
void VNVisitorConst::iterateChildrenBackwardsConst(AstNode* nodep) {
nodep->iterateChildrenBackwardsConst(*this);
}
void VNVisitorConst::iterateAndNextConstNullBackwards(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->iterateListBackwardsConst(*this);
}
void VNVisitorConst::iterateAndNextConstNull(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
}
void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); }
void VNVisitor::iterateNull(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->accept(*this);
}
void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); }
void VNVisitor::iterateChildrenBackwards(AstNode* nodep) {
nodep->iterateChildrenBackwards(*this);
}
void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
void VNVisitor::iterateAndNextNull(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this);
}
void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->iterateListBackwards(*this);
}
void VNVisitor::iterateAndNextConstNull(AstNode* nodep) {
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
}
AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
return nodep->iterateSubtreeReturnEdits(*this);
}
+15 -15
View File
@@ -25,7 +25,7 @@
//######################################################################
// Inline METHODS
int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; }
int AstNode::width() const VL_MT_STABLE { return dtypep() ? dtypep()->width() : 0; }
int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; }
bool AstNode::width1() const { // V3Const uses to know it can optimize
return dtypep() && dtypep()->width() == 1;
@@ -33,13 +33,13 @@ bool AstNode::width1() const { // V3Const uses to know it can optimize
int AstNode::widthInstrs() const {
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
}
bool AstNode::isDouble() const VL_MT_SAFE {
bool AstNode::isDouble() const VL_MT_STABLE {
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
}
bool AstNode::isString() const VL_MT_SAFE {
bool AstNode::isString() const VL_MT_STABLE {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
}
bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); }
bool AstNode::isZero() const {
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
@@ -61,12 +61,12 @@ bool AstNode::sameGateTree(const AstNode* node2p) const {
return sameTreeIter(this, node2p, true, true);
}
int AstNodeArrayDType::left() const VL_MT_SAFE { return rangep()->leftConst(); }
int AstNodeArrayDType::right() const VL_MT_SAFE { return rangep()->rightConst(); }
int AstNodeArrayDType::hi() const VL_MT_SAFE { return rangep()->hiConst(); }
int AstNodeArrayDType::lo() const VL_MT_SAFE { return rangep()->loConst(); }
int AstNodeArrayDType::elementsConst() const VL_MT_SAFE { return rangep()->elementsConst(); }
VNumRange AstNodeArrayDType::declRange() const VL_MT_SAFE { return VNumRange{left(), right()}; }
int AstNodeArrayDType::left() const VL_MT_STABLE { return rangep()->leftConst(); }
int AstNodeArrayDType::right() const VL_MT_STABLE { return rangep()->rightConst(); }
int AstNodeArrayDType::hi() const VL_MT_STABLE { return rangep()->hiConst(); }
int AstNodeArrayDType::lo() const VL_MT_STABLE { return rangep()->loConst(); }
int AstNodeArrayDType::elementsConst() const VL_MT_STABLE { return rangep()->elementsConst(); }
VNumRange AstNodeArrayDType::declRange() const VL_MT_STABLE { return VNumRange{left(), right()}; }
AstRange::AstRange(FileLine* fl, int left, int right)
: ASTGEN_SUPER_Range(fl) {
@@ -78,16 +78,16 @@ AstRange::AstRange(FileLine* fl, const VNumRange& range)
leftp(new AstConst{fl, static_cast<uint32_t>(range.left())});
rightp(new AstConst{fl, static_cast<uint32_t>(range.right())});
}
int AstRange::leftConst() const {
int AstRange::leftConst() const VL_MT_STABLE {
AstConst* const constp = VN_CAST(leftp(), Const);
return (constp ? constp->toSInt() : 0);
}
int AstRange::rightConst() const {
int AstRange::rightConst() const VL_MT_STABLE {
AstConst* const constp = VN_CAST(rightp(), Const);
return (constp ? constp->toSInt() : 0);
}
int AstQueueDType::boundConst() const VL_MT_SAFE {
int AstQueueDType::boundConst() const VL_MT_STABLE {
AstConst* const constp = VN_CAST(boundp(), Const);
return (constp ? constp->toSInt() : 0);
}
@@ -123,8 +123,8 @@ int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nra
int AstBasicDType::elements() const {
return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements());
}
bool AstBasicDType::littleEndian() const {
return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian());
bool AstBasicDType::ascending() const {
return (rangep() ? rangep()->ascending() : m.m_nrange.ascending());
}
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
+116 -96
View File
@@ -60,10 +60,12 @@ public:
/// are compound when methods calls operate on object, or when
/// under another compound-requiring object e.g. class
virtual bool isCompound() const = 0;
// Integral or packed, allowed inside an unpacked union/struct
virtual bool isIntegralOrPacked() const { return !isCompound(); }
// (Slow) recurse down to find basic data type
virtual AstBasicDType* basicp() const = 0;
virtual AstBasicDType* basicp() const VL_MT_STABLE = 0;
// recurses over typedefs/const/enum to next non-typeref type
virtual AstNodeDType* skipRefp() const = 0;
virtual AstNodeDType* skipRefp() const VL_MT_STABLE = 0;
// recurses over typedefs to next non-typeref-or-const type
virtual AstNodeDType* skipRefToConstp() const = 0;
// recurses over typedefs/const to next non-typeref-or-enum/struct type
@@ -84,7 +86,7 @@ public:
// Assignable equivalence. Call skipRefp() on this and samep before calling
virtual bool similarDType(const AstNodeDType* samep) const = 0;
// Iff has a non-null subDTypep(), as generic node function
virtual AstNodeDType* subDTypep() const { return nullptr; }
virtual AstNodeDType* subDTypep() const VL_MT_SAFE { return nullptr; }
virtual bool isFourstate() const;
// Ideally an IEEE $typename
virtual string prettyDTypeName() const { return prettyTypeName(); }
@@ -124,12 +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_SAFE;
bool isLiteralType() const VL_MT_SAFE; // Represents a C++ LiteralType? (can be constexpr)
string cType(const string& name, bool forFunc, bool isRef) const VL_MT_STABLE;
// Represents a C++ LiteralType? (can be constexpr)
bool isLiteralType() const VL_MT_STABLE;
private:
class CTypeRecursed;
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_SAFE;
CTypeRecursed cTypeRecurse(bool compound) const VL_MT_STABLE;
};
class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
@@ -168,29 +171,29 @@ public:
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_SAFE {
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE {
AstBasicDType* basicp() const override VL_MT_STABLE {
return subDTypep()->basicp();
} // (Slow) recurse down to find basic data type
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
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 subDTypep()->widthAlignBytes(); }
int widthTotalBytes() const override {
return elementsConst() * subDTypep()->widthTotalBytes();
}
inline int left() const;
inline int right() const;
inline int hi() const;
inline int lo() const;
inline int elementsConst() const;
inline VNumRange declRange() const;
inline int left() const VL_MT_STABLE;
inline int right() const VL_MT_STABLE;
inline int hi() const VL_MT_STABLE;
inline int lo() const VL_MT_STABLE;
inline int elementsConst() const VL_MT_STABLE;
inline VNumRange declRange() const VL_MT_STABLE;
};
class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
// A struct or union; common handling
@@ -200,6 +203,7 @@ private:
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;
const int m_uniqueNum;
bool m_packed;
@@ -228,7 +232,7 @@ public:
: VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType));
}
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
@@ -238,14 +242,14 @@ public:
bool similarDType(const AstNodeDType* samep) const override {
return this == samep; // We don't compare members, require exact equivalence
}
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& flag) override { m_name = flag; }
bool packed() const VL_MT_SAFE { return m_packed; }
void packed(bool flag) { m_packed = flag; }
// packed() but as don't support unpacked, presently all structs
static bool packedUnsup() { return true; }
void isFourstate(bool flag) { m_isFourstate = flag; }
bool isFourstate() const override { return m_isFourstate; }
bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; }
void clearCache() { m_members.clear(); }
void repairMemberCache();
AstMemberDType* findMember(const string& name) const {
@@ -255,6 +259,8 @@ public:
static int lo() { return 0; }
int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange{hi(), lo()}; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
};
// === Concrete node types =====================================================
@@ -275,7 +281,7 @@ public:
this->valuep(valuep);
}
ASTGEN_MEMBERS_AstEnumItem;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override { return true; }
bool hasDType() const override { return true; }
void name(const string& flag) override { m_name = flag; }
@@ -331,7 +337,7 @@ public:
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_SAFE {
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
@@ -340,13 +346,13 @@ public:
AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; }
void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); }
//
AstNodeDType* keyDTypep() const VL_MT_SAFE {
AstNodeDType* keyDTypep() const VL_MT_STABLE {
return m_keyDTypep ? m_keyDTypep : keyChildDTypep();
}
void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
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 subDTypep()->widthAlignBytes(); }
@@ -396,14 +402,11 @@ public:
ASTGEN_MEMBERS_AstBasicDType;
void dump(std::ostream& str) const override;
// width/widthMin/numeric compared elsewhere
bool same(const AstNode* samep) const override {
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
return m == sp->m;
}
bool same(const AstNode* samep) const override;
bool similarDType(const AstNodeDType* samep) const override {
return type() == samep->type() && same(samep);
}
string name() const override { return m.m_keyword.ascii(); }
string name() const override VL_MT_STABLE { return m.m_keyword.ascii(); }
string prettyDTypeName() const override;
const char* broken() const override {
BROKEN_RTN(dtypep() != this);
@@ -418,8 +421,8 @@ public:
}
}
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return (AstBasicDType*)this; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstBasicDType* basicp() const override VL_MT_STABLE { return (AstBasicDType*)this; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
@@ -462,14 +465,15 @@ public:
inline int hi() const;
inline int lo() const;
inline int elements() const;
int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration
int right() const { return littleEndian() ? hi() : lo(); }
inline bool littleEndian() const;
int left() const { return ascending() ? lo() : hi(); } // How to show a declaration
int right() const { return ascending() ? hi() : lo(); }
inline bool ascending() const;
bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; }
bool untyped() const { return keyword() == VBasicDTypeKwd::UNTYPED; }
VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; }
void cvtRangeConst(); // Convert to smaller representation
bool isCompound() const override { return isString(); }
bool isIntegralOrPacked() const override { return keyword().isIntNumeric(); }
};
class AstBracketArrayDType final : public AstNodeDType {
// Associative/Queue/Normal array data type, ie "[dtype_or_expr]"
@@ -485,13 +489,13 @@ public:
}
ASTGEN_MEMBERS_AstBracketArrayDType;
bool similarDType(const AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); }
AstNodeDType* subDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE { return childDTypep(); }
// METHODS
// Will be removed in V3Width, which relies on this
// being a child not a dtype pointed node
bool maybePointedTo() const override { return false; }
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
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 { V3ERROR_NA_RETURN(0); }
@@ -524,19 +528,19 @@ public:
}
void dump(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
string name() const override;
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
string name() const override VL_MT_STABLE;
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 0; }
int widthTotalBytes() const override { return 0; }
AstNodeDType* virtRefDTypep() const override { return nullptr; }
void virtRefDTypep(AstNodeDType* nodep) override {}
AstNodeDType* subDTypep() const override { return nullptr; }
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
AstClass* classp() const { return m_classp; }
AstClass* classp() const VL_MT_STABLE { return m_classp; }
void classp(AstClass* nodep) { m_classp = nodep; }
bool isCompound() const override { return true; }
};
@@ -572,13 +576,15 @@ public:
return skipRefp()->similarDType(samep->skipRefp());
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
@@ -619,18 +625,20 @@ public:
return type() == samep->type() && same(samep);
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
}
void* containerp() const { return m_containerp; }
// METHODS
// op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); }
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
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 dtypep()->widthAlignBytes(); }
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& flag) override { m_name = flag; }
bool isCompound() const override { return false; }
};
@@ -673,15 +681,15 @@ public:
string prettyDTypeName() const override;
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_SAFE {
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
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 subDTypep()->widthAlignBytes(); }
@@ -700,13 +708,13 @@ public:
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
bool undead() const override { return true; }
AstNodeDType* subDTypep() const override { return nullptr; }
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_SAFE { return nullptr; }
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
@@ -750,17 +758,19 @@ public:
}
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& flag) override { m_name = flag; }
void dump(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
@@ -812,8 +822,8 @@ public:
void dump(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
void cloneRelink() override;
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
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; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
@@ -839,6 +849,7 @@ class AstMemberDType final : public AstNodeDType {
// A member of a struct/union
// PARENT: AstNodeUOrStructDType
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op3 := valuep : Optional[AstNode]
private:
AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing)
string m_name; // Name of variable
@@ -846,10 +857,12 @@ private:
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
// UNSUP: int m_randType; // Randomization type (IEEE)
public:
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp)
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
AstNode* valuep)
: ASTGEN_SUPER_MemberDType(fl)
, m_name{name} {
childDTypep(dtp); // Only for parser
this->valuep(valuep);
dtypep(nullptr); // V3Width will resolve
refDTypep(nullptr);
}
@@ -862,7 +875,8 @@ public:
widthFromSub(subDTypep());
}
ASTGEN_MEMBERS_AstMemberDType;
string name() const override { return m_name; } // * = Var name
void dumpSmall(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
const char* broken() const override {
@@ -873,7 +887,9 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
@@ -881,10 +897,10 @@ public:
//
// (Slow) recurse down to find basic data type (Note don't need virtual -
// AstVar isn't a NodeDType)
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
// op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
@@ -921,9 +937,11 @@ public:
ASTGEN_MEMBERS_AstParamTypeDType;
void dump(std::ostream& str = std::cout) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
}
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
bool similarDType(const AstNodeDType* samep) const override {
@@ -934,7 +952,7 @@ public:
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
// METHODS
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override { return true; }
bool hasDType() const override { return true; }
void name(const string& flag) override { m_name = flag; }
@@ -957,8 +975,8 @@ public:
AstNodeDType* dtypep() const { return nullptr; }
// METHODS
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return nullptr; }
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
@@ -1012,17 +1030,17 @@ public:
void dumpSmall(std::ostream& str) const override;
string prettyDTypeName() const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_SAFE {
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
inline int boundConst() const;
inline int boundConst() const VL_MT_STABLE;
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
@@ -1072,15 +1090,15 @@ public:
}
void dump(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
string prettyDTypeName() const override {
return subDTypep() ? prettyName(subDTypep()->name()) : prettyName();
}
AstBasicDType* basicp() const override VL_MT_SAFE {
AstBasicDType* basicp() const override VL_MT_STABLE {
return subDTypep() ? subDTypep()->basicp() : nullptr;
}
AstNodeDType* subDTypep() const override;
AstNodeDType* skipRefp() const override VL_MT_SAFE {
AstNodeDType* subDTypep() const override VL_MT_STABLE;
AstNodeDType* skipRefp() const override VL_MT_STABLE {
// Skip past both the Ref and the Typedef
if (subDTypep()) {
return subDTypep()->skipRefp();
@@ -1109,9 +1127,9 @@ public:
int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); }
void name(const string& flag) override { m_name = flag; }
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
AstTypedef* typedefp() const { return m_typedefp; }
AstTypedef* typedefp() const VL_MT_SAFE { return m_typedefp; }
void typedefp(AstTypedef* nodep) { m_typedefp = nodep; }
AstNodeDType* refDTypep() const { return m_refDTypep; }
AstNodeDType* refDTypep() const VL_MT_SAFE { return m_refDTypep; }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return refDTypep(); }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
@@ -1153,13 +1171,15 @@ public:
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
// op1 = Range of variable
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
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 sizeof(std::map<std::string, std::string>); }
@@ -1191,13 +1211,15 @@ public:
bool similarDType(const AstNodeDType* samep) const override;
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
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 subDTypep()->widthAlignBytes(); }
@@ -1216,13 +1238,13 @@ public:
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
bool undead() const override { return true; }
AstNodeDType* subDTypep() const override { return nullptr; }
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_SAFE { return nullptr; }
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
@@ -1256,15 +1278,15 @@ public:
bool similarDType(const AstNodeDType* samep) const override;
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_SAFE {
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); }
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 sizeof(std::map<std::string, std::string>); }
@@ -1315,19 +1337,17 @@ public:
std::vector<AstUnpackArrayDType*> unpackDimensions();
void isCompound(bool flag) { m_isCompound = flag; }
bool isCompound() const override VL_MT_SAFE { return m_isCompound; }
bool isIntegralOrPacked() const override { return false; }
};
// === AstNodeUOrStructDType ===
class AstStructDType final : public AstNodeUOrStructDType {
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
public:
// VSigning below is mispurposed to indicate if packed or not
AstStructDType(FileLine* fl, VSigning numericUnpack)
: ASTGEN_SUPER_StructDType(fl, numericUnpack) {}
ASTGEN_MEMBERS_AstStructDType;
string verilogKwd() const override { return "struct"; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
};
class AstUnionDType final : public AstNodeUOrStructDType {
public:
+211 -34
View File
@@ -236,7 +236,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
void dump(std::ostream& str = std::cout) const override;
string name() const override { return m_name; } // * = Var name
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool isGateOptimizable() const override;
string dotted() const { return m_dotted; } // * = Scope name or ""
string inlinedDots() const { return m_inlinedDots; }
@@ -249,6 +249,7 @@ 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;
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
@@ -321,7 +322,7 @@ public:
ASTGEN_MEMBERS_AstNodeTermop;
// Know no children, and hot function, so skip iterator for speed
// cppcheck-suppress functionConst
void iterateChildren(VNVisitor& v) {}
void iterateChildren(VNVisitorConst& v) {}
void dump(std::ostream& str) const override;
};
class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
@@ -473,7 +474,7 @@ public:
const char* broken() const override;
int instrCount() const override { return widthInstrs(); }
void cloneRelink() override;
string name() const override { return m_name; } // * = Var name
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
@@ -491,7 +492,7 @@ public:
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
// Know no children, and hot function, so skip iterator for speed
// cppcheck-suppress functionConst
void iterateChildren(VNVisitor& v) {}
void iterateChildren(VNVisitorConst& v) {}
};
// === Concrete node types =====================================================
@@ -531,7 +532,7 @@ public:
}
ASTGEN_MEMBERS_AstArg;
bool hasDType() const override { return false; }
string name() const override { return m_name; } // * = Pin name, ""=go by number
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
void name(const string& name) override { m_name = name; }
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
@@ -609,7 +610,7 @@ public:
this->addPinsp(pinsp);
}
ASTGEN_MEMBERS_AstCMethodHard;
string name() const override { return m_name; } // * = Var name
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);
@@ -643,7 +644,7 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastParse final : public AstNodeExpr {
// Cast to appropriate type, where we haven't determined yet what the data type is
@@ -688,7 +689,7 @@ public:
}
ASTGEN_MEMBERS_AstCellArrayRef;
// ACCESSORS
string name() const override { return m_name; } // * = Array name
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -709,7 +710,7 @@ public:
}
ASTGEN_MEMBERS_AstCellRef;
// ACCESSORS
string name() const override { return m_name; } // * = Array name
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -745,7 +746,7 @@ public:
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
}
void dump(std::ostream& str = std::cout) const override;
string name() const override { return m_name; } // * = Var name
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
AstNodeModule* classOrPackagep() const;
@@ -790,6 +791,51 @@ public:
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstConsPackMember final : public AstNodeExpr {
// Construct a packed array single emement [member1: value1]
// Don't need the member we are constructing, as the dtypep can get us to it
// @astgen op2 := rhsp : AstNodeExpr
public:
explicit AstConsPackMember(FileLine* fl, AstMemberDType* dtypep, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ConsPackMember(fl) {
this->dtypep(dtypep);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsPackMember;
const char* broken() const override {
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), MemberDType));
return nullptr;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstConsPackUOrStruct final : public AstNodeExpr {
// Construct a packed struct and return object, '{member1: value1, member2: value2}
// Don't need the class we are constructing, as the dtypep can get us to it
// @astgen op1 := membersp : List[AstConsPackMember]
public:
explicit AstConsPackUOrStruct(FileLine* fl, AstNodeUOrStructDType* dtypep,
AstConsPackMember* membersp = nullptr)
: ASTGEN_SUPER_ConsPackUOrStruct(fl) {
this->dtypep(dtypep);
this->addMembersp(membersp);
}
ASTGEN_MEMBERS_AstConsPackUOrStruct;
const char* broken() const override {
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), NodeUOrStructDType));
return nullptr;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstConsQueue final : public AstNodeExpr {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// @astgen op1 := lhsp : Optional[AstNode]
@@ -944,7 +990,7 @@ public:
initWithNumber();
}
ASTGEN_MEMBERS_AstConst;
string name() const override { return num().ascii(); } // * = Value
string name() const override VL_MT_STABLE { return num().ascii(); } // * = Value
const V3Number& num() const VL_MT_SAFE { return m_num; } // * = Value
V3Number& num() { return m_num; } // * = Value
uint32_t toUInt() const { return num().toUInt(); }
@@ -1012,7 +1058,7 @@ public:
}
ASTGEN_MEMBERS_AstEnumItemRef;
void dump(std::ostream& str) const override;
string name() const override { return itemp()->name(); }
string name() const override VL_MT_STABLE { return itemp()->name(); }
int instrCount() const override { return 0; }
const char* broken() const override;
void cloneRelink() override {
@@ -1022,7 +1068,7 @@ public:
const AstEnumItemRef* const sp = static_cast<const AstEnumItemRef*>(samep);
return itemp() == sp->itemp();
}
AstEnumItem* itemp() const { return m_itemp; }
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
@@ -1063,9 +1109,50 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
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 same(const AstNode* /*samep*/) const override { return true; }
};
class AstFOpen final : public AstNodeExpr {
// @astgen op2 := filenamep : AstNodeExpr
// @astgen op3 := modep : AstNodeExpr
public:
AstFOpen(FileLine* fl, AstNodeExpr* filenamep, AstNodeExpr* modep)
: ASTGEN_SUPER_FOpen(fl) {
this->filenamep(filenamep);
this->modep(modep);
}
ASTGEN_MEMBERS_AstFOpen;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
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 isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstFOpenMcd final : public AstNodeExpr {
// @astgen op2 := filenamep : AstNodeExpr
public:
AstFOpenMcd(FileLine* fl, AstNodeExpr* filenamep)
: ASTGEN_SUPER_FOpenMcd(fl) {
this->filenamep(filenamep);
}
ASTGEN_MEMBERS_AstFOpenMcd;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
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 isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstFRead final : public AstNodeExpr {
// @astgen op1 := memp : AstNode // VarRef for result
// @astgen op2 := filep : AstNode // file (must be a VarRef)
@@ -1122,7 +1209,7 @@ public:
this->filep(filep);
}
ASTGEN_MEMBERS_AstFScanF;
string name() const override { return m_text; }
string name() const override VL_MT_STABLE { return m_text; }
string verilogKwd() const override { return "$fscanf"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -1183,9 +1270,10 @@ class AstFell final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstFell(FileLine* fl, AstNodeExpr* exprp)
AstFell(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Fell(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstFell;
string emitVerilog() override { return "$fell(%l)"; }
@@ -1318,7 +1406,7 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
string name() const override { return m_name; } // * = Var name
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
bool index() const { return m_index; }
};
@@ -1344,7 +1432,8 @@ public:
void cloneRelink() override;
const char* broken() const override;
void dump(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
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; }
@@ -1408,7 +1497,7 @@ public:
}
ASTGEN_MEMBERS_AstParseRef;
void dump(std::ostream& str) const override;
string name() const override { return m_name; } // * = Var name
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);
return (expect() == asamep->expect() && m_name == asamep->m_name);
@@ -1485,7 +1574,7 @@ public:
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
};
class AstRand final : public AstNodeExpr {
// $random/$random(seed) or $urandom/$urandom(seed)
@@ -1531,14 +1620,35 @@ public:
bool reset() const { return m_reset; }
bool urandom() const { return m_urandom; }
};
class AstRandRNG final : public AstNodeExpr {
// Random used in a class using VlRNG
// Return a random number, based upon width()
public:
AstRandRNG(FileLine* fl, AstNodeDType* dtp)
: ASTGEN_SUPER_RandRNG(fl) {
dtypep(dtp);
}
ASTGEN_MEMBERS_AstRandRNG;
string emitVerilog() override { return "%f$rngrandom()"; }
string emitC() override {
return isWide() ? "VL_RANDOM_RNG_%nq(__Vm_rng, %nw, %P)" //
: "VL_RANDOM_RNG_%nq(__Vm_rng)";
}
bool cleanOut() const override { return false; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstRose final : public AstNodeExpr {
// Verilog $rose
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstRose(FileLine* fl, AstNodeExpr* exprp)
AstRose(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Rose(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstRose;
string emitVerilog() override { return "$rose(%l)"; }
@@ -1581,7 +1691,7 @@ public:
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstSFormatF;
string name() const override { return m_text; }
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();
@@ -1616,7 +1726,7 @@ public:
this->fromp(fromp);
}
ASTGEN_MEMBERS_AstSScanF;
string name() const override { return m_text; }
string name() const override VL_MT_STABLE { return m_text; }
string verilogKwd() const override { return "$sscanf"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
@@ -1754,9 +1864,10 @@ class AstStable final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstStable(FileLine* fl, AstNodeExpr* exprp)
AstStable(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Stable(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstStable;
string emitVerilog() override { return "$stable(%l)"; }
@@ -1800,7 +1911,8 @@ public:
dtypep(nullptr); // V3Width will resolve
}
ASTGEN_MEMBERS_AstStructSel;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
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; }
@@ -1880,7 +1992,7 @@ public:
bool same(const AstNode* /*samep*/) const override { return true; }
bool cleanOut() const override { return true; }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
};
class AstTimePrecision final : public AstNodeExpr {
// Verilog $timeprecision
@@ -2108,7 +2220,7 @@ public:
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opCompareNN(lhs, rhs, m_ignoreCase);
}
string name() const override { return m_ignoreCase ? "icompare" : "compare"; }
string name() const override VL_MT_STABLE { return m_ignoreCase ? "icompare" : "compare"; }
string emitVerilog() override {
return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))";
}
@@ -2313,6 +2425,7 @@ public:
bool sizeMattersLhs() const override { return false; }
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
AstNode* filep() const { return lhsp(); }
AstNode* charp() const { return rhsp(); }
@@ -2331,7 +2444,7 @@ public:
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGetcN(lhs, rhs);
}
string name() const override { return "getc"; }
string name() const override VL_MT_STABLE { return "getc"; }
string emitVerilog() override { return "%k(%l.getc(%r))"; }
string emitC() override { return "VL_GETC_N(%li,%ri)"; }
string emitSimpleOperator() override { return ""; }
@@ -3304,6 +3417,30 @@ public:
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstEqT final : public AstNodeBiCom {
// Equal (==) for data types
public:
AstEqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqT(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEqT;
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
return new AstEqT{fileline(), lhsp, rhsp};
}
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
V3ERROR_NA;
}
string emitVerilog() override { return "%k(%l %f== %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
};
class AstLogEq final : public AstNodeBiCom {
public:
AstLogEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
@@ -3419,6 +3556,30 @@ public:
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstNeqT final : public AstNodeBiCom {
// Not-equal (!=) for data types
public:
AstNeqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqT(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeqT;
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
return new AstNeqT{fileline(), lhsp, rhsp};
}
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
V3ERROR_NA;
}
string emitVerilog() override { return "%k(%l %f!= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
};
// === AstNodeBiComAsv ===
class AstAdd final : public AstNodeBiComAsv {
@@ -3913,7 +4074,6 @@ public:
BROKEN_RTN(!fromp());
return nullptr;
}
void dump(std::ostream& str) const override;
};
class AstNew final : public AstNodeFTaskRef {
// New as constructor
@@ -4164,7 +4324,7 @@ public:
const V3Number& ths) override {
out.opPutcN(lhs, rhs, ths);
}
string name() const override { return "putc"; }
string name() const override VL_MT_STABLE { return "putc"; }
string emitVerilog() override { return "%k(%l.putc(%r,%t))"; }
string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; }
string emitSimpleOperator() override { return ""; }
@@ -4271,7 +4431,7 @@ public:
const V3Number& ths) override {
out.opSubstrN(lhs, rhs, ths);
}
string name() const override { return "substr"; }
string name() const override VL_MT_STABLE { return "substr"; }
string emitVerilog() override { return "%k(%l.substr(%r,%t))"; }
string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; }
string emitSimpleOperator() override { return ""; }
@@ -4348,15 +4508,15 @@ public:
}
ASTGEN_MEMBERS_AstAtoN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); }
string name() const override {
string name() const override VL_MT_STABLE {
switch (m_fmt) {
case ATOI: return "atoi";
case ATOHEX: return "atohex";
case ATOOCT: return "atooct";
case ATOBIN: return "atobin";
case ATOREAL: return "atoreal";
default: V3ERROR_NA;
}
V3ERROR_NA_RETURN("");
}
string emitVerilog() override { return "%l." + name() + "()"; }
string emitC() override {
@@ -4366,8 +4526,8 @@ public:
case ATOOCT: return "VL_ATOI_N(%li, 8)";
case ATOBIN: return "VL_ATOI_N(%li, 2)";
case ATOREAL: return "std::atof(%li.c_str())";
default: V3ERROR_NA;
}
V3ERROR_NA_RETURN("");
}
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
@@ -4495,7 +4655,7 @@ public:
dtypeSetString();
}
ASTGEN_MEMBERS_AstCvtPackString;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
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)"; }
bool cleanOut() const override { return true; }
@@ -4559,6 +4719,7 @@ public:
bool cleanLhs() const override { return true; }
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
AstNode* filep() const { return lhsp(); }
};
@@ -4575,6 +4736,7 @@ public:
bool cleanLhs() const override { return true; }
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
AstNode* filep() const { return lhsp(); }
};
@@ -4674,6 +4836,21 @@ public:
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstNToI final : public AstNodeUniop {
// String to any-size integral
public:
AstNToI(FileLine* fl, AstNodeExpr* lhsp, AstNodeDType* dtypep = nullptr)
: ASTGEN_SUPER_NToI(fl, lhsp) {
this->dtypep(dtypep);
}
ASTGEN_MEMBERS_AstNToI;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNToI(lhs); }
string emitVerilog() override { return "'(%l)"; }
string emitC() override { return "VL_NTOI_%nq(%nw, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstNegate final : public AstNodeUniop {
public:
AstNegate(FileLine* fl, AstNodeExpr* lhsp)
+95 -110
View File
@@ -48,7 +48,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeBlock;
void dump(std::ostream& str) const override;
string name() const override { return m_name; } // * = Block name
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
void name(const string& name) override { m_name = name; }
bool unnamed() const { return m_unnamed; }
bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); }
@@ -118,7 +118,7 @@ protected:
public:
ASTGEN_MEMBERS_AstNodeFTask;
void dump(std::ostream& str = std::cout) const override;
string name() const override { return m_name; } // * = Var name
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool maybePointedTo() const override { return true; }
bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); }
// {AstFunc only} op1 = Range output variable
@@ -186,7 +186,7 @@ public:
, m_name{name} {}
ASTGEN_MEMBERS_AstNodeFile;
void dump(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstNodeModule VL_NOT_FINAL : public AstNode {
@@ -210,6 +210,7 @@ private:
bool m_modTrace : 1; // Tracing this module
bool m_inLibrary : 1; // From a library, no error if not used, never top level
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
bool m_hasGParam : 1; // Has global parameter (for link)
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
bool m_internal : 1; // Internally created
bool m_recursive : 1; // Recursive module
@@ -223,6 +224,7 @@ protected:
, m_modTrace{false}
, m_inLibrary{false}
, m_dead{false}
, m_hasGParam{false}
, m_hierBlock{false}
, m_internal{false}
, m_recursive{false}
@@ -232,7 +234,7 @@ public:
ASTGEN_MEMBERS_AstNodeModule;
void dump(std::ostream& str) const override;
bool maybePointedTo() const override { return true; }
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
virtual bool timescaleMatters() const = 0;
// ACCESSORS
void name(const string& name) override { m_name = name; }
@@ -250,6 +252,8 @@ public:
bool modTrace() const { return m_modTrace; }
void dead(bool flag) { m_dead = flag; }
bool dead() const { return m_dead; }
void hasGParam(bool flag) { m_hasGParam = flag; }
bool hasGParam() const { return m_hasGParam; }
void hierBlock(bool flag) { m_hierBlock = flag; }
bool hierBlock() const { return m_hierBlock; }
void internal(bool flag) { m_internal = flag; }
@@ -369,7 +373,7 @@ public:
this->addPasssp(passsp);
}
ASTGEN_MEMBERS_AstNodeCoverOrAssert;
string name() const override { return m_name; } // * = Var name
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool same(const AstNode* samep) const override { return samep->name() == name(); }
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str = std::cout) const override;
@@ -508,7 +512,7 @@ public:
}
ASTGEN_MEMBERS_AstActive;
void dump(std::ostream& str = std::cout) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
const char* broken() const override;
void cloneRelink() override;
// Statements are broken into pieces, as some must come before others.
@@ -533,7 +537,7 @@ public:
}
ASTGEN_MEMBERS_AstBind;
// ACCESSORS
string name() const override { return m_name; } // * = Bind Target name
string name() const override VL_MT_STABLE { return m_name; } // * = Bind Target name
void name(const string& name) override { m_name = name; }
};
class AstCFunc final : public AstNode {
@@ -603,7 +607,7 @@ public:
m_dpiTraceInit = false;
}
ASTGEN_MEMBERS_AstCFunc;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
const char* broken() const override;
void cloneRelink() override;
bool maybePointedTo() const override { return true; }
@@ -698,7 +702,7 @@ public:
, m_useType{useType} {}
ASTGEN_MEMBERS_AstCUse;
void dump(std::ostream& str = std::cout) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
VUseType useType() const { return m_useType; }
};
class AstCaseItem final : public AstNode {
@@ -751,7 +755,7 @@ public:
const char* broken() const override;
bool maybePointedTo() const override { return true; }
// ACCESSORS
string name() const override { return m_name; } // * = Cell name
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
void name(const string& name) override { m_name = name; }
string origName() const override { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; }
@@ -790,7 +794,7 @@ public:
void dump(std::ostream& str) const override;
const char* broken() const override;
// ACCESSORS
string name() const override { return m_name; } // * = Cell name
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
void name(const string& name) override { m_name = name; }
void scopep(AstScope* scp) { m_scopep = scp; }
@@ -799,19 +803,24 @@ public:
VTimescale timeunit() const { return m_timeunit; }
};
class AstClassExtends final : public AstNode {
// class extends class name, or class implements class name
// Children: List of AstParseRef for packages/classes
// during early parse, then moves to dtype
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := classOrPkgsp : Optional[AstNode]
const bool m_isImplements = false; // class implements
public:
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp)
: ASTGEN_SUPER_ClassExtends(fl) {
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements)
: ASTGEN_SUPER_ClassExtends(fl)
, m_isImplements{isImplements} {
this->classOrPkgsp(classOrPkgsp); // Only for parser
}
ASTGEN_MEMBERS_AstClassExtends;
void dump(std::ostream& str) const override;
bool hasDType() const override { return true; }
string verilogKwd() const override { return "extends"; }
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
AstClass* classp() const; // Class being extended (after link)
bool isImplements() const { return m_isImplements; }
};
class AstClocking final : public AstNode {
// Parents: MODULE
@@ -822,19 +831,23 @@ class AstClocking final : public AstNode {
// @astgen op4 := eventp : Optional[AstVar]
std::string m_name; // Clocking block name
const bool m_isDefault = false; // True if default clocking
const bool m_isGlobal = false; // True if global clocking
public:
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
AstClockingItem* itemsp, bool isDefault)
AstClockingItem* itemsp, bool isDefault, bool isGlobal)
: ASTGEN_SUPER_Clocking(fl)
, m_isDefault{isDefault} {
, m_isDefault{isDefault}
, m_isGlobal{isGlobal} {
m_name = name;
this->sensesp(sensesp);
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstClocking;
std::string name() const override { return m_name; }
void dump(std::ostream& str) const override;
std::string name() const override VL_MT_STABLE { return m_name; }
bool isDefault() const { return m_isDefault; }
bool isGlobal() const { return m_isGlobal; }
};
class AstClockingItem final : public AstNode {
// Parents: CLOCKING
@@ -850,8 +863,8 @@ public:
: ASTGEN_SUPER_ClockingItem(fl) {
m_direction = direction;
this->skewp(skewp);
if (AstAssign* const assignp = VN_CAST(clockingDeclp, Assign)) {
this->assignp(assignp);
if (AstAssign* const clkAssignp = VN_CAST(clockingDeclp, Assign)) {
this->assignp(clkAssignp);
} else {
exprp(VN_AS(clockingDeclp, NodeExpr));
}
@@ -903,7 +916,7 @@ public:
, m_path{path} {
this->rhsp(rhsp);
}
string name() const override { return m_name; } // * = Scope name
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
ASTGEN_MEMBERS_AstDefParam;
bool same(const AstNode*) const override { return true; }
string path() const { return m_path; }
@@ -921,7 +934,7 @@ public:
, m_name{vname}
, m_cname{cname} {}
ASTGEN_MEMBERS_AstDpiExport;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& name) override { m_name = name; }
string cname() const { return m_cname; }
void cname(const string& cname) { m_cname = cname; }
@@ -939,7 +952,7 @@ public:
BROKEN_RTN(!fmtp());
return nullptr;
}
string verilogKwd() const override { return (string("$") + string(displayType().ascii())); }
string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
@@ -982,7 +995,7 @@ public:
BROKEN_RTN(!m_depGraphp);
return nullptr;
}
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
V3Graph* depGraphp() { return m_depGraphp; }
const V3Graph* depGraphp() const { return m_depGraphp; }
};
@@ -1020,7 +1033,7 @@ public:
AstIntfRef(FileLine* fl, const string& name)
: ASTGEN_SUPER_IntfRef(fl)
, m_name{name} {}
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
ASTGEN_MEMBERS_AstIntfRef;
};
class AstMTaskBody final : public AstNode {
@@ -1057,7 +1070,7 @@ public:
, m_name{name} {
this->addVarsp(varsp);
}
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override { return true; }
ASTGEN_MEMBERS_AstModport;
};
@@ -1079,7 +1092,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
void dump(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool isImport() const { return !m_export; }
bool isExport() const { return m_export; }
AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable
@@ -1102,7 +1115,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
void dump(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
void direction(const VDirection& flag) { m_direction = flag; }
VDirection direction() const { return m_direction; }
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
@@ -1136,9 +1149,9 @@ public:
ASTGEN_MEMBERS_AstNetlist;
const char* broken() const override;
void cloneRelink() override { V3ERROR_NA; }
string name() const override { return "$root"; }
string name() const override VL_MT_STABLE { return "$root"; }
void dump(std::ostream& str) const override;
AstNodeModule* topModulep() const { // Top module in hierarchy
AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy
return modulesp(); // First one in the list, for now
}
AstTypeTable* typeTablep() { return m_typeTablep; }
@@ -1185,7 +1198,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
void dump(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
};
@@ -1211,7 +1224,7 @@ public:
const char* broken() const override;
void cloneRelink() override;
void dump(std::ostream& str) const override;
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
};
@@ -1224,7 +1237,8 @@ private:
AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule.
AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule.
bool m_param = false; // Pin connects to parameter
bool m_svImplicit = false; // Pin is SystemVerilog .name'ed
bool m_svDotName = false; // Pin is SystemVerilog .name'ed
bool m_svImplicit = false; // Pin is SystemVerilog .name'ed, allow implicit
public:
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
: ASTGEN_SUPER_Pin(fl)
@@ -1236,7 +1250,7 @@ public:
ASTGEN_MEMBERS_AstPin;
void dump(std::ostream& str) const override;
const char* broken() const override;
string name() const override { return m_name; } // * = Pin name, ""=go by number
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
void name(const string& name) override { m_name = name; }
string prettyOperatorName() const override;
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
@@ -1248,6 +1262,8 @@ public:
void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; }
bool param() const { return m_param; }
void param(bool flag) { m_param = flag; }
bool svDotName() const { return m_svDotName; }
void svDotName(bool flag) { m_svDotName = flag; }
bool svImplicit() const { return m_svImplicit; }
void svImplicit(bool flag) { m_svImplicit = flag; }
};
@@ -1262,7 +1278,7 @@ public:
, m_pinNum{pinnum}
, m_name{name} {}
ASTGEN_MEMBERS_AstPort;
string name() const override { return m_name; } // * = Port name
string name() const override VL_MT_STABLE { return m_name; } // * = Port name
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
};
class AstPragma final : public AstNode {
@@ -1340,11 +1356,11 @@ public:
void cloneRelink() override;
const char* broken() const override;
bool maybePointedTo() const override { return true; }
string name() const override { return m_name; } // * = Scope name
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str) const override;
string nameDotless() const;
string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); }
string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); }
AstNodeModule* modp() const { return m_modp; }
//
AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; }
@@ -1528,9 +1544,11 @@ public:
ASTGEN_MEMBERS_AstTypedef;
void dump(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
}
// METHODS
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override { return true; }
bool hasDType() const override { return true; }
void name(const string& flag) override { m_name = flag; }
@@ -1550,7 +1568,7 @@ public:
, m_name{name} {}
ASTGEN_MEMBERS_AstTypedefFwd;
// METHODS
string name() const override { return m_name; }
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override { return true; }
};
class AstUdpTable final : public AstNode {
@@ -1570,7 +1588,7 @@ public:
: ASTGEN_SUPER_UdpTableLine(fl)
, m_text{text} {}
ASTGEN_MEMBERS_AstUdpTableLine;
string name() const override { return m_text; }
string name() const override VL_MT_STABLE { return m_text; }
string text() const { return m_text; }
};
class AstVar final : public AstNode {
@@ -1740,7 +1758,7 @@ public:
}
ASTGEN_MEMBERS_AstVar;
void dump(std::ostream& str) const override;
string name() const override VL_MT_SAFE { return m_name; } // * = Var name
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
string origName() const override { return m_origName; } // * = Original name
@@ -1771,17 +1789,17 @@ public:
string dpiTmpVarType(const string& varName) const;
// Return Verilator internal type for argument: CData, SData, IData, WData
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "",
bool asRef = false) const VL_MT_SAFE;
bool asRef = false) const VL_MT_STABLE;
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration
void combineType(VVarType type);
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* dtypeSkipRefp() const VL_MT_SAFE { return subDTypep()->skipRefp(); }
AstNodeDType* dtypeSkipRefp() const VL_MT_STABLE { return subDTypep()->skipRefp(); }
// (Slow) recurse down to find basic data type (Note don't need virtual -
// AstVar isn't a NodeDType)
AstBasicDType* basicp() const VL_MT_SAFE { return subDTypep()->basicp(); }
virtual AstNodeDType* subDTypep() const VL_MT_SAFE {
AstBasicDType* basicp() const VL_MT_STABLE { return subDTypep()->basicp(); }
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
}
void ansi(bool flag) { m_ansi = flag; }
@@ -1980,11 +1998,11 @@ public:
return nullptr;
}
bool maybePointedTo() const override { return true; }
string name() const override { return scopep()->name() + "->" + varp()->name(); }
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
void dump(std::ostream& str) const override;
bool hasDType() const override { return true; }
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
void scopep(AstScope* nodep) { m_scopep = nodep; }
bool isTrace() const { return m_trace; }
void trace(bool flag) { m_trace = flag; }
@@ -2090,14 +2108,17 @@ public:
// === AstNodeModule ===
class AstClass final : public AstNodeModule {
// @astgen op4 := extendsp : Optional[AstClassExtends]
// @astgen op4 := extendsp : List[AstClassExtends]
// TYPES
using MemberNameMap = std::map<const std::string, AstNode*>;
// MEMBERS
MemberNameMap m_members; // Members or method children
AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under
bool m_virtual = false; // Virtual class
bool m_extended = false; // Is extension or extended by other classes
bool m_interfaceClass = false; // Interface class
bool m_needRNG = false; // Need RNG, uses srandom/randomize
bool m_virtual = false; // Virtual class
bool m_parameterized = false; // Parameterized class
void insertCache(AstNode* nodep);
public:
@@ -2125,11 +2146,19 @@ public:
}
bool isExtended() const { return m_extended; }
void isExtended(bool flag) { m_extended = flag; }
bool isInterfaceClass() const { return m_interfaceClass; }
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; }
bool needRNG() const { return m_needRNG; }
void needRNG(bool flag) { m_needRNG = flag; }
bool isParameterized() const { return m_parameterized; }
void isParameterized(bool flag) { m_parameterized = flag; }
// Return true if this class is an extension of base class (SLOW)
// Accepts nullptrs
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
// Return the lowest class extended from, or this class
AstClass* baseMostClassp();
};
class AstClassPackage final : public AstNodeModule {
// The static information portion of a class (treated similarly to a package)
@@ -2315,20 +2344,20 @@ public:
inline AstRange(FileLine* fl, int left, int right);
inline AstRange(FileLine* fl, const VNumRange& range);
ASTGEN_MEMBERS_AstRange;
inline int leftConst() const VL_MT_SAFE;
inline int rightConst() const VL_MT_SAFE;
int hiConst() const VL_MT_SAFE {
inline int leftConst() const VL_MT_STABLE;
inline int rightConst() const VL_MT_STABLE;
int hiConst() const VL_MT_STABLE {
const int l = leftConst();
const int r = rightConst();
return l > r ? l : r;
}
int loConst() const VL_MT_SAFE {
int loConst() const VL_MT_STABLE {
const int l = leftConst();
const int r = rightConst();
return l > r ? r : l;
}
int elementsConst() const VL_MT_SAFE { return hiConst() - loConst() + 1; }
bool littleEndian() const { return leftConst() < rightConst(); }
int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; }
bool ascending() const { return leftConst() < rightConst(); }
void dump(std::ostream& str) const override;
virtual string emitC() { V3ERROR_NA_RETURN(""); }
bool same(const AstNode* /*samep*/) const override { return true; }
@@ -2431,7 +2460,7 @@ public:
, m_name{name}
, m_showAt{showAt} {}
ASTGEN_MEMBERS_AstComment;
string name() const override { return m_name; } // * = Text
string name() const override VL_MT_STABLE { return m_name; } // * = Text
bool same(const AstNode* samep) const override { return true; } // Ignore name in comments
virtual bool showAt() const { return m_showAt; }
};
@@ -2572,7 +2601,7 @@ public:
: ASTGEN_SUPER_Disable(fl)
, m_name{name} {}
ASTGEN_MEMBERS_AstDisable;
string name() const override { return m_name; } // * = Block name
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
void name(const string& flag) override { m_name = flag; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
@@ -2614,8 +2643,8 @@ public:
return nullptr;
}
string verilogKwd() const override {
return (filep() ? string("$f") + string(displayType().ascii())
: string("$") + string(displayType().ascii()));
return (filep() ? string{"$f"} + string{displayType().ascii()}
: string{"$"} + string{displayType().ascii()});
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
@@ -2632,17 +2661,13 @@ public:
bool addNewline() const { return displayType().addNewline(); }
};
class AstDoWhile final : public AstNodeStmt {
// @astgen op1 := precondsp : List[AstNode]
// @astgen op2 := condp : AstNodeExpr
// @astgen op3 := stmtsp : List[AstNode]
// @astgen op4 := incsp : List[AstNode]
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := stmtsp : List[AstNode]
public:
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr,
AstNode* incsp = nullptr)
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr)
: ASTGEN_SUPER_DoWhile(fl) {
condp(conditionp);
addStmtsp(stmtsp);
addIncsp(incsp);
}
ASTGEN_MEMBERS_AstDoWhile;
bool isGateOptimizable() const override { return false; }
@@ -2720,46 +2745,6 @@ public:
bool isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstFOpen final : public AstNodeStmt {
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
// @astgen op1 := filep : AstNodeExpr
// @astgen op2 := filenamep : AstNodeExpr
// @astgen op3 := modep : AstNodeExpr
public:
AstFOpen(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep, AstNodeExpr* modep)
: ASTGEN_SUPER_FOpen(fl) {
this->filep(filep);
this->filenamep(filenamep);
this->modep(modep);
}
ASTGEN_MEMBERS_AstFOpen;
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 isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstFOpenMcd final : public AstNodeStmt {
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
// @astgen op1 := filep : AstNodeExpr
// @astgen op2 := filenamep : AstNodeExpr
public:
AstFOpenMcd(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep)
: ASTGEN_SUPER_FOpenMcd(fl) {
this->filep(filep);
this->filenamep(filenamep);
}
ASTGEN_MEMBERS_AstFOpenMcd;
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 isUnlikely() const override { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstFinish final : public AstNodeStmt {
public:
explicit AstFinish(FileLine* fl)
@@ -2802,7 +2787,7 @@ public:
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstJumpBlock final : public AstNodeStmt {
// Block of code including a JumpGo and JumpLabel
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
// Parents: {statement list}
// Children: {statement list, with JumpGo and JumpLabel below}
// @astgen op1 := stmtsp : List[AstNode]
@@ -2907,7 +2892,7 @@ public:
: ASTGEN_SUPER_PrintTimeScale(fl) {}
ASTGEN_MEMBERS_AstPrintTimeScale;
void name(const string& name) override { m_name = name; }
string name() const override { return m_name; } // * = Var name
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void dump(std::ostream& str) const override;
string verilogKwd() const override { return "$printtimescale"; }
bool isGateOptimizable() const override { return false; }
@@ -3126,7 +3111,7 @@ public:
void dump(std::ostream& str) const override;
int instrCount() const override { return 100; } // Large...
ASTGEN_MEMBERS_AstTraceDecl;
string name() const override { return m_showname; }
string name() const override VL_MT_STABLE { return m_showname; }
bool maybePointedTo() const override { return true; }
bool hasDType() const override { return true; }
bool same(const AstNode* samep) const override { return false; }
+59 -30
View File
@@ -60,6 +60,12 @@ 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::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
const char* AstNodeVarRef::broken() const {
@@ -109,6 +115,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
}
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);
@@ -226,6 +233,15 @@ 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());
}
}
int AstNodeUOrStructDType::widthTotalBytes() const {
if (width() <= 8) {
return 1;
@@ -381,7 +397,7 @@ string AstVar::verilogKwd() const {
}
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
bool asRef) const VL_MT_SAFE {
bool asRef) const VL_MT_STABLE {
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string ostatic;
@@ -567,7 +583,7 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
} else {
class converter final : public dpiTypesToStringConverter {
string bitLogicVector(const AstVar* varp, bool isBit) const override {
return string(varp->isReadOnly() ? "const " : "")
return string{varp->isReadOnly() ? "const " : ""}
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
}
string primitive(const AstVar* varp) const override {
@@ -630,13 +646,13 @@ string AstVar::dpiTmpVarType(const string& varName) const {
string AstVar::scType() const {
if (isScBigUint()) {
return (string("sc_biguint<") + cvtToStr(widthMin())
return (string{"sc_biguint<"} + cvtToStr(widthMin())
+ "> "); // Keep the space so don't get >>
} else if (isScUint()) {
return (string("sc_uint<") + cvtToStr(widthMin())
return (string{"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_bv<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
} else if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_IDATASIZE) {
@@ -675,7 +691,7 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
return nullptr;
}
bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
bool AstNodeDType::isFourstate() const { return basicp() && basicp()->isFourstate(); }
class AstNodeDType::CTypeRecursed final {
public:
@@ -698,12 +714,12 @@ public:
}
};
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_SAFE {
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_STABLE {
const CTypeRecursed info = cTypeRecurse(false);
return info.render(name, isRef);
}
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_MT_STABLE {
// Legacy compound argument currently just passed through and unused
CTypeRecursed info;
@@ -728,18 +744,18 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlSampleQueue<" + sub.m_type + ">";
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
info.m_type = "VlClassRef<" + EmitCBase::prefixNameProtect(adtypep) + ">";
} else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) {
info.m_type = EmitCBaseVisitor::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
info.m_type = EmitCBase::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (adtypep->isCompound()) compound = true;
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
info.m_type = "VlUnpacked<" + sub.m_type;
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
info.m_type += ">";
} else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, StructDType);
info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep);
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
info.m_type = EmitCBase::prefixNameProtect(sdtypep);
} else if (const AstBasicDType* const bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
@@ -840,7 +856,7 @@ int AstNodeDType::widthPow2() const {
return 1;
}
bool AstNodeDType::isLiteralType() const VL_MT_SAFE {
bool AstNodeDType::isLiteralType() const VL_MT_STABLE {
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
return dtypep->keyword().isLiteralType();
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
@@ -869,7 +885,7 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
continue;
}
// AstNodeSelPre stashes the associated variable under an ATTROF
// of VAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
// of VAttrType::VAR_BASE so it isn't constified
else if (VN_IS(nodep, AttrOf)) {
nodep = VN_AS(nodep, AttrOf)->fromp();
continue;
@@ -910,10 +926,10 @@ void AstScope::cloneRelink() {
}
}
string AstScope::nameDotless() const {
string out = shortName();
string result = shortName();
string::size_type pos;
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
return out;
while ((pos = result.find('.')) != string::npos) result.replace(pos, 1, "__");
return result;
}
AstVarScope* AstScope::createTemp(const string& name, unsigned width) {
@@ -1448,6 +1464,13 @@ void AstClass::repairCache() {
}
}
}
AstClass* AstClass::baseMostClassp() {
AstClass* basep = this;
while (basep->extendsp() && basep->extendsp()->classp()) {
basep = basep->extendsp()->classp();
}
return basep;
}
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
// TAIL RECURSIVE
if (!refClassp || !baseClassp) return false;
@@ -1458,6 +1481,7 @@ bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* ba
void AstClass::dump(std::ostream& str) const {
this->AstNodeModule::dump(str);
if (isExtended()) str << " [EXT]";
if (isInterfaceClass()) str << " [IFCCLS]";
if (isVirtual()) str << " [VIRT]";
}
const char* AstClass::broken() const {
@@ -1471,6 +1495,10 @@ void AstClass::cloneRelink() {
m_classOrPackagep = m_classOrPackagep->clonep();
}
}
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.'
@@ -1509,6 +1537,11 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
if (immediate()) str << " [IMMEDIATE]";
}
void AstClocking::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isDefault()) str << " [DEFAULT]";
if (isGlobal()) str << " [GLOBAL]";
}
void AstDisplay::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
// str << " " << displayType().ascii();
@@ -1636,6 +1669,10 @@ 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";
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
str << " -> ";
@@ -1652,15 +1689,6 @@ const char* AstMemberSel::broken() const {
BROKEN_RTN(m_varp && !m_varp->brokeExists());
return nullptr;
}
void AstMethodCall::dump(std::ostream& str) const {
this->AstNodeFTaskRef::dump(str);
str << " -> ";
if (taskp()) {
taskp()->dump(str);
} else {
str << " -> UNLINKED";
}
}
void AstModportFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isExport()) str << " EXPORT";
@@ -1704,6 +1732,7 @@ void AstPin::dump(std::ostream& str) const {
} else {
str << " ->UNLINKED";
}
if (svDotName()) str << " [.n]";
if (svImplicit()) str << " [.SV]";
}
const char* AstPin::broken() const {
@@ -1746,7 +1775,7 @@ void AstTypedef::dump(std::ostream& str) const {
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstRange::dump(std::ostream& str) const {
this->AstNodeRange::dump(str);
if (littleEndian()) str << " [LITTLE]";
if (ascending()) str << " [ASCENDING]";
}
void AstParamTypeDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
@@ -1792,7 +1821,7 @@ void AstRefDType::cloneRelink() {
m_classOrPackagep = m_classOrPackagep->clonep();
}
}
AstNodeDType* AstRefDType::subDTypep() const {
AstNodeDType* AstRefDType::subDTypep() const VL_MT_STABLE {
if (typedefp()) return typedefp()->subDTypep();
return refDTypep(); // Maybe nullptr
}
@@ -2292,7 +2321,7 @@ 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.
if (basicp->isTriggerVec() && m_name == "at") {
if (basicp->isTriggerVec() && m_name == "word") {
// This is an important special case for scheduling so we compute it precisely,
// it is simply a load.
return INSTR_COUNT_LD;
+46 -4
View File
@@ -19,6 +19,7 @@
// Look for BEGINs
// BEGIN(VAR...) -> VAR ... {renamed}
// FOR -> WHILEs
// Move static function variables and their AstInitialStatic blocks before a function
//
// There are two scopes; named BEGINs change %m and variable scopes.
// Unnamed BEGINs change only variable, not $display("%m") scope.
@@ -64,13 +65,14 @@ private:
// STATE
BeginState* const m_statep; // Current global state
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
string m_displayScope; // Name of %m in $display/AstScopeName
string m_namedScope; // Name of begin blocks above us
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
@@ -121,11 +123,41 @@ 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 this begin to group its statements together
// Keep begins in forks to group their statements together
VL_RESTORER(m_keepBegins);
m_keepBegins = true;
// If a statement is not a begin, wrap it in a begin. This fixes an issue when the
// statement is a task call that gets inlined later (or any other statement that gets
// replaced with multiple statements)
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (!VN_IS(stmtp, Begin)) {
AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr};
stmtp->replaceWith(beginp);
beginp->addStmtsp(stmtp);
stmtp = beginp;
}
}
dotNames(nodep, "__FORK__");
nodep->name("");
}
@@ -165,6 +197,7 @@ private:
m_ftaskp = nodep;
m_liftedp = nullptr;
iterateChildren(nodep);
renameAndStaticsRecurse(nodep);
if (m_liftedp) {
// Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced
if (AstNode* const stmtsp = nodep->stmtsp()) {
@@ -174,6 +207,7 @@ private:
nodep->addStmtsp(m_liftedp);
m_liftedp = nullptr;
}
m_staticFuncVars.clear();
m_ftaskp = nullptr;
}
}
@@ -210,7 +244,15 @@ private:
}
}
void visit(AstVar* nodep) override {
if (m_unnamedScope != "") {
// If static variable, move it outside a function.
if (nodep->lifetime().isStatic() && m_ftaskp) {
const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name();
nodep->name(newName);
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
m_staticFuncVars.insert(nodep);
nodep->funcLocal(false);
} else if (m_unnamedScope != "") {
// Rename it
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
@@ -257,7 +299,7 @@ private:
// To keep correct visual order, must add before other Text's
AstText* const afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->addScopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
nodep->addScopeAttrp(new AstText{nodep->fileline(), string{"__DOT__"} + scname});
if (afterp) nodep->addScopeAttrp(afterp);
}
iterateChildren(nodep);
+7 -7
View File
@@ -38,7 +38,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// Branch state, as a visitor of each AstNode
class BranchVisitor final : public VNVisitor {
class BranchVisitor final : public VNVisitorConst {
private:
// NODE STATE
// Entire netlist:
@@ -71,12 +71,12 @@ private:
{
// Do if
reset();
iterateAndNextNull(nodep->thensp());
iterateAndNextConstNull(nodep->thensp());
const int ifLikely = m_likely;
const int ifUnlikely = m_unlikely;
// Do else
reset();
iterateAndNextNull(nodep->elsesp());
iterateAndNextConstNull(nodep->elsesp());
const int elseLikely = m_likely;
const int elseUnlikely = m_unlikely;
// Compute
@@ -91,16 +91,16 @@ private:
void visit(AstNodeCCall* nodep) override {
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstCFunc* nodep) override {
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstNode* nodep) override {
checkUnlikely(nodep);
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
// METHODS
@@ -114,7 +114,7 @@ public:
// CONSTRUCTORS
explicit BranchVisitor(AstNetlist* nodep) {
reset();
iterateChildren(nodep);
iterateChildrenConst(nodep);
calc_tasks();
}
~BranchVisitor() override = default;
+7 -2
View File
@@ -62,6 +62,8 @@ public:
}
} s_brokenCntGlobal;
static bool s_brokenAllowMidvisitorCheck = false;
//######################################################################
// Table of allocated AstNode pointers
@@ -144,7 +146,7 @@ bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinka
//######################################################################
// Check every node in tree
class BrokenCheckVisitor final : public VNVisitor {
class BrokenCheckVisitor final : public VNVisitorConst {
bool m_inScope = false; // Under AstScope
// Constants for marking we are under/not under a node
@@ -172,6 +174,7 @@ private:
const char* const whyp = nodep->broken();
UASSERT_OBJ(!whyp, nodep,
"Broken link in node (or something without maybePointedTo): " << whyp);
if (!s_brokenAllowMidvisitorCheck) nodep->checkIter();
if (nodep->dtypep()) {
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
@@ -312,7 +315,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterateConstNull(nodep); }
~BrokenCheckVisitor() override = default;
};
@@ -351,6 +354,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
}
}
void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck = flag; }
//######################################################################
// Self test
+3
View File
@@ -32,6 +32,9 @@ public:
static bool isLinkable(const AstNode* nodep);
static void addNewed(const AstNode* nodep);
static void deleted(const AstNode* nodep);
// Called on error to say may be inside visitor,
// Disables checks that may misfire if not called at stable point between visitors
static void allowMidvisitorCheck(bool flag);
static void selfTest();
};
+6 -2
View File
@@ -70,7 +70,7 @@ private:
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
string preventUnusedStmt;
if (m_type.isClass()) {
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->argTypes(EmitCBase::symClassVar());
preventUnusedStmt = "if (false && vlSymsp) {} // Prevent unused\n";
} else if (m_type.isCoverage()) {
funcp->argTypes("bool first");
@@ -148,6 +148,7 @@ private:
m_modp = nodep;
V3CCtorsBuilder var_reset{nodep, "_ctor_var_reset",
VN_IS(nodep, Class) ? VCtorType::CLASS : VCtorType::MODULE};
// cppcheck-suppress danglingLifetime
m_varResetp = &var_reset;
iterateChildren(nodep);
@@ -155,6 +156,9 @@ private:
V3CCtorsBuilder configure_coverage{nodep, "_configure_coverage", VCtorType::COVERAGE};
for (AstNode* np = nodep->stmtsp(); np; np = np->nextp()) {
if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) {
// ... else we don't have a static VlSym to be able to coverage insert
UASSERT_OBJ(!VN_IS(nodep, Class), coverp,
"CoverDecl should be in class's package, not class itself");
np = coverp->backp();
configure_coverage.add(coverp->unlinkFrBack());
}
@@ -198,7 +202,7 @@ private:
public:
// CONSTRUCTORS
CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
explicit CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
~CCtorsVisitor() override = default;
};
+1 -1
View File
@@ -75,7 +75,7 @@ class CUseVisitor final : public VNVisitor {
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
// Add a CUse for every struct that requires a declaration
AstStructDType* const stypep = VN_CAST(nodep->skipRefp(), StructDType);
AstNodeUOrStructDType* const stypep = VN_CAST(nodep->skipRefp(), NodeUOrStructDType);
if (stypep && stypep->classOrPackagep()) {
addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name());
iterateChildren(stypep);
+5 -5
View File
@@ -53,7 +53,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
class CaseLintVisitor final : public VNVisitor {
class CaseLintVisitor final : public VNVisitorConst {
private:
const AstNodeCase* m_caseExprp
= nullptr; // Under a CASE value node, if so the relevant case statement
@@ -79,10 +79,10 @@ private:
// Check for X/Z in non-casex statements
{
m_caseExprp = nodep;
iterate(nodep->exprp());
iterateConst(nodep->exprp());
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) {
iterateAndNextNull(itemp->condsp());
iterateAndNextConstNull(itemp->condsp());
}
m_caseExprp = nullptr;
}
@@ -108,11 +108,11 @@ private:
}
}
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public:
// CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); }
explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); }
~CaseLintVisitor() override = default;
};
-765
View File
@@ -1,765 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Clock Domain Crossing Lint
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-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
//
//*************************************************************************
// V3Cdc's Transformations:
//
// Create V3Graph-ish graph
// Find all negedge reset flops
// Trace back to previous flop
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3Cdc.h"
#include "V3Ast.h"
#include "V3Const.h"
#include "V3EmitV.h"
#include "V3File.h"
#include "V3Global.h"
#include "V3Graph.h"
#include <algorithm>
#include <deque>
#include <iomanip>
#include <memory>
VL_DEFINE_DEBUG_FUNCTIONS;
constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic
//######################################################################
class CdcBaseVisitor VL_NOT_FINAL : public VNVisitor {
public:
};
//######################################################################
// Graph support classes
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
AstScope* const m_scopep;
AstNode* const m_nodep;
AstSenTree* m_srcDomainp = nullptr;
AstSenTree* m_dstDomainp = nullptr;
bool m_srcDomainSet : 1;
bool m_dstDomainSet : 1;
bool m_asyncPath : 1;
public:
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
: V3GraphVertex{graphp}
, m_scopep{scopep}
, m_nodep{nodep}
, m_srcDomainSet{false}
, m_dstDomainSet{false}
, m_asyncPath{false} {}
~CdcEitherVertex() override = default;
// ACCESSORS
FileLine* fileline() const override { return nodep()->fileline(); }
AstScope* scopep() const { return m_scopep; }
AstNode* nodep() const { return m_nodep; }
AstSenTree* srcDomainp() const { return m_srcDomainp; }
void srcDomainp(AstSenTree* nodep) { m_srcDomainp = nodep; }
bool srcDomainSet() const { return m_srcDomainSet; }
void srcDomainSet(bool flag) { m_srcDomainSet = flag; }
AstSenTree* dstDomainp() const { return m_dstDomainp; }
void dstDomainp(AstSenTree* nodep) { m_dstDomainp = nodep; }
bool dstDomainSet() const { return m_dstDomainSet; }
void dstDomainSet(bool flag) { m_dstDomainSet = flag; }
bool asyncPath() const { return m_asyncPath; }
void asyncPath(bool flag) { m_asyncPath = flag; }
};
class CdcVarVertex final : public CdcEitherVertex {
AstVarScope* const m_varScp;
int m_cntAsyncRst = 0;
bool m_fromFlop = false;
public:
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: CdcEitherVertex{graphp, scopep, varScp}
, m_varScp{varScp} {}
~CdcVarVertex() override = default;
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
string dotColor() const override {
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
}
int cntAsyncRst() const { return m_cntAsyncRst; }
void cntAsyncRst(int flag) { m_cntAsyncRst = flag; }
bool fromFlop() const { return m_fromFlop; }
void fromFlop(bool flag) { m_fromFlop = flag; }
};
class CdcLogicVertex final : public CdcEitherVertex {
bool m_hazard : 1;
bool m_isFlop : 1;
public:
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
: CdcEitherVertex{graphp, scopep, nodep}
, m_hazard{false}
, m_isFlop{false} {
srcDomainp(sensenodep);
dstDomainp(sensenodep);
}
~CdcLogicVertex() override = default;
// ACCESSORS
string name() const override { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
string dotColor() const override { return hazard() ? "black" : "yellow"; }
bool hazard() const { return m_hazard; }
void setHazard(AstNode* nodep) {
m_hazard = true;
nodep->user3(true);
}
void clearHazard() { m_hazard = false; }
bool isFlop() const { return m_isFlop; }
void isFlop(bool flag) { m_isFlop = flag; }
};
//######################################################################
class CdcDumpVisitor final : public CdcBaseVisitor {
private:
// NODE STATE
// Entire netlist:
// {statement}Node::user3 -> bool, indicating not hazard
std::ofstream* const m_ofp = nullptr; // Output file
string m_prefix;
void visit(AstNode* nodep) override {
*m_ofp << m_prefix;
if (nodep->user3()) {
*m_ofp << " %%";
} else {
*m_ofp << " ";
}
*m_ofp << nodep->prettyTypeName() << "\n";
const string lastPrefix = m_prefix;
m_prefix = lastPrefix + "1:";
iterateAndNextNull(nodep->op1p());
m_prefix = lastPrefix + "2:";
iterateAndNextNull(nodep->op2p());
m_prefix = lastPrefix + "3:";
iterateAndNextNull(nodep->op3p());
m_prefix = lastPrefix + "4:";
iterateAndNextNull(nodep->op4p());
m_prefix = lastPrefix;
}
public:
// CONSTRUCTORS
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix)
: m_ofp{ofp}
, m_prefix{prefix} {
iterate(nodep);
}
~CdcDumpVisitor() override = default;
};
//######################################################################
class CdcWidthVisitor final : public CdcBaseVisitor {
private:
size_t m_maxFilenameLen = 0;
int m_maxLineno = 0;
void visit(AstNode* nodep) override {
iterateChildren(nodep);
// Keeping line+filename lengths separate is much faster than calling ascii().length()
if (nodep->fileline()->lineno() >= m_maxLineno) {
m_maxLineno = nodep->fileline()->lineno() + 1;
}
if (nodep->fileline()->filename().length() >= m_maxFilenameLen) {
m_maxFilenameLen = nodep->fileline()->filename().length() + 1;
}
}
public:
// CONSTRUCTORS
explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); }
~CdcWidthVisitor() override = default;
// ACCESSORS
int maxWidth() const {
size_t width = 1;
width += m_maxFilenameLen;
width += 1; // The :
width += cvtToStr(m_maxLineno).length();
width += 1; // Final :
return static_cast<int>(width);
}
};
//######################################################################
// Cdc class functions
class CdcVisitor final : public CdcBaseVisitor {
private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet
// AstVarScope::user2 -> bool Used in sensitivity list
// {statement}Node::user1p -> CdcLogicVertex* for this statement
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
const VNUser1InUse m_inuser1;
const VNUser2InUse m_inuser2;
const VNUser3InUse m_inuser3;
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
AstScope* m_scopep = nullptr; // Current scope being processed
const AstNodeModule* m_modp = nullptr; // Current module
AstSenTree* m_domainp = nullptr; // Current sentree
bool m_inDly = false; // In delayed assign
int m_inSenItem = 0; // Number of senitems
string m_ofFilename; // Output filename
std::ofstream* m_ofp; // Output file
uint32_t m_userGeneration = 0; // Generation count to avoid slow userClearVertices
int m_filelineWidth = 0; // Characters in longest fileline
// METHODS
void iterateNewStmt(AstNode* nodep) {
if (m_scopep) {
VL_RESTORER(m_logicVertexp);
UINFO(4, " STMT " << nodep << endl);
m_logicVertexp = new CdcLogicVertex{&m_graph, m_scopep, nodep, m_domainp};
if (m_domainp && m_domainp->hasClocked()) { // To/from a flop
m_logicVertexp->isFlop(true);
m_logicVertexp->srcDomainp(m_domainp);
m_logicVertexp->srcDomainSet(true);
m_logicVertexp->dstDomainp(m_domainp);
m_logicVertexp->dstDomainSet(true);
}
iterateChildren(nodep);
if (false && debug() >= 9) {
UINFO(9, "Trace Logic:\n");
nodep->dumpTree("- log1: ");
}
}
}
CdcVarVertex* makeVarVertex(AstVarScope* varscp) {
CdcVarVertex* vertexp = reinterpret_cast<CdcVarVertex*>(varscp->user1p());
if (!vertexp) {
UINFO(6, "New vertex " << varscp << endl);
vertexp = new CdcVarVertex{&m_graph, m_scopep, varscp};
varscp->user1p(vertexp);
if (varscp->varp()->isUsedClock()) {}
if (varscp->varp()->isPrimaryIO()) {
// Create IO vertex - note it's relative to the pointed to var, not where we are
// now This allows reporting to easily print the input statement
CdcLogicVertex* const ioVertexp
= new CdcLogicVertex{&m_graph, varscp->scopep(), varscp->varp(), nullptr};
if (varscp->varp()->isWritable()) {
new V3GraphEdge{&m_graph, vertexp, ioVertexp, 1};
} else {
new V3GraphEdge{&m_graph, ioVertexp, vertexp, 1};
}
}
}
if (m_inSenItem) {
varscp->user2(true); // It's like a clock...
// TODO: In the future mark it here and do normal clock tree glitch checks also
} else if (varscp->user2()) { // It was detected in a sensitivity list earlier
// And now it's used as logic. So must be a reset.
vertexp->cntAsyncRst(vertexp->cntAsyncRst() + 1);
}
return vertexp;
}
void warnAndFile(AstNode* nodep, V3ErrorCode code, const string& msg) {
static bool told_file = false;
nodep->v3warnCode(code, msg);
if (!told_file) {
told_file = true;
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
}
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << '\n';
}
void setNodeHazard(AstNode* nodep) {
// Need to not clear if warnings are off (rather than when report it)
// as bypassing this warning may turn up another path that isn't warning off'ed.
// We can't modifyWarnOff here, as one instantiation might not be
// an issue until we find a hitting flop.
// Furthermore, a module like a "Or" module would only get flagged
// once, even though the signals feeding it are radically different.
if (!m_domainp || m_domainp->hasCombo()) {
// Source flop logic in a posedge block is OK for reset (not async though)
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
UINFO(8, "Set hazard " << nodep << endl);
m_logicVertexp->setHazard(nodep);
}
}
}
static string spaces(int level) {
string out;
while (level--) out += " ";
return out;
} // LCOV_EXCL_LINE
static string pad(unsigned column, const string& in) {
string out = in;
while (out.length() < column) out += ' ';
return out;
}
void analyze() {
UINFO(3, __FUNCTION__ << ": " << endl);
if (dumpGraph() > 6) m_graph.dumpDotFilePrefixed("cdc_pre");
// This will MAX across edge weights
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
//
if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("cdc_simp");
//
analyzeReset();
}
int filelineWidth() {
if (!m_filelineWidth) {
const CdcWidthVisitor visitor{v3Global.rootp()};
m_filelineWidth = visitor.maxWidth();
}
return m_filelineWidth;
}
//----------------------------------------
// RESET REPORT
void analyzeReset() {
// Find all async reset wires, and trace backwards
// userClearVertices is very slow, so we use a generation count instead
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (vvertexp->cntAsyncRst()) {
m_userGeneration++; // Effectively a userClearVertices()
UINFO(8, " Trace One async: " << vvertexp << endl);
// Twice, as we need to detect, then propagate
CdcEitherVertex* const markp = traceAsyncRecurse(vvertexp, false);
if (markp) { // Mark is non-nullptr if something bad on this path
UINFO(9, " Trace One bad! " << vvertexp << endl);
m_userGeneration++; // Effectively a userClearVertices()
traceAsyncRecurse(vvertexp, true);
m_userGeneration++; // Effectively a userClearVertices()
dumpAsync(vvertexp, markp);
}
}
}
}
}
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
// First pass: Return vertex of any hazardous stuff attached, or nullptr if OK
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
if (vertexp->user() >= m_userGeneration) return nullptr; // Processed - prevent loop
vertexp->user(m_userGeneration);
CdcEitherVertex* mark_outp = nullptr;
UINFO(9, " Trace: " << vertexp << endl);
// Clear out in prep for marking next path
if (!mark) vertexp->asyncPath(false);
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Any logic considered bad, at the moment, anyhow
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
// And keep tracing back so the user can understand what's up
} else if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true);
// If primary I/O, it's ok here back
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
// Show the source "input" statement if it exists
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return nullptr;
}
// Also ok if from flop, but partially trace the flop so more obvious to users
if (vvertexp->fromFlop()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return nullptr;
}
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const submarkp = traceAsyncRecurse(eFromVertexp, mark);
if (submarkp && !mark_outp) mark_outp = submarkp;
}
if (mark) vertexp->asyncPath(true);
return mark_outp;
}
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
const AstNode* const nodep = vertexp->varScp();
*m_ofp << "\n";
*m_ofp << "\n";
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
if (!eToVertexp) targetp = eToVertexp;
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
if (vvertexp->isFlop() // IE the target flop that is upsetting us
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
targetp = eToVertexp;
// UINFO(9," targetasync "<<targetp->name()<<" "<<" from
// "<<vertexp->name()<<endl);
break;
}
} // else it might be random logic that's not relevant
}
// UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
warnAndFile(markp->nodep(), V3ErrorCode::CDCRSTLOGIC,
"Logic in path that feeds async reset, via signal: " + nodep->prettyNameQ());
dumpAsyncRecurse(targetp, "", " ", 0);
}
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep,
int level) {
// level=0 is special, indicates to dump destination flop
// Return true if printed anything
// If mark, also mark the output even if nothing hazardous below
if (vertexp->user() >= m_userGeneration) return false; // Processed - prevent loop
vertexp->user(m_userGeneration);
if (!vertexp->asyncPath() && level != 0) return false; // Not part of path
// Other logic in the path
const string cont = prefix + sep;
string nextsep = " ";
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
}
// Dump single variable/logic block
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
AstNode* const nodep = vertexp->nodep();
const string front
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
if (VN_IS(nodep, VarScope)) {
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
} else {
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(),
vertexp->srcDomainp(), true);
if (debug()) { CdcDumpVisitor{nodep, m_ofp, front + "DBG: "}; }
}
nextsep = " | ";
if (level)
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Now that we've printed a path with this hazard, don't bother to print any more
// Otherwise, we'd get a path for almost every destination flop
vvertexp->clearHazard();
}
return true;
}
//----------------------------------------
// EDGE REPORTS
void edgeReport() {
// Make report of all signal names and what clock edges they have
//
// Due to flattening, many interesting direct-connect signals are
// lost, so we can't make a report showing I/Os for a low level
// module. Disabling flattening though makes us consider each
// signal in it's own unique clock domain.
UINFO(3, __FUNCTION__ << ": " << endl);
// Trace all sources and sinks
for (const bool& traceDests : {false, true}) {
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
m_graph.userClearVertices(); // user1: bool - was analyzed
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
UINFO(9, " Trace One edge: " << vvertexp << endl);
edgeDomainRecurse(vvertexp, traceDests, 0);
}
}
}
const string filename
= v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
if (ofp->fail()) v3fatal("Can't write " << filename);
*ofp << "Edge Report for " << v3Global.opt.prefix() << '\n';
std::deque<string> report; // Sort output by name
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
const AstVar* const varp = vvertexp->varScp()->varp();
{
string what = "wire";
if (varp->isPrimaryIO()) what = varp->direction().prettyName();
std::ostringstream os;
os.setf(std::ios::left);
// Module name - doesn't work due to flattening having lost the original
// so we assume the modulename matches the filebasename
const string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
os << " " << std::setw(20) << fname;
os << " " << std::setw(8) << what;
os << " " << std::setw(40) << vvertexp->varScp()->prettyName();
os << " SRC=";
if (vvertexp->srcDomainp()) {
V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
}
os << " DST=";
if (vvertexp->dstDomainp()) {
V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
}
os << std::setw(0);
os << '\n';
report.push_back(os.str());
}
}
}
stable_sort(report.begin(), report.end());
for (const auto& line : report) *ofp << line;
}
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
// Scan back to inputs/outputs, flops, and compute clock domain information
UINFO(8, spaces(level) << " Tracein " << vertexp << endl);
if (vertexp->user() >= m_userGeneration) return; // Mid-Processed - prevent loop
vertexp->user(m_userGeneration);
// Variables from flops already are domained
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) {
return;
} // Fully computed
std::set<AstSenTree*> senouts; // List of all sensitivities for new signal
if (dynamic_cast<CdcLogicVertex*>(vertexp)) {
} else if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
// If primary I/O, give it domain of the input
const AstVar* const varp = vvertexp->varScp()->varp();
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
senouts.insert(new AstSenTree{
varp->fileline(), new AstSenItem{varp->fileline(), AstSenItem::Combo{}}});
}
}
// Now combine domains of sources/dests
if (traceDests) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
}
} else {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
}
}
// Convert list of senses into one sense node
AstSenTree* senoutp = nullptr;
bool senedited = false;
for (const auto& itr : senouts) {
if (!senoutp) {
senoutp = itr;
} else {
if (!senedited) {
senedited = true;
senoutp = senoutp->cloneTree(true);
}
senoutp->addSensesp(itr->sensesp()->cloneTree(true));
}
}
// If multiple domains need to do complicated optimizations
if (senedited) senoutp = VN_AS(V3Const::constifyExpensiveEdit(senoutp), SenTree);
if (traceDests) {
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->dstDomainp(senoutp);
if (debug() >= 9) {
UINFO(9, spaces(level) + " Tracedst " << vertexp);
if (senoutp) {
V3EmitV::verilogForTree(senoutp, cout);
cout << endl;
}
}
} else {
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->srcDomainp(senoutp);
if (debug() >= 9) {
UINFO(9, spaces(level) + " Tracesrc " << vertexp);
if (senoutp) {
V3EmitV::verilogForTree(senoutp, cout);
cout << endl;
}
}
}
}
// VISITORS
void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
{
m_modp = nodep;
iterateChildren(nodep);
}
}
void visit(AstScope* nodep) override {
UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
m_logicVertexp = nullptr;
iterateChildren(nodep);
m_scopep = nullptr;
}
void visit(AstActive* nodep) override {
// Create required blocks and add to module
UINFO(4, " BLOCK " << nodep << endl);
AstNode::user2ClearTree();
m_domainp = nodep->sensesp();
// Ignore static initializers, initial and final blocks
if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) {
iterateNewStmt(nodep);
}
m_domainp = nullptr;
AstNode::user2ClearTree();
}
void visit(AstNodeVarRef* nodep) override {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* const varscp = nodep->varScopep();
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
CdcVarVertex* const varvertexp = makeVarVertex(varscp);
UINFO(5, " VARREF to " << varscp << endl);
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
// When simplify we'll take the MAX weight
if (nodep->access().isWriteOrRW()) {
new V3GraphEdge{&m_graph, m_logicVertexp, varvertexp, 1};
if (m_inDly) {
varvertexp->fromFlop(true);
varvertexp->srcDomainp(m_domainp);
varvertexp->srcDomainSet(true);
}
} else {
if (varvertexp->cntAsyncRst()) {
// UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
new V3GraphEdge{&m_graph, varvertexp, m_logicVertexp, CDC_WEIGHT_ASYNC};
} else {
// UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
new V3GraphEdge{&m_graph, varvertexp, m_logicVertexp, 1};
}
}
}
}
void visit(AstAssignDly* nodep) override {
VL_RESTORER(m_inDly);
m_inDly = true;
iterateChildren(nodep);
m_inDly = false;
}
void visit(AstSenItem* nodep) override {
m_inSenItem = true;
iterateChildren(nodep);
m_inSenItem = false;
}
void visit(AstAlways* nodep) override { iterateNewStmt(nodep); }
void visit(AstAlwaysPublic* nodep) override {
// CDC doesn't care about public variables
}
void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); }
void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); }
// Expressions that shouldn't cause us to clear hazard
void visit(AstConst*) override {}
void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
void visit(AstConcat* nodep) override { iterateChildren(nodep); }
void visit(AstNot* nodep) override { iterateChildren(nodep); }
void visit(AstSel* nodep) override {
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
}
void visit(AstNodeSel* nodep) override {
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
}
// Ignores
void visit(AstInitial*) override {}
void visit(AstInitialAutomatic*) override {}
void visit(AstInitialStatic*) override {}
void visit(AstTraceDecl*) override {}
void visit(AstCoverToggle*) override {}
void visit(AstNodeDType*) override {}
//--------------------
// Default
void visit(AstNodeExpr* nodep) override {
setNodeHazard(nodep);
iterateChildren(nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CdcVisitor(AstNode* nodep) {
// Make report of all signal names and what clock edges they have
const string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt";
m_ofp = V3File::new_ofstream(filename);
if (m_ofp->fail()) v3fatal("Can't write " << filename);
m_ofFilename = filename;
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << '\n';
*m_ofp
<< "Each dump below traces logic from inputs/source flops to destination flop(s).\n";
*m_ofp << "First source logic is listed, then a variable that logic generates,\n";
*m_ofp << "repeating recursively forwards to the destination flop(s).\n";
*m_ofp << "%% Indicates the operator considered potentially hazardous.\n";
iterate(nodep);
analyze();
if (debug() >= 1) edgeReport(); // Not useful to users at the moment
if (false) {
*m_ofp << "\nDBG-test-dumper\n";
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true);
*m_ofp << '\n';
}
}
~CdcVisitor() override {
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
}
};
//######################################################################
// Cdc class functions
void V3Cdc::cdcAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CdcVisitor{nodep}; }
}
-32
View File
@@ -1,32 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Break always into sensitivity block domains
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-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
//
//*************************************************************************
#ifndef VERILATOR_V3CDC_H_
#define VERILATOR_V3CDC_H_
#include "config_build.h"
#include "verilatedos.h"
class AstNetlist;
//============================================================================
class V3Cdc final {
public:
static void cdcAll(AstNetlist* nodep);
};
#endif // Guard
+13 -6
View File
@@ -156,6 +156,11 @@ private:
// m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep));
//}
}
void visit(AstCoverDecl* nodep) override {
// Need to declare coverage in package, where we have access to symbol table
iterateChildren(nodep);
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
}
void visit(AstInitial* nodep) override {
// But not AstInitialAutomatic, which remains under the class
iterateChildren(nodep);
@@ -171,24 +176,26 @@ private:
}
}
void setStructModulep(AstStructDType* const dtypep) {
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
// Give it a pointer to its package and a final name
dtypep->classOrPackagep(m_modp);
dtypep->name(dtypep->name() + "__struct" + cvtToStr(dtypep->uniqueNum()));
dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp);
dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct")
+ cvtToStr(dtypep->uniqueNum()));
for (const AstMemberDType* itemp = dtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstStructDType* const subp = VN_CAST(itemp->skipRefp(), StructDType);
AstNodeUOrStructDType* const subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
// Recurse only into anonymous unpacked structs inside this definition,
// other unpacked structs will be reached from another typedefs
if (subp && !subp->packed() && subp->name().empty()) { setStructModulep(subp); }
if (subp && !subp->packed() && subp->name().empty()) setStructModulep(subp);
}
}
void visit(AstTypedef* nodep) override {
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
AstStructDType* const dtypep = VN_CAST(nodep->dtypep(), StructDType);
AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType);
if (dtypep && !dtypep->packed()) {
dtypep->name(nodep->name());
setStructModulep(dtypep);
+5 -4
View File
@@ -87,7 +87,8 @@ private:
}
void computeCppWidth(AstNode* nodep) {
if (!nodep->user2() && nodep->hasDType()) {
if (VN_IS(nodep, Var)
if (VN_IS(nodep, Var) //
|| VN_IS(nodep, ConsPackMember) //
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|| VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType)
@@ -97,9 +98,9 @@ private:
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) {
} else {
const AstStructDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), StructDType);
if (!dtypep || dtypep->packed()) { setCppWidth(nodep); }
const AstNodeUOrStructDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), NodeUOrStructDType);
if (!dtypep || dtypep->packed()) setCppWidth(nodep);
}
}
}
+5 -3
View File
@@ -95,7 +95,7 @@ private:
if (vscp->user1p()) return VN_AS(vscp->user1p(), VarScope);
const AstVar* const varp = vscp->varp();
const string newvarname
= string("__Vsampled__") + vscp->scopep()->nameDotless() + "__" + varp->name();
= string{"__Vsampled__"} + vscp->scopep()->nameDotless() + "__" + varp->name();
FileLine* const flp = vscp->fileline();
AstVar* const newvarp = new AstVar{flp, VVarType::MODULETEMP, newvarname, varp->dtypep()};
newvarp->noReset(true); // Reset by below assign
@@ -146,17 +146,19 @@ private:
UASSERT_OBJ(nodep->hasClocked(), nodep, "Should have been converted by V3Sched");
UASSERT_OBJ(nodep->stmtsp(), nodep, "Should not have been created if empty");
VNRelinker relinker;
nodep->unlinkFrBack(&relinker);
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
// Create 'if' statement, if needed
if (!m_lastSenp || !nodep->sensesp()->sameTree(m_lastSenp)) {
VNRelinker relinker;
nodep->unlinkFrBack(&relinker);
clearLastSen();
m_lastSenp = nodep->sensesp();
// Make a new if statement
m_lastIfp = makeActiveIf(m_lastSenp);
relinker.relink(m_lastIfp);
} else {
nodep->unlinkFrBack();
}
// Move statements to if
+7 -7
View File
@@ -37,7 +37,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
static void makeVlToString(AstClass* nodep) {
AstCFunc* const funcp
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) + ">& obj");
funcp->argTypes("const VlClassRef<" + EmitCBase::prefixNameProtect(nodep) + ">& obj");
funcp->isMethod(false);
funcp->isConst(false);
funcp->isStatic(false);
@@ -51,7 +51,7 @@ static void makeVlToString(AstClass* nodep) {
static void makeVlToString(AstIface* nodep) {
AstCFunc* const funcp
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "* obj");
funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "* obj");
funcp->isMethod(false);
funcp->isConst(false);
funcp->isStatic(false);
@@ -61,11 +61,11 @@ static void makeVlToString(AstIface* nodep) {
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp);
}
static void makeVlToString(AstStructDType* nodep) {
static void makeVlToString(AstNodeUOrStructDType* nodep) {
AstNodeModule* const modp = nodep->classOrPackagep();
AstCFunc* const funcp
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "& obj");
funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "& obj");
funcp->isMethod(false);
funcp->isConst(false);
funcp->isStatic(false);
@@ -79,7 +79,7 @@ static void makeVlToString(AstStructDType* nodep) {
} else {
stmt += ", ";
}
stmt += itemp->nameProtect() + ":\" + ";
stmt += VIdProtect::protect(itemp->prettyName()) + ":\" + ";
if (VN_IS(itemp->dtypep()->skipRefp(), BasicDType) && itemp->isWide()) {
stmt += "VL_TO_STRING_W";
} else {
@@ -137,7 +137,7 @@ static void makeToStringMiddle(AstClass* nodep) {
string stmt = "out += ";
if (!comma.empty()) stmt += "\", \"+ ";
// comma = ", "; // Nothing further so not needed
stmt += EmitCBaseVisitor::prefixNameProtect(nodep->extendsp()->dtypep());
stmt += EmitCBase::prefixNameProtect(nodep->extendsp()->dtypep());
stmt += "::to_string_middle();\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
@@ -168,7 +168,7 @@ void V3Common::commonAll() {
}
for (AstNode* nodep = v3Global.rootp()->typeTablep()->typesp(); nodep;
nodep = nodep->nextp()) {
if (AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) {
if (AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) {
if (!dtypep->packed()) makeVlToString(dtypep);
}
}
+16 -8
View File
@@ -40,25 +40,31 @@ template <typename T>
class V3ConfigWildcardResolver final {
using Map = std::map<const std::string, T>;
Map m_mapWildcard; // Wildcard strings to entities
Map m_mapResolved; // Resolved strings to converged entities
mutable V3Mutex m_mutex; // protects members
Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities
Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities
public:
V3ConfigWildcardResolver() = default;
~V3ConfigWildcardResolver() = default;
/// Update into maps from other
void update(const V3ConfigWildcardResolver& other) {
void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex)
VL_EXCLUDES(other.m_mutex) {
V3LockGuard lock{m_mutex};
V3LockGuard otherLock{other.m_mutex};
for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second);
for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second);
}
// Access and create a (wildcard) entity
T& at(const string& name) {
T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
V3LockGuard lock{m_mutex};
// Don't store into wildcards if the name is not a wildcard string
return m_mapWildcard[name];
}
// Access an entity and resolve wildcards that match it
T* resolve(const string& name) {
T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
V3LockGuard lock{m_mutex};
// Lookup if it was resolved before, typically not
auto it = m_mapResolved.find(name);
if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second;
@@ -78,7 +84,10 @@ public:
return newp;
}
// Flush on update
void flush() { m_mapResolved.clear(); }
void flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
V3LockGuard lock{m_mutex};
m_mapResolved.clear();
}
};
// Only public_flat_rw has the sensitity tree
@@ -332,8 +341,7 @@ public:
}
bool waive(V3ErrorCode code, const string& match) {
for (const auto& itr : m_waivers) {
if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT)
|| (code.unusedError() && itr.first == V3ErrorCode::I_UNUSED))
if ((code.isUnder(itr.first) || (itr.first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, itr.second)) {
return true;
}
+1
View File
@@ -23,6 +23,7 @@
#include "V3Ast.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Mutex.h"
//######################################################################
+136 -99
View File
@@ -70,7 +70,7 @@ static int countTrailingZeroes(uint64_t val) {
// This visitor can be used in the post-expanded Ast from V3Expand, where the Ast satisfies:
// - Constants are 64 bit at most (because words are accessed via AstWordSel)
// - Variables are scoped.
class ConstBitOpTreeVisitor final : public VNVisitor {
class ConstBitOpTreeVisitor final : public VNVisitorConst {
// NODE STATE
// AstVarRef::user4u -> Base index of m_varInfos that points VarInfo
// AstVarScope::user4u -> Same as AstVarRef::user4
@@ -416,7 +416,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
{
VL_RESTORER(m_leafp);
m_leafp = &info;
iterate(nodep);
iterateConst(nodep);
}
bool ok = !m_failed;
@@ -431,7 +431,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
// VISITORS
void visit(AstNode* nodep) override { CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); }
void visit(AstCCast* nodep) override {
iterateChildren(nodep);
iterateChildrenConst(nodep);
if (m_leafp) m_leafp->updateBitRange(nodep);
}
void visit(AstShiftR* nodep) override {
@@ -440,7 +440,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
m_lsb += constp->toUInt();
incrOps(nodep, __LINE__);
iterate(nodep->lhsp());
iterateConst(nodep->lhsp());
m_leafp->updateBitRange(nodep);
m_lsb -= constp->toUInt();
}
@@ -449,12 +449,10 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
AstNode* lhsp = nodep->lhsp();
AstCCast* const castp = VN_CAST(lhsp, CCast);
if (castp) lhsp = castp->lhsp();
CONST_BITOP_RETURN_IF(!VN_IS(lhsp, VarRef) && !VN_IS(lhsp, Xor) && !VN_IS(lhsp, RedXor)
&& !VN_IS(lhsp, ShiftR),
lhsp);
CONST_BITOP_RETURN_IF(!isXorTree() && !VN_IS(lhsp, VarRef) && !VN_IS(lhsp, ShiftR), lhsp);
incrOps(nodep, __LINE__);
m_polarity = !m_polarity;
iterateChildren(nodep);
iterateChildrenConst(nodep);
// Don't restore m_polarity for Xor as it counts parity of the entire tree
if (!isXorTree()) m_polarity = !m_polarity;
if (m_leafp && castp) m_leafp->updateBitRange(castp);
@@ -465,7 +463,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
UASSERT_OBJ(m_leafp->wordIdx() == -1, nodep, "Unexpected nested WordSel");
m_leafp->wordIdx(constp->toSInt());
iterate(nodep->fromp());
iterateConst(nodep->fromp());
}
void visit(AstVarRef* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
@@ -529,7 +527,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
// Always reach past a plain making AND
Restorer restorer{*this};
incrOps(nodep, __LINE__);
iterate(nodep->rhsp());
iterateConst(nodep->rhsp());
CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp());
restorer.disableRestore(); // Now all checks passed
} else if (nodep->type() == m_rootp->type()) { // And, Or, Xor
@@ -542,13 +540,14 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
m_leafp = &leafInfo;
AstNodeExpr* opp = right ? nodep->rhsp() : nodep->lhsp();
const bool origFailed = m_failed;
iterate(opp);
iterateConst(opp);
if (leafInfo.constp() || m_failed) {
// Revert changes in leaf
restorer.restoreNow();
// Reach past a cast then add to frozen nodes to be added to final reduction
if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp();
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{m_polarity, m_lsb});
const bool pol = isXorTree() || m_polarity; // Only AND/OR tree needs polarity
m_frozenNodes.emplace_back(opp, FrozenNodeInfo{pol, m_lsb});
m_failed = origFailed;
continue;
}
@@ -647,11 +646,11 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
m_varInfos.push_back(nullptr);
CONST_BITOP_RETURN_IF(!isAndTree() && !isOrTree() && !isXorTree(), nodep);
if (AstNodeBiop* const biopp = VN_CAST(nodep, NodeBiop)) {
iterate(biopp);
iterateConst(biopp);
} else {
UASSERT_OBJ(VN_IS(nodep, RedXor), nodep, "Must be RedXor");
incrOps(nodep, __LINE__);
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
for (auto&& entry : m_bitPolarities) {
getVarInfo(entry.m_info).setPolarity(entry.m_polarity, entry.m_bit);
@@ -900,6 +899,7 @@ private:
bool m_doV = false; // Verilog, not C++ conversion
bool m_doGenerate = false; // Postpone width checking inside generate
bool m_hasJumpDelay = false; // JumpGo or Delay under this while
bool m_underRecFunc = false; // Under a recursive function
AstNodeModule* m_modp = nullptr; // Current module
const AstArraySel* m_selp = nullptr; // Current select
const AstNode* m_scopep = nullptr; // Current scope
@@ -1384,15 +1384,6 @@ private:
// but for now can disable en masse until V3Purify takes effect.
return m_doShort || VN_IS(nodep, VarRef) || VN_IS(nodep, Const);
}
bool isTreePureRecurse(AstNode* nodep) {
// Should memoize this if call commonly
if (!nodep->isPure()) return false;
if (nodep->op1p() && !isTreePureRecurse(nodep->op1p())) return false;
if (nodep->op2p() && !isTreePureRecurse(nodep->op2p())) return false;
if (nodep->op3p() && !isTreePureRecurse(nodep->op3p())) return false;
if (nodep->op4p() && !isTreePureRecurse(nodep->op4p())) return false;
return true;
}
// Extraction checks
bool warnSelect(AstSel* nodep) {
@@ -1466,6 +1457,7 @@ private:
if (!thensp->lhsp()->sameGateTree(elsesp->lhsp())) return false;
if (!thensp->rhsp()->gateTree()) return false;
if (!elsesp->rhsp()->gateTree()) return false;
if (m_underRecFunc) return false; // This optimization may lead to infinite recursion
return true;
}
bool operandIfIf(const AstNodeIf* nodep) {
@@ -2272,7 +2264,7 @@ private:
// VISITORS
void visit(AstNetlist* nodep) override {
// Iterate modules backwards, in bottom-up order. That's faster
iterateChildrenBackwards(nodep);
iterateChildrenBackwardsConst(nodep);
}
void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
@@ -2754,52 +2746,74 @@ private:
}
}
struct SenItemCmp {
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
if (lhsp->type() < rhsp->type()) return true;
if (lhsp->type() > rhsp->type()) return false;
// Looks visually better if we keep sorted by name
if (!lhsp->sensp() && rhsp->sensp()) return true;
if (lhsp->sensp() && !rhsp->sensp()) return false;
if (lhsp->varrefp() && !rhsp->varrefp()) return true;
if (!lhsp->varrefp() && rhsp->varrefp()) return false;
if (lhsp->varrefp() && rhsp->varrefp()) {
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
class SenItemCmp final {
static int cmp(const AstNodeExpr* ap, const AstNodeExpr* bp) {
const VNType aType = ap->type();
const VNType bType = bp->type();
if (aType != bType) return static_cast<int>(bType) - static_cast<int>(aType);
if (const AstVarRef* const aRefp = VN_CAST(ap, VarRef)) {
const AstVarRef* const bRefp = VN_AS(bp, VarRef);
// Looks visually better if we keep sorted by name
if (aRefp->name() < bRefp->name()) return -1;
if (aRefp->name() > bRefp->name()) return 1;
// But might be same name with different scopes
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) return true;
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) return false;
if (aRefp->varScopep() < bRefp->varScopep()) return -1;
if (aRefp->varScopep() > bRefp->varScopep()) return 1;
// Or rarely, different data types
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
} else if (AstCMethodHard* const lp = VN_CAST(lhsp->sensp(), CMethodHard)) {
if (AstCMethodHard* const rp = VN_CAST(rhsp->sensp(), CMethodHard)) {
if (AstVarRef* const lRefp = VN_CAST(lp->fromp(), VarRef)) {
if (AstVarRef* const rRefp = VN_CAST(rp->fromp(), VarRef)) {
if (lRefp->name() < rRefp->name()) return true;
if (lRefp->name() > rRefp->name()) return false;
// But might be same name with different scopes
if (lRefp->varScopep() < rRefp->varScopep()) return true;
if (lRefp->varScopep() > rRefp->varScopep()) return false;
// Or rarely, different data types
if (lRefp->dtypep() < rRefp->dtypep()) return true;
if (lRefp->dtypep() > rRefp->dtypep()) return false;
}
}
if (AstConst* lConstp = VN_CAST(lp->pinsp(), Const)) {
if (AstConst* rConstp = VN_CAST(rp->pinsp(), Const)) {
if (lConstp->toUInt() < rConstp->toUInt()) return true;
if (lConstp->toUInt() > rConstp->toUInt()) return false;
}
}
}
if (aRefp->dtypep() < bRefp->dtypep()) return -1;
if (aRefp->dtypep() > bRefp->dtypep()) return 1;
return 0;
}
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
// note the SenTree optimizer requires this order (more
// general first, less general last)
if (lhsp->edgeType() < rhsp->edgeType()) return true;
if (lhsp->edgeType() > rhsp->edgeType()) return false;
return false;
if (const AstConst* const aConstp = VN_CAST(ap, Const)) {
const AstConst* const bConstp = VN_AS(bp, Const);
if (aConstp->toUQuad() < bConstp->toUQuad()) return -1;
if (aConstp->toUQuad() > bConstp->toUQuad()) return 1;
return 0;
}
if (const AstNodeBiop* const aBiOpp = VN_CAST(ap, NodeBiop)) {
const AstNodeBiop* const bBiOpp = VN_AS(bp, NodeBiop);
// Compare RHSs first as LHS might be const, but the variable term should become
// adjacent for optimization if identical.
if (const int c = cmp(aBiOpp->rhsp(), bBiOpp->rhsp())) return c;
return cmp(aBiOpp->lhsp(), bBiOpp->lhsp());
}
if (const AstCMethodHard* const aCallp = VN_CAST(ap, CMethodHard)) {
const AstCMethodHard* const bCallp = VN_AS(bp, CMethodHard);
if (aCallp->name() < bCallp->name()) return -1;
if (aCallp->name() > bCallp->name()) return 1;
if (const int c = cmp(aCallp->fromp(), bCallp->fromp())) return c;
AstNodeExpr* aPinsp = aCallp->pinsp();
AstNodeExpr* bPinsp = bCallp->pinsp();
while (aPinsp && bPinsp) {
if (const int c = cmp(aPinsp, bPinsp)) return c;
aPinsp = VN_AS(aPinsp->nextp(), NodeExpr);
bPinsp = VN_AS(bPinsp->nextp(), NodeExpr);
}
return aPinsp ? -1 : bPinsp ? 1 : 0;
}
return 0;
}
public:
bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
AstNodeExpr* const lSensp = lhsp->sensp();
AstNodeExpr* const rSensp = rhsp->sensp();
if (lSensp && rSensp) {
// If both terms have sensitivity expressions, recursively compare them
if (const int c = cmp(lSensp, rSensp)) return c < 0;
} else if (lSensp || rSensp) {
// Terms with sensitivity expressions come after those without
return rSensp;
}
// Finally sort by edge, AFTER variable, as we want multiple edges for same var
// adjacent. note the SenTree optimizer requires this order (more general first,
// less general last)
return lhsp->edgeType() < rhsp->edgeType();
}
};
@@ -2824,9 +2838,8 @@ private:
}
}
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
// Make things a little faster; check first if we need a sort
// Pass 1: Sort the sensitivity items so "posedge a or b" and "posedge b or a" and
// similar, optimizable expressions end up next to each other.
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
nextp = VN_AS(senp->nextp(), SenItem);
// cppcheck-suppress unassignedVariable // cppcheck bug
@@ -2846,35 +2859,53 @@ private:
}
}
// Pass2, remove dup edges
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
// Pass 2, remove duplicates and simplify adjacent terms if possible
for (AstSenItem *senp = nodep->sensesp(), *nextp; senp; senp = nextp) {
nextp = VN_AS(senp->nextp(), SenItem);
AstSenItem* const litemp = senp;
AstSenItem* const ritemp = nextp;
if (ritemp) {
if ((litemp->sensp() && ritemp->sensp()
&& litemp->sensp()->sameGateTree(ritemp->sensp()))
|| (!litemp->sensp() && !ritemp->sensp())) {
// We've sorted in the order ANY, BOTH, POS, NEG,
// so we don't need to try opposite orders
if ((litemp->edgeType() == VEdgeType::ET_POSEDGE // POS or NEG -> BOTH
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|| (litemp->edgeType() == ritemp->edgeType()) // Identical edges
) {
// Fix edge of old node
if (litemp->edgeType() == VEdgeType::ET_POSEDGE
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
// Remove redundant node
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
VL_DANGLING(ritemp);
// Try to collapse again
nextp = litemp;
if (!nextp) break;
AstSenItem* const lItemp = senp;
AstSenItem* const rItemp = nextp;
AstNodeExpr* const lSenp = lItemp->sensp();
AstNodeExpr* const rSenp = rItemp->sensp();
if (!lSenp || !rSenp) continue;
if (lSenp->sameGateTree(rSenp)) {
// POSEDGE or NEGEDGE -> BOTHEDGE. (We've sorted POSEDGE, before NEGEDGE, so we
// do not need to test for the opposite orders.)
if (lItemp->edgeType() == VEdgeType::ET_POSEDGE
&& rItemp->edgeType() == VEdgeType::ET_NEGEDGE) {
// Make both terms BOTHEDGE, the second will be removed below
lItemp->edgeType(VEdgeType::ET_BOTHEDGE);
rItemp->edgeType(VEdgeType::ET_BOTHEDGE);
}
// Remove identical expressions
if (lItemp->edgeType() == rItemp->edgeType()) {
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
nextp = lItemp;
}
continue;
}
// Not identical terms, check if they can be combined
if (lSenp->width() != rSenp->width()) continue;
if (AstAnd* const lAndp = VN_CAST(lSenp, And)) {
if (AstAnd* const rAndp = VN_CAST(rSenp, And)) {
if (AstConst* const lConstp = VN_CAST(lAndp->lhsp(), Const)) {
if (AstConst* const rConstp = VN_CAST(rAndp->lhsp(), Const)) {
if (lAndp->rhsp()->sameTree(rAndp->rhsp())) {
const V3Number lNum{lConstp->num()};
lConstp->num().opOr(lNum, rConstp->num());
// Remove redundant term
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
nextp = lItemp;
}
}
}
}
}
}
// nodep->dumpTree("- ssou: ");
}
}
@@ -2954,7 +2985,7 @@ private:
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) {
if (!isTreePureRecurse(nodep->condp())) {
if (!nodep->condp()->isTreePureRecurse()) {
// Condition has side effect - leave - perhaps in
// future simplify to remove all but side effect terms
} else {
@@ -2982,6 +3013,7 @@ private:
AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext();
AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext();
AstIf* const ifp = new AstIf{nodep->fileline(), condp, elsesp, thensp};
ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info
ifp->branchPred(nodep->branchPred().invert());
nodep->replaceWith(ifp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@@ -3094,12 +3126,12 @@ private:
if (!inPct && ch == '%') {
inPct = true;
fmt = ch;
} else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) {
} else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) {
fmt += ch;
} else if (inPct) {
inPct = false;
fmt += ch;
switch (tolower(ch)) {
switch (std::tolower(ch)) {
case '%': break; // %% - just output a %
case 'm': break; // %m - auto insert "name"
case 'l': break; // %l - auto insert "library"
@@ -3137,6 +3169,11 @@ private:
VL_DO_DANGLING(replaceConstString(nodep, nodep->name()), nodep);
}
}
void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_underRecFunc);
if (nodep->recursive()) m_underRecFunc = true;
iterateChildren(nodep);
}
void visit(AstFuncRef* nodep) override {
iterateChildren(nodep);
@@ -3190,7 +3227,7 @@ private:
void visit(AstStmtExpr* nodep) override {
iterateChildren(nodep);
if (!nodep->exprp()) {
if (!nodep->exprp() || VN_IS(nodep->exprp(), Const)) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
@@ -3209,7 +3246,7 @@ private:
void visit(AstJumpGo* nodep) override {
iterateChildren(nodep);
// Jump to label where label immediately follows label is not useful
// Jump to label where label immediately follows this go is not useful
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
// Keep the label, might be other jumps pointing to it, gets cleaned later
+4 -1
View File
@@ -124,7 +124,10 @@ private:
UINFO(9, "new " << declp << endl);
AstCoverInc* const incp = new AstCoverInc{fl, declp};
if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) {
if (!trace_var_name.empty()
&& v3Global.opt.traceCoverage()
// No module handle to trace inside classes
&& !VN_IS(m_modp, Class)) {
FileLine* const fl_nowarn = new FileLine{incp->fileline()};
fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
AstVar* const varp = new AstVar{fl_nowarn, VVarType::MODULETEMP, trace_var_name,
+1 -1
View File
@@ -324,7 +324,7 @@ private:
}
}
bool shouldDeleteTypedef(AstTypedef* typedefp) {
if (auto* structp = VN_CAST(typedefp->subDTypep(), StructDType)) {
if (auto* const structp = VN_CAST(typedefp->subDTypep(), NodeUOrStructDType)) {
if (structp->user1() && !structp->packed()) return false;
}
return m_elimCells && !typedefp->attrPublic();
+11 -9
View File
@@ -262,8 +262,8 @@ private:
if (VN_IS(dimp, Const)) { // bit = const, can just use it
dimreadps.push_front(dimp);
} else {
const string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
const string bitvarname = string{"__Vdlyvdim"} + cvtToStr(dimension) + "__"
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
AstVarScope* const bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
AstAssign* const bitassignp = new AstAssign{
@@ -282,8 +282,8 @@ private:
// vlsb = constant, can just push constant into where we use it
bitreadp = lsbvaluep;
} else {
const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
+ cvtToStr(modVecNum));
const string bitvarname
= string{"__Vdlyvlsb__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
AstVarScope* const bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
AstAssign* const bitassignp = new AstAssign{
@@ -301,7 +301,7 @@ private:
valreadp = nodep->rhsp()->unlinkFrBack();
} else {
const string valvarname
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
= string{"__Vdlyvval__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
AstVarScope* const valvscp
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef{nodep->fileline(), valvscp, VAccess::WRITE};
@@ -321,7 +321,7 @@ private:
++m_statSharedSet;
} else { // Create new one
const string setvarname
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
= string{"__Vdlyvset__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum);
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
if (!m_inSuspendableOrFork) {
// Suspendables reset __Vdlyvset__ in the AstAlwaysPost
@@ -474,14 +474,16 @@ private:
m_inSuspendableOrFork = true;
iterateChildren(nodep);
}
void visit(AstCAwait* nodep) override { m_timingDomains.insert(nodep->sensesp()); }
void visit(AstCAwait* nodep) override {
if (nodep->sensesp()) m_timingDomains.insert(nodep->sensesp());
}
void visit(AstFireEvent* nodep) override {
UASSERT_OBJ(v3Global.hasEvents(), nodep, "Inconsistent");
FileLine* const flp = nodep->fileline();
if (nodep->isDelayed()) {
AstVarRef* const vrefp = VN_AS(nodep->operandp(), VarRef);
vrefp->unlinkFrBack();
const string newvarname = (string("__Vdly__") + vrefp->varp()->shortName());
const string newvarname = string{"__Vdly__"} + vrefp->varp()->shortName();
AstVarScope* const dlyvscp = createVarSc(vrefp->varScopep(), newvarname, 1, nullptr);
const auto dlyRef = [=](VAccess access) {
@@ -570,7 +572,7 @@ private:
checkActivePost(nodep, oldactivep);
}
if (!dlyvscp) { // First use of this delayed variable
const string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
const string newvarname = string{"__Vdly__"} + nodep->varp()->shortName();
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
AstNodeAssign* const prep = new AstAssignPre{
nodep->fileline(),
+2 -1
View File
@@ -63,7 +63,7 @@ private:
AstCCall* const callp = new AstCCall{nodep->fileline(), funcp};
callp->dtypeSetVoid();
if (VN_IS(m_modp, Class)) {
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->argTypes(EmitCBase::symClassVar());
callp->argTypes("vlSymsp");
}
UINFO(6, " New " << callp << endl);
@@ -93,6 +93,7 @@ private:
}
}
void visit(AstStmtExpr* nodep) override {} // Stop recursion after introducing new function
void visit(AstJumpBlock*) override {} // Stop recursion as can't break up across a jump
void visit(AstNodeStmt* nodep) override {
m_depth++;
if (m_depth > v3Global.opt.compLimitBlocks()) { // Already done
+2 -2
View File
@@ -166,7 +166,7 @@ private:
new AstEq{
funcp->fileline(), new AstCExpr{funcp->fileline(), "this", 64},
new AstCExpr{funcp->fileline(),
string("&(") + funcp->scopep()->nameVlSym() + ")",
string{"&("} + funcp->scopep()->nameVlSym() + ")",
64}},
returnp};
newfuncp->addStmtsp(ifp);
@@ -178,7 +178,7 @@ private:
// to come up with some return value
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
// VDisplayType::DT_WARNING,
// string("%%Error: ")+name+"() called with bad
// string{"%%Error: "}+name+"() called with bad
// scope", nullptr));
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
if (debug() >= 9) newfuncp->dumpTree("- newfunc: ");
+10 -5
View File
@@ -503,14 +503,19 @@ public:
inline bool inlined() const;
// Methods that allow DfgVertex to participate in error reporting/messaging
void v3errorEnd(std::ostringstream& str) const { m_filelinep->v3errorEnd(str); }
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN {
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
m_filelinep->v3errorEnd(str);
}
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex) {
m_filelinep->v3errorEndFatal(str);
}
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
return fileline()->warnContextPrimary();
}
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
string warnMore() const { return fileline()->warnMore(); }
string warnOther() const { return fileline()->warnOther(); }
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
private:
// For internal use only.
+1 -2
View File
@@ -59,8 +59,7 @@ AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( //
const DfgCountOnes* vtxp, AstNodeExpr* op1) {
AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1};
// Set dtype same as V3Width
const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
nodep->dtypeSetLogicSized(selwidth, VSigning::UNSIGNED);
nodep->dtypeSetLogicSized(32, VSigning::UNSIGNED);
return nodep;
}
+20 -14
View File
@@ -39,7 +39,7 @@ EmitCParentModule::EmitCParentModule() {
//######################################################################
// EmitCBaseVisitor implementation
string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
modp = modp ? modp : EmitCParentModule::get(nodep);
string name;
if (nodep->isConstructor()) {
@@ -57,15 +57,21 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
return name;
}
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) {
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
cfilep->slow(slow);
cfilep->source(source);
if (add) v3Global.rootp()->addFilesp(cfilep);
AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source) {
AstCFile* const cfilep = createCFile(filename, slow, source);
v3Global.rootp()->addFilesp(cfilep);
return cfilep;
}
string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
AstCFile* EmitCBaseVisitorConst::createCFile(const string& filename, bool slow,
bool source) VL_MT_SAFE {
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
cfilep->slow(slow);
cfilep->source(source);
return cfilep;
}
string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) {
// Return argument list for given C function
string args;
if (nodep->isLoose() && !nodep->isStatic()) {
@@ -95,8 +101,8 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
return args;
}
void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
bool withScope) {
void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
bool withScope) {
if (funcp->slow()) puts("VL_ATTR_COLD ");
if (!funcp->isConstructor() && !funcp->isDestructor()) {
puts(funcp->rtnTypeVoid());
@@ -114,8 +120,8 @@ void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModul
if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const");
}
void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
bool cLinkage) {
void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
bool cLinkage) {
ensureNewLine();
if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n");
if (cLinkage) puts("extern \"C\" ");
@@ -129,7 +135,7 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule*
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
}
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
const AstBasicDType* const basicp = nodep->basicp();
bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType);
@@ -217,7 +223,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
}
}
void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) {
void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) {
string nl;
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
@@ -235,7 +241,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType)
puts(nl);
}
void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, VNType type) {
void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) {
// Short circuit if nothing to do. This can save a lot of time on large designs as this
// function needs to traverse the entire module linearly.
if (!v3Global.hasSCTextSections()) return;
+45 -38
View File
@@ -40,7 +40,7 @@ public:
EmitCParentModule();
VL_UNCOPYABLE(EmitCParentModule);
static const AstNodeModule* get(const AstNode* nodep) {
static const AstNodeModule* get(const AstNode* nodep) VL_MT_STABLE {
return VN_AS(nodep->user4p(), NodeModule);
}
};
@@ -48,51 +48,23 @@ public:
//######################################################################
// Base Visitor class -- holds output file pointer
class EmitCBaseVisitor VL_NOT_FINAL : public VNVisitor {
class EmitCBase VL_NOT_FINAL {
public:
// STATE
V3OutCFile* m_ofp = nullptr;
bool m_trackText = false; // Always track AstText nodes
// METHODS
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
void putbs(const string& str) { ofp()->putbs(str); }
void putsDecoration(const string& str) {
if (v3Global.opt.decoration()) puts(str);
}
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
void ensureNewLine() { ofp()->ensureNewLine(); }
bool optSystemC() { return v3Global.opt.systemC(); }
static string protect(const string& name) { return VIdProtect::protectIf(name, true); }
static string protectIf(const string& name, bool doIt) {
return VIdProtect::protectIf(name, doIt);
}
static string protectWordsIf(const string& name, bool doIt) {
return VIdProtect::protectWordsIf(name, doIt);
}
static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; }
static string voidSelfAssign(const AstNodeModule* modp) {
const string className = prefixNameProtect(modp);
return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className
+ "*>(voidSelf);\n";
}
static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); }
static string symClassName() VL_MT_STABLE {
return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms");
}
static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; }
static string symClassAssign() {
return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n";
}
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
return v3Global.opt.modPrefix() + "_" + protect(nodep->name());
static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix
return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name());
}
static string topClassName() { // Return name of top wrapper module
return v3Global.opt.prefix();
}
static bool isConstPoolMod(const AstNode* modp) {
return modp == v3Global.rootp()->constPoolp()->modp();
}
static bool isAnonOk(const AstVar* varp) {
return v3Global.opt.compLimitMembers() != 0 // Enabled
&& !varp->isStatic() // Not a static variable
@@ -100,8 +72,43 @@ public:
&& !VN_IS(varp->dtypep()->skipRefp(), SampleQueueDType) // Aggregates can't be anon
&& (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon
}
static bool isConstPoolMod(const AstNode* modp) {
return modp == v3Global.rootp()->constPoolp()->modp();
}
};
static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true);
class EmitCBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst, public EmitCBase {
public:
// STATE
V3OutCFile* m_ofp = nullptr;
bool m_trackText = false; // Always track AstText nodes
// METHODS
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
void putsHeader() { ofp()->putsHeader(); }
void putbs(const string& str) { ofp()->putbs(str); }
void putsDecoration(const string& str) {
if (v3Global.opt.decoration()) puts(str);
}
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
void ensureNewLine() { ofp()->ensureNewLine(); }
bool optSystemC() { return v3Global.opt.systemC(); }
static string protect(const string& name) VL_MT_SAFE { return VIdProtect::protect(name); }
static string protectIf(const string& name, bool doIt) {
return VIdProtect::protectIf(name, doIt);
}
static string protectWordsIf(const string& name, bool doIt) {
return VIdProtect::protectWordsIf(name, doIt);
}
static string ifNoProtect(const string& in) VL_MT_SAFE {
return v3Global.opt.protectIds() ? "" : in;
}
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
static string topClassName() VL_MT_SAFE { // Return name of top wrapper module
return v3Global.opt.prefix();
}
static AstCFile* newCFile(const string& filename, bool slow, bool source);
static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE;
string cFuncArgs(const AstCFunc* nodep);
void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope);
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
@@ -110,8 +117,8 @@ public:
void emitTextSection(const AstNodeModule* modp, VNType type);
// CONSTRUCTORS
EmitCBaseVisitor() = default;
~EmitCBaseVisitor() override = default;
EmitCBaseVisitorConst() = default;
~EmitCBaseVisitorConst() override = default;
};
#endif // guard
+3 -3
View File
@@ -26,7 +26,7 @@
//######################################################################
// Emitter that can emit constant initializer expressions
class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor {
class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitorConst {
// MEMBERS
uint32_t m_unpackedWord = 0;
bool m_inUnpacked = false;
@@ -64,7 +64,7 @@ protected:
ofp()->printf("%" PRIx64 "ULL", itr.first);
ofp()->putsNoTracking(":");
ofp()->putsNoTracking("{");
iterate(nodep->getIndexValuep(itr.first));
iterateConst(nodep->getIndexValuep(itr.first));
ofp()->putsNoTracking("}");
}
puts("\n");
@@ -83,7 +83,7 @@ protected:
for (uint64_t n = 0; n < size; ++n) {
m_unpackedWord = n;
if (n) puts((n % tabMod) ? ", " : ",\n");
iterate(nodep->getIndexDefaultedValuep(n));
iterateConst(nodep->getIndexDefaultedValuep(n));
}
puts("\n");
puts("}");
+1 -1
View File
@@ -87,7 +87,7 @@ class EmitCConstPool final : public EmitCConstInit {
puts("extern const ");
puts(varp->dtypep()->cType(nameProtect, false, false));
puts(" = ");
iterate(varp->valuep());
iterateConst(varp->valuep());
puts(";\n");
// Keep track of stats
if (VN_IS(varp->dtypep(), UnpackArrayDType)) {
+23 -17
View File
@@ -138,7 +138,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
case 'i':
COMMA;
UASSERT_OBJ(detailp, nodep, "emitOperator() references undef node");
iterateAndNextNull(detailp);
iterateAndNextConstNull(detailp);
needComma = true;
break;
default:
@@ -155,7 +155,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
puts("(");
} else {
// Normal text
if (isalnum(pos[0])) needComma = true;
if (std::isalnum(pos[0])) needComma = true;
COMMA;
string s;
s += pos[0];
@@ -174,7 +174,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
isStmt = false;
puts("VL_FSCANF_IX(");
iterate(dispp->filep());
iterateConst(dispp->filep());
puts(",");
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
isStmt = false;
@@ -184,13 +184,13 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
puts("X(");
puts(cvtToStr(dispp->fromp()->widthMin()));
puts(",");
iterate(dispp->fromp());
iterateConst(dispp->fromp());
puts(",");
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
isStmt = true;
if (dispp->filep()) {
puts("VL_FWRITEF(");
iterate(dispp->filep());
iterateConst(dispp->filep());
puts(",");
} else {
puts("VL_WRITEF(");
@@ -200,7 +200,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
puts("VL_SFORMAT_X(");
puts(cvtToStr(dispp->lhsp()->widthMin()));
putbs(",");
iterate(dispp->lhsp());
iterateConst(dispp->lhsp());
putbs(",");
} else if (VN_IS(nodep, SFormatF)) {
isStmt = false;
@@ -223,7 +223,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
} else if (argp) {
const bool addrof = isScan || (fmt == '@');
if (addrof) puts("&(");
iterate(argp);
iterateConst(argp);
if (!addrof) emitDatap(argp);
if (addrof) puts(")");
}
@@ -262,7 +262,7 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
}
if (argp->widthMin() > 8 && fmtLetter == 'c') {
// Technically legal, but surely not what the user intended.
argp->v3warn(WIDTH, dispp->verilogKwd() << "of %c format of > 8 bit value");
argp->v3warn(WIDTHTRUNC, dispp->verilogKwd() << "of %c format of > 8 bit value");
}
}
// string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter;
@@ -275,9 +275,9 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
double dchars = mantissabits / 3.321928094887362 + 1.0;
if (fmtLetter == 'd') dchars++; // space for sign
const int nchars = int(dchars);
pfmt = string("%") + cvtToStr(nchars) + fmtLetter;
pfmt = string{"%"} + cvtToStr(nchars) + fmtLetter;
} else {
pfmt = string("%") + vfmt + fmtLetter;
pfmt = string{"%"} + vfmt + fmtLetter;
}
m_emitDispState.pushFormat(pfmt);
if (!ignore) {
@@ -329,7 +329,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri
m_emitDispState.pushFormat(*pos);
} else { // Format character
inPct = false;
switch (tolower(pos[0])) {
switch (std::tolower(pos[0])) {
case '0': // FALLTHRU
case '1': // FALLTHRU
case '2': // FALLTHRU
@@ -452,16 +452,16 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
puts(cvtToStr(nodep->widthWords()));
puts(", ");
}
iterateAndNextNull(nodep);
iterateAndNextConstNull(nodep);
puts(")");
}
}
void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
putbs("VL_CVT_W_A(");
iterate(nodep);
iterateConst(nodep);
puts(", ");
iterate(fromp);
iterateConst(fromp);
putbs(".atDefault()"); // Not accessed; only to get the proper type of values
puts(")");
}
@@ -541,6 +541,12 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
if (int(nodep->num().toDouble()) == nodep->num().toDouble()
&& nodep->num().toDouble() < 1000 && nodep->num().toDouble() > -1000) {
ofp()->printf("%3.1f", nodep->num().toDouble()); // Force decimal point
} else if (std::isinf(nodep->num().toDouble())) {
if (std::signbit(nodep->num().toDouble())) puts("-");
ofp()->puts("std::numeric_limits<double>::infinity()");
} else if (std::isnan(nodep->num().toDouble())) {
if (std::signbit(nodep->num().toDouble())) puts("-");
ofp()->puts("std::numeric_limits<double>::quiet_NaN()");
} else {
// Not %g as will not always put in decimal point, so not obvious to compiler
// is a real number
@@ -666,15 +672,15 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp,
"Should have swapped msb & lsb earlier.");
const string ivar = string("__Vi") + cvtToStr(depth);
const string ivar = string{"__Vi"} + cvtToStr(depth);
const string pre = ("for (int " + ivar + " = " + cvtToStr(0) + "; " + ivar + " < "
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
const string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(),
depth + 1, suffix + "[" + ivar + "]");
const string post = "}\n";
return below.empty() ? "" : pre + below + post;
} else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, StructDType);
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
string literal;
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
+142 -122
View File
@@ -34,13 +34,13 @@ constexpr int EMITC_NUM_CONSTW = 8;
//######################################################################
// Emit lazy forward declarations
class EmitCLazyDecls final : public VNVisitor {
class EmitCLazyDecls final : public VNVisitorConst {
// NODE STATE/TYPES
// None allowed to support threaded emitting
// MEMBERS
std::unordered_set<string> m_emittedManually; // Set of names already declared manually.
EmitCBaseVisitor& m_emitter; // For access to file output
EmitCBaseVisitorConst& m_emitter; // For access to file output
bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic)
std::set<AstNode*> m_emitted; // -> in set. Already emitted decl for symbols.
@@ -72,18 +72,18 @@ class EmitCLazyDecls final : public VNVisitor {
// VISITORS
void visit(AstNodeCCall* nodep) override {
lazyDeclare(nodep->funcp());
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstAddrOfCFunc* nodep) override {
lazyDeclare(nodep->funcp());
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstVarRef* nodep) override {
AstVar* const varp = nodep->varp();
// Only constant pool symbols are lazy declared for now ...
if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) {
if (EmitCBase::isConstPoolMod(EmitCParentModule::get(varp))) {
lazyDeclareConstPoolVar(varp);
}
}
@@ -91,7 +91,7 @@ class EmitCLazyDecls final : public VNVisitor {
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public:
explicit EmitCLazyDecls(EmitCBaseVisitor& emitter)
explicit EmitCLazyDecls(EmitCBaseVisitorConst& emitter)
: m_emitter(emitter) {}
void emit(AstNode* nodep) {
m_needsBlankLine = false;
@@ -203,12 +203,12 @@ public:
// variables. That way we could just invoke the appropriate emitter as needed.
VL_RESTORER(m_emitConstInit);
m_emitConstInit = true;
iterate(initp);
iterateConst(initp);
}
void putCommaIterateNext(AstNode* nodep, bool comma = false) {
for (AstNode* subnodep = nodep; subnodep; subnodep = subnodep->nextp()) {
if (comma) puts(", ");
iterate(subnodep);
iterateConst(subnodep);
comma = true;
}
}
@@ -273,17 +273,17 @@ public:
if (nodep->initsp()) {
putsDecoration("// Init\n");
iterateAndNextNull(nodep->initsp());
iterateAndNextConstNull(nodep->initsp());
}
if (nodep->stmtsp()) {
putsDecoration("// Body\n");
iterateAndNextNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->stmtsp());
}
if (nodep->finalsp()) {
putsDecoration("// Final\n");
iterateAndNextNull(nodep->finalsp());
iterateAndNextConstNull(nodep->finalsp());
}
puts("}\n");
@@ -309,9 +309,9 @@ public:
} else {
puts("I(");
}
iterateAndNextNull(selp->lsbp());
iterateAndNextConstNull(selp->lsbp());
puts(", ");
iterateAndNextNull(selp->fromp());
iterateAndNextConstNull(selp->fromp());
if (rhs) puts(", ");
} else {
putbs("VL_ASSIGNSEL_");
@@ -320,18 +320,18 @@ public:
puts("(");
puts(cvtToStr(selp->fromp()->widthMin()) + ",");
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextNull(selp->lsbp());
iterateAndNextConstNull(selp->lsbp());
puts(", ");
iterateAndNextNull(selp->fromp());
iterateAndNextConstNull(selp->fromp());
puts(", ");
}
} else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
iterateAndNextNull(selp->lhsp());
iterateAndNextConstNull(selp->lhsp());
puts(" = ");
putbs("VL_PUTC_N(");
iterateAndNextNull(selp->lhsp());
iterateAndNextConstNull(selp->lhsp());
puts(", ");
iterateAndNextNull(selp->rhsp());
iterateAndNextConstNull(selp->rhsp());
puts(", ");
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) {
putbs("VL_ASSIGN_"); // Set a systemC variable
@@ -339,7 +339,7 @@ public:
emitIQW(nodep);
puts("(");
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) {
putbs("VL_ASSIGN_"); // Get a systemC variable
@@ -347,7 +347,7 @@ public:
emitScIQW(varp);
puts("(");
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
} else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) //
&& !VN_IS(nodep->rhsp(), CExpr) //
@@ -361,41 +361,41 @@ public:
} else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
putbs("VL_ASSIGN_W(");
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
} else {
paren = false;
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(" ");
ofp()->blockInc();
decind = true;
if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak();
puts("= ");
}
if (rhs) iterateAndNextNull(nodep->rhsp());
if (rhs) iterateAndNextConstNull(nodep->rhsp());
if (paren) puts(")");
if (decind) ofp()->blockDec();
puts(";\n");
}
void visit(AstAlwaysPublic*) override {}
void visit(AstAssocSel* nodep) override {
iterateAndNextNull(nodep->fromp());
iterateAndNextConstNull(nodep->fromp());
putbs(".at(");
AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType);
UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type");
if (adtypep->keyDTypep()->isWide()) {
emitCvtWideArray(nodep->bitp(), nodep->fromp());
} else {
iterateAndNextNull(nodep->bitp());
iterateAndNextConstNull(nodep->bitp());
}
puts(")");
}
void visit(AstWildcardSel* nodep) override {
iterateAndNextNull(nodep->fromp());
iterateAndNextConstNull(nodep->fromp());
putbs(".at(");
AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType);
UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type");
iterateAndNextNull(nodep->bitp());
iterateAndNextConstNull(nodep->bitp());
puts(")");
}
void visit(AstCCall* nodep) override {
@@ -427,14 +427,14 @@ public:
void visit(AstCMethodCall* nodep) override {
const AstCFunc* const funcp = nodep->funcp();
UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall");
iterate(nodep->fromp());
iterateConst(nodep->fromp());
putbs("->");
puts(funcp->nameProtect());
emitCCallArgs(nodep, "");
}
void visit(AstCAwait* nodep) override {
puts("co_await ");
iterate(nodep->exprp());
iterateConst(nodep->exprp());
}
void visit(AstCNew* nodep) override {
if (VN_IS(nodep->dtypep(), VoidDType)) {
@@ -447,7 +447,7 @@ public:
puts(")");
}
void visit(AstCMethodHard* nodep) override {
iterate(nodep->fromp());
iterateConst(nodep->fromp());
puts(".");
puts(nodep->name());
puts("(");
@@ -458,7 +458,7 @@ public:
if (VN_IS(nodep->fromp()->dtypep(), QueueDType) && subnodep->dtypep()->isWide()) {
emitCvtWideArray(subnodep, nodep->fromp());
} else {
iterate(subnodep);
iterateConst(subnodep);
}
comma = true;
}
@@ -477,7 +477,7 @@ public:
}
// Probably fragile, V3Task may need to convert to a AstCReturn
puts(") { return ");
iterateAndNextNull(nodep->exprp());
iterateAndNextConstNull(nodep->exprp());
puts("; }\n");
}
void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE
@@ -492,9 +492,9 @@ public:
if (!v3Global.opt.protectIds()) return;
}
if (!(nodep->protect() && v3Global.opt.protectIds())) {
putsDecoration(string("// ") + nodep->name() + at + "\n");
putsDecoration(string{"// "} + nodep->name() + at + "\n");
}
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstCoverDecl* nodep) override {
puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
@@ -537,7 +537,7 @@ public:
}
void visit(AstCReturn* nodep) override {
puts("return (");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(");\n");
}
void visit(AstDisplay* nodep) override {
@@ -615,7 +615,7 @@ public:
emitCvtPackStr(nodep->searchp());
puts(", ");
putbs("");
iterateAndNextNull(nodep->outp());
iterateAndNextConstNull(nodep->outp());
puts(")");
}
void visit(AstTestPlusArgs* nodep) override {
@@ -624,10 +624,15 @@ public:
puts(")");
}
void visit(AstFError* nodep) override {
puts("VL_FERROR_IN(");
iterateAndNextNull(nodep->filep());
puts("VL_FERROR_I");
puts(nodep->strp()->isString() ? "N(" : "W(");
iterateAndNextConstNull(nodep->filep());
putbs(", ");
iterateAndNextNull(nodep->strp());
if (nodep->strp()->isWide()) {
puts(cvtToStr(nodep->strp()->widthWords()));
putbs(", ");
}
iterateAndNextConstNull(nodep->strp());
puts(")");
}
void visit(AstFGetS* nodep) override {
@@ -644,8 +649,7 @@ public:
}
}
void visit(AstFOpen* nodep) override {
iterateAndNextNull(nodep->filep());
puts(" = VL_FOPEN_NN(");
puts("VL_FOPEN_NN(");
emitCvtPackStr(nodep->filenamep());
putbs(", ");
if (nodep->modep()->width() > 4 * 8)
@@ -654,8 +658,7 @@ public:
puts(");\n");
}
void visit(AstFOpenMcd* nodep) override {
iterateAndNextNull(nodep->filep());
puts(" = VL_FOPEN_MCD_N(");
puts("VL_FOPEN_MCD_N(");
emitCvtPackStr(nodep->filenamep());
puts(");\n");
}
@@ -691,18 +694,18 @@ public:
{
const bool need_ptr = !VN_IS(nodep->memp()->dtypep(), AssocArrayDType);
if (need_ptr) puts(" &(");
iterateAndNextNull(nodep->memp());
iterateAndNextConstNull(nodep->memp());
if (need_ptr) puts(")");
}
putbs(", ");
if (nodep->lsbp()) {
iterateAndNextNull(nodep->lsbp());
iterateAndNextConstNull(nodep->lsbp());
} else {
puts(cvtToStr(array_lo));
}
putbs(", ");
if (nodep->msbp()) {
iterateAndNextNull(nodep->msbp());
iterateAndNextConstNull(nodep->msbp());
} else {
puts("~0ULL");
}
@@ -710,39 +713,37 @@ public:
}
void visit(AstFClose* nodep) override {
puts("VL_FCLOSE_I(");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
puts("); ");
iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it.
puts(" = 0;\n");
}
void visit(AstFFlush* nodep) override {
if (!nodep->filep()) {
puts("Verilated::runFlushCallbacks();\n");
} else {
puts("if (");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
puts(") { VL_FFLUSH_I(");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
puts("); }\n");
}
}
void visit(AstFSeek* nodep) override {
puts("(VL_FSEEK_I(");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
puts(",");
iterateAndNextNull(nodep->offset());
iterateAndNextConstNull(nodep->offset());
puts(",");
iterateAndNextNull(nodep->operation());
iterateAndNextConstNull(nodep->operation());
puts(") == -1 ? -1 : 0)");
}
void visit(AstFTell* nodep) override {
puts("VL_FTELL_I(");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
puts(")");
}
void visit(AstFRewind* nodep) override {
puts("(VL_FSEEK_I(");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
puts(", 0, 0) == -1 ? -1 : 0)");
}
void visit(AstFRead* nodep) override {
@@ -770,19 +771,19 @@ public:
puts(cvtToStr(array_size));
putbs(", ");
puts("&(");
iterateAndNextNull(nodep->memp());
iterateAndNextConstNull(nodep->memp());
puts(")");
putbs(", ");
iterateAndNextNull(nodep->filep());
iterateAndNextConstNull(nodep->filep());
putbs(", ");
if (nodep->startp()) {
iterateAndNextNull(nodep->startp());
iterateAndNextConstNull(nodep->startp());
} else {
puts(cvtToStr(array_lo));
}
putbs(", ");
if (nodep->countp()) {
iterateAndNextNull(nodep->countp());
iterateAndNextConstNull(nodep->countp());
} else {
puts(cvtToStr(array_size));
}
@@ -790,7 +791,7 @@ public:
}
void visit(AstSysFuncAsTask* nodep) override {
if (!nodep->lhsp()->isWide()) puts("(void)");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
if (!nodep->lhsp()->isWide()) puts(";");
}
void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); }
@@ -804,7 +805,7 @@ public:
putbs(", ");
}
checkMaxWords(nodep->lhsp());
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(");\n");
}
void visit(AstSystemF* nodep) override {
@@ -816,18 +817,18 @@ public:
putbs(", ");
}
checkMaxWords(nodep->lhsp());
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(")");
}
void visit(AstStmtExpr* node) override {
iterate(node->exprp());
iterateConst(node->exprp());
puts(";\n");
}
void visit(AstJumpBlock* nodep) override {
nodep->labelNum(++m_labelNum);
puts("{\n"); // Make it visually obvious label jumps outside these
iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->endStmtsp());
iterateAndNextConstNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->endStmtsp());
puts("}\n");
}
void visit(AstJumpGo* nodep) override {
@@ -837,13 +838,13 @@ public:
puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
}
void visit(AstWhile* nodep) override {
iterateAndNextNull(nodep->precondsp());
iterateAndNextConstNull(nodep->precondsp());
puts("while (");
iterateAndNextNull(nodep->condp());
iterateAndNextConstNull(nodep->condp());
puts(") {\n");
iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->incsp());
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
iterateAndNextConstNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->incsp());
iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop
puts("}\n");
}
void visit(AstNodeIf* nodep) override {
@@ -852,20 +853,20 @@ public:
puts(nodep->branchPred().ascii());
puts("(");
}
iterateAndNextNull(nodep->condp());
iterateAndNextConstNull(nodep->condp());
if (!nodep->branchPred().unknown()) puts(")");
puts(") {\n");
iterateAndNextNull(nodep->thensp());
iterateAndNextConstNull(nodep->thensp());
puts("}");
if (!nodep->elsesp()) {
puts("\n");
} else {
if (VN_IS(nodep->elsesp(), NodeIf) && !nodep->elsesp()->nextp()) {
puts(" else ");
iterateAndNextNull(nodep->elsesp());
iterateAndNextConstNull(nodep->elsesp());
} else {
puts(" else {\n");
iterateAndNextNull(nodep->elsesp());
iterateAndNextConstNull(nodep->elsesp());
puts("}\n");
}
}
@@ -874,9 +875,9 @@ public:
// GCC allows compound statements in expressions, but this is not standard.
// So we use an immediate-evaluation lambda and comma operator
putbs("([&]() {\n");
iterateAndNextNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->stmtsp());
puts("}(), ");
iterateAndNextNull(nodep->resultp());
iterateAndNextConstNull(nodep->resultp());
puts(")");
}
void visit(AstStop* nodep) override {
@@ -904,6 +905,9 @@ public:
void visit(AstRand* nodep) override {
emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr);
}
void visit(AstRandRNG* nodep) override {
emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr);
}
void visit(AstTime* nodep) override {
puts("VL_TIME_UNITED_Q(");
if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units");
@@ -920,13 +924,13 @@ public:
}
void visit(AstTimeFormat* nodep) override {
puts("VL_TIMEFORMAT_IINI(");
iterateAndNextNull(nodep->unitsp());
iterateAndNextConstNull(nodep->unitsp());
puts(", ");
iterateAndNextNull(nodep->precisionp());
iterateAndNextConstNull(nodep->precisionp());
puts(", ");
emitCvtPackStr(nodep->suffixp());
puts(", ");
iterateAndNextNull(nodep->widthp());
iterateAndNextConstNull(nodep->widthp());
puts(", vlSymsp->_vm_contextp__);\n");
}
void visit(AstTimePrecision* nodep) override {
@@ -945,23 +949,23 @@ public:
void visit(AstTextBlock* nodep) override {
visit(static_cast<AstNodeSimpleText*>(nodep));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
iterateConst(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
}
}
void visit(AstCStmt* nodep) override {
putbs("");
iterateAndNextNull(nodep->exprsp());
iterateAndNextConstNull(nodep->exprsp());
}
void visit(AstCExpr* nodep) override {
putbs("");
iterateAndNextNull(nodep->exprsp());
iterateAndNextConstNull(nodep->exprsp());
}
void visit(AstUCStmt* nodep) override {
VL_RESTORER(m_inUC);
m_inUC = true;
putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n"));
iterateAndNextNull(nodep->exprsp());
iterateAndNextConstNull(nodep->exprsp());
puts("\n");
}
void visit(AstUCFunc* nodep) override {
@@ -969,7 +973,7 @@ public:
m_inUC = true;
puts("\n");
putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n"));
iterateAndNextNull(nodep->exprsp());
iterateAndNextConstNull(nodep->exprsp());
puts("\n");
}
@@ -991,7 +995,7 @@ public:
putbs("(");
puts(nodep->emitSimpleOperator());
puts(" ");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(")");
} else {
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr);
@@ -1007,11 +1011,11 @@ public:
}
if (emitSimpleOk(nodep)) {
putbs("(");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(" ");
putbs(nodep->emitSimpleOperator());
puts(" ");
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(")");
} else {
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
@@ -1033,7 +1037,7 @@ public:
putbs("VL_REDXOR_");
puts(cvtToStr(widthPow2));
puts("(");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(")");
}
}
@@ -1044,7 +1048,7 @@ public:
} else {
puts("(QData)(");
}
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(")");
}
void visit(AstNodeCond* nodep) override {
@@ -1053,27 +1057,27 @@ public:
emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep());
} else {
putbs("(");
iterateAndNextNull(nodep->condp());
iterateAndNextConstNull(nodep->condp());
putbs(" ? ");
iterateAndNextNull(nodep->thenp());
iterateAndNextConstNull(nodep->thenp());
putbs(" : ");
iterateAndNextNull(nodep->elsep());
iterateAndNextConstNull(nodep->elsep());
puts(")");
}
}
void visit(AstMemberSel* nodep) override {
iterateAndNextNull(nodep->fromp());
iterateAndNextConstNull(nodep->fromp());
putbs("->");
puts(nodep->varp()->nameProtect());
}
void visit(AstStructSel* nodep) override {
iterateAndNextNull(nodep->fromp());
iterateAndNextConstNull(nodep->fromp());
putbs(".");
puts(nodep->nameProtect());
}
void visit(AstNullCheck* nodep) override {
puts("VL_NULL_CHECK(");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
putsQuoted(protect(nodep->fileline()->filename()));
puts(", ");
@@ -1083,7 +1087,7 @@ public:
void visit(AstNewCopy* nodep) override {
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", ");
puts("*"); // i.e. make into a reference
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(")");
}
void visit(AstSel* nodep) override {
@@ -1101,9 +1105,9 @@ public:
puts("OI(");
if (nodep->lhsp()) puts(cvtToStr(nodep->lhsp()->widthMin()));
puts(",");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(")");
} else {
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
@@ -1121,7 +1125,7 @@ public:
puts("I(");
puts(cvtToStr(nodep->lhsp()->widthMin()));
puts(", ");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
const uint32_t rd_log2 = V3Number::log2b(VN_AS(nodep->rhsp(), Const)->toUInt());
puts(cvtToStr(rd_log2) + ")");
@@ -1133,9 +1137,9 @@ public:
}
void visit(AstCastDynamic* nodep) override {
putbs("VL_CAST_DYNAMIC(");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(")");
}
void visit(AstCountBits* nodep) override {
@@ -1149,16 +1153,16 @@ public:
// (which is always 32)
puts(", ");
}
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(", ");
iterateAndNextNull(nodep->thsp());
iterateAndNextConstNull(nodep->thsp());
puts(", ");
iterateAndNextNull(nodep->fhsp());
iterateAndNextConstNull(nodep->fhsp());
puts(")");
}
void visit(AstInitItem* nodep) override { iterateChildren(nodep); }
void visit(AstInitItem* nodep) override { iterateChildrenConst(nodep); }
// Terminals
void visit(AstVarRef* nodep) override {
const AstVar* const varp = nodep->varp();
@@ -1216,17 +1220,17 @@ public:
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
iterateAndNextNull(nodep->defaultp());
iterateAndNextConstNull(nodep->defaultp());
puts(")");
}
}
void visit(AstSetAssoc* nodep) override {
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
putbs(".set(");
iterateAndNextNull(nodep->keyp());
iterateAndNextConstNull(nodep->keyp());
puts(", ");
putbs("");
iterateAndNextNull(nodep->valuep());
iterateAndNextConstNull(nodep->valuep());
puts(")");
}
void visit(AstConsWildcard* nodep) override {
@@ -1234,17 +1238,17 @@ public:
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
iterateAndNextNull(nodep->defaultp());
iterateAndNextConstNull(nodep->defaultp());
puts(")");
}
}
void visit(AstSetWildcard* nodep) override {
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
putbs(".set(");
iterateAndNextNull(nodep->keyp());
iterateAndNextConstNull(nodep->keyp());
puts(", ");
putbs("");
iterateAndNextNull(nodep->valuep());
iterateAndNextConstNull(nodep->valuep());
puts(")");
}
void visit(AstConsDynArray* nodep) override {
@@ -1253,27 +1257,43 @@ public:
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(")");
}
}
void visit(AstConsPackUOrStruct* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
puts("{");
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
iterateConst(memberp);
if (memberp->nextp()) { puts(", "); }
}
puts("}");
}
void visit(AstConsPackMember* nodep) override {
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
putbs(".");
puts(vdtypep->name());
puts(" = ");
iterateConst(nodep->rhsp());
}
void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
iterateAndNextConstNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
iterateAndNextConstNull(nodep->rhsp());
puts(")");
}
}
@@ -1290,8 +1310,8 @@ public:
// Default
void visit(AstNode* nodep) override {
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
iterateChildren(nodep);
puts(string{"\n???? // "} + nodep->prettyTypeName() + "\n");
iterateChildrenConst(nodep);
// LCOV_EXCL_START
if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress
nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName());
@@ -1305,7 +1325,7 @@ public:
: EmitCFunc{} {
m_ofp = ofp;
m_trackText = trackText;
iterate(nodep);
iterateConst(nodep);
}
~EmitCFunc() override = default;
};
+17 -11
View File
@@ -117,7 +117,12 @@ class EmitCHeader final : public EmitCConstInit {
emitCurrentList();
}
void emitInternalVarDecls(const AstNodeModule* modp) {
if (!VN_IS(modp, Class)) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
if (classp->needRNG()) {
putsDecoration("\n// INTERNAL VARIABLES\n");
puts("VlRNG __Vm_rng;\n");
}
} else { // not class
putsDecoration("\n// INTERNAL VARIABLES\n");
puts(symClassName() + "* const vlSymsp;\n");
}
@@ -136,7 +141,7 @@ class EmitCHeader final : public EmitCConstInit {
puts(varp->dtypep()->cType(varp->nameProtect(), false, false));
if (canBeConstexpr) {
puts(" = ");
iterate(varp->valuep());
iterateConst(varp->valuep());
}
puts(";\n");
}
@@ -161,7 +166,7 @@ class EmitCHeader final : public EmitCConstInit {
puts("void " + protect("__Vconfigure") + "(bool first);\n");
}
if (v3Global.opt.coverage()) {
if (v3Global.opt.coverage() && !VN_IS(modp, Class)) {
decorateFirst(first, section);
puts("void __vlCoverInsert(");
puts(v3Global.opt.threads() ? "std::atomic<uint32_t>" : "uint32_t");
@@ -200,7 +205,7 @@ class EmitCHeader final : public EmitCConstInit {
}
puts(itemp->nameProtect());
puts(" = ");
iterate(itemp->valuep());
iterateConst(itemp->valuep());
if (VN_IS(itemp->nextp(), EnumItem)) puts(",");
puts("\n");
}
@@ -208,13 +213,13 @@ class EmitCHeader final : public EmitCConstInit {
}
}
}
void emitStructDecl(const AstNodeModule* modp, AstStructDType* sdtypep,
std::set<AstStructDType*>& emitted) {
void emitStructDecl(const AstNodeModule* modp, AstNodeUOrStructDType* sdtypep,
std::set<AstNodeUOrStructDType*>& emitted) {
if (emitted.count(sdtypep) > 0) return;
emitted.insert(sdtypep);
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstStructDType* subp = VN_CAST(itemp->skipRefp(), StructDType);
AstNodeUOrStructDType* subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
if (subp && !subp->packed()) {
// Recurse if it belongs to the current module
if (subp->classOrPackagep() == modp) {
@@ -223,7 +228,8 @@ class EmitCHeader final : public EmitCConstInit {
}
}
}
puts("struct " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n");
puts(sdtypep->verilogKwd()); // "struct"/"union"
puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n");
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false));
@@ -234,12 +240,12 @@ class EmitCHeader final : public EmitCConstInit {
void emitStructs(const AstNodeModule* modp) {
bool first = true;
// Track structs that've been emitted already
std::set<AstStructDType*> emitted;
std::set<AstNodeUOrStructDType*> emitted;
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
const AstTypedef* const tdefp = VN_CAST(nodep, Typedef);
if (!tdefp) continue;
AstStructDType* const sdtypep
= VN_CAST(tdefp->dtypep()->skipRefToEnump(), StructDType);
AstNodeUOrStructDType* const sdtypep
= VN_CAST(tdefp->dtypep()->skipRefToEnump(), NodeUOrStructDType);
if (!sdtypep) continue;
if (sdtypep->packed()) continue;
decorateFirst(first, "\n// UNPACKED STRUCT TYPES\n");
+27 -28
View File
@@ -33,27 +33,27 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// Visitor that gathers the headers required by an AstCFunc
class EmitCGatherDependencies final : VNVisitor {
class EmitCGatherDependencies final : VNVisitorConst {
// Ordered set, as it is used as a key in another map.
std::set<string> m_dependencies; // Header names to be included in output C++ file
// METHODS
void addSymsDependency() { m_dependencies.insert(EmitCBaseVisitor::symClassName()); }
void addSymsDependency() { m_dependencies.insert(EmitCBase::symClassName()); }
void addModDependency(const AstNodeModule* modp) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(classp->classOrPackagep()));
m_dependencies.insert(EmitCBase::prefixNameProtect(classp->classOrPackagep()));
} else {
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(modp));
m_dependencies.insert(EmitCBase::prefixNameProtect(modp));
}
}
void addDTypeDependency(const AstNodeDType* nodep) {
if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) {
m_dependencies.insert(
EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep()));
} else if (const AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) {
EmitCBase::prefixNameProtect(dtypep->classp()->classOrPackagep()));
} else if (const AstNodeUOrStructDType* const dtypep
= VN_CAST(nodep, NodeUOrStructDType)) {
if (!dtypep->packed()) {
m_dependencies.insert(
EmitCBaseVisitor::prefixNameProtect(dtypep->classOrPackagep()));
m_dependencies.insert(EmitCBase::prefixNameProtect(dtypep->classOrPackagep()));
}
}
}
@@ -141,7 +141,7 @@ class EmitCGatherDependencies final : VNVisitor {
// declaration of the receiver class, but their body very likely includes at least one
// relative reference, so we are probably not loosing much.
addModDependency(EmitCParentModule::get(cfuncp));
iterate(cfuncp);
iterateConst(cfuncp);
}
public:
@@ -174,8 +174,7 @@ class EmitCImp final : EmitCFunc {
// Unfortunately we have some lint checks here, so we can't just skip processing.
// We should move them to a different stage.
const string filename = VL_DEV_NULL;
m_cfilesr.push_back(
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true));
m_ofp = new V3OutCFile{filename};
} else {
string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp);
@@ -185,12 +184,11 @@ class EmitCImp final : EmitCFunc {
}
if (m_slow) filename += "__Slow";
filename += ".cpp";
m_cfilesr.push_back(
newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false));
m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true));
m_ofp = v3Global.opt.systemC() ? new V3OutScFile{filename} : new V3OutCFile{filename};
}
ofp()->putsHeader();
putsHeader();
puts("// DESCRIPTION: Verilator output: Design implementation internals\n");
puts("// See " + topClassName() + ".h for the primary calling header\n");
@@ -198,6 +196,7 @@ class EmitCImp final : EmitCFunc {
puts("\n#include \"verilated.h\"\n");
if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n");
puts("\n");
puts("#include \"" + symClassName() + ".h\"\n");
for (const string& name : headers) puts("#include \"" + name + ".h\"\n");
emitTextSection(m_modp, VNType::atScImpHdr);
@@ -262,7 +261,7 @@ class EmitCImp final : EmitCFunc {
puts(", ");
puts(varp->nameProtect());
puts("(");
iterate(varp->valuep());
iterateConst(varp->valuep());
puts(")\n");
} else if (varp->isIO() && varp->isSc()) {
puts(", ");
@@ -401,7 +400,7 @@ class EmitCImp final : EmitCFunc {
const int vecnum = vects++;
UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp,
"Should have swapped msb & lsb earlier.");
const string ivar = string("__Vi") + cvtToStr(vecnum);
const string ivar = string{"__Vi"} + cvtToStr(vecnum);
puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0));
puts("; " + ivar + " < " + cvtToStr(arrayp->elementsConst()));
puts("; ++" + ivar + ") {\n");
@@ -415,7 +414,7 @@ class EmitCImp final : EmitCFunc {
if (elementp->isWide()
&& !(basicp && basicp->keyword() == VBasicDTypeKwd::STRING)) {
const int vecnum = vects++;
const string ivar = string("__Vi") + cvtToStr(vecnum);
const string ivar = string{"__Vi"} + cvtToStr(vecnum);
puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0));
puts("; " + ivar + " < " + cvtToStr(elementp->widthWords()));
puts("; ++" + ivar + ") {\n");
@@ -454,9 +453,9 @@ class EmitCImp final : EmitCFunc {
emitCtorImp(modp);
emitConfigureImp(modp);
emitDestructorImp(modp);
emitCoverageImp();
}
emitSavableImp(modp);
emitCoverageImp();
} else {
// From `systemc_implementation
emitTextSection(modp, VNType::atScImp);
@@ -514,7 +513,7 @@ class EmitCImp final : EmitCFunc {
// Compute the hash of the dependencies, so we can add it to the filenames to
// disambiguate them
V3Hash hash;
for (const string& name : *m_requiredHeadersp) { hash += name; }
for (const string& name : *m_requiredHeadersp) hash += name;
m_subFileName = "DepSet_" + hash.toString();
// Open output file
openNextOutputFile(*m_requiredHeadersp, m_subFileName);
@@ -522,7 +521,7 @@ class EmitCImp final : EmitCFunc {
for (AstCFunc* const funcp : pair.second) {
VL_RESTORER(m_modp);
m_modp = EmitCParentModule::get(funcp);
iterate(funcp);
iterateConst(funcp);
}
// Close output file
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
@@ -597,7 +596,7 @@ class EmitCTrace final : EmitCFunc {
if (m_slow) filename += "__Slow";
filename += ".cpp";
AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/);
AstCFile* const cfilep = createCFile(filename, m_slow, true /*source*/);
cfilep->support(true);
m_cfilesr.push_back(cfilep);
@@ -606,9 +605,9 @@ class EmitCTrace final : EmitCFunc {
} else {
m_ofp = new V3OutCFile{filename};
}
m_ofp->putsHeader();
m_ofp->puts("// DESCR"
"IPTION: Verilator output: Tracing implementation internals\n");
putsHeader();
puts("// DESCR"
"IPTION: Verilator output: Tracing implementation internals\n");
// Includes
puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n");
@@ -774,7 +773,7 @@ class EmitCTrace final : EmitCFunc {
}
void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) {
iterateAndNextNull(nodep->precondsp());
iterateAndNextConstNull(nodep->precondsp());
const string func = nodep->full() ? "full" : "chg";
bool emitWidth = true;
if (nodep->dtypep()->basicp()->isDouble()) {
@@ -817,7 +816,7 @@ class EmitCTrace final : EmitCFunc {
} else if (emitTraceIsScBv(nodep)) {
puts("VL_SC_BV_DATAP(");
}
iterate(varrefp); // Put var name out
iterateConst(varrefp); // Put var name out
// Tracing only supports 1D arrays
if (nodep->declp()->arrayRange().ranged()) {
if (arrayindex == -2) {
@@ -839,7 +838,7 @@ class EmitCTrace final : EmitCFunc {
puts(")");
} else {
puts("(");
iterate(nodep->valuep());
iterateConst(nodep->valuep());
puts(")");
}
}
@@ -901,7 +900,7 @@ class EmitCTrace final : EmitCFunc {
openNextOutputFile();
// Emit functions
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterate(funcp); }
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterateConst(funcp); }
}
// Close output file
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
+8 -8
View File
@@ -28,7 +28,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
class EmitCInlines final : EmitCBaseVisitor {
class EmitCInlines final : EmitCBaseVisitorConst {
// STATE
// METHODS
@@ -37,26 +37,26 @@ class EmitCInlines final : EmitCBaseVisitor {
void visit(AstCNew* nodep) override {
if (v3Global.opt.savable())
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstDumpCtl* nodep) override {
if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstNodeDistBiop* nodep) override {
v3Global.setUsesProbDist();
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
void visit(AstNodeDistTriop* nodep) override {
v3Global.setUsesProbDist();
iterateChildren(nodep);
iterateChildrenConst(nodep);
}
//---------------------------------------
void visit(AstNode* nodep) override { iterateChildren(nodep); }
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public:
explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); }
explicit EmitCInlines(AstNetlist* nodep) { iterateConst(nodep); }
};
//######################################################################
@@ -64,5 +64,5 @@ public:
void V3EmitC::emitcInlines() {
UINFO(2, __FUNCTION__ << ": " << endl);
EmitCInlines(v3Global.rootp());
{ EmitCInlines{v3Global.rootp()}; }
}
+2 -2
View File
@@ -29,12 +29,12 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
class EmitCMain final : EmitCBaseVisitor {
class EmitCMain final : EmitCBaseVisitorConst {
// METHODS
// VISITORS
// This visitor doesn't really iterate, but exist to appease base class
void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // LCOV_EXCL_LINE
public:
// CONSTRUCTORS

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