Compare commits

...
142 Commits
Author SHA1 Message Date
Wilson Snyder 95c4b6aaba Version bump 2020-03-08 08:38:53 -04:00
Wilson Snyder 1c1319079b Tests: Add driver --hashset for Travis. 2020-03-07 22:02:03 -05:00
Wilson Snyder 328fef8190 Tests: Add driver --hashset for Travis. 2020-03-07 21:38:44 -05:00
Wilson Snyder e2dec043a0 Tests: Backout part of previous commit. 2020-03-07 21:01:36 -05:00
Wilson Snyder bd42e31b2a Tests: For travis, skip Bit::Vector and show intall dates. 2020-03-07 20:08:41 -05:00
Wilson Snyder 6d73237b27 Travis: Don't cpan test to save time. 2020-03-07 19:24:05 -05:00
Wilson Snyder 6c6d70a5e5 Fix FST when multi-model tracing. 2020-03-07 18:39:58 -05:00
Wilson Snyder 6f49f802b1 Tests: Add fst_identical. 2020-03-07 16:59:46 -05:00
Wilson Snyder 808c958d42 Internals: Add AstNodeCCall and other items towards classes. 2020-03-07 12:52:11 -05:00
Wilson Snyder 961ac49c5c Internals: Merge parse type from classes branch. No functional change intended. 2020-03-07 11:00:57 -05:00
Wilson Snyder 2d52f525c5 Add --structs-packed for forward compatibility, #1541. 2020-03-07 10:51:06 -05:00
Wilson Snyder e70cba77e6 Add support for dynamic arrays, #379. 2020-03-07 10:24:27 -05:00
Wilson Snyder 8054fc47ea Internals: Refectoring. No functional change intended. 2020-03-07 08:24:57 -05:00
Wilson Snyder e673875b3b Fix clang warning, last commit. 2020-03-06 07:31:56 -05:00
Wilson Snyder 29923b78fd Internals: Use VL_TO_STRING instead of to_string. 2020-03-05 23:28:41 -05:00
Wilson Snyder 135cbcd79a Internals: Move 'new' unsupported forward from parse into Ast. 2020-03-05 22:33:31 -05:00
Wilson Snyder 75ecad591a Implement $displayb/o/h, $writeb/o/h, etc, Closes #1637. 2020-03-05 21:49:25 -05:00
Wilson Snyder c108f5def9 Commentary, Closes #2177. 2020-03-05 19:09:58 -05:00
Wilson Snyder dab1cb610a Tests: Allow iv to run SystemVerilog tests 2020-03-05 18:12:10 -05:00
Wilson Snyder fd656f6cc1 Fix clang asserted missing lock on m_dumping. 2020-03-03 19:20:04 -05:00
Wilson Snyder a7e65379fa Ignore $dumpflush, think causes travis thread error. 2020-03-02 17:56:42 -05:00
Wilson Snyder 905067d13f Fix $dumpvar multithreaded assert, broke last commit. 2020-03-02 07:43:10 -05:00
Wilson Snyder 30a33a6104 Add support for and , #2126. 2020-03-01 21:39:23 -05:00
Wilson Snyder 0ca0e07354 Internals: Vcd doesn't need code when registering. No functional change intended. 2020-02-29 20:42:52 -05:00
Wilson Snyder aac02acf92 Tests: Rename 2020-02-29 10:06:52 -05:00
Wilson Snyder 082c9e0b1d Tests: Add two-design trace tests. 2020-02-29 09:44:51 -05:00
Wilson Snyder a7bd934fe3 Tests: Cleanup false used as 0. No functional change. 2020-02-29 08:56:49 -05:00
David Stanford e98a380b44 Tests: Update some tests to skip if prerequisites aren't installed (#2181) 2020-02-29 07:20:23 -05:00
Wilson Snyder 4878fe3a1f Add split_var metacomment to assist UNOPTFLAT fixes, #2066. 2020-02-28 19:15:08 -05:00
Wilson Snyder c6b755a12e Commentary 2020-02-27 19:35:49 -05:00
Wilson Snyder 991d81cd0a Recommend -Os. 2020-02-27 07:46:34 -05:00
Wilson Snyder c06a97a221 Remove OBJCACHE_HOSTS; dead code. 2020-02-27 07:18:15 -05:00
Wilson Snyder 6131bcdbb0 Verilator_gantt: Fix CPU count in report. 2020-02-27 07:12:50 -05:00
Wilson Snyder 68b6a0b667 Fix genblk naming with directly nested generate blocks, #2176. 2020-02-25 22:21:16 -05:00
Wilson Snyder 4c438bbc67 Commentary 2020-02-25 19:01:14 -05:00
Wilson Snyder 5b83484f20 Remove dead genblk code & some cleanups. 2020-02-25 18:57:51 -05:00
Wilson Snyder 93ac79981b Tests: Rename t_var_dotted. No functional change. 2020-02-24 18:51:44 -05:00
Wilson Snyder c9b74847d1 Docs: Tighter margins, save 10 pages. 2020-02-24 18:11:56 -05:00
Wilson Snyder 23eb96579c Fix duplicate __STDC_FORMAT_MACROS definition. 2020-02-24 18:11:41 -05:00
Todd Strader 8319ea6c73 Changes 2020-02-24 06:36:13 -05:00
Todd Strader 60f82961b4 De-tabify 2020-02-24 06:36:13 -05:00
Todd Strader f7d1c6ca72 emacs verilog-batch-indent 2020-02-24 06:36:13 -05:00
Todd Strader 4b4f10f5e6 Follow other clock gating examples 2020-02-24 06:36:13 -05:00
Todd Strader 120f62fe85 Fix is probably to mark as a clock 2020-02-24 06:36:13 -05:00
Todd Strader db6ecbd57e Test for #2169 2020-02-24 06:36:13 -05:00
Wilson Snyder 28e19cef90 Fix undeclared VL_SHIFTR_WWQ, #2114. 2020-02-23 19:33:37 -05:00
Tobias Wölfel 18f8cd0529 Allow assert disable (#2168)
* Add +verilator+noassert flag

This allows to disable the assert check per simulation argument.

* Add AssertOn check for assert

Insert the check AssertOn to allow disabling of asserts.
Asserts can be disabled by not using the `--assert` flag or by calling
`AssertOn(false)`, or passing the "+verilator+noassert" runtime flag.
Add tests for this behavior.
Bad tests check that the assert still causes a stop.
Non bad tests check that asserts are properly disabled and cause no stop
of the simulation.

Fixes #2162.

Signed-off-by: Tobias Wölfel <[email protected]>

* Correct file location

Signed-off-by: Tobias Wölfel <[email protected]>

* Add description for single test execution

Without this description it is not obvious how to run a single test from
the regression test suite.

Signed-off-by: Tobias Wölfel <[email protected]>
2020-02-15 18:17:23 -06:00
Wilson Snyder 02786b3f09 Commentary 2020-02-12 22:46:59 -05:00
Wilson Snyder 70358e8587 Fix compiler warning. 2020-02-08 10:58:07 -05:00
Wilson Snyder 95b66feeb8 devel release 2020-02-08 09:16:35 -05:00
Wilson Snyder 890cecc15b Version bump 2020-02-08 09:03:51 -05:00
Wilson Snyder f7bad37e88 Fix GCC 4.4.7 errors. 2020-02-08 07:09:41 -05:00
Wilson Snyder 134b5efd70 Tests: Ignore obj_iv. 2020-02-07 18:00:07 -05:00
Wilson Snyder 0d6ebf21b3 Suggest svSetScope, #2152. 2020-02-07 17:59:02 -05:00
Wilson Snyder 2d1b804e80 Fix OpenSolaris issues, #2154. 2020-02-07 17:35:04 -05:00
Todd Strader 77f1b3eef4 Support parameter access from arrays of interfaces, #2155. 2020-02-06 19:19:23 -05:00
Wilson Snyder 609a5dc26d Fix cppcheck warnings. No functional change intended. 2020-02-03 23:21:56 -05:00
Wilson Snyder 0aabe6ce00 Internals: Fix cppcheck warning including missing init. 2020-02-03 22:10:29 -05:00
Wilson Snyder 20cc4e57d5 tests: Driver style fix. 2020-02-03 18:43:56 -05:00
Wilson Snyder f3ebdc40c6 Fix some coverage lost when multithreaded, #2151. 2020-02-03 18:43:41 -05:00
Wilson Snyder 2ca9f73b31 Internals: Cleanup Emit towards constructor/destructor output. 2020-02-02 21:15:07 -05:00
Wilson Snyder 73f5e3f808 Internals: Add missing const. No functional change. 2020-02-02 10:34:29 -05:00
Wilson Snyder 8d3dad510f Fix unused variable. 2020-02-02 06:52:28 -05:00
Wilson Snyder 2576c136f6 Fix `pragma pedantic check to work with -E. 2020-02-01 22:03:18 -05:00
Wilson Snyder a8ad97eef2 Add VL_CACHE_LINE_BYTES and use 64 as defult. 2020-02-01 20:28:03 -05:00
Wilson Snyder ee7da1e690 Remove .h comments for empty sections. 2020-02-01 20:11:21 -05:00
Wilson Snyder 969a46faf6 Internals: V3Emit refactoring. No functional change intended. 2020-02-01 19:32:04 -05:00
Wilson Snyder 820df28ad9 Internals: V3CUse state refactoring. No functional change intended. 2020-02-01 19:11:19 -05:00
Yutetsu TAKATSUKASA 50fb7fc8b4 Tests: Resolve self assignment in t_unoptflat_simple_2, Closes #2149. 2020-02-01 19:07:02 -05:00
Wilson Snyder 119162912a Internals: Determine emit forward declaraions in new pass, towards classes. 2020-02-01 16:51:05 -05:00
Wilson Snyder 80d94891e1 Internals: Allow const & non-member CFuncs for class branch. No functional change. 2020-02-01 10:57:55 -05:00
Geza Lore f00ff61559 Link Verilator binary partially statically, Closes #2146.
The build is now by default configured to link performance critical
libraries (libgcc, libstdc++, libtcmalloc) statically. This improves
Verilation speed by between 4.5-7% based on my measurements as it
eliminates approx 20% of the mispredicted branches from the execution.
With partial static linking, the size of the .text section in
verilator_bin is increased by about 14%, and the binary is itself only
about 800KB bigger on disk, so hopefully this is not a big issue in
exchange for the faster compilation speed. A configure option
"--disable-partial-static" is provided to restore the old behaviour of
linking everything dynamically.

Note: This patch also changes to use libtcmalloc_minimal, which is all
we really need and itself has fewer dependencies.
2020-01-31 19:13:55 -05:00
Wilson Snyder 2d195ebae5 Cleanup IEEE references. 2020-01-30 20:23:57 -05:00
Wilson Snyder 9a6bc3ddcf Commentary 2020-01-30 19:52:58 -05:00
Wilson Snyder d218f1746c Add warning on genvar in normal for loop, #2143. 2020-01-29 21:16:44 -05:00
Yutetsu TAKATSUKASA 8d8eb1b9f3 Tests: Resolve racing among initial blocks in t_display_signed.v, #2144. 2020-01-29 17:07:45 -05:00
Wilson Snyder d4614c290e Fix WIDTH warning on </<= of narrower value, #2141. 2020-01-28 20:10:10 -05:00
Tobias Rosenkranz 027cce35c0 Support enum.next(k) with constant k > 1, #2125. 2020-01-27 17:25:25 -05:00
Wilson Snyder 9fd81b2c6b Support string character access via indexing. 2020-01-26 16:38:22 -05:00
Wilson Snyder 5430e4ac9b Cleanup more errors showing data types. 2020-01-26 15:54:57 -05:00
Wilson Snyder 619214b48f Support $sampled. 2020-01-26 13:38:15 -05:00
Wilson Snyder 68fa82fb14 Support $typename, and use to cleanup error messages. 2020-01-26 13:21:25 -05:00
Wilson Snyder cac50282eb Fix pattern replication without key. 2020-01-26 11:38:34 -05:00
Wilson Snyder b50ef9ff39 Tests: Disabled test for 5.9. 2020-01-26 11:23:52 -05:00
Wilson Snyder 8a8f1135b7 Support type(expression) operator, #1650. 2020-01-26 10:28:13 -05:00
Wilson Snyder f0b2336345 Internals: Fix cell recursion with future module-in-module. 2020-01-25 18:15:55 -05:00
Wilson Snyder 52907e7b02 astgen: Preserve #line, #2138. 2020-01-25 15:36:37 -05:00
Geza Lore ef5250f0ca Internals: Further performance improvement of AstNode type tests, #2138. No functional change intended.
Replace the virtual type() method on AstNode with a non-virtual, inlined
accessor to a const member variable m_type.  This means that in order to be
able to use this for type testing, it needs to be initialized based on the
final type of the node. This is achieved by passing the relevant AstType
value back through the constructor call chain. Most of the boilerplate
involved is auto generated by first feeding V3AstNodes.h through astgen to
get V3AstNodes__gen.h, which is then included in V3Ast.h. No client code
needs to be aware and there is no functional change intended.

Eliminating the virtual function call to fetch the node type identifier
results in measured compilation speed improvement of 5-10% as it
eliminates up to 20% of all mispredicted branches from the execution.
2020-01-25 15:29:44 -05:00
Wilson Snyder eafed88a6e Internals: Add assertions. No functional change intended. 2020-01-25 10:19:59 -05:00
Wilson Snyder d64e6b3f9c Internals: Refactoring towards classes. No functional change intended. 2020-01-25 09:33:43 -05:00
Wilson Snyder d68ffba8cd Internals: Rename to prefixNameProtect. No functional change intended. 2020-01-25 09:16:00 -05:00
Wilson Snyder f0f370490f Internals: Style cleanups. 2020-01-25 07:59:25 -05:00
Wilson Snyder 708fd36563 Tests: Show entering/exit so goto-error works on compile errors. 2020-01-24 22:40:19 -05:00
Wilson Snyder a4e8d39932 Spelling fixes 2020-01-24 20:10:44 -05:00
Wilson Snyder 8f0e8e0696 Fix FST tracing of enums inside structs. 2020-01-24 19:46:46 -05:00
Wilson Snyder 11380bc3b2 Merge from upstream gtkwave includes. 2020-01-23 17:48:27 -05:00
Geza Lore 7ab2bdb6bb Support libgoogle-perftools-dev's libtcmalloc if available. #2137.
As Verilator continuously allocates and releases small objects (e.g.:
AstNode, V3GraphVertex, V3GraphEdge), it spends a significant amount of
time in malloc/free and friends. This patch adds the --enable-tcmalloc
configure option to link Verilator against the high performance malloc
implementation library libtcmalloc. The default is to use libtcmalloc if
available on the system. Note that there are no source code change, we
are simply replacing the standard library memory allocation functions.

Measured major compilation speed improvement of 27% when running
Verilator with -O3 on a large design.
2020-01-23 17:32:19 -05:00
Pieter Kapsenberg 5d037c3c8c Docs: Add initial XML dovcument description. #2136. 2020-01-23 07:26:11 -05:00
Geza Lore c5d04631d1 Internals: More performance efficient AstNode casting. Closes #2133.
dynamic_cast can have large run-time cost, so here we implement type
tests for AstNode instances by checking the unique type() property, which
in turn is a constant generated by astgen. For leaf types in the AstNode
type hierarchy, this is a simple equality check. To handle intermediate
types, we generate the type ids of leaf types in a pre-order traversal of
the type hierarchy. This yields contiguous ranges of ids for sub-type
trees, which means we can check membership of a non-leaf type via 2
comparisons against a low and high id. This single patch makes Verilator
itself 6-13% faster (depending on which optimizations are enabled) on a
large design of over 250k lines of Verilog.
2020-01-22 19:07:48 -05:00
Pieter Kapsenberg 957c1d606b Add detailed XML location to cell elements, #2134, #2122.
This was accidentally omitted from the previous PR #2122.
2020-01-22 07:18:50 -05:00
Wilson Snyder 48dd358c03 Fix clang warnings from override. 2020-01-21 20:22:32 -05:00
Geza Lore 220daa5f33 Internals: Restore AstNode naming property. #2133.
The intention was that all subclasses of AstNode which are
intermediate must be abstract as well and called AstNode*. This was
violated recently by 28b9db1903. This
patch restores that property by:
- Renaming AstFile to AstNodeFile
- Introducing AstNodeSimpleText as the common base of AstText and
  AstTextBlock, rather than AstTextBlock deriving from AstText.
2020-01-21 19:54:14 -05:00
Wilson Snyder d76b5b7823 Fix C++11 intrusion. 2020-01-21 19:45:44 -05:00
Wilson Snyder 4266d31443 Internals: Add VL_OVERRIDE to includes. No functional change intended. 2020-01-21 18:02:23 -05:00
Yutetsu TAKATSUKASA fbdf5f2dad Internals: Mark all visit() with VL_OVERRIDE. Closes #2132.
* Add VL_OVERRIDE macro so that compiler can tell my typo when trying to override a function.

* Mark visit() with VL_OVERRIDE. No functional change intended.
2020-01-21 17:35:56 -05:00
Stefan Wallentowitz 8e26bdd098 Fix vpi scope naming (#2130)
Dedot and shorten the name so that public modules and interface cells
are accessible too via VPI.

Fixes #2109
2020-01-21 17:03:21 +01:00
Stefan Wallentowitz 22088c907f Set maximum number width (#2128)
Adjust the maximum number width to 64K. Add --max-num-width option to
adjust this setting.

Closes #2082
2020-01-21 12:17:31 +01:00
Matthew Ballance d87648c258 Correct FST-support issue with some GCC versions. Closes #2129. 2020-01-20 17:33:40 -05:00
Wilson Snyder abf3850d08 Internals: Misc cleanups for classes. 2020-01-20 16:53:27 -05:00
Pieter Kapsenberg 4a122fd0f2 Add detailed location to XML output (#2122)
* Add detailed location to XML output

* Fixing build failures

* less cryptic regulary expressions

* correcting typo in test

* Adding file letter to the location attribute, and cleaning up the regular expression in the tests.

* Add remaining test expected output files for XML changes

* spacing fix, adding documentation on changes
2020-01-20 14:08:13 -05:00
Wilson Snyder 0352ceea44 Internals: Refactor some emit code towards classes. No functional change intended. 2020-01-20 14:07:03 -05:00
Wilson Snyder e8ff191a17 Internals: Prepare for hierarchical NodeModule's. No functional change intended. 2020-01-20 13:27:27 -05:00
Wilson Snyder 5ae09daf5b Internals: Style cleanup. No functional change. 2020-01-20 11:56:08 -05:00
Wilson Snyder 1acff950d0 Commentary: Add deprecations section to docs. Closes #2081. 2020-01-20 10:06:45 -05:00
Stefan Wallentowitz f28d837930 Docker: Tag stable as latest (#2098) 2020-01-20 15:53:26 +01:00
Pieter Kapsenberg 1dd9a74b6c Internals: Move V3Global function definitions to their own files. No functional change intended. Closes #2120. 2020-01-19 07:23:26 -05:00
Pieter Kapsenberg 165833a97c Add compile_commands.json to .gitignore (#2119)
When running make with the "bear" command, the generated
compile_commands.json file shouldn't be considered new source. This file
allows clangd-based code completion tools (e.g. YouCompleteMe) to know
the flags that each file was compiled with.
2020-01-18 22:44:03 -05:00
Wilson Snyder 18e837336a Internals: Rename MethodCall. No functional change. 2020-01-18 14:11:05 -05:00
Wilson Snyder 835f668aaa Internals: Refactor statement tracking. No functional change intended. 2020-01-18 13:02:42 -05:00
Wilson Snyder 09199f79a6 Internals: Add VL_DO_CLEAR delete protections. No functional change intended. 2020-01-18 10:29:49 -05:00
Wilson Snyder 2f4954ca68 Commentary 2020-01-18 09:18:57 -05:00
Wilson Snyder 7024ea8cb6 Cleaner tristate error. #2117. 2020-01-18 07:56:50 -05:00
Wilson Snyder 623c4ec103 Internals: Create VL_DO_DANGLING. No functional change intended. 2020-01-16 20:17:11 -05:00
Wilson Snyder 023526ad4b Internals: Minor refactoring from class branch. 2020-01-15 20:18:12 -05:00
Wilson Snyder e2ba1c041f Commentary 2020-01-15 20:09:19 -05:00
Tobias Rosenkranz b41b9417b9 Fix sign compare warning. Closes #2112. 2020-01-15 07:40:22 -05:00
Pieter Kapsenberg 4443ab34fd Support left justified . Closes #2101. 2020-01-15 07:32:45 -05:00
Wilson Snyder e9a309ea8d Clang warning fix. 2020-01-15 07:27:04 -05:00
Wilson Snyder 81e8127168 Add parameter values in XML. #2110. 2020-01-14 18:51:20 -05:00
Wilson Snyder 47803c3591 Tests: Better message for contributors. 2020-01-14 17:49:04 -05:00
Wilson Snyder af38e8d387 Improve error on > 127 char modnames. #2106. 2020-01-14 07:33:12 -05:00
Wilson Snyder 67bb0c78c8 Codacity fix. 2020-01-14 07:13:35 -05:00
Wilson Snyder 918df2e618 Support / with assoc arrarys. Closes #2100. 2020-01-14 07:01:17 -05:00
Wilson Snyder 7bed17b14b Fix clang warning 2020-01-13 19:01:30 -05:00
Stefan Wallentowitz fad465abf1 Add lint_off -match waivers (#2102)
* Add more directives to configuration files

Allow to set the same directives in configuration files that can also
be set by comment attributes (such as /* verilator public */ etc).

* Add support for lint messsage waivers

Add configuration file switch '-match' for lint_off. It takes a string
with wildcards allowed and warnings will be matched against it (if
rule and file also match). If it matches, the warning is waived.

Fixes #1649 and #1514 
Closes #2072
2020-01-12 10:03:17 +01:00
Wilson Snyder 98fb7ec193 Commentary. 2020-01-11 21:08:20 -05:00
Wilson Snyder b71eb76252 For / allow 64-bit addressing. 2020-01-11 14:08:07 -05:00
Wilson Snyder 1d2a7b2f41 Style cleanups. No functional change. 2020-01-11 12:36:30 -05:00
Wilson Snyder cd38e88fb8 For travis, add VERILATOR_AUTHOR_SITE to get -Werror. Closes #2099. 2020-01-11 10:52:13 -05:00
Todd Strader a15aa0b82b Fix clang warning 2020-01-11 09:59:42 -05:00
Wilson Snyder fe94f9891b Add error on misused define. 2020-01-11 09:16:26 -05:00
Wilson Snyder fe9cf9bd42 devel release 2020-01-11 09:08:33 -05:00
439 changed files with 16293 additions and 5566 deletions
+1
View File
@@ -17,6 +17,7 @@
README
TAGS
autom4te.cache
compile_commands.json
config.cache
config.status
configure
+11 -3
View File
@@ -16,6 +16,7 @@ env:
- VERILATOR_ROOT=$PWD
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
- VERILATOR_AUTHOR_SITE=1
- OBJCACHE=ccache
cache:
@@ -24,8 +25,10 @@ cache:
before_install:
# Perl modules needed for testing
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker Bit::Vector
# Not listing Bit::Vector as slow to install, and only skips one test
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
- sudo apt-get install gdb gtkwave
- sudo apt-get install libgoogle-perftools-dev
before_script:
- bash -x ci/build_vcddiff.sh
- bash -x ci/build_verilator.sh
@@ -56,9 +59,14 @@ jobs:
script: ci/test.sh vlt
- if: type != cron
stage: test
name: Vltmt test
name: Vltmt set 0 test
compiler: gcc
script: ci/test.sh vltmt
script: ci/test.sh vltmt0
- if: type != cron
stage: test
name: Vltmt set 1 test
compiler: gcc
script: ci/test.sh vltmt1
# Cron builds try different OS/compiler combinations
- if: type = cron
stage: "Build Verilator"
+73 -2
View File
@@ -2,6 +2,75 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.030 2020-03-08
** Add split_var metacomment to assist UNOPTFLAT fixes, #2066. [Yutetsu TAKATSUKASA]
** Add support for $dumpfile and $dumpvars, #2126. [Alexander Grobman]
** Add support for dynamic arrays, #379.
*** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel]
*** Add check for assertOn for asserts, #2162. [Tobias Wölfel]
*** Add --structs-packed for forward compatibility.
*** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman]
**** Implement $displayb/o/h, $writeb/o/h, etc, #1637.
**** Use gcc -Os in examples instead of -O2 for better average performance.
**** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov]
* Verilator 4.028 2020-02-08
** Support attributes (public, isolate_assignments, etc.) in configuration files.
** Add -match to lint_off to waive warnings. [Philipp Wagner]
*** Link Verilator binary partially statically, #2146. [Geza Lore]
*** Verilation speed improvements, #2133, #2138. [Geza Lore]
*** Support libgoogle-perftools-dev's libtcmalloc if available, #2137. [Geza Lore]
*** Support $readmem/$writemem with assoc arrarys, #2100. [agrobman]
**** Support type(expression) operator and $typename, #1650.
**** Support left justified $display, #2101. [Pieter Kapsenberg]
**** Support string character access via indexing.
**** Support enum.next(k) with constant k > 1, #2125. [Tobias Rosenkranz]
**** Support parameter access from arrays of interfaces, #2155. [Todd Strader]
**** Add parameter values in XML. #2110. [Pieter Kapsenberg]
**** Add loc column location in XML (replaces fl), #2122. [Pieter Kapsenberg]
**** Add error on misused define. [Topa Tota]
**** Add parameter to set maximum signal width, #2082. [Øyvind Harboe]
**** Add warning on genvar in normal for loop, #2143. [yurivict]
**** Fix VPI scope naming for public modules. [Nandu Raj]
**** Fix FST tracing of enums inside structs. [fsiegle]
**** Fix WIDTH warning on </<= of narrower value, #2141. [agrobman]
**** Fix OpenSolaris issues, #2154. [brancoliticus]
**** Fix gated clocks under --protect-lib, #2169. [Todd Strader]
* Verilator 4.026 2020-01-11
** Docker images are now available for Verilator releases.
@@ -128,10 +197,10 @@ The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.020 2019-10-06
*** Support $fseek, $ftell, $frewind, #1496. [Howard Su]
*** Add --public-flat-rw, #1511. [Stefan Wallentowitz]
*** Support $fseek, $ftell, $frewind, #1496. [Howard Su]
*** Support vpiModule, #1469. [Stefan Wallentowitz]
**** Make Syms file honor --output-split-cfuncs, #1499. [Todd Strader]
@@ -152,6 +221,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix case statements with strings, #1536. [Philipp Wagner]
**** Fix some coverage lost when multithreaded, #2151.
* Verilator 4.018 2019-08-29
+3 -2
View File
@@ -19,14 +19,15 @@
\.codacy\.yml
\.travis\.yml
/build/
/obj_dir/
/obj_dbg/
/obj_dir/
/obj_dist/
/obj_iv/
/obj_nc/
/obj_opt/
/obj_vcs/
/obj_vlt/
/obj_vltmt/
/obj_dist/
/INCA_libs/
/cov_work/
/logs/
+1 -6
View File
@@ -148,6 +148,7 @@ DISTFILES_INC = $(INFOS) .gitignore \
docs/install.adoc \
docs/internals.adoc \
docs/verilator_logo.png \
docs/xml.adoc \
install-sh configure *.pod \
include/*.[chv]* \
include/*.in \
@@ -207,12 +208,6 @@ EXAMPLES_FIRST = \
EXAMPLES = $(EXAMPLES_FIRST) $(filter-out $(EXAMPLES_FIRST), $(sort $(wildcard examples/*)))
ifeq ($(OBJCACHE_JOBS),)
ifneq ($(OBJCACHE_HOSTS),)
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
endif
endif
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_gantt.1 verilator_profcfunc.1
+16 -5
View File
@@ -16,6 +16,7 @@ ifndef::env-github[]
:link_verilator_contributing: https://github.com/verilator/verilator/blob/master/docs/CONTRIBUTING.adoc
:link_verilator_install: https://verilator.org/install
endif::[]
:link_verilator_commercial_support: https://verilator.org/verilator_commercial_support
== Welcome to Verilator
@@ -24,7 +25,7 @@ endif::[]
^.^| *Welcome to Verilator, the fastest free Verilog HDL simulator.*
+++ <br/> +++ &bullet; Accepts synthesizable Verilog or SystemVerilog
+++ <br/> +++ &bullet; Performs lint code-quality checks
+++ <br/> +++ &bullet; Compiles into multithreaded {cpp}, SystemC, or (soon) {cpp}-under-Python
+++ <br/> +++ &bullet; Compiles into multithreaded {cpp}, or SystemC
+++ <br/> +++ &bullet; Creates XML to front-end your own tools
<.^|image:https://www.veripool.org/img/verilator_256_200_min.png[Logo,256,200]
@@ -38,12 +39,18 @@ endif::[]
+++ <br/> +++ &bullet; Out-of-the-box support from Arm, and RISC-V vendor IP
<.^|image:https://www.veripool.org/img/verilator_usage_400x200-min.png[,400,200]
>.^|image:https://www.veripool.org/img/chips_alliance_logo_225x75-min.png[CHIPS Alliance,link=https://chipsalliance.org]
image:https://www.veripool.org/img/osi_logo_125x125-min.png[,125,125]
>.^|image:https://www.veripool.org/img/verilator_community_400x125-min.png[,400,125]
^.^| *Community Driven & Openly Licensed*
+++ <br/> +++ &bullet; Guided by the https://chipsalliance.org/[CHIPS Alliance] and https://www.linuxfoundation.org/[Linux Foundation]
+++ <br/> +++ &bullet; Open, and free as in both speech and beer
+++ <br/> +++ &bullet; More simulation for your verification budget
^.^| *Commercial Support Available*
+++ <br/> +++ &bullet; Commercial support contracts
+++ <br/> +++ &bullet; Design support contracts
+++ <br/> +++ &bullet; Enhancement contracts
<.^|image:https://www.veripool.org/img/verilator_support_400x125-min.png[,400,125]
|===
== What Verilator Does
@@ -74,7 +81,7 @@ touch of {cpp} code, Verilator is the tool for you.
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather
than only translate, Verilator compiles your code into a much faster
optimized and optionally thread-partitioned model, which is in turn wrapped
inside a {cpp}/SystemC/Python module. The results are a compiled Verilog
inside a {cpp}/SystemC/{cpp}-under-Python module. The results are a compiled Verilog
model that executes even on a single-thread over 10x faster than standalone
SystemC, and on a single thread is about 100 times faster than interpreted
Verilog simulators such as http://iverilog.icarus.com[Icarus
@@ -109,7 +116,7 @@ or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
* https://verilator.org/issues[Verilator Issues]
== Community Supported
== Support
Verilator is a community project, guided by the
https://chipsalliance.org/[CHIPS Alliance] under the
@@ -120,6 +127,10 @@ We appreciate and welcome your contributions in whatever form; please see
https://verilator.org/verilator_doc.html#CONTRIBUTORS[Contributors and
Sponsors].
Verilator also supports and encourages commercial support models and
organizations; please see {link_verilator_commercial_support}[Verilator
Commercial Support].
== Related Projects
* http://gtkwave.sourceforge.net/[GTKwave] - Waveform viewer for Verilator
+385 -51
View File
@@ -323,6 +323,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--language <lang> Default language standard to parse
+libext+<ext>+[ext]... Extensions for finding modules
--lint-only Lint, but do not make output
--max-num-width <value> Maximum number width (default: 64K)
--MMD Create .d dependency files
--MP Create phony dependency targets
--Mdir <directory> Name of output object directory
@@ -420,6 +421,7 @@ more information.
+verilator+prof+threads+window+I<value> Set profile duration
+verilator+rand+reset+I<value> Set random reset technique
+verilator+seed+I<value> Set random seed
+verilator+noassert Disable assert checking
+verilator+V Verbose version and config
+verilator+version Show version and exit
@@ -968,6 +970,11 @@ stylistic and not enabled by default.
If the design is not to be completely Verilated see also the --bbox-sys and
--bbox-unsup options.
=item --max-num-width I<value>
Set the maximum number literal width (e.g. in 1024'd22 this it the 1024).
Defaults to 64K.
=item --MMD
=item --no-MMD
@@ -1337,6 +1344,13 @@ Creates more detailed statistics, including a list of all the variables by
size (plain --stats just gives a count). See --stats, which is implied by
this.
=item --structs-packed
Converts all unpacked structures to packed structures and issues a UNPACKED
warning. Currently this is the default and --no-structs-packed will not
work. Specifying this option allows for forward compatibility when a
future version of Verilator no longer always packs unpacked structures.
=item -sv
Specifies SystemVerilog language features should be enabled; equivalent to
@@ -1767,6 +1781,11 @@ For $random and "-x-initial unique", set the simulation runtime random seed
value. If zero or not specified picks a value from the system random
number generator.
=item +verilator+noassert
Disable assert checking per runtime argument. This is the same as calling
"Verilated::assertOn(false)" in the model.
=item +verilator+V
Shows the verbose version, including configuration information.
@@ -1894,13 +1913,13 @@ Now we run Verilator on our little example.
We then can compile it
cd obj_dir
make -j -f Vour.mk Vour__ALL.a
make -j -f Vour.mk ../sc_main.o verilated.o
make -j -C obj_dir -f Vour.mk Vour__ALL.a
make -j -C obj_dir -f Vour.mk ../sc_main.o verilated.o
And link with SystemC. Note your path to the libraries may vary,
depending on the operating system.
cd obj_dir
export SYSTEMC_LIBDIR=/path/to/where/libsystemc.a/exists
export LD_LIBRARY_PATH=$SYSTEMC_LIBDIR:$LD_LIBRARY_PATH
# Might be needed if SystemC 2.3.0
@@ -1924,6 +1943,39 @@ when your source changes it will automatically run all of these steps. See
the examples directory in the distribution.
=head1 EVALUATION LOOP
When using SystemC, when Verilator is evaluated is managed by the SystemC
kernel, and for the most part can be ignored. When using C++, the user
must call eval(), or eval_step() and eval_end_step().
1. When there is a single design instantiated at the C++ level that need to
evaluate, just call designp->eval().
2. When there are multiple designs instantiated each at the C++ level that
need to evaluate, call first_designp->eval_step() then ->eval_step() on all
other designs. Then call ->eval_end_step() on the first design then all
other designs. If there is only a single design, you would call
eval_step() then eval_end_step(); in fact eval() described above is just a
wrapper which calls these two functions.
When eval() is called Verilator looks for changes in clock signals and
evaluates related sequential always blocks, such as computing always_ff @
(posedge...) outputs. Then Verilator evaluates combinatorial logic.
Note combinatorial logic is not computed before sequential always blocks
are computed (for speed reasons). Therefore it is best to set any non-clock
inputs up with a separate eval() call before changing clocks().
Alternatively, if all always_ff statements use only the posedge of clocks,
or all inputs go directly to always_ff statements, as is typical, then you
can change non-clock inputs on the negative edge of the input clock, which
will be faster as there will be fewer eval() calls.
For more information on evaluation, see docs/internals.adoc in the
distribution.
=head1 BENCHMARKING & OPTIMIZATION
For best performance, run Verilator with the "-O3 --x-assign fast
@@ -1952,27 +2004,27 @@ OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or
the compiler or linker. Or, just for one run, pass them on the command
line to make:
make OPT_FAST="-O2 -fno-stack-protector" -f Vour.mk Vour__ALL.a
make OPT_FAST="-Os -fno-stack-protector" -f Vour.mk Vour__ALL.a
OPT_FAST specifies optimizations for those programs that are part of the
fast path, mostly code that is executed every cycle. OPT_SLOW specifies
optimizations for slow-path files (plus tracing), which execute only
rarely, yet take a long time to compile with optimization on. OPT
specifies overall optimization and affects all compiles, including those
OPT_FAST and OPT_SLOW control. For best results, use OPT="-O2", and link
OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os", and link
with "-static". Nearly the same results can be had with much better
compile times with OPT_FAST="-O1 -fstrict-aliasing". Higher optimization
such as "-O3" may help, but gcc compile times may be excessive under O3 on
even medium sized designs. Alternatively, some larger designs report
better performance using "-Os".
such as "-O2" or "-O3" may help, but gcc compile times may be excessive
under O3 on even medium sized designs.
Unfortunately, using the optimizer with SystemC files can result in
compiles taking several minutes. (The SystemC libraries have many little
inlined functions that drive the compiler nuts.)
For best results, use GCC 3.3 or newer. GCC 3.2 and earlier have
optimization bugs around pointer aliasing detection, which can result in 2x
performance losses.
For best results, use the latest clang compiler (about 10% faster than
GCC). Note the now fairly old GCC 3.2 and earlier have optimization bugs
around pointer aliasing detection, which can result in 2x performance
losses.
If you will be running many simulations on a single compile, investigate
feedback driven compilation. With GCC, using -fprofile-arcs, then
@@ -1983,6 +2035,9 @@ especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
both compilation and link. Note LTO may cause excessive compile times on
large designs.
Using profile driven compiler optimization, with feedback from a real
design, can yield up to30% improvements.
If you are using your own makefiles, you may want to compile the Verilated
code with -DVL_INLINE_OPT=inline. This will inline functions, however this
requires that all cpp files be compiled in a single compiler run.
@@ -1993,7 +2048,7 @@ either oprofile or gprof to see where in the C++ code the time is spent.
Run the gprof output through verilator_profcfunc and it will tell you what
Verilog line numbers on which most of the time is being spent.
When done, please let the author know the results. I like to keep tabs on
When done, please let the author know the results. We like to keep tabs on
how Verilator compares, and may be able to suggest additional improvements.
@@ -2068,7 +2123,7 @@ After running Make, the C++ compiler may produce the following:
A generic Linux/OS variable specifying what directories have shared object
(.so) files. This path should include SystemC and any other shared objects
needed at simultion runtime.
needed at simulation runtime.
=item OBJCACHE
@@ -2197,7 +2252,7 @@ example:
Note signals are read and written as member variables of the lower module.
You call the eval() method to evaluate the model. When the simulation is
complete call the final() method to wrap up any SystemVerilog final blocks,
and complete any assertions.
and complete any assertions. See L</"EVALUATION LOOP">.
=head1 CONNECTING TO SYSTEMC
@@ -2769,6 +2824,8 @@ purposes.
=item lint_off [-rule <message>] [-file "<filename>" [-lines <line> [ - <line>]]]
=item lint_off [-rule <message>] [-file "<filename>"] [-match "<string>"]
Enable/disables the specified lint warning, in the specified filename (or
wildcard with '*' or '?', or all files if omitted) and range of line
numbers (or all lines if omitted).
@@ -2780,6 +2837,10 @@ If the -rule is omitted, all lint warnings (see list in -Wno-lint) are
enabled/disabled. This will override all later lint warning enables for
the specified region.
If -match is set the linter warnings are matched against this (wildcard)
string and are waived in case they match iff rule and file (with wildcard)
also match.
In previous versions -rule was named -msg. The latter is deprecated, but
still works with a deprecation info, it may be removed in future versions.
@@ -2794,6 +2855,124 @@ and range of line numbers (or all lines if omitted).
For tracing_off, cells below any module in the files/ranges specified will
also not be traced.
=item clock_enable -module "<modulename>" -signal "<signame>"
Indicate the signal is used to gate a clock, and the user takes responsibility
for insuring there are no races related to it.
Same as /*verilator clock_enable*/, see L</"LANGUAGE EXTENSIONS"> for
more information and an example.
=item clocker -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
=item clocker -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
=item no_clocker -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
=item no_clocker -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
Indicate the signal is used as clock or not. This information is used by
Verilator to mark the signal as clocker and propagate the clocker attribute
automatically to derived signals. See C<--clk> for more information.
Same as /*verilator clocker*/, see L</"LANGUAGE EXTENSIONS"> for more
information.
=item coverage_block_off -module "<modulename>" -block "<blockname>"
=item coverage_block_off -file "<filename>" -line <lineno>
Specifies the entire begin/end block should be ignored for coverage
analysis purposes. Can either be specified as a named block or as a
filename and line number.
Same as /*verilator coverage_block_off*/, see L</"LANGUAGE
EXTENSIONS"> for more information.
=item full_case -file "<filename>" -lines <lineno>
=item parallel_case -file "<filename>" -lines <lineno>
Same as "//synopsys full_case" and "//synopsys parallel_case". When
these synthesis directives are discovered, Verilator will either
formally prove the directive to be true, or failing that, will insert
the appropriate code to detect failing cases at simulation runtime and
print an "Assertion failed" error message.
=item inline -module "<modulename>"
Specifies the module may be inlined into any modules that use this
module. This is useful to speed up simulation runtime with some small
loss of trace visibility and modularity. Note signals under inlined
submodules will be named I<submodule>__DOT__I<subsignal> as C++ does
not allow "." in signal names. When tracing such signals the tracing
routines will replace the __DOT__ with the period.
Same as /*verilator inline_module*/, see L</"LANGUAGE EXTENSIONS"> for
more information.
=item isolate_assignments -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
=item isolate_assignments -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
=item isolate_assignments -module "<modulename>" -function "<fname>"
Used to indicate the assignments to this signal in any blocks should be
isolated into new blocks. When there is a large combinatorial block that
is resulting in a UNOPTFLAT warning, attaching this to the signal causing
a false loop may clear up the problem.
Same as /* verilator isolate_assignments */, see L</"LANGUAGE
EXTENSIONS"> for more information.
=item no_inline -module "<modulename>"
Specifies the module should not be inlined into any modules that use
this module. This is useful especially at the top level module to
reduce the size of the interface class, to aid compile time at a small
performance loss.
Same as /*verilator no_inline_module*/, see L</"LANGUAGE EXTENSIONS">
for more information.
=item no_inline [-module "<modulename>"] -task "<taskname>"
=item no_inline [-module "<modulename>"] -function "<funcname>"
Specify the function or task should not be inlined into where it is
used. This may reduce the size of the final executable when a task is
used a very large number of times. For this flag to work, the task
and tasks below it must be pure; they cannot reference any variables
outside the task itself.
Same as /*verilator no_inline_task*/, see L</"LANGUAGE EXTENSIONS">
for more information.
=item sc_bv -module "<modulename>" [-task "<taskname>"] -signal "<signame>"
=item sc_bv -module "<modulename>" [-function "<funcname>"] -signal "<signame>"
Sets the port to be of sc_bv<I<width>> type, instead of bool, vluint32_t or
vluint64_t. This may be useful if the port width is parameterized and
different of such modules interface a templated module (such as a transactor)
or for other reasons. In general you should avoid using this attribute when
not necessary as with increasing usage of sc_bv the performance decreases
significantly.
Same as /*verilator sc_bv*/, see L</"LANGUAGE EXTENSIONS"> for more
information.
=item sformat [-module "<modulename>"] [-task "<taskname>"] -signal "<signame>"
=item sformat [-module "<modulename>"] [-function "<funcname>"] -signal "<signame>"
Final input of a function or task "input string" to indicate the
function or task should pass all remaining arguments through
$sformatf. This allows creation of DPI functions with $display like
behavior. See the test_regress/t/t_dpi_display.v file for an example.
Same as /*verilator sformat*/, see L</"LANGUAGE EXTENSIONS"> for more
information.
=back
@@ -2929,7 +3108,8 @@ per the C standard (it's unspecified in Verilog).
Specifies the entire begin/end block should be ignored for coverage
analysis. Must be inside a basic block, e.g. within a begin/end pair.
Same as /* verilator coverage_block_off */.
Same as /* verilator coverage_block_off */ and C<coverage_block_off> in
L</"CONFIGURATION FILES">.
=item `systemc_header
@@ -3019,7 +3199,10 @@ analysis.) For example:
The clock_enable attribute will cause the clock gate to be ignored in the
scheduling algorithm, sometimes required for correct clock behavior, and
always improving performance. It's also a good idea to enable the
IMPERFECTSCH warning, to insure all clock enables are properly recognized.
IMPERFECTSCH warning, to ensure all clock enables are properly recognized.
Same as C<clock_enable> in configuration files, see L</"CONFIGURATION
FILES"> for more information.
=item /*verilator clocker*/
@@ -3030,11 +3213,17 @@ not. This information is used by Verilator to mark the signal as clocker
and propagate the clocker attribute automatically to derived signals. See
C<--clk> for more information.
Same as C<clocker> and C<no_clocker> in configuration files, see
L</"CONFIGURATION FILES"> for more information.
=item /*verilator coverage_block_off*/
Specifies the entire begin/end block should be ignored for coverage
analysis purposes.
Same as C<coverage_block_off> in configuration files, see
L</"CONFIGURATION FILES"> for more information.
=item /*verilator coverage_off*/
Specifies that following lines of code should have coverage disabled.
@@ -3055,6 +3244,9 @@ submodules will be named I<submodule>__DOT__I<subsignal> as C++ does not
allow "." in signal names. When tracing such signals the tracing routines
will replace the __DOT__ with the period.
Same as C<inline> in configuration files, see L</"CONFIGURATION FILES">
for more information.
=item /*verilator isolate_assignments*/
Used after a signal declaration to indicate the assignments to this signal
@@ -3091,6 +3283,9 @@ It would then internally break it into (sort of):
end
end
Same as C<isolate_assignments> in configuration files, see
L</"CONFIGURATION FILES"> for more information.
=item /*verilator lint_off I<msg>*/
Disable the specified warning message for any warnings following the comment.
@@ -3126,6 +3321,9 @@ modules that use this module. This is useful especially at the top level
module to reduce the size of the interface class, to aid compile time at a
small performance loss.
Same as C<no_inline> in configuration files, see L</"CONFIGURATION
FILES"> for more information.
=item /*verilator no_inline_task*/
Used in a function or task variable definition section to specify the
@@ -3134,6 +3332,9 @@ reduce the size of the final executable when a task is used a very large
number of times. For this flag to work, the task and tasks below it must
be pure; they cannot reference any variables outside the task itself.
Same as C<no_inline> in configuration files, see L</"CONFIGURATION
FILES"> for more information.
=item /*verilator public*/ (parameter)
Used after a parameter declaration to indicate the emitted C code should
@@ -3161,6 +3362,9 @@ Instead of using public variables, consider instead making a DPI or public
function that accesses the variable. This is nicer as it provides an
obvious entry point that is also compatible across simulators.
Same as C<public> in configuration files, see L</"CONFIGURATION FILES">
for more information.
=item /*verilator public*/ (task/function)
Used inside the declaration section of a function or task declaration to
@@ -3183,6 +3387,9 @@ the model will NOT notice changes made to variables in these functions.
You may want to use DPI exports instead, as it's compatible with other
simulators.
Same as C<public> in configuration files, see L</"CONFIGURATION FILES">
for more information.
=item /*verilator public_flat*/ (variable)
Used after an input, output, register, or wire declaration to indicate the
@@ -3191,11 +3398,17 @@ signal. This will not declare this module public, which means the name of
the signal or path to it may change based upon the module inlining which
takes place.
Same as C<public_flat> in configuration files, see L</"CONFIGURATION
FILES"> for more information.
=item /*verilator public_flat_rd*/ (variable)
Used after an input, output, register, or wire declaration to indicate the
signal should be declared public_flat (see above), but read-only.
Same as C<public_flat_rd> in configuration files, see L</"CONFIGURATION
FILES"> for more information.
=item /*verilator public_flat_rw @(<edge_list>) */ (variable)
Used after an input, output, register, or wire declaration to indicate the
@@ -3204,6 +3417,9 @@ where writes should be considered to have the timing specified by the given
sensitivity edge list. Set for all variables, ports and wires using the
--public-flat-rw switch.
Same as C<public_flat_rw> in configuration files, see L</"CONFIGURATION
FILES"> for more information.
=item /*verilator public_module*/
Used after a module statement to indicate the module should not be inlined
@@ -3212,9 +3428,12 @@ Verilator automatically sets this attribute when the module contains any
public signals or `systemc_ directives. Also set for all modules when
using the --public switch.
Same as C<public> in configuration files, see L</"CONFIGURATION FILES">
for more information.
=item /*verilator sc_clock*/
Rarely needed. Used after an input declaration to indicate the signal
Deprecated. Used after an input declaration to indicate the signal
should be declared in SystemC as a sc_clock instead of a bool. This was
needed in SystemC 1.1 and 1.2 only; versions 2.0 and later do not require
clock pins to be sc_clocks and this is no longer needed.
@@ -3226,7 +3445,10 @@ type, instead of bool, vluint32_t or vluint64_t. This may be useful if
the port width is parameterized and different of such modules interface
a templated module (such as a transactor) or for other reasons. In general
you should avoid using this attribute when not necessary as with increasing
usage of sc_bv the performance increases significantly.
usage of sc_bv the performance decreases significantly.
Same as C<sc_bv> in configuration files, see L</"CONFIGURATION FILES">
for more information.
=item /*verilator sformat*/
@@ -3235,6 +3457,36 @@ indicate the function or task should pass all remaining arguments through
$sformatf. This allows creation of DPI functions with $display like
behavior. See the test_regress/t/t_dpi_display.v file for an example.
Same as C<sformat> in configuration files, see L</"CONFIGURATION FILES">
for more information.
=item /*verilator split_var*/
Attached to a variable or a net declaration to break the variable into
multiple pieces typically to resolve UNOPTFLAT performance issues.
Typically the variables to attach this to are recommeded by Verilator
itself, see UNOPTFLAT below.
For example, Verilator will internally convert a variable with the
metacomment such as:
logic [7:0] x [0:1] /*verilator split_var*/;
To:
logic [7:0] x__BRA__0__KET__ /*verilator split_var*/;
logic [7:0] x__BRA__1__KET__ /*verilator split_var*/;
Note that the generated packed variables retain the split_var metacomment
because they may be split into further smaller pieces accorting to the
access patterns.
This only supports unpacked arrays, packed arrays, and packed structs of
integer types (reg, logic, bit, byte, int...); otherwise if a split was
requested but cannot occur a SPLITVAR warning is issued. Splitting large
arrays may slow donw the Verilation speed, so use this only on variables
that require it.
=item /*verilator tag <text...>*/
Attached after a variable or structure member to indicate opaque (to
@@ -3570,17 +3822,29 @@ $unsigned, $warning.
Generally supported.
=item $display, $write, $fdisplay, $fwrite, $swrite
$display and friends must have a constant format string as the first
argument (as with C's printf). The rare usage which lists variables
standalone without a format is not supported.
=item $displayb, $displayh, $displayo, $writeb, $writeh, $writeo, etc
The sized display functions are rarely used and so not supported. Replace
them with a $write with the appropriate format specifier.
=item $dump/$dumpports and related
$dumpfile or $dumpports will create a VCD or FST file (which is based on
the --trace argument given when the model was Verilated). This will take
effect starting at the next eval() call. If you have multiple Verilated
designs under the same C model, then this will dump signals only from the
design containing the $dumpvar.
$dumpvars and $dumpports module identifier is ignored; the traced instances
will always start at the top of the design. The levels argument is also
ignored, use tracing_on/tracing_off pragmas instead.
$dumpportson/$dumpportsoff/$dumpportsall/$dumpportslimit filename argument
is ignored, only a single trace file may be active at once.
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
$dumplimit/$dumpportlimit are currently ignored.
=item $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored.
@@ -4198,6 +4462,29 @@ Ignoring this warning may make Verilator simulations differ from other
simulators, if the increased precision of real affects your model or DPI
calls.
=item SPLITVAR
Warns that a variable with a C<split_var> metacomment was not split.
Some possible reasons for this are:
* The datatype of the variable is not supported for splitting. (e.g. is a
real).
* The access pattern of the variable can not be determined
statically. (e.g. is accessed as a memory).
* The index of the array exceeds the array size.
* The variable is accessed from outside using dotted reference.
(e.g. top.instance0.variable0 = 1).
* The variable is not declared in a module, but in a package or an
interface.
* The variable is a parameter, localparam, genvar, or queue.
* The variable is tirstate or bidirectional. (e.g. inout or ref).
=item STMTDLY
Warns that you have a statement with a delayed time in front of it, for
@@ -4329,6 +4616,11 @@ being generated from an always statement that consumed high bits of the
same bus processed by another series of always blocks. The fix is the
same; split it into two separate signals generated from each block.
Another way to resolve this warning is to add a C<split_var> metacomment
described above. This will cause the variable to be split internally,
potentially resolving the conflict. If you run with --report-unoptflat
Verilator will suggest possible candidates for C<split_var>.
The UNOPTFLAT warning may also be due to clock enables, identified from the
reported path going through a clock gating cell. To fix these, use the
clock_enable meta comment described above.
@@ -4476,6 +4768,37 @@ that is not yet supported in Verilator. See the Limitations chapter.
=back
=head1 DEPRECATIONS
The following deprecated items are scheduled for future removal:
=over 4
=item Pre-C++11 compiler support
Verilator supports pre-C++11 compilers for non-threaded models when
configured with --enable-prec11. This flag will be removed and C++11
compilers will be required for both compiling Verilator and compiling
Verilated models no sooner than September 2020.
=item SystemC 2.1 and earlier support
Support for SystemC versions 2.1 and earlier and the related sc_clock
variable attribute will be removed no sooner than July 2020.
=item Configuration File -msg
The -msg argument to lint_off has been replaced with -rule. -msg is
planned for removal no sooner than January 2021.
=item XML locations
The XML C<fl> attribute has been replaced with C<loc>. C<fl> is planned
for removal no sooner than January 2021.
=back
=head1 FAQ/FREQUENTLY ASKED QUESTIONS
=over 4
@@ -4564,19 +4887,20 @@ designs have topped 16GB.
See the next question for tracing in SystemC mode.
Add the --trace switch to Verilator, and in your top level C code, call
Verilated::traceEverOn(true). Then create a VerilatedVcdC object, and
in your main loop call "trace_object->dump(time)" every time step, and
finally call "trace_object->close()". For an example, see below and the
examples/make_tracing_c/sim_main.cpp file of the distribution.
A. Add the --trace switch to Verilator, and in your top level C code, call
Verilated::traceEverOn(true). Then you may use $dumpfile and $dumpvars to
enable traces, same as with any Verilog simulator. See
C<examples/make_tracing_c>.
You also need to compile verilated_vcd_c.cpp and add it to your link,
preferably by adding the dependencies in $(VK_GLOBAL_OBJS) to your
Makefile's link rule. This is done for you if using the Verilator --exe
flag.
Note you can also call ->trace on multiple Verilated objects with the same
trace file if you want all data to land in the same output file.
B. Or, for finer-grained control, or C++ files with multiple Verilated
modules you may also create the trace purely from C++. Create a
VerilatedVcdC object, and in your main loop call "trace_object->dump(time)"
every time step, and finally call "trace_object->close()". You also need
to compile verilated_vcd_c.cpp and add it to your link, preferably by
adding the dependencies in $(VK_GLOBAL_OBJS) to your Makefile's link rule.
This is done for you if using the Verilator --exe flag. Note you can also
call ->trace on multiple Verilated objects with the same trace file if you
want all data to land in the same output file.
#include "verilated_vcd_c.h"
...
@@ -4596,11 +4920,17 @@ trace file if you want all data to land in the same output file.
=item How do I generate waveforms (traces) in SystemC?
Add the --trace switch to Verilator, and in your top level C sc_main code,
include verilated_vcd_sc.h. Then call Verilated::traceEverOn(true). Then
create a VerilatedVcdSc object as you would create a normal SystemC trace
file. For an example, see the call to VerilatedVcdSc in the
examples/make_tracing_sc/sc_main.cpp file of the distribution, and below.
A. Add the --trace switch to Verilator, and in your top level sc_main, call
Verilated::traceEverOn(true). Then you may use $dumpfile and $dumpvars to
enable traces, same as with any Verilog simulator, see the non-SystemC
example in C<examples/make_tracing_c>. This will trace only the module
containing the $dumpvar.
B. Or, you may create a trace purely from SystemC, which may trace all
Verilated designs in the SystemC model. Create a VerilatedVcdSc object as
you would create a normal SystemC trace file. For an example, see the call
to VerilatedVcdSc in the examples/make_tracing_sc/sc_main.cpp file of the
distribution, and below.
Alternatively you may use the C++ trace mechanism described in the previous
question, however the timescale and timeprecision will not inherited from
@@ -4630,23 +4960,23 @@ trace file if you want all data to land in the same output file.
=item How do I generate FST waveforms (traces) in C++?
FST a format by GTKWave.
This version provides a basic FST support.
To dump FST format, add the --trace-fst switch to Verilator and change the include
path in the testbench to:
FST a format by GTKWave. This version provides a basic FST support. To
dump FST format, add the --trace-fst switch to Verilator and either A. use
$dumpfile/$dumpvars in Verilog as described in the VCD example above, or
B. in C++ change the include described in the VCD example above:
#include "verilated_fst_c.h"
VerilatedFstC* tfp = new VerilatedFstC;
Note that currently supporting both FST and VCD in a single simulation is impossible,
but such requirement could be rare.
Note that currently supporting both FST and VCD in a single simulation is
impossible, but such requirement should be rare.
=item How do I generate FST waveforms (traces) in SystemC?
=item How do I generate FST waveforms (aka dumps or traces) in SystemC?
The FST library from GTKWave does not currently support SystemC; use VCD
format instead.
=item How do I view waveforms (traces)?
=item How do I view waveforms (aka dumps or traces)?
Verilator makes standard VCD (Value Change Dump) and FST files. VCD files are viewable
with the public domain GTKWave (recommended) or Dinotrace (legacy)
@@ -4707,7 +5037,7 @@ Most synthesis tools similarly define SYNTHESIS for you.
=item Why do I get "unexpected `do'" or "unexpected `bit'" errors?
Do, bit, ref, return, and other words are now SystemVerilog keywords. You
should change your code to not use them to insure it works with newer
should change your code to not use them to ensure it works with newer
tools. Alternatively, surround them by the Verilog 2005/SystemVerilog
begin_keywords pragma to indicate Verilog 2001 code.
@@ -5034,6 +5364,10 @@ redistribute it and/or modify the Verilator internals under the terms of
either the GNU Lesser General Public License Version 3 or the Perl Artistic
License Version 2.0.
All Verilog and C++/SystemC code quoted within this documentation file are
released into the Public Domain. Many example files and test files are
likewise released into the Public Domain as described in the files
themselves.
=head1 SEE ALSO
@@ -5041,7 +5375,7 @@ L<verilator_coverage>, L<verilator_gantt>, L<verilator_profcfunc>, L<make>,
L<verilator --help> which is the source for this document,
and internals.txt in the distribution.
and docs/internals.adoc in the distribution.
=cut
+2 -2
View File
@@ -123,13 +123,13 @@ sub report {
}
my $nthreads = scalar keys %Threads;
$Global{cpus}{cpu_time} = {};
$Global{cpus} = {};
foreach my $thread (keys %Threads) {
# Make potentially multiple characters per column
foreach my $start (keys %{$Threads{$thread}}) {
my $cpu = $Threads{$thread}{$start}{cpu};
my $elapsed = $Threads{$thread}{$start}{end} - $start;
$Global{cpus}{cpu_time}{$cpu} += $elapsed;
$Global{cpus}{$cpu}{cpu_time} += $elapsed;
}
}
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
# DESCRIPTION: Docker hub hook to tag the latest release (stable)
#
# Copyright 2020 by Stefan Wallentowitz. This program is free
# software; you can redistribute it and/or modify it under the terms
# of either the GNU Lesser General Public License Version 3 or the
# Perl Artistic License Version 2.0.FROM ubuntu:18.04
if [ "$SOURCE_BRANCH"="stable" ]; then
docker tag $IMAGE_NAME $DOCKER_REPO:latest
docker push $DOCKER_REPO:latest
fi
+6
View File
@@ -19,6 +19,12 @@ case $1 in
vltmt)
make -C test_regress SCENARIOS=--vltmt
;;
vltmt0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
*)
echo "Usage: test.sh (dist|vlt|vltmt)"
exit -1
+87 -9
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.026 2020-01-11],
AC_INIT([Verilator],[4.030 2020-03-08],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
@@ -25,11 +25,43 @@ AC_ARG_ENABLE([maintainer-mode],
AC_ARG_ENABLE([silent-rules],
[AS_HELP_STRING([--disable-silent-rules], [ignored])])
# Flag to enable linking specific libraries statically
AC_MSG_CHECKING(whether to perform partial static linking of Verilator binary)
AC_ARG_ENABLE([partial-static],
[AS_HELP_STRING([--disable-partial-static],
[By default, for Verilation peformance, Verilator
is linked against some of its dependencies
statically. Use this to link the Verilator binary
fully dynamically.])],
[case "${enableval}" in
yes) CFG_ENABLE_PARTIAL_STATIC=yes ;;
no) CFG_ENABLE_PARTIAL_STATIC=no ;;
*) AC_MSG_ERROR([bad value '${enableval}' for --disable-partial-static]) ;;
esac],
CFG_ENABLE_PARTIAL_STATIC=yes)
AC_MSG_RESULT($CFG_ENABLE_PARTIAL_STATIC)
# Flag to enable linking Verilator with tcmalloc if available
AC_MSG_CHECKING(whether to use tcmalloc)
AC_ARG_ENABLE([tcmalloc],
[AS_HELP_STRING([--enable-tcmalloc],
[Use libtcmalloc_minimal for faster dynamic memory
management in Verilator binary@<:@default=check@:>@])],
[case "${enableval}" in
yes) CFG_WITH_TCMALLOC=yes ;;
no) CFG_WITH_TCMALLOC=no ;;
*) AC_MSG_ERROR([bad value '${enableval}' for --enable-tcmalloc]) ;;
esac],
[CFG_WITH_TCMALLOC=check;])
AC_MSG_RESULT($CFG_WITH_TCMALLOC)
# Special Substitutions - CFG_WITH_DEFENV
AC_MSG_CHECKING(whether to use hardcoded paths)
AC_ARG_ENABLE([defenv],
[AS_HELP_STRING([--disable-defenv],
[disable using some hardcoded data paths extracted from some default environment variables (the default is to use hardcoded paths)])],
[disable using some hardcoded data paths extracted
from some default environment variables (the default
is to use hardcoded paths) in Verilator binary])],
[case "${enableval}" in
yes) CFG_WITH_DEFENV=yes ;;
no) CFG_WITH_DEFENV=no ;;
@@ -43,7 +75,8 @@ AC_MSG_RESULT($CFG_WITH_DEFENV)
AC_MSG_CHECKING(whether to show and stop on compilation warnings)
AC_ARG_ENABLE([ccwarn],
[AS_HELP_STRING([--enable-ccwarn],
[enable showing and stopping on compilation warnings])],
[enable showing and stopping on compilation warnings
in Verilator binrary and Verilated makefiles])],
[case "${enableval}" in
yes) CFG_WITH_CCWARN=yes ;;
no) CFG_WITH_CCWARN=no ;;
@@ -79,7 +112,8 @@ AC_MSG_RESULT($CFG_WITH_LONGTESTS)
AC_MSG_CHECKING(whether allow pre-C++11)
AC_ARG_ENABLE([prec11],
[AS_HELP_STRING([--enable-prec11],
[enable pre-C++11 compilers])],
[enable pre-C++11 compilers for Verilator binary
and Verilated makefiles])],
[case "${enableval}" in
yes) CFG_WITH_PREC11=yes ;;
no) CFG_WITH_PREC11=no ;;
@@ -209,15 +243,26 @@ AC_DEFUN([_MY_LDLIBS_CHECK_FLAG],
LIBS="$ACO_SAVE_LIBS"
])
AC_DEFUN([_MY_LDLIBS_CHECK_OPT],
[# _MY_LDLIBS_CHECK_OPT(flag) -- Check if linker supports specific options
# If it does, append flag to variable
_MY_LDLIBS_CHECK_FLAG($2)
AC_DEFUN([_MY_LDLIBS_CHECK_IFELSE],
[# _MY_LDLIBS_CHECK_IFELSE(flag,action-if-supported,action-if-not-supported)
# Check if linker supports specific flag, if it does do action-if-supported
# otherwise do action-if-not-supported
_MY_LDLIBS_CHECK_FLAG($1)
if test "$_my_result" = "yes" ; then
$1="$$1 $2"
true
$2
else
true
$3
fi
])
AC_DEFUN([_MY_LDLIBS_CHECK_OPT],
[# _MY_LDLIBS_CHECK_OPT(variable, flag) -- Check if linker supports specific
# options. If it does, append flag to variable.
_MY_LDLIBS_CHECK_IFELSE($2, $1="$$1 $2")
])
# Flag to select newest language standard supported
# Macros work such that first option that passes is the one we take
# gnu++17 code is clean, but SystemC in 2018 doesn't link with it (bug1339)
@@ -310,6 +355,39 @@ m4_foreach([ldflag], [
AC_SUBST(CFG_LDLIBS_THREADS)
AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE)
# When linking partially statically
if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libstdc++)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -Xlinker -gc-sections)
LTCMALLOC=-l:libtcmalloc_minimal.a
else
LTCMALLOC=-ltcmalloc_minimal
fi
AC_SUBST(CFG_LDFLAGS_SRC)
# The pthread library is required by tcmalloc, so add it if it exists. If it
# does not, the tcmalloc check below will fail anyway, and linking against
# pthreads is harmless otherwise.
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread)
# Check if tcmalloc is available based on --enable-tcmalloc
_MY_LDLIBS_CHECK_IFELSE(
$LTCMALLOC,
[if test "$CFG_WITH_TCMALLOC" != "no"; then
CFG_LIBS="$LTCMALLOC $CFG_LIBS";
# If using tcmalloc, add some extra options to make the compiler not assume
# it is using it's own versions of the standard library functions
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-free)
fi],
[if test "$CFG_WITH_TCMALLOC" = "yes"; then
AC_MSG_ERROR([--enable-tcmalloc was given but test for ${LTCMALLOC} failed])
fi])
AC_SUBST(CFG_LIBS)
# Set CFG_WITH_THREADED if can support threading
AC_MSG_CHECKING(whether $CXX supports Verilated threads)
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
+1 -1
View File
@@ -11,7 +11,7 @@ contributions flow more efficiently.
https://verilator.org/issues[Verilator Issues].
* If you're unable to find an open issue addressing the problem,
https://verilator.org/issues/new[open a new issue].
https://verilator.org/issues/new[open a new Verilator issue].
** Be sure to include a **code sample** or an **executable test case**
demonstrating the bug and expected behavior that is not occurring.
+6 -1
View File
@@ -11,6 +11,7 @@ Chris Randall
Driss Hafdi
Eric Rippey
Garrett Smith
Geza Lore
Gianfranco Costamagna
Howard Su
Iztok Jeras
@@ -24,13 +25,17 @@ Lukasz Dalek
Maarten De Braekeleer
Matthew Ballance
Mike Popoloski
Peter Monsson
Patrick Stewart
Peter Monsson
Philipp Wagner
Pieter Kapsenberg
Richard Myers
Sebastien Van Cauwenberghe
Stefan Wallentowitz
Tobias Rosenkranz
Tobias Wölfel
Todd Strader
Wilson Snyder
Yutetsu TAKATSUKASA
Yves Mathieu
David Stanford
+7 -1
View File
@@ -84,6 +84,10 @@ To build Verilator you will need to install some standard packages:
sudo apt-get install autoconf
sudo apt-get install flex bison
The following are optional, but improve compilation speed:
sudo apt-get install libgoogle-perftools-dev
Additionally, to build or run Verilator you need these standard packages:
sudo apt-get install perl python3
@@ -94,9 +98,11 @@ Additionally, to build or run Verilator you need these standard packages:
Those developing Verilator may also want these (see internals.adoc):
sudo apt-get install gdb asciidoctor graphviz
sudo apt-get install gdb asciidoctor graphviz cmake
cpan install Pod::Perldoc
cpan install Unix::Processors
cpan install Parallel::Forker
cpan install Bit::Vector
==== Install SystemC
+19 -4
View File
@@ -70,7 +70,10 @@ The AST is represented at the top level by the class `AstNode`. This
abstract class has derived classes for the individual components
(e.g. `AstGenerate` for a generate block) or groups of components
(e.g. `AstNodeFTask` for functions and tasks, which in turn has `AstFunc`
and `AstTask` as derived classes).
and `AstTask` as derived classes). An important property of the `AstNode`
type hierarchy is that all non-final subclasses of `AstNode` (i.e.: those
which themselves have subclasses) must be abstract as well, and be named
with the prefix `AstNode*`. The `astgen` (see below) script relies on this.
Each `AstNode` has pointers to up to four children, accessed by the `op1p`
through `op4p` methods. These methods are then abstracted in a specific
@@ -394,7 +397,7 @@ e.g. threads.
We will work with contributors to fix up indentation style issues, but it
is appreciated if you could match our style:
* All files should contain the magic header to insure standard indentation:
* All files should contain the magic header to ensure standard indentation:
+
// -*- mode: C++; c-file-style: "cc-mode" -*-
+
@@ -622,13 +625,17 @@ with e.g. "sudo cpan install Parallel::Forker".
* vcddiff to find differences in VCD outputs. See the readme at
https://github.com/veripool/vcddiff
* Cmake for build paths that use it.
* Bit::Vector to test vgen.pl
=== Controlling the Test Driver
Test drivers are written in PERL. All invoke the main test driver script,
which can provide detailed help on all the features available when writing
a test driver.
test_regress/t/driver.pl --help
test_regress/driver.pl --help
For convenience, a summary of the most commonly used features is provided
here. All drivers require a call to `compile` subroutine to compile the
@@ -713,6 +720,13 @@ respectively 16,384 and 4,096. The method of doing this is system
dependent, but on Fedora Linux it would require editing the
`/etc/security/limits.conf` file as root.
=== Manual Test Execution
A specific regression test can be executed manually. To start the "EXAMPLE"
test, run the following command.
test_regress/t/t_EXAMPLE.pl
=== Continuous Integration
Verilator has a https://travis-ci.com/verilator/verilator[Travis CI environment]
@@ -959,7 +973,8 @@ src/VParseGrammar.y, as this grammar supports the full SystemVerilog
language and has a lot of back-and-forth with Verilator's grammar. Copy
the appropriate rules to src/verilog.y and modify the productions.
. If a new Ast type is needed, add it to V3AstNodes.h.
. If a new Ast type is needed, add it to V3AstNodes.h. Follow the convention
described above about the AstNode type hierarchy.
. Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
+65
View File
@@ -0,0 +1,65 @@
= Verilator XML Output
:toc: right
// Github doesn't render unless absolute URL
image::https://www.veripool.org/img/verilator_256_200_min.png[Logo,256,200,role="right"]
== Introduction
This document describes Verilator's XML output. For more general information
please see https://verilator.org[verilator.org].
== General
Verilator's XML output is enabled with the `--xml-only` flag. It contains
limited information about the elaborated design including files, modules,
instance hierarchy, logic and data types. There is no formal schema since part
of the structure of the XML document matches the compiled code which would
require the schema to describe legal SystemVerilog structure. The intended
usage is to enable other downstream tools to take advantage of Verilator's
parser.
== Structure
The XML document is consists of 4 sections within the top level `verilator_xml`
element:
`<files>`...`</files>`::
This section contains a list of all design files read, including the
built-in constructs and the command line as their own entries. Each
`<file>` has an attribute `id` which is a short ASCII string unique to that
file. Other elements' `loc` attributes use this id to refer to a particular
file.
`<module_files>`...`</module_files>`::
All files containing Verilog module definitions are listed in this section.
This element's contents is a subset of the `<files>` element's contents.
`<cells>`...`</cells>`::
The cells section of the XML document contains the design instance
hierarchy. Each instance is represented with the `<cell>` element with the
following attributes:
* `fl` (deprecated): The file id and line number where the module was
instanced. Use `loc` instead.
* `loc`: The file id, first line number, last line number, first column
number and last column number of the identifier where the module was
instanced, separated by commas.
* `name`: The instance name.
* `submodname`: The module name uniquified with particular parameter values (if any).
* `hier`: The full hierarchy path.
`<netlist>`...`</netlist>`::
The netlist section contains a number of `<module>`...`</module>` elements,
each describing the contents of that module, and a single `<typetable>`...
`</typetable>` element which lists all used types used within the
modules. Each type has a numeric `id` attribute that is referred to by
elements in the `<module>` elements using the `dtype_id` attribute.
+1 -1
View File
@@ -34,5 +34,5 @@ add_executable(example ../make_tracing_c/sim_main.cpp)
# Add the Verilated circuit to the target
verilate(example COVERAGE TRACE
INCLUDE_DIRS "../make_tracing_c"
VERILATOR_ARGS -f ../make_tracing_c/input.vc -O2 -x-assign 0
VERILATOR_ARGS -f ../make_tracing_c/input.vc -Os -x-assign 0
SOURCES ../make_tracing_c/top.v)
+1 -1
View File
@@ -41,7 +41,7 @@ add_executable(example ../make_tracing_sc/sc_main.cpp)
# Add the Verilated circuit to the target
verilate(example SYSTEMC COVERAGE TRACE
INCLUDE_DIRS "../make_tracing_sc"
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -O2 -x-assign 0
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -Os -x-assign 0
SOURCES ../make_tracing_sc/top.v)
verilator_link_systemc(example)
+1 -1
View File
@@ -34,7 +34,7 @@ VERILATOR_FLAGS =
# Generate C++
VERILATOR_FLAGS += -cc
# Optimize
VERILATOR_FLAGS += -O2 -x-assign 0
VERILATOR_FLAGS += -Os -x-assign 0
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
+1 -1
View File
@@ -38,7 +38,7 @@ VERILATOR_FLAGS += -cc --exe
# Generate makefile dependencies (not shown as complicates the Makefile)
#VERILATOR_FLAGS += -MMD
# Optimize
VERILATOR_FLAGS += -O2 -x-assign 0
VERILATOR_FLAGS += -Os -x-assign 0
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
+1 -1
View File
@@ -38,7 +38,7 @@ endif
# SystemC takes minutes to optimize, thus it is off by default.
OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
OPT_FAST = -O2 -fstrict-aliasing
OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
+24 -46
View File
@@ -10,11 +10,6 @@
// Include model header, generated from Verilating "top.v"
#include "Vtop.h"
// If "verilator --trace" is used, include the tracing class
#if VM_TRACE
# include <verilated_vcd_c.h>
#endif
// Current simulation time (64-bit unsigned)
vluint64_t main_time = 0;
// Called by $time in Verilog
@@ -36,31 +31,21 @@ int main(int argc, char** argv, char** env) {
// May be overridden by commandArgs
Verilated::randReset(2);
// Verilator must compute traced signals
Verilated::traceEverOn(true);
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
// Create logs/ directory in case we have traces to put under it
Verilated::mkdir("logs");
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
#if VM_TRACE
// If verilator was invoked with --trace argument,
// and if at run time passed the +trace argument, turn on tracing
VerilatedVcdC* tfp = NULL;
const char* flag = Verilated::commandArgsPlusMatch("trace");
if (flag && 0==strcmp(flag, "+trace")) {
Verilated::traceEverOn(true); // Verilator must compute traced signals
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
tfp = new VerilatedVcdC;
top->trace(tfp, 99); // Trace 99 levels of hierarchy
Verilated::mkdir("logs");
tfp->open("logs/vlt_dump.vcd"); // Open the dump file
}
#endif
// Set some inputs
top->reset_l = !0;
top->fastclk = 0;
top->clk = 0;
top->in_small = 1;
top->in_quad = 0x1234;
@@ -72,31 +57,29 @@ int main(int argc, char** argv, char** env) {
while (!Verilated::gotFinish()) {
main_time++; // Time passes...
// Toggle clocks and such
top->fastclk = !top->fastclk;
if ((main_time % 10) == 3) {
top->clk = 1;
}
if ((main_time % 10) == 8) {
top->clk = 0;
}
if (main_time > 1 && main_time < 10) {
top->reset_l = !1; // Assert reset
} else {
top->reset_l = !0; // Deassert reset
}
// Toggle a fast (time/2 period) clock
top->clk = !top->clk;
// Assign some other inputs
top->in_quad += 0x12;
// Toggle control signals on an edge that doesn't correspond
// to where the controls are sampled; in this example we do
// this only on a negedge of clk, because we know
// reset is not sampled there.
if (!top->clk) {
if (main_time > 1 && main_time < 10) {
top->reset_l = !1; // Assert reset
} else {
top->reset_l = !0; // Deassert reset
}
// Assign some other inputs
top->in_quad += 0x12;
}
// Evaluate model
// (If you have multiple models being simulated in the same
// timestep then instead of eval(), call eval_step() on each, then
// eval_end_step() on each.)
top->eval();
#if VM_TRACE
// Dump trace data for this cycle
if (tfp) tfp->dump(main_time);
#endif
// Read outputs
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
@@ -107,11 +90,6 @@ int main(int argc, char** argv, char** env) {
// Final model cleanup
top->final();
// Close trace if opened
#if VM_TRACE
if (tfp) { tfp->close(); tfp = NULL; }
#endif
// Coverage analysis (since test passed)
#if VM_COVERAGE
Verilated::mkdir("logs");
-17
View File
@@ -7,25 +7,10 @@
module sub
(
input clk,
input fastclk,
input reset_l
);
// Example counter/flop
reg [31:0] count_f;
always_ff @ (posedge fastclk) begin
if (!reset_l) begin
/*AUTORESET*/
// Beginning of autoreset for uninitialized flops
count_f <= 32'h0;
// End of automatics
end
else begin
count_f <= count_f + 1;
end
end
// Another example flop
reg [31:0] count_c;
always_ff @ (posedge clk) begin
if (!reset_l) begin
@@ -37,8 +22,6 @@ module sub
else begin
count_c <= count_c + 1;
if (count_c >= 3) begin
$display("[%0t] fastclk is %0d times faster than clk\n",
$time, count_f/count_c);
// This write is a magic value the Makefile uses to make sure the
// test completes successfully.
$write("*-* All Finished *-*\n");
+5 -2
View File
@@ -11,7 +11,6 @@ module top
(
// Declare some signals so we can see how I/O works
input clk,
input fastclk,
input reset_l,
output wire [1:0] out_small,
@@ -31,11 +30,15 @@ module top
sub sub (/*AUTOINST*/
// Inputs
.clk (clk),
.fastclk (fastclk),
.reset_l (reset_l));
// Print some stuff as an example
initial begin
if ($test$plusargs("trace") != 0) begin
$display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time);
$dumpfile("logs/vlt_dump.vcd");
$dumpvars();
end
$display("[%0t] Model running...\n", $time);
end
+1 -1
View File
@@ -38,7 +38,7 @@ VERILATOR_FLAGS += -sc --exe
# Generate makefile dependencies (not shown as complicates the Makefile)
#VERILATOR_FLAGS += -MMD
# Optimize
VERILATOR_FLAGS += -O2 -x-assign 0
VERILATOR_FLAGS += -Os -x-assign 0
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
+1 -1
View File
@@ -46,7 +46,7 @@ endif
# SystemC takes minutes to optimize, thus it is off by default.
OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
OPT_FAST = -O2 -fstrict-aliasing
OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
+3
View File
@@ -37,6 +37,9 @@ int sc_main(int argc, char* argv[]) {
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
// Create logs/ directory in case we have traces to put under it
Verilated::mkdir("logs");
// General logfile
ios::sync_with_stdio();
-2
View File
@@ -418,9 +418,7 @@ static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void
const flzuint8* ip = (const flzuint8*) input;
const flzuint8* ip_limit = ip + length;
flzuint8* op = (flzuint8*) output;
#ifdef FASTLZ_SAFE
flzuint8* op_limit = op + maxout;
#endif
flzuint32 ctrl = (*ip++) & 31;
int loop = 1;
-3
View File
@@ -33,9 +33,6 @@
#else
#include <malloc.h>
#endif
#elif defined(_MSC_VER)
#include <malloc.h>
#define alloca _alloca
#endif
#define wave_alloca alloca
#endif
+362 -296
View File
@@ -618,7 +618,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const char* pctp = NULL; // Most recent %##.##g format
bool inPct = false;
bool widthSet = false;
int width = 0;
bool left = false;
size_t width = 0;
for (const char* pos = formatp; *pos; ++pos) {
if (!inPct && pos[0]=='%') {
pctp = pos;
@@ -643,6 +644,10 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
widthSet = true;
width = width*10 + (fmt - '0');
break;
case '-':
left = true;
inPct = true; // Get more digits
break;
case '.':
inPct = true; // Get more digits
break;
@@ -662,8 +667,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
case '@': { // Verilog/C++ string
va_arg(ap, int); // # bits is ignored
const std::string* cstrp = va_arg(ap, const std::string*);
if (width > cstrp->size()) output += std::string(width - cstrp->size(), ' ');
output += *cstrp;
std::string padding;
if (width > cstrp->size()) padding.append(width - cstrp->size(), ' ');
output += left ? (*cstrp + padding) : (padding + *cstrp);
break;
}
case 'e':
@@ -721,8 +727,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
field += (charval==0)?' ':charval;
}
if (width > field.size()) output += std::string(width - field.size(), ' ');
output += field;
std::string padding;
if (width > field.size()) padding.append(width - field.size(), ' ');
output += left ? (field + padding) : (padding + field);
break;
}
case 'd': { // Signed decimal
@@ -743,14 +750,15 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
digits = append.length();
}
int needmore = width-digits;
std::string padding;
if (needmore>0) {
if (pctp && pctp[0] && pctp[1]=='0') { // %0
output.append(needmore, '0'); // Pre-pad zero
padding.append(needmore, '0'); // Pre-pad zero
} else {
output.append(needmore, ' '); // Pre-pad spaces
padding.append(needmore, ' '); // Pre-pad spaces
}
}
output += append;
output += left ? (append + padding) : (padding + append);
break;
}
case '#': { // Unsigned decimal
@@ -764,14 +772,15 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
digits = append.length();
}
int needmore = width-digits;
std::string padding;
if (needmore>0) {
if (pctp && pctp[0] && pctp[1]=='0') { // %0
output.append(needmore, '0'); // Pre-pad zero
padding.append(needmore, '0'); // Pre-pad zero
} else {
output.append(needmore, ' '); // Pre-pad spaces
padding.append(needmore, ' '); // Pre-pad spaces
}
}
output += append;
output += left ? (append + padding) : (padding + append);
break;
}
case 't': { // Time
@@ -786,8 +795,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
VL_FATAL_MT(__FILE__, __LINE__, "", "Unsupported VL_TIME_MULTIPLIER");
}
int needmore = width-digits;
if (needmore>0) output.append(needmore, ' '); // Pre-pad spaces
output += tmp;
std::string padding;
if (needmore>0) padding.append(needmore, ' '); // Pad with spaces
output += left ? (tmp + padding) : (padding + tmp);
break;
}
case 'b':
@@ -1320,146 +1330,6 @@ IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_
return got;
}
void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int,
QData filename, const void* memp, IData start,
IData end) VL_MT_SAFE {
WData fnw[VL_WQ_WORDS_E]; VL_SET_WQ(fnw, filename);
return VL_WRITEMEM_W(hex, width, depth, array_lsb, VL_WQ_WORDS_E, fnw, memp, start, end);
}
void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
WDataInP filenamep, const void* memp, IData start,
IData end) VL_MT_SAFE {
char filenamez[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
_VL_VINT_TO_STRING(fnwords * VL_EDATASIZE, filenamez, filenamep);
std::string filenames(filenamez);
return VL_WRITEMEM_N(hex, width, depth, array_lsb, filenames, memp, start, end);
}
const char* memhFormat(int nBits) {
assert((nBits >= 1) && (nBits <= 32));
static char buf[32];
switch ((nBits - 1) / 4) {
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
case 2: VL_SNPRINTF(buf, 32, "%%03x"); break;
case 3: VL_SNPRINTF(buf, 32, "%%04x"); break;
case 4: VL_SNPRINTF(buf, 32, "%%05x"); break;
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
default: assert(false); break; // LCOV_EXCL_LINE
}
return buf;
}
void VL_WRITEMEM_N(
bool hex, // Hex format, else binary
int width, // Width of each array row
int depth, // Number of rows
int array_lsb, // Index of first row. Valid row addresses
// // range from array_lsb up to (array_lsb + depth - 1)
const std::string& filename, // Output file name
const void* memp, // Array state
IData start, // First array row address to write
IData end // Last address to write, or ~0 when not specified
) VL_MT_SAFE {
if (VL_UNLIKELY(!hex)) {
VL_FATAL_MT(filename.c_str(), 0, "",
"VL_WRITEMEM_N only supports hex format for now, sorry!");
return;
}
// Calculate row address limits
size_t row_min = array_lsb;
size_t row_max = row_min + depth - 1;
// Normalize the last address argument: ~0 => row_max
size_t nend = (end == ~0u) ? row_max : end;
// Bounds check the write address range
if (VL_UNLIKELY((start < row_min) || (start > row_max)
|| (nend < row_min) || (nend > row_max))) {
VL_FATAL_MT(filename.c_str(), 0, "",
"$writemem specified address out-of-bounds");
return;
}
if (VL_UNLIKELY(start > nend)) {
VL_FATAL_MT(filename.c_str(), 0, "",
"$writemem invalid address range");
return;
}
// Calculate row offset range
size_t row_start = start - row_min;
size_t row_end = nend - row_min;
// Bail out on possible 32-bit size_t overflow
if (VL_UNLIKELY(row_end + 1 == 0)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem address is too large");
return;
}
FILE* fp = fopen(filename.c_str(), "w");
if (VL_UNLIKELY(!fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
// cppcheck-suppress resourceLeak // fp is NULL - bug in cppcheck
return;
}
for (size_t row_offset = row_start; row_offset <= row_end; ++row_offset) {
if (width <= 8) {
const CData* datap
= &(reinterpret_cast<const CData*>(memp))[row_offset];
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
fprintf(fp, "\n");
} else if (width <= 16) {
const SData* datap
= &(reinterpret_cast<const SData*>(memp))[row_offset];
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
fprintf(fp, "\n");
} else if (width <= 32) {
const IData* datap
= &(reinterpret_cast<const IData*>(memp))[row_offset];
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
fprintf(fp, "\n");
} else if (width <= 64) {
const QData* datap
= &(reinterpret_cast<const QData*>(memp))[row_offset];
vluint64_t value = VL_MASK_Q(width) & *datap;
vluint32_t lo = value & 0xffffffff;
vluint32_t hi = value >> 32;
fprintf(fp, memhFormat(width - 32), hi);
fprintf(fp, "%08x\n", lo);
} else {
WDataInP memDatap = reinterpret_cast<WDataInP>(memp);
WDataInP datap = &memDatap[row_offset * VL_WORDS_I(width)];
// output as a sequence of VL_EDATASIZE'd words
// from MSB to LSB. Mask off the MSB word which could
// contain junk above the top of valid data.
int word_idx = ((width - 1) / VL_EDATASIZE);
bool first = true;
while (word_idx >= 0) {
EData data = datap[word_idx];
if (first) {
data &= VL_MASK_E(width);
int top_word_nbits = ((width - 1) & (VL_EDATASIZE - 1)) + 1;
fprintf(fp, memhFormat(top_word_nbits), data);
} else {
fprintf(fp, "%08x", data);
}
word_idx--;
first = false;
}
fprintf(fp, "\n");
}
}
fclose(fp);
}
IData VL_FREAD_I(int width, int array_lsb, int array_size,
void* memp, IData fpi, IData start, IData count) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
@@ -1469,14 +1339,14 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size,
// Prep for reading
IData read_count = 0;
IData read_elements = 0;
int start_shift = (width-1) & ~7; // bit+7:bit gets first character
int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
int shift = start_shift;
// Read the data
// We process a character at a time, as then we don't need to deal
// with changing buffer sizes dynamically, etc.
while (1) {
int c = fgetc(fp);
if (VL_UNLIKELY(c==EOF)) break;
if (VL_UNLIKELY(c == EOF)) break;
// Shift value in
IData entry = read_elements + start - array_lsb;
if (width <= 8) {
@@ -1513,144 +1383,6 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size,
return read_count;
}
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
QData filename, void* memp, IData start, IData end) VL_MT_SAFE {
WData fnw[VL_WQ_WORDS_E]; VL_SET_WQ(fnw, filename);
return VL_READMEM_W(hex, width, depth, array_lsb, VL_WQ_WORDS_E, fnw, memp, start, end);
}
void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
WDataInP filenamep, void* memp, IData start, IData end) VL_MT_SAFE {
char filenamez[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
_VL_VINT_TO_STRING(fnwords * VL_EDATASIZE, filenamez, filenamep);
std::string filenames(filenamez);
return VL_READMEM_N(hex, width, depth, array_lsb, filenames, memp, start, end);
}
void VL_READMEM_N(
bool hex, // Hex format, else binary
int width, // Width of each array row
int depth, // Number of rows
int array_lsb, // Index of first row. Valid row addresses
// // range from array_lsb up to (array_lsb + depth - 1)
const std::string& filename, // Input file name
void* memp, // Array state
IData start, // First array row address to read
IData end // Last row address to read
) VL_MT_SAFE {
FILE* fp = fopen(filename.c_str(), "r");
if (VL_UNLIKELY(!fp)) {
// We don't report the Verilog source filename as it slow to have to pass it down
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
// cppcheck-suppress resourceLeak // fp is NULL - bug in cppcheck
return;
}
// Prep for reading
IData addr = start;
int linenum = 1;
bool innum = false;
bool ignore_to_eol = false;
bool ignore_to_cmt = false;
bool needinc = false;
bool reading_addr = false;
int lastc = ' ';
// Read the data
// We process a character at a time, as then we don't need to deal
// with changing buffer sizes dynamically, etc.
while (1) {
int c = fgetc(fp);
if (VL_UNLIKELY(c==EOF)) break;
//printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n",
// linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc);
if (c=='\n') {
linenum++; ignore_to_eol = false;
if (innum) reading_addr = false;
innum = false;
}
else if (c=='\t' || c==' ' || c=='\r' || c=='\f') {
if (innum) reading_addr = false;
innum = false;
}
// Skip // comments and detect /* comments
else if (ignore_to_cmt && lastc=='*' && c=='/') {
ignore_to_cmt = false; if (innum) reading_addr=false; innum=false;
} else if (!ignore_to_eol && !ignore_to_cmt) {
if (lastc=='/' && c=='*') { ignore_to_cmt = true; }
else if (lastc=='/' && c=='/') { ignore_to_eol = true; }
else if (c=='/') {} // Part of /* or //
else if (c=='#') { ignore_to_eol = true; }
else if (c=='_') {}
else if (c=='@') { reading_addr = true; innum=false; needinc=false; }
// Check for hex or binary digits as file format requests
else if (isxdigit(c) || (!reading_addr && (c=='x' || c=='X'))) {
c = tolower(c);
int value = (c >= 'a' ? (c=='x' ? VL_RAND_RESET_I(4) : (c-'a'+10)) : (c-'0'));
if (!innum) { // Prep for next number
if (needinc) { addr++; needinc=false; }
}
if (reading_addr) {
// Decode @ addresses
if (!innum) addr=0;
addr = (addr<<4) + value;
} else {
needinc = true;
//printf(" Value width=%d @%x = %c\n", width, addr, c);
if (VL_UNLIKELY(addr >= static_cast<IData>(depth+array_lsb)
|| addr < static_cast<IData>(array_lsb))) {
VL_FATAL_MT(filename.c_str(), linenum, "",
"$readmem file address beyond bounds of array");
} else {
int entry = addr - array_lsb;
QData shift = hex ? VL_ULL(4) : VL_ULL(1);
// Shift value in
if (width<=8) {
CData* datap = &(reinterpret_cast<CData*>(memp))[entry];
if (!innum) { *datap = 0; }
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
} else if (width<=16) {
SData* datap = &(reinterpret_cast<SData*>(memp))[entry];
if (!innum) { *datap = 0; }
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
} else if (width <= VL_IDATASIZE) {
IData* datap = &(reinterpret_cast<IData*>(memp))[entry];
if (!innum) { *datap = 0; }
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
} else if (width<=VL_QUADSIZE) {
QData* datap = &(reinterpret_cast<QData*>(memp))[entry];
if (!innum) { *datap = 0; }
*datap = ((*datap << static_cast<QData>(shift))
+ static_cast<QData>(value)) & VL_MASK_Q(width);
} else {
WDataOutP datap = &(reinterpret_cast<WDataOutP>(memp))
[ entry*VL_WORDS_I(width) ];
if (!innum) { VL_ZERO_RESET_W(width, datap); }
_VL_SHIFTL_INPLACE_W(width, datap, static_cast<IData>(shift));
datap[0] |= value;
}
if (VL_UNLIKELY(value>=(1<<shift))) {
VL_FATAL_MT(filename.c_str(), linenum, "",
"$readmemb (binary) file contains hex characters");
}
}
}
innum = true;
}
else {
VL_FATAL_MT(filename.c_str(), linenum, "", "$readmem file syntax error");
}
}
lastc = c;
}
if (needinc) { addr++; }
// Final checks
fclose(fp);
if (VL_UNLIKELY(end != VL_UL(0xffffffff) && addr != (end+1))) {
VL_FATAL_MT(filename.c_str(), linenum, "",
"$readmem file ended before specified ending-address");
}
}
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
WData lhsw[VL_WQ_WORDS_E]; VL_SET_WQ(lhsw, lhs);
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
@@ -1795,6 +1527,9 @@ std::string VL_TO_STRING(IData lhs) {
std::string VL_TO_STRING(QData lhs) {
return VL_SFORMATF_NX("'h%0x", 64, lhs);
}
std::string VL_TO_STRING_W(int words, WDataInP obj) {
return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj);
}
std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE {
std::string out = ld;
@@ -1867,6 +1602,334 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
return static_cast<IData>(v);
}
//===========================================================================
// Dumping
const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_SAFE {
// This function performs both accessing and setting so it's easy to make an in-function static
static VL_THREAD_LOCAL std::string t_filename;
if (setit) {
t_filename = filename;
} else {
static VL_THREAD_LOCAL bool t_warned = false;
if (VL_UNLIKELY(t_filename.empty() && !t_warned)) {
t_warned = true;
VL_PRINTF_MT("%%Warning: $dumpvar ignored as not proceeded by $dumpfile\n");
return "";
}
}
return t_filename.c_str();
}
//===========================================================================
// Readmem/writemem
static const char* memhFormat(int nBits) {
assert((nBits >= 1) && (nBits <= 32));
static char buf[32];
switch ((nBits - 1) / 4) {
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
case 2: VL_SNPRINTF(buf, 32, "%%03x"); break;
case 3: VL_SNPRINTF(buf, 32, "%%04x"); break;
case 4: VL_SNPRINTF(buf, 32, "%%05x"); break;
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
default: assert(false); break; // LCOV_EXCL_LINE
}
return buf;
}
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
: m_hex(hex)
, m_bits(bits)
, m_filename(filename)
, m_end(end)
, m_addr(start)
, m_linenum(0) {
m_fp = fopen(filename.c_str(), "r");
if (VL_UNLIKELY(!m_fp)) {
// We don't report the Verilog source filename as it slow to have to pass it down
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
return;
}
}
VlReadMem::~VlReadMem() {
if (m_fp) { fclose(m_fp); m_fp = NULL; }
}
bool VlReadMem::get(QData& addrr, std::string& valuer) {
if (VL_UNLIKELY(!m_fp)) return false;
valuer = "";
// Prep for reading
bool indata = false;
bool ignore_to_eol = false;
bool ignore_to_cmt = false;
bool reading_addr = false;
int lastc = ' ';
// Read the data
// We process a character at a time, as then we don't need to deal
// with changing buffer sizes dynamically, etc.
while (1) {
int c = fgetc(m_fp);
if (VL_UNLIKELY(c == EOF)) break;
// printf("%d: Got '%c' Addr%lx IN%d IgE%d IgC%d\n",
// m_linenum, c, m_addr, indata, ignore_to_eol, ignore_to_cmt);
// See if previous data value has completed, and if so return
if (c == '_') continue; // Ignore _ e.g. inside a number
if (indata && !isxdigit(c) && c != 'x' && c != 'X') {
// printf("Got data @%lx = %s\n", m_addr, valuer.c_str());
indata = false;
ungetc(c, m_fp);
addrr = m_addr;
++m_addr;
return true;
}
// Parse line
if (c == '\n') {
++m_linenum; ignore_to_eol = false;
reading_addr = false;
} else if (c == '\t' || c == ' ' || c == '\r' || c == '\f') {
reading_addr = false;
}
// Skip // comments and detect /* comments
else if (ignore_to_cmt && lastc == '*' && c == '/') {
ignore_to_cmt = false;
reading_addr = false;
} else if (!ignore_to_eol && !ignore_to_cmt) {
if (lastc == '/' && c == '*') { ignore_to_cmt = true; }
else if (lastc == '/' && c == '/') { ignore_to_eol = true; }
else if (c == '/') {} // Part of /* or //
else if (c == '#') { ignore_to_eol = true; }
else if (c == '@') { reading_addr = true; m_addr = 0; }
// Check for hex or binary digits as file format requests
else if (isxdigit(c) || (!reading_addr && (c == 'x' || c == 'X'))) {
c = tolower(c);
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c-'a'+10)) : (c-'0'));
if (reading_addr) {
// Decode @ addresses
m_addr = (m_addr << 4) + value;
} else {
indata = true;
valuer += c;
// printf(" Value width=%d @%x = %c\n", width, m_addr, c);
if (VL_UNLIKELY(value > 1 && !m_hex)) {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
"$readmemb (binary) file contains hex characters");
}
}
} else {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "", "$readmem file syntax error");
}
}
lastc = c;
}
if (VL_UNLIKELY(m_end != ~VL_ULL(0) && m_addr <= m_end)) {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
"$readmem file ended before specified final address (IEEE 2017 21.4)");
}
return false; // EOF
}
void VlReadMem::setData(void* valuep, const std::string& rhs) {
QData shift = m_hex ? VL_ULL(4) : VL_ULL(1);
bool innum = false;
// Shift value in
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
char c = tolower(*it);
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
if (m_bits <= 8) {
CData* datap = reinterpret_cast<CData*>(valuep);
if (!innum) { *datap = 0; }
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
} else if (m_bits <= 16) {
SData* datap = reinterpret_cast<SData*>(valuep);
if (!innum) { *datap = 0; }
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
} else if (m_bits <= VL_IDATASIZE) {
IData* datap = reinterpret_cast<IData*>(valuep);
if (!innum) { *datap = 0; }
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
} else if (m_bits <= VL_QUADSIZE) {
QData* datap = reinterpret_cast<QData*>(valuep);
if (!innum) { *datap = 0; }
*datap = ((*datap << static_cast<QData>(shift)) + static_cast<QData>(value))
& VL_MASK_Q(m_bits);
} else {
WDataOutP datap = reinterpret_cast<WDataOutP>(valuep);
if (!innum) { VL_ZERO_RESET_W(m_bits, datap); }
_VL_SHIFTL_INPLACE_W(m_bits, datap, static_cast<IData>(shift));
datap[0] |= value;
}
innum = true;
}
}
VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end)
: m_bits(bits)
, m_addr(0) {
if (VL_UNLIKELY(!hex)) {
VL_FATAL_MT(filename.c_str(), 0, "",
"Unsupported: $writemem binary format (suggest hex format)");
return;
}
if (VL_UNLIKELY(start > end)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range");
return;
}
m_fp = fopen(filename.c_str(), "w");
if (VL_UNLIKELY(!m_fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
// cppcheck-suppress resourceLeak // m_fp is NULL - bug in cppcheck
return;
}
}
VlWriteMem::~VlWriteMem() {
if (m_fp) { fclose(m_fp); m_fp = NULL; }
}
void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
if (VL_UNLIKELY(!m_fp)) return;
if (addr != m_addr && addrstamp) { // Only assoc has time stamps
fprintf(m_fp, "@%" VL_PRI64 "x\n", addr);
}
m_addr = addr + 1;
if (m_bits <= 8) {
const CData* datap = reinterpret_cast<const CData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else if (m_bits <= 16) {
const SData* datap = reinterpret_cast<const SData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else if (m_bits <= 32) {
const IData* datap = reinterpret_cast<const IData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else if (m_bits <= 64) {
const QData* datap = reinterpret_cast<const QData*>(valuep);
vluint64_t value = VL_MASK_Q(m_bits) & *datap;
vluint32_t lo = value & 0xffffffff;
vluint32_t hi = value >> 32;
fprintf(m_fp, memhFormat(m_bits - 32), hi);
fprintf(m_fp, "%08x\n", lo);
} else {
WDataInP datap = reinterpret_cast<WDataInP>(valuep);
// output as a sequence of VL_EDATASIZE'd words
// from MSB to LSB. Mask off the MSB word which could
// contain junk above the top of valid data.
int word_idx = ((m_bits - 1) / VL_EDATASIZE);
bool first = true;
while (word_idx >= 0) {
EData data = datap[word_idx];
if (first) {
data &= VL_MASK_E(m_bits);
int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1;
fprintf(m_fp, memhFormat(top_word_nbits), data);
} else {
fprintf(m_fp, "%08x", data);
}
word_idx--;
first = false;
}
fprintf(m_fp, "\n");
}
}
void VL_READMEM_N(bool hex, // Hex format, else binary
int bits, // M_Bits of each array row
QData depth, // Number of rows
int array_lsb, // Index of first row. Valid row addresses
// // range from array_lsb up to (array_lsb + depth - 1)
const std::string& filename, // Input file name
void* memp, // Array state
QData start, // First array row address to read
QData end // Last row address to read
) VL_MT_SAFE {
QData addr_max = array_lsb + depth - 1;
if (start < static_cast<QData>(array_lsb)) start = array_lsb;
QData addr_end = end;
if (addr_end > addr_max) addr_end = addr_max;
VlReadMem rmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!rmem.isOpen())) return;
while (1) {
QData addr;
std::string value;
if (rmem.get(addr /*ref*/, value/*ref*/)) {
if (VL_UNLIKELY(addr < static_cast<QData>(array_lsb)
|| addr >= static_cast<QData>(array_lsb + depth))) {
VL_FATAL_MT(filename.c_str(), rmem.linenum(), "",
"$readmem file address beyond bounds of array");
} else {
QData entry = addr - array_lsb;
if (bits <= 8) {
CData* datap = &(reinterpret_cast<CData*>(memp))[entry];
rmem.setData(datap, value);
} else if (bits <= 16) {
SData* datap = &(reinterpret_cast<SData*>(memp))[entry];
rmem.setData(datap, value);
} else if (bits <= VL_IDATASIZE) {
IData* datap = &(reinterpret_cast<IData*>(memp))[entry];
rmem.setData(datap, value);
} else if (bits <= VL_QUADSIZE) {
QData* datap = &(reinterpret_cast<QData*>(memp))[entry];
rmem.setData(datap, value);
} else {
WDataOutP datap = &(reinterpret_cast<WDataOutP>(memp))
[ entry*VL_WORDS_I(bits) ];
rmem.setData(datap, value);
}
}
} else {
break;
}
}
}
void VL_WRITEMEM_N(bool hex, // Hex format, else binary
int bits, // Width of each array row
QData depth, // Number of rows
int array_lsb, // Index of first row. Valid row addresses
// // range from array_lsb up to (array_lsb + depth - 1)
const std::string& filename, // Output file name
const void* memp, // Array state
QData start, // First array row address to write
QData end // Last address to write, or ~0 when not specified
) VL_MT_SAFE {
QData addr_max = array_lsb + depth - 1;
if (start < static_cast<QData>(array_lsb)) start = array_lsb;
if (end > addr_max) end = addr_max;
VlWriteMem wmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!wmem.isOpen())) return;
for (QData addr = start; addr <= end; ++addr) {
QData row_offset = addr - array_lsb;
if (bits <= 8) {
const CData* datap = &(reinterpret_cast<const CData*>(memp))[row_offset];
wmem.print(addr, false, datap);
} else if (bits <= 16) {
const SData* datap = &(reinterpret_cast<const SData*>(memp))[row_offset];
wmem.print(addr, false, datap);
} else if (bits <= 32) {
const IData* datap = &(reinterpret_cast<const IData*>(memp))[row_offset];
wmem.print(addr, false, datap);
} else if (bits <= 64) {
const QData* datap = &(reinterpret_cast<const QData*>(memp))[row_offset];
wmem.print(addr, false, datap);
} else {
WDataInP memDatap = reinterpret_cast<WDataInP>(memp);
WDataInP datap = &memDatap[row_offset * VL_WORDS_I(bits)];
wmem.print(addr, false, datap);
}
}
}
//===========================================================================
// Timescale conversion
@@ -2155,6 +2218,9 @@ void VerilatedImp::commandArgVl(const std::string& arg) {
else if (commandArgVlValue(arg, "+verilator+seed+", value/*ref*/)) {
Verilated::randSeed(atoi(value.c_str()));
}
else if (arg == "+verilator+noassert") {
Verilated::assertOn(false);
}
else if (arg == "+verilator+V") {
versionDump(); // Someday more info too
VL_FATAL_MT("COMMAND_LINE", 0, "",
@@ -2352,9 +2418,9 @@ VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTIN
void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
// Slowpath - Called only when find has failed
std::string msg = (std::string("Testbench C called '")
+VerilatedImp::exportName(funcnum)
+"' but scope wasn't set, perhaps due to dpi import call without 'context'");
std::string msg = (std::string("Testbench C called '") + VerilatedImp::exportName(funcnum)
+ "' but scope wasn't set, perhaps due to dpi import call without "
+ "'context', or missing svSetScope. See IEEE 1800-2017 35.5.3.");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return NULL;
}
+19 -17
View File
@@ -83,6 +83,7 @@ class VerilatedVar;
class VerilatedVarNameMap;
class VerilatedVcd;
class VerilatedVcdC;
class VerilatedVcdSc;
class VerilatedFst;
class VerilatedFstC;
@@ -200,13 +201,19 @@ public:
/// Check that the current thread ID is the same as the construction thread ID
void check() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(m_threadid != VL_THREAD_ID())) {
fatal_different(); // LCOV_EXCL_LINE
if (m_threadid == 0) {
m_threadid = VL_THREAD_ID();
} else {
fatal_different(); // LCOV_EXCL_LINE
}
}
}
void changeThread() { m_threadid = 0; } // Allow intentional change-of-thread
static void fatal_different() VL_MT_SAFE;
#else // !VL_THREADED || !VL_DEBUG
public:
void check() {}
void changeThread() {}
#endif
};
@@ -630,22 +637,6 @@ extern void VL_FCLOSE_I(IData fdi);
extern IData VL_FREAD_I(int width, int array_lsb, int array_size,
void* memp, IData fpi, IData start, IData count);
extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
WDataInP filenamep, void* memp, IData start, IData end);
extern void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
QData filename, void* memp, IData start, IData end);
inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
IData filename, void* memp, IData start, IData end) VL_MT_SAFE {
VL_READMEM_Q(hex, width, depth, array_lsb, fnwords, filename, memp, start, end); }
extern void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
WDataInP filenamep, const void* memp, IData start, IData end);
extern void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
QData filename, const void* memp, IData start, IData end);
inline void VL_WRITEMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
IData filename, const void* memp, IData start, IData end) VL_MT_SAFE {
VL_WRITEMEM_Q(hex, width, depth, array_lsb, fnwords, filename, memp, start, end); }
extern void VL_WRITEF(const char* formatp, ...);
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
@@ -2029,6 +2020,12 @@ static inline WDataOutP VL_SHIFTR_WWW(int obits, int lbits, int rbits,
}
return VL_SHIFTR_WWI(obits, lbits, 32, owp, lwp, rwp[0]);
}
static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits,
WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE {
WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd);
return VL_SHIFTR_WWW(obits, lbits, rbits, owp, lwp, rwp);
}
static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE {
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
@@ -2114,6 +2111,11 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits,
}
return VL_SHIFTRS_WWI(obits, lbits, 32, owp, lwp, rwp[0]);
}
static inline WDataOutP VL_SHIFTRS_WWQ(int obits, int lbits, int rbits,
WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE {
WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd);
return VL_SHIFTRS_WWW(obits, lbits, rbits, owp, lwp, rwp);
}
static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits,
IData lhs, WDataInP rwp) VL_MT_SAFE {
EData overshift = 0; // Huge shift 1>>32 or more
+1 -1
View File
@@ -86,7 +86,7 @@ LDLIBS += $(VM_USER_LDLIBS)
# SystemC takes minutes to optimize, thus it is off by default.
#OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
#OPT_FAST = -O2 -fstrict-aliasing
#OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
+5 -5
View File
@@ -73,12 +73,12 @@ private:
public:
// METHODS
// cppcheck-suppress truncLongCastReturn
virtual vluint64_t count() const { return *m_countp; }
virtual void zero() const { *m_countp = 0; }
virtual vluint64_t count() const VL_OVERRIDE { return *m_countp; }
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
// CONSTRUCTORS
// cppcheck-suppress noExplicitConstructor
VerilatedCoverItemSpec(T* countp) : m_countp(countp) { *m_countp = 0; }
virtual ~VerilatedCoverItemSpec() {}
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
};
//=============================================================================
@@ -222,7 +222,7 @@ private:
void clearGuts() VL_REQUIRES(m_mutex) {
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
VL_DO_DANGLING(delete itemp, itemp);
}
m_items.clear();
m_indexValues.clear();
@@ -244,7 +244,7 @@ public:
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
VL_DO_DANGLING(delete itemp, itemp);
} else {
newlist.push_back(itemp);
}
+32 -19
View File
@@ -20,6 +20,7 @@
//=============================================================================
// SPDIFF_OFF
#define __STDC_LIMIT_MACROS // UINT64_MAX
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_fst_c.h"
@@ -47,6 +48,7 @@
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
#else
# include <stdint.h>
# include <unistd.h>
#endif
@@ -62,9 +64,12 @@ protected:
vluint32_t m_code; ///< Starting code number
// CONSTRUCTORS
VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb,
VerilatedFstCallback_t changecb,
void* ut, vluint32_t code)
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}
VerilatedFstCallback_t changecb, void* ut)
: m_initcb(icb)
, m_fullcb(fcb)
, m_changecb(changecb)
, m_userthis(ut)
, m_code(1) {}
~VerilatedFstCallInfo() {}
};
@@ -72,10 +77,11 @@ protected:
// VerilatedFst
VerilatedFst::VerilatedFst(void* fst)
: m_fst(fst),
m_fullDump(true),
m_scopeEscape('.') {
m_valueStrBuffer.reserve(64+1); // Need enough room for quad
: m_fst(fst)
, m_fullDump(true)
, m_nextCode(1)
, m_scopeEscape('.') {
m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad
}
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
@@ -86,10 +92,12 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
fstWriterSetParallelMode(m_fst, 1);
#endif
m_curScope.clear();
m_nextCode = 1;
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
VerilatedFstCallInfo* cip = m_callbacks[ent];
cip->m_code = 1;
cip->m_code = m_nextCode;
// Initialize; callbacks will call decl* which update m_nextCode
(cip->m_initcb)(this, cip->m_userthis, cip->m_code);
}
@@ -116,9 +124,15 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem
m_local2fstdtype[dtypenum] = enumNum;
}
void VerilatedFst::declSymbol(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, vluint32_t len) {
void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, vluint32_t len,
vluint32_t bits) {
// Make sure deduplicate tracking increments for future declarations
int codesNeeded = 1 + int(bits / 32);
//Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals
m_nextCode = std::max(m_nextCode, code + codesNeeded);
std::pair<Code2SymbolType::iterator, bool> p
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
std::istringstream nameiss(name);
@@ -171,17 +185,16 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name,
//=============================================================================
// Callbacks
void VerilatedFst::addCallback(
VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(isOpen())) {
std::string msg = (std::string("Internal: ")+__FILE__+"::"+__FUNCTION__
+" called with already open file");
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ " called with already open file");
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
VerilatedFstCallInfo* vci = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis, 1);
m_callbacks.push_back(vci);
VerilatedFstCallInfo* cip = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis);
m_callbacks.push_back(cip);
}
//=============================================================================
@@ -190,7 +203,7 @@ void VerilatedFst::addCallback(
void VerilatedFst::dump(vluint64_t timeui) {
if (!isOpen()) return;
if (VL_UNLIKELY(m_fullDump)) {
m_fullDump = false; // No need for more full dumps
m_fullDump = false; // No more need for next dump to be full
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
VerilatedFstCallInfo* cip = m_callbacks[ent];
(cip->m_fullcb)(this, cip->m_userthis, cip->m_code);
+19 -12
View File
@@ -50,6 +50,7 @@ private:
void* m_fst;
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
bool m_fullDump;
vluint32_t m_nextCode; ///< Next code number to assign
char m_scopeEscape;
std::string m_module;
CallbackVec m_callbacks; ///< Routines to perform dumping
@@ -60,12 +61,13 @@ private:
VL_UNCOPYABLE(VerilatedFst);
void declSymbol(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, vluint32_t len);
bool array, int arraynum, vluint32_t len, vluint32_t bits);
// helpers
std::vector<char> m_valueStrBuffer;
public:
explicit VerilatedFst(void* fst=NULL);
~VerilatedFst() { if (m_fst == NULL) { fstWriterClose(m_fst); } }
void changeThread() { m_assertOne.changeThread(); }
bool isOpen() const { return m_fst != NULL; }
void open(const char* filename) VL_MT_UNSAFE;
void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); }
@@ -104,32 +106,35 @@ public:
void declBit(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1);
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1);
}
void declBus(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1);
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
}
void declDouble(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2);
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
}
void declFloat(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1);
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
}
void declQuad(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1);
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
}
void declArray(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1);
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
}
/// Inside dumping routines, dump one signal if it has changed
@@ -167,10 +172,10 @@ public:
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
chgArray(code, newval, bits); }
void declTriBit (vluint32_t code, const char* name, int arraynum);
void declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void declTriBit(vluint32_t code, const char* name, int arraynum);
void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void declTriQuad(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void declTriArray(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
@@ -198,7 +203,9 @@ class VerilatedFstC {
VL_UNCOPYABLE(VerilatedFstC);
public:
explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {}
~VerilatedFstC() {}
~VerilatedFstC() { close(); }
/// Routines can only be called from one thread; allow next call from different thread
void changeThread() { spTrace()->changeThread(); }
public:
// ACCESSORS
/// Is file open?
+95 -7
View File
@@ -42,6 +42,38 @@ extern std::string VL_TO_STRING(SData obj);
extern std::string VL_TO_STRING(IData obj);
extern std::string VL_TO_STRING(QData obj);
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
extern std::string VL_TO_STRING_W(int words, WDataInP obj);
//===================================================================
// Readmem/Writemem operation classes
class VlReadMem {
bool m_hex; // Hex format
int m_bits; // Bit width of values
const std::string& m_filename; // Filename
QData m_end; // End address (as specified by user)
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to read
int m_linenum; // Line number last read from file
public:
VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end);
~VlReadMem();
bool isOpen() const { return m_fp != NULL; }
int linenum() const { return m_linenum; }
bool get(QData& addrr, std::string& valuer);
void setData(void* valuep, const std::string& rhs);
};
class VlWriteMem {
int m_bits; // Bit width of values
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to write
public:
VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end);
~VlWriteMem();
bool isOpen() const { return m_fp != NULL; }
void print(QData addr, bool addrstamp, const void* valuep);
};
//===================================================================
// Verilog array container
@@ -72,6 +104,10 @@ VlWide<T_Words>& VL_CVT_W_A(WDataInP inp, const VlWide<T_Words>&) {
return *((VlWide<T_Words>*)inp);
}
template <std::size_t T_Words>
std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
return VL_TO_STRING_W(T_Words, obj.data());
}
//===================================================================
// Verilog associative array container
@@ -180,12 +216,41 @@ std::string VL_TO_STRING(const VlAssocArray<T_Key, T_Value>& obj) {
return obj.to_string();
}
template <class T_Key, class T_Value>
void VL_READMEM_N(bool hex, int bits, const std::string& filename,
VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
VlReadMem rmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!rmem.isOpen())) return;
while (1) {
QData addr;
std::string data;
if (rmem.get(addr /*ref*/, data /*ref*/)) {
rmem.setData(&(obj.at(addr)), data);
} else {
break;
}
}
}
template <class T_Key, class T_Value>
void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
const VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
VlWriteMem wmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!wmem.isOpen())) return;
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = obj.begin(); it != obj.end();
++it) {
QData addr = it->first;
if (addr >= start && addr <= end) wmem.print(addr, true, &(it->second));
}
}
//===================================================================
// Verilog queue container
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
private:
// TYPES
@@ -215,6 +280,21 @@ public:
void clear() { m_deque.clear(); }
void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); }
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value,T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
@@ -240,6 +320,7 @@ public:
// because we need to be able to insert only when the value is set
T_Value& at(size_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
@@ -249,6 +330,7 @@ public:
// Accessing. Verilog: v = assoc[index]
const T_Value& at(size_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) return atDefault();
else return m_deque[index];
}
@@ -312,12 +394,12 @@ extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld);
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb,
const std::string& filename,
void* memp, IData start, IData end) VL_MT_SAFE;
extern void VL_WRITEMEM_N(bool hex, int width, int depth, int array_lsb,
const std::string& filename,
const void* memp, IData start, IData end) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, void* memp, QData start,
QData end) VL_MT_SAFE;
extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, const void* memp, QData start,
QData end) VL_MT_SAFE;
extern IData VL_SSCANF_INX(int lbits, const std::string& ld,
const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits_ignored, std::string& output,
@@ -377,4 +459,10 @@ 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;
//======================================================================
// Dumping
extern const char* vl_dumpctl_filenamep(bool setit = false,
const std::string& filename = "") VL_MT_SAFE;
#endif // Guard
+7 -7
View File
@@ -164,12 +164,12 @@ private:
public:
// CONSTRUCTORS
VerilatedSave() { m_fd = -1; }
virtual ~VerilatedSave() { close(); }
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
// METHODS
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
virtual void close() VL_MT_UNSAFE_ONE;
virtual void flush() VL_MT_UNSAFE_ONE;
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
};
//=============================================================================
@@ -183,14 +183,14 @@ private:
public:
// CONSTRUCTORS
VerilatedRestore() { m_fd = -1; }
virtual ~VerilatedRestore() { close(); }
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
// METHODS
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
virtual void close() VL_MT_UNSAFE_ONE;
virtual void flush() VL_MT_UNSAFE_ONE {}
virtual void fill() VL_MT_UNSAFE_ONE;
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
virtual void fill() VL_OVERRIDE VL_MT_UNSAFE_ONE;
};
//=============================================================================
+1 -1
View File
@@ -212,7 +212,7 @@ public:
}
}
~vl_unordered_set() {
delete [] m_bucketsp; VL_DANGLING(m_bucketsp);
VL_DO_DANGLING(delete [] m_bucketsp, m_bucketsp);
}
vl_unordered_set& operator=(const vl_unordered_set& other) {
+36 -31
View File
@@ -57,8 +57,8 @@ class VerilatedVcdSingleton {
private:
typedef std::vector<VerilatedVcd*> VcdVec;
struct Singleton {
VerilatedMutex s_vcdMutex; ///< Protect the singleton
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
VerilatedMutex s_vcdMutex; ///< Protect the singleton
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
};
static Singleton& singleton() { static Singleton s; return s; }
public:
@@ -96,16 +96,19 @@ public:
class VerilatedVcdCallInfo {
protected:
friend class VerilatedVcd;
VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function
VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function
VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
void* m_userthis; ///< Fake "this" for caller
vluint32_t m_code; ///< Starting code number
VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function
VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function
VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
void* m_userthis; ///< Fake "this" for caller
vluint32_t m_code; ///< Starting code number (set later by traceInit)
// CONSTRUCTORS
VerilatedVcdCallInfo(VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb,
VerilatedVcdCallback_t changecb,
void* ut, vluint32_t code)
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}
VerilatedVcdCallback_t changecb, void* ut)
: m_initcb(icb)
, m_fullcb(fcb)
, m_changecb(changecb)
, m_userthis(ut)
, m_code(1) {}
~VerilatedVcdCallInfo() {}
};
@@ -116,7 +119,7 @@ protected:
bool VerilatedVcdFile::open(const std::string& name) VL_MT_UNSAFE {
m_fd = ::open(name.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC, 0666);
return (m_fd>=0);
return m_fd >= 0;
}
void VerilatedVcdFile::close() VL_MT_UNSAFE {
@@ -133,7 +136,10 @@ ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE {
// Opening/Closing
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
: m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
: m_isOpen(false)
, m_rolloverMB(0)
, m_modDepth(0)
, m_nextCode(1) {
// Not in header to avoid link issue if header is included without this .cpp file
m_fileNewed = (filep == NULL);
m_filep = m_fileNewed ? new VerilatedVcdFile : filep;
@@ -153,7 +159,7 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
void VerilatedVcd::open(const char* filename) {
m_assertOne.check();
if (isOpen()) return;
if (isOpen() || !filename || !*filename) return;
// Set member variables
m_filename = filename;
@@ -230,9 +236,10 @@ void VerilatedVcd::makeNameMap() {
deleteNameMap();
m_nextCode = 1;
m_namemapp = new NameMap;
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) {
VerilatedVcdCallInfo* cip = m_callbacks[ent];
cip->m_code = m_nextCode;
// Initialize; callbacks will call decl* which update m_nextCode
(cip->m_initcb)(this, cip->m_userthis, cip->m_code);
}
@@ -513,7 +520,7 @@ void VerilatedVcd::dumpHeader() {
printIndent(-1);
printStr("$enddefinitions $end\n\n\n");
assert(m_modDepth==0);
assert(m_modDepth == 0);
// Reclaim storage
deleteNameMap();
@@ -529,12 +536,12 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
if (!code) { VL_FATAL_MT(__FILE__, __LINE__, "",
"Internal: internal trace problem, code 0 is illegal"); }
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
int codesNeeded = 1+int(bits/32);
int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
int codesNeeded = 1 + int(bits / 32);
if (tri) codesNeeded *= 2; // Space in change array for __en signals
// Make sure array is large enough
m_nextCode = std::max(m_nextCode, code+codesNeeded);
m_nextCode = std::max(m_nextCode, code + codesNeeded);
if (m_sigs.capacity() <= m_nextCode) {
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
}
@@ -658,19 +665,16 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
//=============================================================================
// Callbacks
void VerilatedVcd::addCallback(
VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb,
void* userthis) VL_MT_UNSAFE_ONE
{
void VerilatedVcd::addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb,
VerilatedVcdCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(isOpen())) {
std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__
+" called with already open file";
std::string msg = std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ " called with already open file";
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
VerilatedVcdCallInfo* vci
= new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, m_nextCode);
m_callbacks.push_back(vci);
VerilatedVcdCallInfo* cip = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis);
m_callbacks.push_back(cip);
}
//=============================================================================
@@ -680,7 +684,7 @@ void VerilatedVcd::dumpFull(vluint64_t timeui) {
m_assertOne.check();
dumpPrep(timeui);
Verilated::quiesce();
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) {
VerilatedVcdCallInfo* cip = m_callbacks[ent];
(cip->m_fullcb)(this, cip->m_userthis, cip->m_code);
}
@@ -690,7 +694,7 @@ void VerilatedVcd::dump(vluint64_t timeui) {
m_assertOne.check();
if (!isOpen()) return;
if (VL_UNLIKELY(m_fullDump)) {
m_fullDump = false; // No need for more full dumps
m_fullDump = false; // No more need for next dump to be full
dumpFull(timeui);
return;
}
@@ -700,7 +704,7 @@ void VerilatedVcd::dump(vluint64_t timeui) {
}
dumpPrep(timeui);
Verilated::quiesce();
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedVcdCallInfo* cip = m_callbacks[ent];
(cip->m_changecb)(this, cip->m_userthis, cip->m_code);
}
@@ -829,6 +833,7 @@ main() {
#endif
//********************************************************************
// ;compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
//
// Local Variables:
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// End:
+7 -3
View File
@@ -103,9 +103,9 @@ private:
typedef std::vector<VerilatedVcdSig> SigVec;
SigVec m_sigs; ///< Pointer to signal information
typedef std::vector<VerilatedVcdCallInfo*> CallbackVec;
CallbackVec m_callbacks; ///< Routines to perform dumping
CallbackVec m_callbacks; ///< Routines to perform dumping
typedef std::map<std::string,std::string> NameMap;
NameMap* m_namemapp; ///< List of names for the header
NameMap* m_namemapp; ///< List of names for the header
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
@@ -159,6 +159,8 @@ private:
public:
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
~VerilatedVcd();
/// Routines can only be called from one thread; allow next call from different thread
void changeThread() { m_assertOne.changeThread(); }
// ACCESSORS
/// Set size in megabytes after which new file should be created
@@ -445,7 +447,9 @@ class VerilatedVcdC {
public:
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
: m_sptrace(filep) {}
~VerilatedVcdC() {}
~VerilatedVcdC() { close(); }
/// Routines can only be called from one thread; allow next call from different thread
void changeThread() { spTrace()->changeThread(); }
public:
// ACCESSORS
/// Is file open?
+1 -1
View File
@@ -62,7 +62,7 @@ public:
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
# endif
}
virtual ~VerilatedVcdSc() {}
virtual ~VerilatedVcdSc() { close(); }
// METHODS
/// Called by SystemC simulate()
+2 -2
View File
@@ -1993,7 +1993,7 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
}
if (!_error_info_p) return 0; // no error occured
return _error_info_p->level; // return error severity level
};
}
PLI_INT32 vpi_free_object(vpiHandle object) {
VerilatedVpiImp::assertOneCheck();
@@ -2008,7 +2008,7 @@ PLI_INT32 vpi_release_handle(vpiHandle object) {
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!vop)) return 0;
vpi_remove_cb(object); // May not be a callback, but that's ok
delete vop;
VL_DO_DANGLING(delete vop, vop);
return 1;
}
+19 -3
View File
@@ -154,11 +154,19 @@
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
# define VL_DANGLING(v)
# define VL_DANGLING(var)
#else
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
///< After e.g. delete, set variable to NULL to indicate must not use later
# define VL_DANGLING(var) do { (var) = NULL; } while(0)
#endif
///< Perform an e.g. delete, then set variable to NULL to indicate must not use later.
///< Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
#define VL_DO_DANGLING(stmt, var) do { do { stmt; } while(0); VL_DANGLING(var); } while(0)
///< Perform an e.g. delete, then set variable to NULL as a requirement
#define VL_DO_CLEAR(stmt, stmt2) do { do { stmt; } while(0); do { stmt2; } while(0); } while(0)
//=========================================================================
// C++-2011
@@ -176,11 +184,15 @@
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
# endif
# define VL_FINAL final
# define VL_OVERRIDE override
#else
# define VL_EQ_DELETE
# define vl_unique_ptr std::auto_ptr
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
# define VL_FINAL
# define VL_OVERRIDE
#endif
//=========================================================================
@@ -211,9 +223,12 @@
#ifdef __MINGW32__
# define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
#endif
// The inttypes supplied with some GCC & MINGW32 versions requires STDC_FORMAT_MACROS
// to be declared in order to get the PRIxx macros used by fstapi.c
#define __STDC_FORMAT_MACROS
#if defined(__CYGWIN__)
# include <stdint.h>
@@ -324,6 +339,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
/// Bytes this number of bits needs (1 bit=1 byte)
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
+7 -2
View File
@@ -68,6 +68,8 @@ CFG_CXXFLAGS_SRC = @CFG_CXXFLAGS_SRC@
CFG_CXXFLAGS_PARSER = @CFG_CXXFLAGS_PARSER@
# Compiler flags that turn on extra warnings
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
CFG_LDFLAGS_SRC = @CFG_LDFLAGS_SRC@
CFG_LIBS = @CFG_LIBS@
#### End of system configuration section. ####
@@ -91,8 +93,7 @@ endif
#CCMALLOC = /usr/local/lib/ccmalloc-gcc.o -lccmalloc -ldl
# -lfl not needed as Flex invoked with %nowrap option
# -lstdc++ needed for clang, believed harmless with gcc
LIBS = -lm -lstdc++
LIBS = $(CFG_LIBS) -lm
CPPFLAGS += -MMD
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
@@ -106,6 +107,7 @@ CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
else
CPPFLAGS += $(CFG_CXXFLAGS_SRC)
endif
LDFLAGS += $(CFG_LDFLAGS_SRC)
CPPFLAGSWALL = $(CPPFLAGS)
CPPFLAGSPARSER = $(CPPFLAGS) $(CFG_CXXFLAGS_PARSER)
@@ -164,6 +166,7 @@ RAW_OBJS = \
V3Branch.o \
V3Broken.o \
V3CCtors.o \
V3CUse.o \
V3Case.o \
V3Cast.o \
V3Cdc.o \
@@ -193,6 +196,7 @@ RAW_OBJS = \
V3FileLine.o \
V3Gate.o \
V3GenClk.o \
V3Global.o \
V3Graph.o \
V3GraphAlg.o \
V3GraphAcyc.o \
@@ -229,6 +233,7 @@ RAW_OBJS = \
V3Slice.o \
V3Split.o \
V3SplitAs.o \
V3SplitVar.o \
V3Stats.o \
V3StatsReport.o \
V3String.o \
+30 -30
View File
@@ -70,7 +70,7 @@ private:
m_scopep->addActivep(nodep);
}
// VISITORS
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
m_scopep = nodep;
m_iActivep = NULL;
m_cActivep = NULL;
@@ -79,15 +79,15 @@ private:
iterateChildren(nodep);
// Don't clear scopep, the namer persists beyond this visit
}
virtual void visit(AstSenTree* nodep) {
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
// Simplify sensitivity list
V3Const::constifyExpensiveEdit(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep);
}
// Empty visitors, speed things up
virtual void visit(AstNodeStmt* nodep) { }
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE { }
//--------------------
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// Default: Just iterate
iterateChildren(nodep);
}
@@ -163,7 +163,7 @@ private:
AstNode* m_alwaysp; // Always we're under
AstNode* m_assignp; // In assign
// VISITORS
virtual void visit(AstAssignDly* nodep) {
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
if (m_check != CT_SEQ) {
// Convert to a non-delayed assignment
UINFO(5," ASSIGNDLY "<<nodep<<endl);
@@ -181,10 +181,10 @@ private:
nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack());
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
virtual void visit(AstAssign* nodep) {
virtual void visit(AstAssign* nodep) VL_OVERRIDE {
if (m_check == CT_SEQ) {
AstNode* las = m_assignp;
m_assignp = nodep;
@@ -192,7 +192,7 @@ private:
m_assignp = las;
}
}
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
AstVar* varp = nodep->varp();
if (m_check == CT_SEQ
&& m_assignp
@@ -210,7 +210,7 @@ private:
}
}
//--------------------
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -240,7 +240,7 @@ private:
bool m_itemSequent; // Found a SenItem sequential
// VISITORS
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
// Create required actives and add to scope
UINFO(4," SCOPE "<<nodep<<endl);
// Clear last scope's names, and collect this scope's existing names
@@ -248,10 +248,10 @@ private:
m_scopeFinalp = NULL;
iterateChildren(nodep);
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Actives are being formed, so we can ignore any already made
}
virtual void visit(AstInitial* nodep) {
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
// Relink to IACTIVE, unless already under it
UINFO(4," INITIAL "<<nodep<<endl);
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
@@ -259,32 +259,32 @@ private:
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignAlias* nodep) {
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
// Relink to CACTIVE, unless already under it
UINFO(4," ASSIGNW "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
// Relink to CACTIVE, unless already under it
UINFO(4," ASSIGNW "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstCoverToggle* nodep) {
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
// Relink to CACTIVE, unless already under it
UINFO(4," COVERTOGGLE "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstFinal* nodep) {
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
// Relink to CFUNC for the final
UINFO(4," FINAL "<<nodep<<endl);
if (!nodep->bodysp()) { // Empty, Kill it.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
@@ -303,7 +303,7 @@ private:
nodep->unlinkFrBack();
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName(), true));
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext());
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
// METHODS
@@ -316,7 +316,7 @@ private:
// Never executing. Kill it.
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
@@ -353,7 +353,7 @@ private:
// Delete sensitivity list
if (oldsensesp) {
oldsensesp->unlinkFrBackWithNext()->deleteTree(); VL_DANGLING(oldsensesp);
VL_DO_DANGLING(oldsensesp->unlinkFrBackWithNext()->deleteTree(), oldsensesp);
}
// Move node to new active
@@ -372,25 +372,25 @@ private:
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
}
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALW "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
if (!nodep->bodysp()) {
// Empty always. Kill it.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
}
virtual void visit(AstAlwaysPublic* nodep) {
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALWPub "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
}
virtual void visit(AstSenGate* nodep) {
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
AstSenItem* subitemp = nodep->sensesp();
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
@@ -398,12 +398,12 @@ private:
nodep, "Strange activity type under SenGate");
iterateChildren(nodep);
}
virtual void visit(AstSenItem* nodep) {
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
m_itemCombo = true;
// Delete the sensitivity
// We'll add it as a generic COMBO SenItem in a moment.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (nodep->varrefp()) {
// V3LinkResolve should have cleaned most of these up
if (!nodep->varrefp()->width1()) {
@@ -416,10 +416,10 @@ private:
}
// Empty visitors, speed things up
virtual void visit(AstNodeMath* nodep) {}
virtual void visit(AstVarScope* nodep) {}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {}
//--------------------
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
+13 -13
View File
@@ -56,19 +56,19 @@ private:
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstTopScope* nodep) {
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
m_topscopep = nodep;
m_finder.main(m_topscopep);
iterateChildren(nodep);
m_topscopep = NULL;
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Create required actives and add to module
// We can start ordering at a module, or a scope
UINFO(4," MOD "<<nodep<<endl);
iterateChildren(nodep);
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
UINFO(4," ACTIVE "<<nodep<<endl);
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
AstSenTree* sensesp = nodep->sensesp();
@@ -79,7 +79,7 @@ private:
// Never executing. Kill it.
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
// Copy combo tree to settlement tree with duplicated statements
@@ -113,29 +113,29 @@ private:
// No need to do statements under it, they're already moved.
//iterateChildren(nodep);
}
virtual void visit(AstInitial* nodep) { // LCOV_EXCL_LINE
virtual void visit(AstInitial* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignAlias* nodep) { // LCOV_EXCL_LINE
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignW* nodep) { // LCOV_EXCL_LINE
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlways* nodep) { // LCOV_EXCL_LINE
virtual void visit(AstAlways* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlwaysPublic* nodep) { // LCOV_EXCL_LINE
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstFinal* nodep) { // LCOV_EXCL_LINE
virtual void visit(AstFinal* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been deleted");
}
// Empty visitors, speed things up
virtual void visit(AstNodeMath* nodep) {}
virtual void visit(AstVarScope* nodep) {}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {}
//--------------------
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
+29 -22
View File
@@ -115,9 +115,9 @@ private:
if (failsp) failsp->unlinkFrBackWithNext();
if (nodep->immediate()) {
UASSERT_OBJ(!sentreep, nodep, "Immediate assertions don't have sensivity");
UASSERT_OBJ(!sentreep, nodep, "Immediate assertions don't have sensitivity");
} else {
UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensivity");
UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensitivity");
sentreep->unlinkFrBack();
}
//
@@ -150,7 +150,7 @@ private:
// It's more LIKELY that we'll take the NULL if clause
// than the sim-killing else clause:
ifp->branchPred(VBranchPred::BP_LIKELY);
bodysp = ifp;
bodysp = newIfAssertOn(ifp);
} else {
nodep->v3fatalSrc("Unknown node type");
}
@@ -164,17 +164,17 @@ private:
if (selfDestruct) {
// Delete it after making the tree. This way we can tell the user
// if it wasn't constructed nicely or has other errors without needing --coverage.
newp->deleteTree();
VL_DO_DANGLING(newp->deleteTree(), newp);
nodep->unlinkFrBack();
} else {
nodep->replaceWith(newp);
}
// Bye
pushDeletep(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
// VISITORS
virtual void visit(AstIf* nodep) {
virtual void visit(AstIf* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
@@ -234,7 +234,7 @@ private:
}
//========== Case assertions
virtual void visit(AstCase* nodep) {
virtual void visit(AstCase* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!nodep->user1SetOnce()) {
bool has_default = false;
@@ -296,7 +296,7 @@ private:
}
//========== Past
virtual void visit(AstPast* nodep) {
virtual void visit(AstPast* nodep) VL_OVERRIDE {
iterateChildren(nodep);
uint32_t ticks = 1;
if (nodep->ticksp()) {
@@ -326,9 +326,13 @@ private:
}
nodep->replaceWith(inp);
}
virtual void visit(AstSampled* nodep) VL_OVERRIDE {
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
//========== Statements
virtual void visit(AstDisplay* nodep) {
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Replace the special types with standard text
if (nodep->displayType()==AstDisplayType::DT_INFO) {
@@ -341,29 +345,32 @@ private:
}
}
virtual void visit(AstAssert* nodep) {
virtual void visit(AstAssert* nodep) VL_OVERRIDE {
iterateChildren(nodep);
newPslAssertion(nodep, nodep->failsp());
}
virtual void visit(AstCover* nodep) {
virtual void visit(AstCover* nodep) VL_OVERRIDE {
iterateChildren(nodep);
newPslAssertion(nodep, NULL);
}
virtual void visit(AstRestrict* nodep) {
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// IEEE says simulator ignores these
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_modPastNum = 0;
//
iterateChildren(nodep);
// Reset defaults
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
unsigned origPastNum = m_modPastNum;
{
m_modp = nodep;
m_modPastNum = 0;
iterateChildren(nodep);
}
m_modp = origModp;
m_modPastNum = origPastNum;
}
virtual void visit(AstBegin* nodep) {
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
// This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin
AstBegin* lastp = m_beginp;
@@ -374,7 +381,7 @@ private:
m_beginp = lastp;
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
+9 -9
View File
@@ -71,7 +71,7 @@ private:
// VISITORS
//========== Statements
virtual void visit(AstClocking* nodep) {
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
UINFO(8," CLOCKING"<<nodep<<endl);
// Store the new default clock, reset on new module
m_seniDefaultp = nodep->sensesp();
@@ -81,9 +81,9 @@ private:
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->sensesp());
if (nodep->sensesp()) {
m_seniAlwaysp = nodep->sensesp()->sensesp();
@@ -92,7 +92,7 @@ private:
m_seniAlwaysp = NULL;
}
virtual void visit(AstNodeCoverOrAssert* nodep) {
virtual void visit(AstNodeCoverOrAssert* nodep) VL_OVERRIDE {
if (nodep->sentreep()) return; // Already processed
clearAssertInfo();
// Find Clocking's buried under nodep->exprsp
@@ -102,12 +102,12 @@ private:
}
clearAssertInfo();
}
virtual void visit(AstPast* nodep) {
virtual void visit(AstPast* nodep) VL_OVERRIDE {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
nodep->sentreep(newSenTree(nodep));
}
virtual void visit(AstPropClocked* nodep) {
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
// No need to iterate the body, once replace will get iterated
iterateAndNextNull(nodep->sensesp());
if (m_senip) {
@@ -130,14 +130,14 @@ private:
// Unlink and just keep a pointer to it, convert to sentree as needed
m_senip = nodep->sensesp();
nodep->replaceWith(blockp);
pushDeletep(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Reset defaults
m_seniDefaultp = NULL;
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+3 -3
View File
@@ -865,10 +865,10 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
// track, then delete it on completion
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
{
tempp->stmtsp()->accept(v); VL_DANGLING(nodep); // nodep to null as may be replaced
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced
}
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
tempp->deleteTree(); VL_DANGLING(tempp);
VL_DO_DANGLING(tempp->deleteTree(), tempp);
} else {
// Use back to determine who's pointing at us (IE assume new node
// grafts into same place as old one)
@@ -880,7 +880,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself");
{
nodep->accept(v); VL_DANGLING(nodep); // nodep to null as may be replaced
VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced
}
nodep = *nextnodepp; // Grab new node from point where old was connected
}
+356 -164
View File
@@ -51,15 +51,24 @@ typedef std::set<int> MTaskIdSet; // Set of mtaskIds for Var sorting
//######################################################################
// For broken() function, return error string if have a match
#define BROKEN_RTN(test) do { if (VL_UNCOVERABLE(test)) return # test; } while(0)
#define BROKEN_RTN(test) \
do { \
if (VL_UNCOVERABLE(test)) return #test; \
} while (0)
// For broken() function, return error string if a base of this class has a match
#define BROKEN_BASE_RTN(test) \
do { \
const char* reasonp = (test); \
if (VL_UNCOVERABLE(reasonp)) return reasonp; \
} while (0)
// (V)erilator (N)ode is: True if AstNode is of a a given AstType
#define VN_IS(nodep,nodetypename) (AstNode::privateIs ## nodetypename(nodep))
#define VN_IS(nodep,nodetypename) (AstNode::privateIs<Ast ## nodetypename>(nodep))
// (V)erilator (N)ode cast: Cast to given type if can; effectively
// dynamic_cast<nodetypename>(nodep)
#define VN_CAST(nodep,nodetypename) (AstNode::privateCast ## nodetypename(nodep))
#define VN_CAST_CONST(nodep,nodetypename) (AstNode::privateConstCast ## nodetypename(nodep) )
#define VN_CAST(nodep,nodetypename) (AstNode::privateCast<Ast ## nodetypename>(nodep))
#define VN_CAST_CONST(nodep,nodetypename) (AstNode::privateConstCast<Ast ## nodetypename>(nodep))
// (V)erilator (N)ode deleted: Reference to deleted child (for assertions only)
#define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
@@ -79,11 +88,11 @@ public:
inline AstType(en _e) : m_e(_e) {}
explicit inline AstType(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
};
inline bool operator==(AstType lhs, AstType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstType lhs, AstType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstType::en lhs, AstType rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const AstType& lhs, const AstType& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const AstType& lhs, AstType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(AstType::en lhs, const AstType& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return os << rhs.ascii(); }
//######################################################################
@@ -108,7 +117,7 @@ public:
"UNSIGNED", "SIGNED", "NOSIGN"
};
return names[m_e];
};
}
inline AstNumeric() : m_e(UNSIGNED) {}
// cppcheck-suppress noExplicitConstructor
inline AstNumeric(en _e) : m_e(_e) {}
@@ -125,11 +134,13 @@ public:
inline bool isSigned() const { return m_e==SIGNED; }
inline bool isNosign() const { return m_e==NOSIGN; }
// No isUnsigned() as it's ambiguous if NOSIGN should be included or not.
};
inline bool operator==(AstNumeric lhs, AstNumeric rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstNumeric lhs, AstNumeric::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstNumeric::en lhs, AstNumeric rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const AstNumeric& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const AstNumeric& lhs, const AstNumeric& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const AstNumeric& lhs, AstNumeric::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(AstNumeric::en lhs, const AstNumeric& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const AstNumeric& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -142,7 +153,10 @@ public:
NO_INLINE_MODULE,
NO_INLINE_TASK,
PUBLIC_MODULE,
PUBLIC_TASK
PUBLIC_TASK,
FULL_CASE,
PARALLEL_CASE,
ENUM_SIZE
};
enum en m_e;
inline AstPragmaType() : m_e(ILLEGAL) {}
@@ -150,10 +164,12 @@ public:
inline AstPragmaType(en _e) : m_e(_e) {}
explicit inline AstPragmaType(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
};
inline bool operator==(AstPragmaType lhs, AstPragmaType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstPragmaType lhs, AstPragmaType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstPragmaType::en lhs, AstPragmaType rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const AstPragmaType& lhs, const AstPragmaType& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const AstPragmaType& lhs, AstPragmaType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(AstPragmaType::en lhs, const AstPragmaType& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -178,10 +194,12 @@ public:
bool isTrace() const { return (m_e==TRACE_INIT || m_e==TRACE_INIT_SUB
|| m_e==TRACE_FULL || m_e==TRACE_FULL_SUB
|| m_e==TRACE_CHANGE || m_e==TRACE_CHANGE_SUB); }
};
inline bool operator==(AstCFuncType lhs, AstCFuncType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstCFuncType lhs, AstCFuncType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstCFuncType::en lhs, AstCFuncType rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const AstCFuncType& lhs, AstCFuncType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(AstCFuncType::en lhs, const AstCFuncType& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -267,10 +285,10 @@ public:
inline VEdgeType(en _e) : m_e(_e) {}
explicit inline VEdgeType(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
};
inline bool operator==(VEdgeType lhs, VEdgeType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VEdgeType lhs, VEdgeType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VEdgeType::en lhs, VEdgeType rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VEdgeType& lhs, VEdgeType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -301,6 +319,8 @@ public:
//
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
//
TYPENAME, // V3Width processes
//
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
@@ -312,7 +332,8 @@ public:
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
VAR_NO_CLOCKER // V3LinkParse moves to AstVar::attrClocker
VAR_NO_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar
};
enum en m_e;
const char* ascii() const {
@@ -324,22 +345,25 @@ public:
"ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME",
"MEMBER_BASE",
"TYPENAME",
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
"VAR_NO_CLOCKER"
"VAR_NO_CLOCKER", "VAR_SPLIT_VAR"
};
return names[m_e];
};
}
inline AstAttrType() : m_e(ILLEGAL) {}
// cppcheck-suppress noExplicitConstructor
inline AstAttrType(en _e) : m_e(_e) {}
explicit inline AstAttrType(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
};
inline bool operator==(AstAttrType lhs, AstAttrType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstAttrType lhs, AstAttrType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstAttrType::en lhs, AstAttrType rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const AstAttrType& lhs, const AstAttrType& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const AstAttrType& lhs, AstAttrType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(AstAttrType::en lhs, const AstAttrType& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -373,7 +397,7 @@ public:
" MAX"
};
return names[m_e];
};
}
const char* dpiType() const {
static const char* const names[] = {
"%E-unk",
@@ -386,7 +410,7 @@ public:
" MAX"
};
return names[m_e];
};
}
static void selfTest() {
UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), "SelfTest: Enum mismatch");
UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), "SelfTest: Enum mismatch");
@@ -463,10 +487,16 @@ public:
}
bool isDouble() const { return m_e==DOUBLE; }
bool isString() const { return m_e==STRING; }
};
inline bool operator==(AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstBasicDTypeKwd::en lhs, AstBasicDTypeKwd rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const AstBasicDTypeKwd& lhs, const AstBasicDTypeKwd& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const AstBasicDTypeKwd& lhs, AstBasicDTypeKwd::en rhs) {
return lhs.m_e == rhs;
}
inline bool operator==(AstBasicDTypeKwd::en lhs, const AstBasicDTypeKwd& rhs) {
return lhs == rhs.m_e;
}
//######################################################################
@@ -508,11 +538,13 @@ public:
bool isWritable() const { return m_e == OUTPUT || m_e == INOUT
|| m_e == REF; }
bool isRefOrConstRef() const { return m_e == REF || m_e == CONSTREF; }
};
inline bool operator==(VDirection lhs, VDirection rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VDirection lhs, VDirection::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VDirection::en lhs, VDirection rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const VDirection& lhs, const VDirection& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VDirection& lhs, VDirection::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VDirection::en lhs, const VDirection& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -535,14 +567,25 @@ public:
static const char* const names[] = {
"FALSE", "TRUE", "UNK"};
return names[m_e]; }
bool trueU() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; }
bool falseU() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; }
bool trueKnown() const { return m_e == BU_TRUE; }
bool trueUnknown() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; }
bool falseKnown() const { return m_e == BU_FALSE; }
bool falseUnknown() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; }
bool unknown() const { return m_e == BU_UNKNOWN; }
};
inline bool operator==(VBoolOrUnknown lhs, VBoolOrUnknown rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VBoolOrUnknown lhs, VBoolOrUnknown::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VBoolOrUnknown::en lhs, VBoolOrUnknown rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) { return os<<rhs.ascii(); }
void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; }
};
inline bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) {
return lhs.m_e == rhs;
}
inline bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) {
return lhs == rhs.m_e;
}
inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -607,11 +650,13 @@ public:
bool isTemp() const {
return (m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP || m_e==XTEMP);
}
};
inline bool operator==(AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstVarType lhs, AstVarType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstVarType::en lhs, AstVarType rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const AstVarType& lhs, const AstVarType& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const AstVarType& lhs, AstVarType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(AstVarType::en lhs, const AstVarType& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -642,11 +687,15 @@ public:
static const char* const names[] = {
"", "VL_LIKELY", "VL_UNLIKELY"};
return names[m_e]; }
};
inline bool operator==(VBranchPred lhs, VBranchPred rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VBranchPred lhs, VBranchPred::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VBranchPred::en lhs, VBranchPred rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VBranchPred& lhs, VBranchPred::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VBranchPred::en lhs, const VBranchPred& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -675,11 +724,19 @@ public:
static const char* const names[] = {
"", "clker", "non_clker"};
return names[m_e]; }
};
inline bool operator==(VVarAttrClocker lhs, VVarAttrClocker rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VVarAttrClocker lhs, VVarAttrClocker::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VVarAttrClocker::en lhs, VVarAttrClocker rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VVarAttrClocker& lhs, VVarAttrClocker::en rhs) {
return lhs.m_e == rhs;
}
inline bool operator==(VVarAttrClocker::en lhs, const VVarAttrClocker& rhs) {
return lhs == rhs.m_e;
}
inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -701,10 +758,10 @@ public:
static const char* const names[] = {
"always", "always_ff", "always_latch", "always_comb"};
return names[m_e]; }
};
inline bool operator==(VAlwaysKwd lhs, VAlwaysKwd rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VAlwaysKwd lhs, VAlwaysKwd::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VAlwaysKwd::en lhs, VAlwaysKwd rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -722,10 +779,10 @@ public:
inline VCaseType(en _e) : m_e(_e) {}
explicit inline VCaseType(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
};
inline bool operator==(VCaseType lhs, VCaseType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VCaseType lhs, VCaseType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VCaseType::en lhs, VCaseType rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const VCaseType& lhs, const VCaseType& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VCaseType& lhs, VCaseType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -751,10 +808,42 @@ public:
static const char* const names[] = {
"display", "write", "info", "error", "warning", "fatal"};
return names[m_e]; }
};
inline bool operator==(AstDisplayType lhs, AstDisplayType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstDisplayType lhs, AstDisplayType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstDisplayType::en lhs, AstDisplayType rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const AstDisplayType& lhs, const AstDisplayType& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const AstDisplayType& lhs, AstDisplayType::en rhs) {
return lhs.m_e == rhs;
}
inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) {
return lhs == rhs.m_e;
}
//######################################################################
class VDumpCtlType {
public:
enum en { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON };
enum en m_e;
inline VDumpCtlType()
: m_e(ON) {}
// cppcheck-suppress noExplicitConstructor
inline VDumpCtlType(en _e)
: m_e(_e) {}
explicit inline VDumpCtlType(int _e)
: m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush",
"$dumplimit", "$dumpoff", "$dumpon"};
return names[m_e];
}
};
inline bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; }
//######################################################################
@@ -774,11 +863,15 @@ public:
static const char* const names[] = {
"", "TEXT", "PREDOT"};
return names[m_e]; }
};
inline bool operator==(VParseRefExp lhs, VParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VParseRefExp lhs, VParseRefExp::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VParseRefExp::en lhs, VParseRefExp rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VParseRefExp& lhs, VParseRefExp::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VParseRefExp::en lhs, const VParseRefExp& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) {
return os << rhs.ascii();
}
//######################################################################
// VNumRange - Structure containing numeric range information
@@ -840,6 +933,36 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) { rhs.du
//######################################################################
class VUseType {
public:
enum en {
IMP_INCLUDE, // Implementation (.cpp) needs an include
INT_INCLUDE, // Interface (.h) needs an include
IMP_FWD_CLASS, // Implementation (.cpp) needs a forward class declaration
INT_FWD_CLASS, // Interface (.h) needs a forward class declaration
};
enum en m_e;
inline VUseType() : m_e(IMP_FWD_CLASS) {}
// cppcheck-suppress noExplicitConstructor
inline VUseType(en _e) : m_e(_e) {}
explicit inline VUseType(int _e) : m_e(static_cast<en>(_e)) {}
bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; }
bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; }
operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"};
return names[m_e];
}
};
inline bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
return os << rhs.ascii();
}
//######################################################################
class VBasicTypeKey {
public:
int m_width; // From AstNodeDType: Bit width of operation
@@ -934,14 +1057,14 @@ protected:
clearcnt(id, cntGblRef, userBusyRef); // Includes a checkUse for us
userBusyRef = false;
}
static void clearcnt(int id, uint32_t& cntGblRef, bool& userBusyRef) {
static void clearcnt(int id, uint32_t& cntGblRef, const bool& userBusyRef) {
UASSERT_STATIC(userBusyRef, "Clear of User"+cvtToStr(id)+"() not under AstUserInUse");
// If this really fires and is real (after 2^32 edits???)
// we could just walk the tree and clear manually
++cntGblRef;
UASSERT_STATIC(cntGblRef, "User*() overflowed!");
}
static void checkcnt(int id, uint32_t&, bool& userBusyRef) {
static void checkcnt(int id, uint32_t&, const bool& userBusyRef) {
UASSERT_STATIC(userBusyRef, "Check of User"+cvtToStr(id)+"() failed, not under AstUserInUse");
}
};
@@ -1106,7 +1229,7 @@ public:
explicit V3Hash(VNUser u) { m_both = u.toInt(); }
V3Hash operator+= (const V3Hash& rh) {
setBoth(depth()+rh.depth(), (hshval()*31+rh.hshval()));
return *this; };
return *this; }
// Creating from raw data (sameHash functions)
V3Hash() { setBoth(1, 0); }
// cppcheck-suppress noExplicitConstructor
@@ -1153,6 +1276,8 @@ class AstNode {
AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list
const AstType m_type; // Node sub-type identifier
FileLine* m_fileline; // Where it was declared
vluint64_t m_editCount; // When it was last edited
static vluint64_t s_editCntGbl; // Global edit counter
@@ -1207,8 +1332,10 @@ public:
protected:
// CONSTRUCTORS
AstNode() { init(); }
explicit AstNode(FileLine* fileline) {init(); m_fileline = fileline; }
AstNode(AstType t)
: m_type(t) { init(); }
AstNode(AstType t, FileLine* fl)
: m_type(t) { init(); m_fileline = fl; }
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
virtual void cloneRelink() {}
void cloneRelinkTree();
@@ -1239,7 +1366,7 @@ protected:
public:
// ACCESSORS
virtual AstType type() const = 0;
inline AstType type() const { return m_type; }
const char* typeName() const { return type().ascii(); } // See also prettyTypeName
AstNode* nextp() const { return m_nextp; }
AstNode* backp() const { return m_backp; }
@@ -1295,7 +1422,7 @@ public:
static string vcdName(const string& namein); // Name for printing out to vcd files
string prettyName() const { return prettyName(name()); }
string prettyNameQ() const { return prettyNameQ(name()); }
string prettyTypeName() const; // "VARREF" for error messages
string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name)
virtual string prettyOperatorName() const { return "operator "+prettyTypeName(); }
FileLine* fileline() const { return m_fileline; }
void fileline(FileLine* fl) { m_fileline = fl; }
@@ -1529,11 +1656,22 @@ private:
// CONVERSION
public:
#include "V3Ast__gen_interface.h" // From ./astgen
// Things like:
// AstAlways* castAlways();
// These for use by VN_IS macro only
template<class T>
static bool privateIs(const AstNode* nodep);
// These for use by VN_CAST macro only
template<class T>
static T* privateCast(AstNode* nodep);
// These for use by VN_CAST_CONST macro only
template<class T>
static const T* privateConstCast(const AstNode* nodep);
};
// Specialisations of privateIs/privateCast
#include "V3Ast__gen_impl.h" // From ./astgen
inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
if (!rhs) os<<"NULL"; else rhs->dump(os); return os;
}
@@ -1553,8 +1691,8 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
class AstNodeMath : public AstNode {
// Math -- anything that's part of an expression tree
public:
explicit AstNodeMath(FileLine* fl)
: AstNode(fl) {}
AstNodeMath(AstType t, FileLine* fl)
: AstNode(t, fl) {}
ASTNODE_BASE_FUNCS(NodeMath)
// METHODS
virtual bool hasDType() const { return true; }
@@ -1570,8 +1708,8 @@ public:
class AstNodeTermop : public AstNodeMath {
// Terminal operator -- a operator with no "inputs"
public:
explicit AstNodeTermop(FileLine* fl)
: AstNodeMath(fl) {}
AstNodeTermop(AstType t, FileLine* fl)
: AstNodeMath(t, fl) {}
ASTNODE_BASE_FUNCS(NodeTermop)
// Know no children, and hot function, so skip iterator for speed
// See checkTreeIter also that asserts no children
@@ -1582,8 +1720,8 @@ public:
class AstNodeUniop : public AstNodeMath {
// Unary math
public:
AstNodeUniop(FileLine* fl, AstNode* lhsp)
: AstNodeMath(fl) {
AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp)
: AstNodeMath(t, fl) {
dtypeFrom(lhsp);
setOp1p(lhsp); }
ASTNODE_BASE_FUNCS(NodeUniop)
@@ -1604,8 +1742,8 @@ public:
class AstNodeBiop : public AstNodeMath {
// Binary math
public:
AstNodeBiop(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeMath(fl) {
AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeMath(t, fl) {
setOp1p(lhs); setOp2p(rhs); }
ASTNODE_BASE_FUNCS(NodeBiop)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; // Clone single node, just get same type back.
@@ -1631,8 +1769,8 @@ public:
class AstNodeTriop : public AstNodeMath {
// Trinary math
public:
AstNodeTriop(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNodeMath(fl) {
AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNodeMath(t, fl) {
setOp1p(lhs); setOp2p(rhs); setOp3p(ths); }
ASTNODE_BASE_FUNCS(NodeTriop)
AstNode* lhsp() const { return op1p(); }
@@ -1659,22 +1797,22 @@ public:
class AstNodeBiCom : public AstNodeBiop {
// Binary math with commutative properties
public:
AstNodeBiCom(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiop(fl, lhs, rhs) {}
AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiop(t, fl, lhs, rhs) {}
ASTNODE_BASE_FUNCS(NodeBiCom)
};
class AstNodeBiComAsv : public AstNodeBiCom {
// Binary math with commutative & associative properties
public:
AstNodeBiComAsv(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiCom(fl, lhs, rhs) {}
AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiCom(t, fl, lhs, rhs) {}
ASTNODE_BASE_FUNCS(NodeBiComAsv)
};
class AstNodeCond : public AstNodeTriop {
public:
AstNodeCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
: AstNodeTriop(fl, condp, expr1p, expr2p) {
AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
: AstNodeTriop(t, fl, condp, expr1p, expr2p) {
if (expr1p) dtypeFrom(expr1p);
else if (expr2p) dtypeFrom(expr2p);
}
@@ -1700,8 +1838,8 @@ public:
class AstNodePreSel : public AstNode {
// Something that becomes an AstSel
public:
AstNodePreSel(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNode(fl) {
AstNodePreSel(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNode(t, fl) {
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
ASTNODE_BASE_FUNCS(NodePreSel)
AstNode* lhsp() const { return op1p(); }
@@ -1720,20 +1858,23 @@ public:
class AstNodeStmt : public AstNode {
// Statement -- anything that's directly under a function
bool m_statement; // Really a statement (e.g. not a function with return)
public:
explicit AstNodeStmt(FileLine* fl)
: AstNode(fl) {}
AstNodeStmt(AstType t, FileLine* fl, bool statement = true)
: AstNode(t, fl)
, m_statement(statement) {}
ASTNODE_BASE_FUNCS(NodeStmt)
// METHODS
virtual bool isStatement() const { return true; } // Really a statement
bool isStatement() const { return m_statement; } // Really a statement
void statement(bool flag) { m_statement = flag; }
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
};
class AstNodeAssign : public AstNodeStmt {
public:
AstNodeAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeStmt(fl) {
AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeStmt(t, fl) {
setOp1p(rhsp); setOp2p(lhsp);
dtypeFrom(lhsp);
}
@@ -1755,9 +1896,9 @@ public:
class AstNodeFor : public AstNodeStmt {
public:
AstNodeFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp,
AstNode* incsp, AstNode* bodysp)
: AstNodeStmt(fileline) {
: AstNodeStmt(t, fl) {
addNOp1p(initsp); setOp2p(condp); addNOp3p(incsp); addNOp4p(bodysp);
}
ASTNODE_BASE_FUNCS(NodeFor)
@@ -1775,8 +1916,8 @@ class AstNodeIf : public AstNodeStmt {
private:
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
public:
AstNodeIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
: AstNodeStmt(fl) {
AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
: AstNodeStmt(t, fl) {
setOp1p(condp); addNOp2p(ifsp); addNOp3p(elsesp);
}
ASTNODE_BASE_FUNCS(NodeIf)
@@ -1797,8 +1938,8 @@ public:
class AstNodeCase : public AstNodeStmt {
public:
AstNodeCase(FileLine* fl, AstNode* exprp, AstNode* casesp)
: AstNodeStmt(fl) {
AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp)
: AstNodeStmt(t, fl) {
setOp1p(exprp); addNOp2p(casesp);
}
ASTNODE_BASE_FUNCS(NodeCase)
@@ -1813,7 +1954,8 @@ public:
class AstNodeSenItem : public AstNode {
// An AstSenItem or AstSenGate
public:
explicit AstNodeSenItem(FileLine* fl) : AstNode(fl) {}
AstNodeSenItem(AstType t, FileLine* fl)
: AstNode(t, fl) {}
ASTNODE_BASE_FUNCS(NodeSenItem)
virtual bool isClocked() const = 0;
virtual bool isCombo() const = 0;
@@ -1834,14 +1976,14 @@ private:
bool m_hierThis; // Hiername points to "this" function
void init();
public:
AstNodeVarRef(FileLine* fl, const string& name, bool lvalue)
: AstNodeMath(fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL),
m_packagep(NULL), m_name(name), m_hierThis(false) {
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
: AstNodeMath(t, fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL)
, m_packagep(NULL), m_name(name), m_hierThis(false) {
init();
}
AstNodeVarRef(FileLine* fl, const string& name, AstVar* varp, bool lvalue)
: AstNodeMath(fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL),
m_packagep(NULL), m_name(name), m_hierThis(false) {
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
: AstNodeMath(t, fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL)
, m_packagep(NULL), m_name(name), m_hierThis(false) {
// May have varp==NULL
init();
}
@@ -1876,8 +2018,8 @@ private:
string m_text;
public:
// Node that simply puts text into the output stream
AstNodeText(FileLine* fileline, const string& textp)
: AstNode(fileline) {
AstNodeText(AstType t, FileLine* fl, const string& textp)
: AstNode(t, fl) {
m_text = textp; // Copy it
}
ASTNODE_BASE_FUNCS(NodeText)
@@ -1902,7 +2044,8 @@ private:
static int s_uniqueNum; // Unique number assigned to each dtype during creation for IEEE matching
public:
// CONSTRUCTORS
explicit AstNodeDType(FileLine* fl) : AstNode(fl) {
AstNodeDType(AstType t, FileLine* fl)
: AstNode(t, fl) {
m_width = 0; m_widthMin = 0; m_generic = false;
}
ASTNODE_BASE_FUNCS(NodeDType)
@@ -1924,6 +2067,8 @@ public:
virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling
virtual AstNodeDType* subDTypep() const { return NULL; } // Iff has a non-null subDTypep(), as generic node function
virtual bool isFourstate() const;
virtual string prettyDTypeName() const { return prettyTypeName(); } // Ideally an IEEE $typename
string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; }
//
// Changing the width may confuse the data type resolution, so must clear
// TypeTable cache after use.
@@ -1962,8 +2107,8 @@ private:
bool m_isFourstate;
MemberNameMap m_members;
public:
AstNodeUOrStructDType(FileLine* fl, AstNumeric numericUnpack)
: AstNodeDType(fl) {
AstNodeUOrStructDType(AstType t, FileLine* fl, AstNumeric numericUnpack)
: AstNodeDType(t, fl) {
// AstNumeric::NOSIGN overloaded to indicate not packed
m_packed = (numericUnpack != AstNumeric::NOSIGN);
m_isFourstate = false; // V3Width computes
@@ -2013,7 +2158,8 @@ private:
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable
public:
explicit AstNodeArrayDType(FileLine* fl) : AstNodeDType(fl) {
AstNodeArrayDType(AstType t, FileLine* fl)
: AstNodeDType(t, fl) {
m_refDTypep = NULL;
}
ASTNODE_BASE_FUNCS(NodeArrayDType)
@@ -2064,8 +2210,8 @@ public:
class AstNodeSel : public AstNodeBiop {
// Single bit range extraction, perhaps with non-constant selection or array selection
public:
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
: AstNodeBiop(fl, fromp, bitp) {}
AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp)
: AstNodeBiop(t, fl, fromp, bitp) {}
ASTNODE_BASE_FUNCS(NodeSel)
AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
void fromp(AstNode* nodep) { setOp1p(nodep); }
@@ -2078,7 +2224,8 @@ public:
class AstNodeStream : public AstNodeBiop {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
public:
AstNodeStream(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeBiop(t, fl, lhsp, rhsp) {
if (lhsp->dtypep()) {
dtypeSetLogicSized(lhsp->dtypep()->width(), AstNumeric::UNSIGNED);
}
@@ -2089,6 +2236,54 @@ public:
//######################################################################
// Tasks/functions common handling
class AstNodeCCall : public AstNodeStmt {
// A call of a C++ function, perhaps a AstCFunc or perhaps globally named
// Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
AstCFunc* m_funcp;
string m_hiername;
string m_argTypes;
public:
AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL)
: AstNodeStmt(t, fl, true)
, m_funcp(funcp) {
addNOp2p(argsp);
}
// Replacement form for V3Combine
// Note this removes old attachments from the oldp
AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp)
: AstNodeStmt(t, oldp->fileline(), true)
, m_funcp(funcp) {
m_funcp = funcp;
m_hiername = oldp->hiername();
m_argTypes = oldp->argTypes();
if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext());
}
ASTNODE_BASE_FUNCS(NodeCCall)
virtual void dump(std::ostream& str=std::cout) const;
virtual void cloneRelink();
virtual const char* broken() const;
virtual int instrCount() const { return instrCountCall(); }
virtual V3Hash sameHash() const { return V3Hash(funcp()); }
virtual bool same(const AstNode* samep) const {
const AstNodeCCall* asamep = static_cast<const AstNodeCCall*>(samep);
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
}
AstNode* exprsp() const { return op2p(); } // op2 = expressions to print
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const;
virtual bool isOutputter() const { return !isPure(); }
AstCFunc* funcp() const { return m_funcp; }
string hiername() const { return m_hiername; }
void hiername(const string& hn) { m_hiername = hn; }
string hiernameProtect() const;
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
// op1p reserved for AstCMethodCall
AstNode* argsp() const { return op2p(); }
void addArgsp(AstNode* nodep) { addOp2p(nodep); }
};
class AstNodeFTask : public AstNode {
private:
string m_name; // Name of task
@@ -2104,8 +2299,8 @@ private:
bool m_dpiTask:1; // DPI import task (vs. void function)
bool m_pure:1; // DPI import pure
public:
AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp)
: AstNode(fileline)
AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
: AstNode(t, fl)
, m_name(name)
, m_dpiOpenParent(0), m_taskPublic(false)
, m_attrIsolateAssign(false), m_prototype(false)
@@ -2167,15 +2362,15 @@ private:
string m_inlinedDots; // Dotted hierarchy flattened out
AstPackage* m_packagep; // Package hierarchy
public:
AstNodeFTaskRef(FileLine* fl, AstNode* namep, AstNode* pinsp)
: AstNodeStmt(fl)
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
: AstNodeStmt(t, fl, statement)
, m_taskp(NULL), m_packagep(NULL) {
setOp1p(namep); addNOp2p(pinsp);
setOp1p(namep); addNOp3p(pinsp);
}
AstNodeFTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
: AstNodeStmt(fl)
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp)
: AstNodeStmt(t, fl, statement)
, m_taskp(NULL), m_name(name), m_packagep(NULL) {
addNOp2p(pinsp);
addNOp3p(pinsp);
}
ASTNODE_BASE_FUNCS(NodeFTaskRef)
virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; }
@@ -2197,12 +2392,13 @@ public:
void packagep(AstPackage* nodep) { m_packagep = nodep; }
// op1 = namep
AstNode* namep() const { return op1p(); }
// op2 = Pin interconnection list
AstNode* pinsp() const { return op2p(); }
void addPinsp(AstNode* nodep) { addOp2p(nodep); }
// op3 = scope tracking
AstScopeName* scopeNamep() const { return VN_CAST(op3p(), ScopeName); }
void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
// op2 = reserved for AstMethodCall
// op3 = Pin interconnection list
AstNode* pinsp() const { return op3p(); }
void addPinsp(AstNode* nodep) { addOp3p(nodep); }
// op4 = scope tracking
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
};
class AstNodeModule : public AstNode {
@@ -2224,8 +2420,8 @@ private:
int m_varNum; // Incrementing variable number
int m_typeNum; // Incrementing implicit type number
public:
AstNodeModule(FileLine* fl, const string& name)
: AstNode(fl)
AstNodeModule(AstType t, FileLine* fl, const string& name)
: AstNode(t, fl)
, m_name(name), m_origName(name)
, m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false)
, m_internal(false), m_recursive(false), m_recursiveClone(false)
@@ -2238,7 +2434,7 @@ public:
AstActive* activesp() const { return VN_CAST(op3p(), Active); } // op3 = List of i/sblocks
// METHODS
void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
void addStmtp(AstNode* nodep) { addNOp2p(nodep); }
void addActivep(AstNode* nodep) { addOp3p(nodep); }
// ACCESSORS
virtual void name(const string& name) { m_name = name; }
@@ -2269,18 +2465,14 @@ public:
class AstNodeRange : public AstNode {
// A range, sized or unsized
public:
explicit AstNodeRange(FileLine* fl) : AstNode(fl) { }
AstNodeRange(AstType t, FileLine* fl)
: AstNode(t, fl) {}
ASTNODE_BASE_FUNCS(NodeRange)
};
//######################################################################
#include "V3AstNodes.h"
#include "V3Ast__gen_impl.h" // From ./astgen
// Things like:
// inline AstAlways* AstNode::castAlways() { return dynamic_cast<AstAlways*>(this); }
// inline bool AstNode::privateIsaAlways(const AstNode* nodep) { return nodep && nodep->type() == AstType::atAlways; }
#include "V3AstNodes__gen.h"
//######################################################################
// Inline AstNVisitor METHODS
+105 -18
View File
@@ -26,6 +26,7 @@
#include "V3Global.h"
#include "V3Graph.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3EmitCBase.h"
#include <cstdarg>
#include <iomanip>
@@ -88,6 +89,27 @@ const char* AstNodeUOrStructDType::broken() const {
return NULL;
}
void AstNodeCCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (funcp()) {
str << " " << funcp()->name() << " => ";
funcp()->dump(str);
} else {
str << " " << name();
}
}
void AstNodeCCall::cloneRelink() {
if (m_funcp && m_funcp->clonep()) { m_funcp = m_funcp->clonep(); }
}
const char* AstNodeCCall::broken() const {
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
return NULL;
}
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
string AstNodeCCall::hiernameProtect() const {
return VIdProtect::protectWordsIf(hiername(), protect());
}
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs,
const V3Number& rhs, const V3Number& ths) {
if (lhs.isNeqZero()) out.opAssign(rhs); else out.opAssign(ths);
@@ -168,11 +190,11 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
AstExecGraph::AstExecGraph(FileLine* fileline)
: AstNode(fileline) {
: AstNode(AstType::atExecGraph, fileline) {
m_depGraphp = new V3Graph;
}
AstExecGraph::~AstExecGraph() {
delete m_depGraphp; VL_DANGLING(m_depGraphp);
VL_DO_DANGLING(delete m_depGraphp, m_depGraphp);
}
bool AstVar::isSigPublic() const {
@@ -278,6 +300,17 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
string out = "VlQueue<";
out += sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
out += "> ";
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
VlArgTypeRecursed info;
@@ -630,7 +663,7 @@ std::pair<uint32_t,uint32_t> AstNodeDType::dimensions(bool includeBasic) {
else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
}
else if (const AstStructDType* sdtypep = VN_CAST(dtypep, StructDType)) {
else if (VN_IS(dtypep, StructDType)) {
packed++;
}
break;
@@ -668,10 +701,6 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variabl
return nodep;
}
string AstCCall::hiernameProtect() const {
return VIdProtect::protectWordsIf(hiername(), protect());
}
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
@@ -798,7 +827,7 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd)
// check the detailed map for this same node
// Also adds this new node to the detailed map
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) new1p->deleteTree();
if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p);
else addTypesp(newp);
//
m_basicps[kwd] = newp;
@@ -809,7 +838,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
int width, int widthMin, AstNumeric numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) new1p->deleteTree();
if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p);
else addTypesp(newp);
return newp;
}
@@ -818,7 +847,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
VNumRange range, int widthMin, AstNumeric numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) new1p->deleteTree();
if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p);
else addTypesp(newp);
return newp;
}
@@ -943,6 +972,14 @@ void AstBasicDType::dump(std::ostream& str) const {
str<<" kwd="<<keyword().ascii();
if (isRanged() && !rangep()) str<<" range=["<<left()<<":"<<right()<<"]";
}
string AstBasicDType::prettyDTypeName() const {
std::ostringstream os;
os << keyword().ascii();
if (isRanged() && !rangep() && keyword().width() <= 1) {
os << "[" << left() << ":" << right() << "]";
}
return os.str();
}
void AstCCast::dump(std::ostream& str) const {
this->AstNode::dump(str);
str<<" sz"<<size();
@@ -999,6 +1036,22 @@ void AstJumpGo::dump(std::ostream& str) const {
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> ";
if (varp()) { varp()->dump(str); }
else { str << "%Error:UNLINKED"; }
}
void AstMethodCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isStatement()) str << " [STMT]";
str << " -> ";
if (taskp()) {
taskp()->dump(str);
} else {
str << " -> UNLINKED";
}
}
void AstModportFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isExport()) str<<" EXPORT";
@@ -1073,6 +1126,24 @@ void AstNodeArrayDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
str<<" "<<declRange();
}
string AstPackArrayDType::prettyDTypeName() const {
std::ostringstream os;
os << subDTypep()->prettyDTypeName() << declRange();
return os.str();
}
string AstUnpackArrayDType::prettyDTypeName() const {
std::ostringstream os;
string ranges = cvtToStr(declRange());
// Unfortunately we need a single $ for the first unpacked, and all
// dimensions shown in "reverse" order
AstNodeDType* subp = subDTypep()->skipRefp();
while (AstUnpackArrayDType* adtypep = VN_CAST(subp, UnpackArrayDType)) {
ranges += cvtToStr(adtypep->declRange());
subp = adtypep->subDTypep()->skipRefp();
}
os << subp->prettyDTypeName() << "$" << ranges;
return os.str();
}
void AstNodeModule::dump(std::ostream& str) const {
this->AstNode::dump(str);
str<<" L"<<level();
@@ -1133,10 +1204,25 @@ void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"[assoc-"<<(void*)keyDTypep()<<"]";
}
string AstAssocArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
}
void AstDynArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"[]";
}
string AstDynArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[]";
}
void AstQueueDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"[queue]";
}
string AstQueueDType::prettyDTypeName() const {
string str = subDTypep()->prettyDTypeName() + "[$";
if (boundConst()) str += ":" + cvtToStr(boundConst());
return str + "]";
}
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"[]";
@@ -1242,6 +1328,7 @@ void AstBegin::dump(std::ostream& str) const {
if (unnamed()) str<<" [UNNAMED]";
if (generate()) str<<" [GEN]";
if (genforp()) str<<" [GENFOR]";
if (implied()) str<<" [IMPLIED]";
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str);
@@ -1284,20 +1371,20 @@ void AstCFile::dump(std::ostream& str) const {
if (source()) str<<" [SRC]";
if (slow()) str<<" [SLOW]";
}
void AstCCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (funcp()) {
str<<" "<<funcp()->name()<<" => ";
funcp()->dump(str);
}
}
void AstCFunc::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (slow()) str<<" [SLOW]";
if (pure()) str<<" [PURE]";
if (isStatic().unknown()) str<<" [STATICU]";
else if (isStatic().trueU()) str<<" [STATIC]";
else if (isStatic().trueUnknown()) str<<" [STATIC]";
if (dpiImport()) str<<" [DPII]";
if (dpiExport()) str<<" [DPIX]";
if (dpiExportWrapper()) str<<" [DPIXWR]";
if (isConstructor()) str<<" [CTOR]";
if (isDestructor()) str<<" [DTOR]";
if (isVirtual()) str<<" [VIRT]";
}
void AstCUse::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << useType() << "]";
}
+890 -641
View File
File diff suppressed because it is too large Load Diff
+22 -22
View File
@@ -72,20 +72,21 @@ private:
AstNodeFTask* m_ftaskp; // Current function/task
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_repeatNum; // Repeat counter
int m_ifDepth; // Current if depth
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_repeatNum = 0;
iterateChildren(nodep);
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstNodeFTask* nodep) {
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
UINFO(8," "<<nodep<<endl);
// Rename it
if (m_unnamedScope != "") {
@@ -110,7 +111,7 @@ private:
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
}
virtual void visit(AstBegin* nodep) {
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8," "<<nodep<<endl);
string oldScope = m_namedScope;
@@ -124,7 +125,7 @@ private:
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (!nodep->unnamed()) {
if (nodep->name() != "") {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
}
@@ -157,9 +158,9 @@ private:
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstVar* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
@@ -170,7 +171,7 @@ private:
else m_modp->addStmtp(nodep);
}
}
virtual void visit(AstCell* nodep) {
virtual void visit(AstCell* nodep) VL_OVERRIDE {
UINFO(8," CELL "<<nodep<<endl);
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
@@ -183,14 +184,14 @@ private:
}
iterateChildren(nodep);
}
virtual void visit(AstVarXRef* nodep) {
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
UINFO(9, " VARXREF "<<nodep<<endl);
if (m_namedScope != "" && nodep->inlinedDots() == "") {
nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to "<<nodep<<endl);
}
}
virtual void visit(AstScopeName* nodep) {
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's
@@ -203,13 +204,13 @@ private:
}
iterateChildren(nodep);
}
virtual void visit(AstCoverDecl* nodep) {
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
// Don't need to fix path in coverage statements, they're not under
// any BEGINs, but V3Coverage adds them all under the module itself.
iterateChildren(nodep);
}
// VISITORS - LINT CHECK
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered
// Check IFDEPTH warning - could be in other transform files if desire
int prevIfDepth = m_ifDepth;
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
@@ -223,7 +224,7 @@ private:
iterateChildren(nodep);
m_ifDepth = prevIfDepth;
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -232,7 +233,6 @@ public:
m_statep = statep;
m_modp = NULL;
m_ftaskp = NULL;
m_repeatNum = 0;
m_ifDepth = 0;
iterate(nodep);
}
@@ -249,21 +249,21 @@ private:
// AstNodeFTask::user1p // Node replaced, rename it
// VISITORS
virtual void visit(AstNodeFTaskRef* nodep) {
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
if (nodep->taskp()->user1()) { // It was converted
UINFO(9, " relinkFTask "<<nodep<<endl);
nodep->name(nodep->taskp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef "<<nodep<<endl);
nodep->name(nodep->varp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstIfaceRefDType* nodep) {
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
// May have changed cell names
// TypeTable is always after all modules, so names are stable
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
@@ -272,7 +272,7 @@ private:
iterateChildren(nodep);
}
//--------------------
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
+4 -4
View File
@@ -70,7 +70,7 @@ private:
}
// VISITORS
virtual void visit(AstNodeIf* nodep) {
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
UINFO(4," IF: "<<nodep<<endl);
int lastLikely = m_likely;
int lastUnlikely = m_unlikely;
@@ -96,17 +96,17 @@ private:
m_likely = lastLikely;
m_unlikely = lastUnlikely;
}
virtual void visit(AstCCall* nodep) {
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
checkUnlikely(nodep);
iterateChildren(nodep);
}
+3 -3
View File
@@ -209,7 +209,7 @@ private:
iterateChildrenConst(nodep);
}
// VISITORS
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
processAndIterate(nodep);
}
public:
@@ -257,7 +257,7 @@ private:
iterateChildrenConst(nodep);
BrokenTable::setUnder(nodep, false);
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
@@ -265,7 +265,7 @@ private:
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
processAndIterate(nodep);
}
public:
+125
View File
@@ -0,0 +1,125 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Handle SV classes
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// V3Class's Transformations:
//
// Each module:
// Each cell:
// Create CUse for cell forward declaration
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3Global.h"
#include "V3CUse.h"
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include VL_INCLUDE_UNORDERED_MAP
//######################################################################
class CUseState {
private:
// MEMBERS
AstNodeModule* m_modInsertp; // Current module to insert AstCUse under
typedef std::pair<VUseType, string> UseString;
std::map<UseString, AstCUse*> m_didUse; // What we already used
// NODE STATE
// Entire netlist:
// AstClass::user1() -> bool. True if class needs to_string dumper
AstUser1InUse m_inuser1;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
public:
AstCUse* newUse(AstNode* nodep, VUseType useType, const string& name) {
UseString key(useType, name);
if (m_didUse.find(key) == m_didUse.end()) {
AstCUse* newp = new AstCUse(nodep->fileline(), useType, name);
m_modInsertp->addStmtp(newp);
UINFO(8, "Insert " << newp << endl);
m_didUse[key] = newp;
}
return m_didUse[key];
}
// CONSTRUCTORS
explicit CUseState(AstNodeModule* nodep)
: m_modInsertp(nodep) {}
virtual ~CUseState() {}
VL_UNCOPYABLE(CUseState);
};
class CUseVisitor : public AstNVisitor {
// MEMBERS
CUseState m_state; // Inserter state
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// Module use builders
void makeUseCells(AstNodeModule* nodep) {
for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) {
if (AstCell* cellp = VN_CAST(itemp, Cell)) {
// Currently no include because we include __Syms which has them all
m_state.newUse(nodep, VUseType::INT_FWD_CLASS, cellp->modp()->name());
}
}
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
if (v3Global.opt.trace()) {
AstCUse* usep
= m_state.newUse(nodep, VUseType::INT_FWD_CLASS, v3Global.opt.traceClassBase());
usep->protect(false);
}
makeUseCells(nodep);
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {} // All in AstNodeModule
public:
// CONSTRUCTORS
explicit CUseVisitor(AstNodeModule* nodep)
: m_state(nodep) {
iterate(nodep);
}
virtual ~CUseVisitor() {}
VL_UNCOPYABLE(CUseVisitor);
};
//######################################################################
// Class class functions
void V3CUse::cUseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
// Call visitor separately for each module, so visitor state is cleared
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
// Insert under this module; someday we should e.g. make Ast
// for each output file and put under that
CUseVisitor visitor(modp);
}
V3Global::dumpCheckGlobalTree("cuse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+37
View File
@@ -0,0 +1,37 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Pre C-Emit stage changes
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CUSE_H_
#define _V3CUSE_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
//============================================================================
class V3CUse {
public:
static void cUseAll(AstNetlist* nodep);
};
#endif // Guard
+15 -15
View File
@@ -62,7 +62,7 @@ private:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstNodeCase* nodep) {
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
@@ -89,7 +89,7 @@ private:
m_caseExprp = NULL;
}
}
virtual void visit(AstConst* nodep) {
virtual void visit(AstConst* nodep) VL_OVERRIDE {
// See also neverItem
if (m_caseExprp && nodep->num().isFourState()) {
if (VN_IS(m_caseExprp, GenCase)) {
@@ -106,7 +106,7 @@ private:
}
}
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -250,7 +250,7 @@ private:
if (m_valueItem[a] != m_valueItem[b]) { same = false; break; }
}
if (same) {
tree1p->deleteTree(); VL_DANGLING(tree1p);
VL_DO_DANGLING(tree1p->deleteTree(), tree1p);
return tree0p;
}
@@ -299,8 +299,8 @@ private:
if (ifrootp) nodep->replaceWith(ifrootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
cexprp->deleteTree(); VL_DANGLING(cexprp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
if (debug()>=9) ifrootp->dumpTree(cout, " _simp: ");
}
@@ -331,7 +331,7 @@ private:
AstConst* iconstp = VN_CAST(icondp, Const);
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
@@ -357,7 +357,7 @@ private:
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
@@ -375,7 +375,7 @@ private:
itemp->condsp(ifexprp);
}
}
cexprp->deleteTree(); VL_DANGLING(cexprp);
VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
if (!hadDefault) {
// If there was no default, add a empty one, this greatly simplifies below code
// and constant propagation will just eliminate it for us later.
@@ -418,7 +418,7 @@ private:
{ // Make the new lower IF and attach in the tree
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
itemexprp->deleteTree(); VL_DANGLING(itemexprp);
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
@@ -434,7 +434,7 @@ private:
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
if (grouprootp) nodep->replaceWith(grouprootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceCaseParallel(AstCase* nodep, bool noOverlapsAllCovered) {
@@ -460,7 +460,7 @@ private:
}
// VISITORS
virtual void visit(AstCase* nodep) {
virtual void visit(AstCase* nodep) VL_OVERRIDE {
V3Case::caseLint(nodep);
iterateChildren(nodep);
if (debug()>=9) nodep->dumpTree(cout, " case_old: ");
@@ -468,15 +468,15 @@ private:
// It's a simple priority encoder or complete statement
// we can make a tree of statements to avoid extra comparisons
++m_statCaseFast;
replaceCaseFast(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceCaseFast(nodep), nodep);
} else {
++m_statCaseSlow;
replaceCaseComplicated(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceCaseComplicated(nodep), nodep);
}
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+20 -20
View File
@@ -75,7 +75,7 @@ private:
relinkHandle.relink(castp);
//if (debug()>8) castp->dumpTree(cout, "-castins: ");
//
insureLower32Cast(castp);
ensureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
}
int castSize(AstNode* nodep) {
@@ -84,13 +84,13 @@ private:
else if (nodep->width() <= 16) return 16;
else return VL_IDATASIZE;
}
void insureCast(AstNode* nodep) {
void ensureCast(AstNode* nodep) {
if (castSize(nodep->backp()) != castSize(nodep)
|| !nodep->user1()) {
insertCast(nodep, castSize(nodep->backp()));
}
}
void insureLower32Cast(AstCCast* nodep) {
void ensureLower32Cast(AstCCast* nodep) {
// If we have uint64 = CAST(uint64(x)) then the upcasting
// really needs to be CAST(uint64(CAST(uint32(x))).
// Otherwise a (uint64)(a>b) would return wrong value, as
@@ -102,33 +102,33 @@ private:
}
// VISITORS
virtual void visit(AstNodeUniop* nodep) {
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
}
virtual void visit(AstNodeBiop* nodep) {
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) {
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1()
| nodep->thsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) insureCast(nodep->thsp());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
}
virtual void visit(AstCCast* nodep) {
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureLower32Cast(nodep);
ensureLower32Cast(nodep);
nodep->user1(1);
}
virtual void visit(AstNegate* nodep) {
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin()==1) {
@@ -137,10 +137,10 @@ private:
// out = {32{a<b}} => out = - (a<b)
insertCast(nodep->lhsp(), castSize(nodep));
} else {
insureCast(nodep->lhsp());
ensureCast(nodep->lhsp());
}
}
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (!nodep->lvalue()
&& !VN_IS(nodep->backp(), CCast)
&& VN_IS(nodep->backp(), NodeMath)
@@ -153,7 +153,7 @@ private:
}
nodep->user1(1);
}
virtual void visit(AstConst* nodep) {
virtual void visit(AstConst* nodep) VL_OVERRIDE {
// Constants are of unknown size if smaller than 33 bits, because
// we're too lazy to wrap every constant in the universe in
// ((IData)#).
@@ -161,11 +161,11 @@ private:
}
// NOPs
virtual void visit(AstVar* nodep) {}
virtual void visit(AstVar* nodep) VL_OVERRIDE {}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+33 -30
View File
@@ -136,7 +136,7 @@ private:
std::ofstream* m_ofp; // Output file
string m_prefix;
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
*m_ofp<<m_prefix;
if (nodep->user3()) *m_ofp<<" %%";
else *m_ofp<<" ";
@@ -170,7 +170,7 @@ private:
int m_maxLineno;
size_t m_maxFilenameLen;
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Keeping line+filename lengths separate is much faster than calling ascii().length()
if (nodep->fileline()->lineno() >= m_maxLineno) {
@@ -608,19 +608,22 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
iterateChildren(nodep);
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," SCOPE "<<nodep<<endl);
m_scopep = nodep;
m_logicVertexp = NULL;
iterateChildren(nodep);
m_scopep = NULL;
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Create required blocks and add to module
UINFO(4," BLOCK "<<nodep<<endl);
AstNode::user2ClearTree();
@@ -631,7 +634,7 @@ private:
m_domainp = NULL;
AstNode::user2ClearTree();
}
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
@@ -659,72 +662,72 @@ private:
}
}
}
virtual void visit(AstAssignDly* nodep) {
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
m_inDly = true;
iterateChildren(nodep);
m_inDly = false;
}
virtual void visit(AstSenItem* nodep) {
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
// Note we look at only AstSenItems, not AstSenGate's
// The gating term of a AstSenGate is normal logic
m_inSenItem = true;
iterateChildren(nodep);
m_inSenItem = false;
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstAlwaysPublic* nodep) {
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
// CDC doesn't care about public variables
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstSenGate* nodep) {
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep) {
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
// Math that shouldn't cause us to clear hazard
virtual void visit(AstConst* nodep) { }
virtual void visit(AstReplicate* nodep) {
virtual void visit(AstConst* nodep) VL_OVERRIDE { }
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstConcat* nodep) {
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstNot* nodep) {
virtual void visit(AstNot* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstSel* nodep) {
virtual void visit(AstSel* nodep) VL_OVERRIDE {
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNodeSel* nodep) {
virtual void visit(AstNodeSel* nodep) VL_OVERRIDE {
if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
}
// Ignores
virtual void visit(AstInitial* nodep) { }
virtual void visit(AstTraceInc* nodep) { }
virtual void visit(AstCoverToggle* nodep) { }
virtual void visit(AstNodeDType* nodep) { }
virtual void visit(AstInitial* nodep) VL_OVERRIDE { }
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE { }
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { }
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { }
//--------------------
// Default
virtual void visit(AstNodeMath* nodep) {
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
setNodeHazard(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
@@ -761,7 +764,7 @@ public:
}
}
virtual ~CdcVisitor() {
if (m_ofp) { delete m_ofp; m_ofp = NULL; }
if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
}
};
+11 -11
View File
@@ -97,7 +97,7 @@ public:
new AstLogOr(m_scopetopp->fileline(), callp,
returnp->lhsp()->unlinkFrBack()));
returnp->replaceWith(newp);
returnp->deleteTree(); VL_DANGLING(returnp);
VL_DO_DANGLING(returnp->deleteTree(), returnp);
}
m_numStmts = 0;
}
@@ -148,13 +148,13 @@ private:
m_statep->m_numStmts += visitor.count();
}
virtual void visit(AstBasicDType* nodep) {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
newChangeDet();
}
virtual void visit(AstPackArrayDType* nodep) {
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE {
newChangeDet();
}
virtual void visit(AstUnpackArrayDType* nodep) {
virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE {
for (int index=0; index < nodep->elementsConst(); ++index) {
AstNode* origVEp = m_varEqnp;
AstNode* origNLEp = m_newLvEqnp;
@@ -175,7 +175,7 @@ private:
m_newRvEqnp = origNREp;
}
}
virtual void visit(AstNodeUOrStructDType* nodep) {
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
if (nodep->packedUnsup()) {
newChangeDet();
} else {
@@ -185,7 +185,7 @@ private:
<<m_vscp->varp()->prettyNameQ());
}
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
@@ -247,7 +247,7 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
if (nodep->isTop()) {
m_statep->m_topModp = nodep;
@@ -255,7 +255,7 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) {
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
UINFO(4," TS "<<nodep<<endl);
// Clearing
AstNode::user1ClearTree();
@@ -279,7 +279,7 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstVarScope* nodep) {
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
if (nodep->isCircular()) {
UINFO(8," CIRC "<<nodep<<endl);
if (!nodep->user1SetOnce()) {
@@ -287,12 +287,12 @@ private:
}
}
}
virtual void visit(AstNodeMath* nodep) {
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
// Short-circuit
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+51 -47
View File
@@ -88,6 +88,7 @@ private:
if (!nodep->user2() && nodep->hasDType()) {
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|| VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|| VN_IS(nodep->dtypep()->skipRefp(), QueueDType)
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
@@ -135,15 +136,15 @@ private:
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
relinkHandle.relink(cleanp);
}
void insureClean(AstNode* nodep) {
void ensureClean(AstNode* nodep) {
computeCppWidth(nodep);
if (!isClean(nodep)) insertClean(nodep);
}
void insureCleanAndNext(AstNode* nodep) {
void ensureCleanAndNext(AstNode* nodep) {
// Editing list, careful looping!
for (AstNode* exprp = nodep; exprp; ) {
AstNode* nextp = exprp->nextp();
insureClean(exprp);
ensureClean(exprp);
exprp = nextp;
}
}
@@ -153,10 +154,10 @@ private:
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) {
insureClean(nodep->lhsp());
ensureClean(nodep->lhsp());
}
if (nodep->cleanRhs()) {
insureClean(nodep->rhsp());
ensureClean(nodep->rhsp());
}
//no setClean.. must do it in each user routine.
}
@@ -164,70 +165,73 @@ private:
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) {
insureClean(nodep->lhsp());
ensureClean(nodep->lhsp());
}
if (nodep->cleanRhs()) {
insureClean(nodep->rhsp());
ensureClean(nodep->rhsp());
}
if (nodep->cleanThs()) {
insureClean(nodep->thsp());
ensureClean(nodep->thsp());
}
//no setClean.. must do it in each user routine.
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
iterateChildren(nodep);
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstNodeUniop* nodep) {
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) {
insureClean(nodep->lhsp());
ensureClean(nodep->lhsp());
}
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeBiop* nodep) {
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
operandBiop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstAnd* nodep) {
virtual void visit(AstAnd* nodep) VL_OVERRIDE {
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
}
virtual void visit(AstXor* nodep) {
virtual void visit(AstXor* nodep) VL_OVERRIDE {
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
}
virtual void visit(AstOr* nodep) {
virtual void visit(AstOr* nodep) VL_OVERRIDE {
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
}
virtual void visit(AstNodeMath* nodep) {
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanRhs()) {
insureClean(nodep->rhsp());
ensureClean(nodep->rhsp());
}
}
virtual void visit(AstText* nodep) {
virtual void visit(AstText* nodep) VL_OVERRIDE {
setClean(nodep, true);
}
virtual void visit(AstScopeName* nodep) {
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
setClean(nodep, true);
}
virtual void visit(AstSel* nodep) {
virtual void visit(AstSel* nodep) VL_OVERRIDE {
operandTriop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstUCFunc* nodep) {
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
setClean(nodep, false);
@@ -235,66 +239,66 @@ private:
if (!VN_IS(nodep->backp(), And)) {
insertClean(nodep);
}
insureCleanAndNext(nodep->bodysp());
ensureCleanAndNext(nodep->bodysp());
}
virtual void visit(AstTraceDecl* nodep) {
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
virtual void visit(AstTraceInc* nodep) {
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureCleanAndNext(nodep->valuep());
ensureCleanAndNext(nodep->valuep());
}
virtual void visit(AstTypedef* nodep) {
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
virtual void visit(AstParamTypeDType* nodep) {
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
// Control flow operators
virtual void visit(AstNodeCond* nodep) {
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureClean(nodep->condp());
ensureClean(nodep->condp());
setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p()));
}
virtual void visit(AstWhile* nodep) {
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureClean(nodep->condp());
ensureClean(nodep->condp());
}
virtual void visit(AstNodeIf* nodep) {
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureClean(nodep->condp());
ensureClean(nodep->condp());
}
virtual void visit(AstSFormatF* nodep) {
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureCleanAndNext(nodep->exprsp());
ensureCleanAndNext(nodep->exprsp());
setClean(nodep, true); // generates a string, so not relevant
}
virtual void visit(AstUCStmt* nodep) {
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureCleanAndNext(nodep->bodysp());
ensureCleanAndNext(nodep->bodysp());
}
virtual void visit(AstCCall* nodep) {
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureCleanAndNext(nodep->argsp());
ensureCleanAndNext(nodep->argsp());
setClean(nodep, true);
}
virtual void visit(AstCMethodCall* nodep) {
virtual void visit(AstCMethodHard* nodep) VL_OVERRIDE {
iterateChildren(nodep);
insureCleanAndNext(nodep->pinsp());
ensureCleanAndNext(nodep->pinsp());
setClean(nodep, true);
}
virtual void visit(AstIntfRef* nodep) {
virtual void visit(AstIntfRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
setClean(nodep, true); // generates a string, so not relevant
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
}
+25 -22
View File
@@ -189,7 +189,7 @@ private:
}
// VISITORS
virtual void visit(AstTopScope* nodep) {
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
UINFO(4," TOPSCOPE "<<nodep<<endl);
m_topScopep = nodep;
m_scopep = nodep->scopep();
@@ -254,13 +254,16 @@ private:
m_topScopep = NULL;
m_scopep = NULL;
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
//UINFO(4," MOD "<<nodep<<endl);
m_modp = nodep;
iterateChildren(nodep);
m_modp= NULL;
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
//UINFO(4," SCOPE "<<nodep<<endl);
m_scopep = nodep;
iterateChildren(nodep);
@@ -271,25 +274,25 @@ private:
}
m_scopep = NULL;
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstAlwaysPost* nodep) {
virtual void visit(AstAlwaysPost* nodep) VL_OVERRIDE {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCoverToggle* nodep) {
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
//nodep->dumpTree(cout, "ct:");
//COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
@@ -307,18 +310,18 @@ private:
newp->addIfsp(new AstAssign(nodep->fileline(),
changep->cloneTree(false),
origp->cloneTree(false)));
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstInitial* nodep) {
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Link to global function
if (nodep->formCallTree()) {
@@ -328,7 +331,7 @@ private:
m_finalFuncp->addStmtsp(callp);
}
}
virtual void visit(AstSenTree* nodep) {
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
// Delete it later; Actives still pointing to it
nodep->unlinkFrBack();
pushDeletep(nodep);
@@ -342,14 +345,14 @@ private:
void addToInitial(AstNode* stmtsp) {
m_initFuncp->addStmtsp(stmtsp); // add to top level function
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Careful if adding variables here, ACTIVES can be under other ACTIVES
// Need to save and restore any member state in AstUntilStable block
if (!m_topScopep || !nodep->stmtsp()) {
// Not at the top or empty block...
// Only empty blocks should be leftover on the non-top. Killem.
UASSERT_OBJ(!nodep->stmtsp(), nodep, "Non-empty lower active");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (m_mtaskBodyp) {
UINFO(4," TR ACTIVE "<<nodep<<endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
@@ -374,7 +377,7 @@ private:
clearLastSen();
m_mtaskBodyp->addStmtsp(stmtsp);
}
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else {
UINFO(4," ACTIVE "<<nodep<<endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
@@ -407,10 +410,10 @@ private:
// Move statements to function
addToEvalLoop(stmtsp);
}
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
}
virtual void visit(AstExecGraph* nodep) {
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody);
m_mtaskBodyp;
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
@@ -427,7 +430,7 @@ private:
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+20 -20
View File
@@ -66,7 +66,7 @@ protected:
static bool emptyFunctionDeletion() { return true; }
static bool duplicateFunctionCombine() { return true; }
// Note this is disabled, it still needed work
// Also repair it for DPI functions; when make __common need to insure proper
// Also repair it for DPI functions; when make __common need to ensure proper
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
// get split between functions causing the text to have a dangling reference.
bool statementCombine() { return false; } // duplicateFunctionCombine();
@@ -107,7 +107,7 @@ public:
callp->unlinkFrBack();
}
callp->user3(true); // Dead now
pushDeletep(callp); VL_DANGLING(callp);
VL_DO_DANGLING(pushDeletep(callp), callp);
m_callMmap.erase(eqit); // Fix the table
}
}
@@ -131,13 +131,13 @@ public:
}
private:
// VISITORS
virtual void visit(AstCCall* nodep) {
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
addCall(nodep);
}
// Speed things up
virtual void visit(AstNodeAssign* nodep) {}
virtual void visit(AstNodeMath* nodep) {}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -160,7 +160,7 @@ private:
// OUTPUT:
// AstNode::user3() -> bool. True to indicate duplicated
// VISITORS
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
nodep->user3(true);
iterateChildren(nodep);
}
@@ -228,7 +228,7 @@ private:
CombMarkVisitor visitor(oldfuncp);
m_call.replaceFunc(oldfuncp, NULL);
oldfuncp->unlinkFrBack();
pushDeletep(oldfuncp); VL_DANGLING(oldfuncp);
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
}
}
}
@@ -260,7 +260,7 @@ private:
CombMarkVisitor visitor(oldfuncp);
m_call.replaceFunc(oldfuncp, newfuncp);
oldfuncp->unlinkFrBack();
pushDeletep(oldfuncp); VL_DANGLING(oldfuncp);
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
}
void replaceOnlyCallFunc(AstCCall* nodep) {
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
@@ -272,7 +272,7 @@ private:
UINFO(9," Function only has call "<<oldfuncp<<endl);
m_call.deleteCall(nodep);
CombMarkVisitor visitor(oldfuncp);
replaceFuncWFunc(oldfuncp, nodep->funcp()); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep);
}
}
}
@@ -384,12 +384,12 @@ private:
m_call.addCall(call2p);
// If either new statement makes a func with only a single call, replace
// the above callers to call it directly
replaceOnlyCallFunc(call1p); VL_DANGLING(call1p);
replaceOnlyCallFunc(call2p); VL_DANGLING(call2p);
VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p);
VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p);
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
// Track all callers of each function
m_call.main(nodep);
//
@@ -398,7 +398,7 @@ private:
// Required so that a module instantiating another can benefit from collapsing.
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
m_modp = nodep;
m_modNFuncs = 0;
@@ -427,7 +427,7 @@ private:
}
m_modp = NULL;
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
m_funcp = nodep;
if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) {
@@ -438,7 +438,7 @@ private:
}
m_funcp = NULL;
}
virtual void visit(AstNodeStmt* nodep) {
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
@@ -453,10 +453,10 @@ private:
//--------------------
// Default: Just iterate
virtual void visit(AstVar*) {}
virtual void visit(AstTraceDecl*) {}
virtual void visit(AstTraceInc*) {}
virtual void visit(AstNode* nodep) {
virtual void visit(AstVar*) VL_OVERRIDE {}
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+449 -93
View File
@@ -30,133 +30,489 @@
#include <string>
//######################################################################
// Resolve wildcards in files, modules, ftasks or variables
class V3ConfigLine {
// Template for a class that serves as a map for entities that can be specified
// as wildcards and are accessed by a resolved name. It rebuilds a name lookup
// cache of resolved entities. Entities stored in this container need an update
// function that takes a reference of this type to join multiple entities into one.
template <typename T> class V3ConfigWildcardResolver {
typedef std::map<string, T> Map;
Map m_mapWildcard; // Wildcard strings to entities
Map m_mapResolved; // Resolved strings to converged entities
public:
int m_lineno; // Line number to make change at
V3ErrorCode m_code; // Error code
bool m_on; // True to enable message
V3ConfigLine(V3ErrorCode code, int lineno, bool on)
: m_lineno(lineno), m_code(code), m_on(on) {}
~V3ConfigLine() {}
inline bool operator< (const V3ConfigLine& rh) const {
if (m_lineno<rh.m_lineno) return true;
if (m_lineno>rh.m_lineno) return false;
if (m_code<rh.m_code) return true;
if (m_code>rh.m_code) return false;
V3ConfigWildcardResolver() {}
~V3ConfigWildcardResolver() {}
/// Update into maps from other
void update(const V3ConfigWildcardResolver& other) {
typename Map::const_iterator it;
for (it = other.m_mapResolved.begin(); it != other.m_mapResolved.end(); ++it) {
m_mapResolved[it->first].update(it->second);
}
for (it = other.m_mapWildcard.begin(); it != other.m_mapWildcard.end(); ++it) {
m_mapWildcard[it->first].update(it->second);
}
}
// Access and create a (wildcard) entity
T& at(const string& name) {
// 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) {
// Lookup if it was resolved before, typically not
typename Map::iterator it = m_mapResolved.find(name);
if (VL_UNLIKELY(it != m_mapResolved.end())) { return &it->second; }
T* newp = NULL;
// Cannot be resolved, create if matched
// Update this entity with all matches in the wildcards
for (it = m_mapWildcard.begin(); it != m_mapWildcard.end(); ++it) {
if (VString::wildmatch(name, it->first)) {
if (!newp) {
newp = &m_mapResolved[name]; // Emplace and get pointer
}
newp->update(it->second);
}
}
return newp;
}
// Flush on update
void flush() { m_mapResolved.clear(); }
};
// Only public_flat_rw has the sensitity tree
class V3ConfigVarAttr {
public:
AstAttrType m_type; // Type of attribute
AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw
V3ConfigVarAttr(AstAttrType type, AstSenTree* sentreep)
: m_type(type)
, m_sentreep(sentreep) {}
};
// Overload vector with the required update function and to apply all entries
class V3ConfigVar : public std::vector<V3ConfigVarAttr> {
public:
// Update from other by copying all attributes
void update(const V3ConfigVar& node) {
reserve(size() + node.size());
insert(end(), node.begin(), node.end());
}
// Apply all attributes to the variable
void apply(AstVar* varp) {
for (const_iterator it = begin(); it != end(); ++it) {
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
varp->addAttrsp(newp);
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, NULL));
}
}
}
};
typedef V3ConfigWildcardResolver<V3ConfigVar> V3ConfigVarResolver;
//######################################################################
// Function or task: Have variables and properties
class V3ConfigFTask {
V3ConfigVarResolver m_vars; // Variables in function/task
bool m_isolate; // Isolate function return
bool m_noinline; // Don't inline function/task
bool m_public; // Public function/task
public:
V3ConfigFTask()
: m_isolate(false)
, m_noinline(false)
, m_public(false) {}
void update(const V3ConfigFTask& f) {
// Don't overwrite true with false
if (f.m_isolate) m_isolate = true;
if (f.m_noinline) m_noinline = true;
if (f.m_public) m_public = true;
m_vars.update(f.m_vars);
}
V3ConfigVarResolver& vars() { return m_vars; }
void setIsolate(bool set) { m_isolate = set; }
void setNoInline(bool set) { m_noinline = set; }
void setPublic(bool set) { m_public = set; }
void apply(AstNodeFTask* ftaskp) {
if (m_noinline)
ftaskp->addStmtsp(new AstPragma(ftaskp->fileline(), AstPragmaType::NO_INLINE_TASK));
if (m_public)
ftaskp->addStmtsp(new AstPragma(ftaskp->fileline(), AstPragmaType::PUBLIC_TASK));
// Only functions can have isolate (return value)
if (VN_IS(ftaskp, Func)) ftaskp->attrIsolateAssign(m_isolate);
}
};
typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
//######################################################################
// Modules have tasks, variables, named blocks and properties
class V3ConfigModule {
typedef vl_unordered_set<string> StringSet;
V3ConfigFTaskResolver m_tasks; // Functions/tasks in module
V3ConfigVarResolver m_vars; // Variables in module
StringSet m_coverageOffBlocks; // List of block names for coverage_off
bool m_inline; // Whether to force the inline
bool m_inlineValue; // The inline value (on/off)
bool m_public; // Public module
public:
V3ConfigModule()
: m_inline(false)
, m_inlineValue(false)
, m_public(false) {}
void update(const V3ConfigModule& m) {
m_tasks.update(m.m_tasks);
m_vars.update(m.m_vars);
for (StringSet::const_iterator it = m.m_coverageOffBlocks.begin();
it != m.m_coverageOffBlocks.end(); ++it) {
m_coverageOffBlocks.insert(*it);
}
if (!m_inline) {
m_inline = m.m_inline;
m_inlineValue = m.m_inlineValue;
}
if (!m_public) m_public = m.m_public;
}
V3ConfigFTaskResolver& ftasks() { return m_tasks; }
V3ConfigVarResolver& vars() { return m_vars; }
void addCoverageBlockOff(const string& name) { m_coverageOffBlocks.insert(name); }
void setInline(bool set) {
m_inline = true;
m_inlineValue = set;
}
void setPublic(bool set) { m_public = set; }
void apply(AstNodeModule* modp) {
if (m_inline) {
AstPragmaType type
= m_inlineValue ? AstPragmaType::INLINE_MODULE : AstPragmaType::NO_INLINE_MODULE;
AstNode* nodep = new AstPragma(modp->fileline(), type);
modp->addStmtp(nodep);
}
if (m_public) {
AstNode* nodep = new AstPragma(modp->fileline(), AstPragmaType::PUBLIC_MODULE);
modp->addStmtp(nodep);
}
}
void applyBlock(AstBegin* nodep) {
AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF;
if (!nodep->unnamed()) {
for (StringSet::const_iterator it = m_coverageOffBlocks.begin();
it != m_coverageOffBlocks.end(); ++it) {
if (VString::wildmatch(nodep->name(), *it)) {
nodep->addStmtsp(new AstPragma(nodep->fileline(), pragma));
}
}
}
}
};
typedef V3ConfigWildcardResolver<V3ConfigModule> V3ConfigModuleResolver;
//######################################################################
// Files have:
// - Line ignores (lint/coverage/tracing on/off)
// - Line attributes: Attributes attached to lines
// lint/coverage/tracing on/off
class V3ConfigIgnoresLine {
public:
int m_lineno; // Line number to make change at
V3ErrorCode m_code; // Error code
bool m_on; // True to enable message
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
: m_lineno(lineno)
, m_code(code)
, m_on(on) {}
~V3ConfigIgnoresLine() {}
inline bool operator<(const V3ConfigIgnoresLine& rh) const {
if (m_lineno < rh.m_lineno) return true;
if (m_lineno > rh.m_lineno) return false;
if (m_code < rh.m_code) return true;
if (m_code > rh.m_code) return false;
// Always turn "on" before "off" so that overlapping lines will end
// up finally with the error "off"
return (m_on>rh.m_on);
return (m_on > rh.m_on);
}
};
std::ostream& operator<<(std::ostream& os, V3ConfigLine rhs) {
return os<<rhs.m_lineno<<", "<<rhs.m_code<<", "<<rhs.m_on; }
std::ostream& operator<<(std::ostream& os, V3ConfigIgnoresLine rhs) {
return os << rhs.m_lineno << ", " << rhs.m_code << ", " << rhs.m_on;
}
class V3ConfigIgnores {
typedef std::multiset<V3ConfigLine> IgnLines; // list of {line,code,on}
typedef std::map<string,IgnLines> IgnFiles; // {filename} => list of {line,code,on}
// Some attributes are attached to entities of the occur on a fileline
// and multiple attributes can be attached to a line
typedef std::bitset<AstPragmaType::ENUM_SIZE> V3ConfigLineAttribute;
// MEMBERS
string m_lastFilename; // Last filename looked up
int m_lastLineno; // Last linenumber looked up
// File entity
class V3ConfigFile {
typedef std::map<int, V3ConfigLineAttribute> LineAttrMap; // Map line->bitset of attributes
typedef std::multiset<V3ConfigIgnoresLine> IgnLines; // list of {line,code,on}
typedef std::pair<V3ErrorCode, string> WaiverSetting; // Waive code if string matches
typedef std::vector<WaiverSetting> Waivers; // List of {code,wildcard string}
IgnLines::const_iterator m_lastIt; // Point with next linenumber > current line number
IgnLines::const_iterator m_lastEnd; // Point with end()
LineAttrMap m_lineAttrs; // Atributes to line mapping
IgnLines m_ignLines; // Ignore line settings
Waivers m_waivers; // Waive messages
IgnFiles m_ignWilds; // Ignores for each wildcarded filename
IgnFiles m_ignFiles; // Ignores for each non-wildcarded filename
struct {
int lineno; // Last line number
IgnLines::const_iterator it; // Point with next linenumber > current line number
} m_lastIgnore; // Last ignore line run
static V3ConfigIgnores s_singleton; // Singleton (not via local static, as that's slow)
V3ConfigIgnores() { m_lastLineno = -1; }
~V3ConfigIgnores() {}
// METHODS
inline IgnLines* findWilds(const string& wildname) {
IgnFiles::iterator it = m_ignWilds.find(wildname);
if (it != m_ignWilds.end()) {
return &(it->second);
} else {
m_ignWilds.insert(make_pair(wildname, IgnLines()));
it = m_ignWilds.find(wildname);
return &(it->second);
}
}
inline void absBuild(const string& filename) {
// Given a filename, find all wildcard matches against it and build
// hash with the specific filename. This avoids having to wildmatch
// more than once against any filename.
IgnFiles::iterator it = m_ignFiles.find(filename);
if (it == m_ignFiles.end()) {
// Haven't seen this filename before
m_ignFiles.insert(make_pair(filename, IgnLines()));
it = m_ignFiles.find(filename);
// Make new list for this file of all matches
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
if (VString::wildmatch(filename.c_str(), fnit->first.c_str())) {
for (IgnLines::iterator lit = fnit->second.begin();
lit != fnit->second.end(); ++lit) {
it->second.insert(*lit);
}
}
}
}
m_lastIt = it->second.begin();
m_lastEnd = it->second.end();
// Match a given line and attribute to the map, line 0 is any
bool lineMatch(int lineno, AstPragmaType type) {
if (m_lineAttrs.find(0) != m_lineAttrs.end() && m_lineAttrs[0][type]) return true;
if (m_lineAttrs.find(lineno) == m_lineAttrs.end()) return false;
return m_lineAttrs[lineno][type];
}
public:
inline static V3ConfigIgnores& singleton() { return s_singleton; }
V3ConfigFile() {
m_lastIgnore.lineno = -1;
m_lastIgnore.it = m_ignLines.begin();
}
void update(const V3ConfigFile& file) {
// Copy in all Attributes
for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin();
it != file.m_lineAttrs.end(); ++it) {
m_lineAttrs[it->first] |= it->second;
}
// Copy in all ignores
for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end();
++it) {
m_ignLines.insert(*it);
}
// Update the iterator after the list has changed
m_lastIgnore.it = m_ignLines.begin();
m_waivers.reserve(m_waivers.size() + file.m_waivers.size());
m_waivers.insert(m_waivers.end(), file.m_waivers.begin(), file.m_waivers.end());
}
void addLineAttribute(int lineno, AstPragmaType attr) { m_lineAttrs[lineno].set(attr); }
void addIgnore(V3ErrorCode code, int lineno, bool on) {
m_ignLines.insert(V3ConfigIgnoresLine(code, lineno, on));
m_lastIgnore.it = m_ignLines.begin();
}
void addWaiver(V3ErrorCode code, const string& match) {
m_waivers.push_back(make_pair(code, match));
}
void addIgnore(V3ErrorCode code, const string& wildname, int lineno, bool on) {
// Insert
IgnLines* linesp = findWilds(wildname);
UINFO(9,"config addIgnore "<<wildname<<":"<<lineno<<", "<<code<<", "<<on<<endl);
linesp->insert(V3ConfigLine(code, lineno, on));
// Flush the match cache, due to a change in the rules.
m_ignFiles.clear();
m_lastFilename = " ";
void applyBlock(AstBegin* nodep) {
// Apply to block at this line
AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF;
if (lineMatch(nodep->fileline()->lineno(), pragma)) {
nodep->addStmtsp(new AstPragma(nodep->fileline(), pragma));
}
}
void applyCase(AstCase* nodep) {
// Apply to this case at this line
int lineno = nodep->fileline()->lineno();
if (lineMatch(lineno, AstPragmaType::FULL_CASE)) nodep->fullPragma(true);
if (lineMatch(lineno, AstPragmaType::PARALLEL_CASE)) nodep->parallelPragma(true);
}
inline void applyIgnores(FileLine* filelinep) {
// HOT routine, called each parsed token line
if (m_lastLineno != filelinep->lastLineno()
|| m_lastFilename != filelinep->filename()) {
//UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
if (VL_UNLIKELY(m_lastFilename != filelinep->filename())) {
absBuild(filelinep->filename());
m_lastFilename = filelinep->filename();
}
// HOT routine, called each parsed token line of this filename
if (m_lastIgnore.lineno != filelinep->lineno()) {
// UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
// Process all on/offs for lines up to and including the current line
int curlineno = filelinep->lastLineno();
for (; m_lastIt != m_lastEnd; ++m_lastIt) {
if (m_lastIt->m_lineno > curlineno) break;
//UINFO(9," Hit "<<*m_lastIt<<endl);
filelinep->warnOn(m_lastIt->m_code, m_lastIt->m_on);
for (; m_lastIgnore.it != m_ignLines.end(); ++m_lastIgnore.it) {
if (m_lastIgnore.it->m_lineno > curlineno) break;
// UINFO(9," Hit "<<*m_lastIt<<endl);
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
}
if (0 && debug() >= 9) {
for (IgnLines::const_iterator it=m_lastIt; it != m_lastEnd; ++it) {
UINFO(9," NXT "<<*it<<endl);
for (IgnLines::const_iterator it = m_lastIgnore.it; it != m_ignLines.end(); ++it) {
UINFO(9, " NXT " << *it << endl);
}
}
m_lastLineno = filelinep->lastLineno();
m_lastIgnore.lineno = filelinep->lastLineno();
}
}
bool waive(V3ErrorCode code, const string& match) {
for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) {
if (((it->first == code) || (it->first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, it->second)) return true;
}
return false;
}
};
V3ConfigIgnores V3ConfigIgnores::s_singleton;
typedef V3ConfigWildcardResolver<V3ConfigFile> V3ConfigFileResolver;
//######################################################################
// Resolve modules and files in the design
class V3ConfigResolver {
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow)
V3ConfigResolver() {}
~V3ConfigResolver() {}
public:
inline static V3ConfigResolver& s() { return s_singleton; }
V3ConfigModuleResolver& modules() { return m_modules; }
V3ConfigFileResolver& files() { return m_files; }
};
V3ConfigResolver V3ConfigResolver::s_singleton;
//######################################################################
// V3Config
void V3Config::addCaseFull(const string& filename, int lineno) {
V3ConfigFile& file = V3ConfigResolver::s().files().at(filename);
file.addLineAttribute(lineno, AstPragmaType::FULL_CASE);
}
void V3Config::addCaseParallel(const string& filename, int lineno) {
V3ConfigFile& file = V3ConfigResolver::s().files().at(filename);
file.addLineAttribute(lineno, AstPragmaType::PARALLEL_CASE);
}
void V3Config::addCoverageBlockOff(const string& filename, int lineno) {
V3ConfigFile& file = V3ConfigResolver::s().files().at(filename);
file.addLineAttribute(lineno, AstPragmaType::COVERAGE_BLOCK_OFF);
}
void V3Config::addCoverageBlockOff(const string& module, const string& blockname) {
V3ConfigResolver::s().modules().at(module).addCoverageBlockOff(blockname);
}
void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max) {
if (filename=="*") {
FileLine::globalWarnOff(code,!on);
if (filename == "*") {
FileLine::globalWarnOff(code, !on);
} else {
V3ConfigIgnores::singleton().addIgnore(code, filename, min, on);
if (max) V3ConfigIgnores::singleton().addIgnore(code, filename, max, !on);
V3ConfigResolver::s().files().at(filename).addIgnore(code, min, on);
if (max) V3ConfigResolver::s().files().at(filename).addIgnore(code, max, !on);
V3ConfigResolver::s().files().flush();
}
}
void V3Config::applyIgnores(FileLine* filelinep) {
V3ConfigIgnores::singleton().applyIgnores(filelinep);
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
if (ftask.empty()) {
V3ConfigResolver::s().modules().at(module).setInline(on);
} else {
if (!on) {
fl->v3error("no_inline not supported for tasks" << endl);
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setNoInline(on);
}
}
}
void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& var, AstAttrType attr, AstSenTree* sensep) {
// Semantics: sensep only if public_flat_rw
if ((attr != AstAttrType::VAR_PUBLIC_FLAT_RW) && sensep) {
sensep->v3error("sensitivity not expected for attribute" << endl);
return;
}
// Semantics: Most of the attributes operate on signals
if (var.empty()) {
if (attr == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
if (ftask.empty()) {
fl->v3error("isolate_assignments only applies to signals or functions/tasks"
<< endl);
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setIsolate(true);
}
} else if (attr == AstAttrType::VAR_PUBLIC) {
if (ftask.empty()) {
// public module, this is the only exception from var here
V3ConfigResolver::s().modules().at(module).setPublic(true);
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
}
} else {
fl->v3error("missing -signal" << endl);
}
} else {
V3ConfigModule& mod = V3ConfigResolver::s().modules().at(module);
if (ftask.empty()) {
mod.vars().at(var).push_back(V3ConfigVarAttr(attr, sensep));
} else {
mod.ftasks().at(ftask).vars().at(var).push_back(V3ConfigVarAttr(attr, sensep));
}
}
}
void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& match) {
V3ConfigResolver::s().files().at(filename).addWaiver(code, match);
}
void V3Config::applyCase(AstCase* nodep) {
const string& filename = nodep->fileline()->filename();
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
if (filep) filep->applyCase(nodep);
}
void V3Config::applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep) {
const string& filename = nodep->fileline()->filename();
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
if (filep) filep->applyBlock(nodep);
const string& modname = modulep->name();
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
if (modp) modp->applyBlock(nodep);
}
void V3Config::applyIgnores(FileLine* filelinep) {
const string& filename = filelinep->filename();
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
if (filep) filep->applyIgnores(filelinep);
}
void V3Config::applyModule(AstNodeModule* modulep) {
const string& modname = modulep->name();
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
if (modp) modp->apply(modulep);
}
void V3Config::applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp) {
const string& modname = modulep->name();
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
if (!modp) return;
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
if (ftp) ftp->apply(ftaskp);
}
void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp) {
V3ConfigVar* vp;
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modulep->name());
if (!modp) return;
if (ftaskp) {
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
if (!ftp) return;
vp = ftp->vars().resolve(varp->name());
} else {
vp = modp->vars().resolve(varp->name());
}
if (vp) vp->apply(varp);
}
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());
if (!filep) return false;
return filep->waive(code, message);
}
+14
View File
@@ -26,13 +26,27 @@
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Ast.h"
//######################################################################
class V3Config {
public:
static void addCaseFull(const string& file, int lineno);
static void addCaseParallel(const string& file, int lineno);
static void addCoverageBlockOff(const string& file, int lineno);
static void addCoverageBlockOff(const string& module, const string& blockname);
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
static void addWaiver(V3ErrorCode code, const string& filename, const string& msg);
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, AstAttrType type, AstSenTree* nodep);
static void applyCase(AstCase* nodep);
static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep);
static void applyIgnores(FileLine* filelinep);
static void applyModule(AstNodeModule* nodep);
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& match);
};
#endif // Guard
+142 -136
View File
@@ -46,10 +46,10 @@ class ConstVarMarkVisitor : public AstNVisitor {
// AstVar::user4p -> bool, Var marked, 0=not set yet
private:
// VISITORS
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varp()) nodep->varp()->user4(1);
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -68,10 +68,10 @@ class ConstVarFindVisitor : public AstNVisitor {
bool m_found;
private:
// VISITORS
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varp() && nodep->varp()->user4()) m_found = true;
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -212,7 +212,7 @@ private:
if (!operandsSame(ap, bp)) return false;
// Do it
cp->unlinkFrBack();
andp->unlinkFrBack()->deleteTree(); VL_DANGLING(andp); VL_DANGLING(notp);
VL_DO_DANGLING(andp->unlinkFrBack()->deleteTree(), andp); VL_DANGLING(notp);
// Replace whichever branch is now dangling
if (nodep->rhsp()) nodep->lhsp(cp);
else nodep->rhsp(cp);
@@ -240,7 +240,7 @@ private:
newp->dtypeFrom(nodep);
newp->expr1p()->dtypeFrom(nodep); // As And might have been to change widths
newp->expr2p()->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
return true;
}
static bool operandShiftSame(const AstNode* nodep) {
@@ -343,7 +343,7 @@ private:
&& nodep->lsbConst()==0
&& static_cast<int>(nodep->widthConst()) == extendp->lhsp()->width()
)) return false;
replaceWChild(nodep, extendp->lhsp()); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWChild(nodep, extendp->lhsp()), nodep);
return true;
}
bool operandSelBiLower(AstSel* nodep) {
@@ -362,7 +362,7 @@ private:
bip->lhsp(new AstSel(nodep->fileline(), bilhsp, 0, nodep->widthConst()));
bip->rhsp(new AstSel(nodep->fileline(), birhsp, 0, nodep->widthConst()));
if (debug()>=9) bip->dumpTree(cout, "SEL(BI)-ou:");
replaceWChild(nodep, bip); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWChild(nodep, bip), nodep);
return true;
}
bool operandSelShiftLower(AstSel* nodep) {
@@ -390,7 +390,7 @@ private:
newLsb, nodep->widthConst());
newp->dtypeFrom(nodep);
if (debug()>=9) newp->dumpTree(cout, "SEL(SH)-ou:");
nodep->replaceWith(newp); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->replaceWith(newp), nodep);
return true;
}
@@ -409,14 +409,14 @@ private:
//
if (debug()>=9) nodep->dumpTree(cout, "BI(EXTEND)-in:");
smallerp->unlinkFrBack();
extendp->unlinkFrBack()->deleteTree(); // aka nodep->lhsp.
VL_DO_DANGLING(extendp->unlinkFrBack()->deleteTree(), extendp); // aka nodep->lhsp.
nodep->rhsp(smallerp);
constp->unlinkFrBack();
V3Number num (constp, subsize);
num.opAssign(constp->num());
nodep->lhsp(new AstConst(constp->fileline(), num));
constp->deleteTree(); VL_DANGLING(constp);
VL_DO_DANGLING(constp->deleteTree(), constp);
if (debug()>=9) nodep->dumpTree(cout, "BI(EXTEND)-ou:");
return true;
}
@@ -622,11 +622,11 @@ private:
if (debug()>5) oldp->dumpTree(cout, " const_old: ");
if (debug()>5) newp->dumpTree(cout, " _new: ");
oldp->replaceWith(newp);
oldp->deleteTree(); VL_DANGLING(oldp);
VL_DO_DANGLING(oldp->deleteTree(), oldp);
}
void replaceNum(AstNode* nodep, uint32_t val) {
V3Number num (nodep, nodep->width(), val);
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
}
void replaceNumSigned(AstNodeBiop* nodep, uint32_t val) {
// We allow both sides to be constant, as one may have come from
@@ -634,48 +634,48 @@ private:
if (m_warn && !(VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const))) {
nodep->v3warn(UNSIGNED, "Comparison is constant due to unsigned arithmetic");
}
replaceNum(nodep, val); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, val), nodep);
}
void replaceNumLimited(AstNodeBiop* nodep, uint32_t val) {
// Avoids gcc warning about same
if (m_warn) nodep->v3warn(CMPCONST, "Comparison is constant due to limited range");
replaceNum(nodep, val); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, val), nodep);
}
void replaceZero(AstNode* nodep) {
replaceNum(nodep, 0); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, 0), nodep);
}
void replaceZeroChkPure(AstNode* nodep, AstNode* checkp) {
// For example, "0 * n" -> 0 if n has no side effects
// Else strength reduce it to 0 & n.
// If ever change the operation note AstAnd rule specially ignores this created pattern
if (isTPure(checkp)) {
replaceNum(nodep, 0); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, 0), nodep);
} else {
AstNode* newp = new AstAnd(nodep->fileline(),
new AstConst(nodep->fileline(), 0),
checkp->unlinkFrBack());
newp->dtypeFrom(nodep);
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
void replaceAllOnes(AstNode* nodep) {
V3Number ones (nodep, nodep->width(), 0);
ones.setMask(nodep->width());
replaceNum(nodep, ones); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, ones), nodep);
}
void replaceConst(AstNodeUniop* nodep) {
V3Number num (nodep, nodep->width());
nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num());
UINFO(4,"UNICONST -> "<<num<<endl);
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
}
void replaceConst(AstNodeBiop* nodep) {
V3Number num (nodep, nodep->width());
nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num(),
VN_CAST(nodep->rhsp(), Const)->num());
UINFO(4,"BICONST -> "<<num<<endl);
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
}
void replaceConst(AstNodeTriop* nodep) {
V3Number num (nodep, nodep->width());
@@ -683,7 +683,7 @@ private:
VN_CAST(nodep->rhsp(), Const)->num(),
VN_CAST(nodep->thsp(), Const)->num());
UINFO(4,"TRICONST -> "<<num<<endl);
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
}
void replaceConstString(AstNode* oldp, const string& num) {
@@ -693,7 +693,7 @@ private:
if (debug()>5) oldp->dumpTree(cout, " const_old: ");
if (debug()>5) newp->dumpTree(cout, " _new: ");
oldp->replaceWith(newp);
oldp->deleteTree(); VL_DANGLING(oldp);
VL_DO_DANGLING(oldp->deleteTree(), oldp);
}
//----------------------------------------
// Replacement functions.
@@ -706,7 +706,7 @@ private:
// This may adversely affect the operation of the node being replaced.
childp->dtypeFrom(nodep);
nodep->replaceWith(childp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
//! Replace a ternary node with its RHS after iterating
@@ -794,15 +794,15 @@ private:
lp->rhsp(nodep);
nodep->lhsp(lrp);
nodep->rhsp(rrp);
rp->deleteTree();
rlp->deleteTree();
VL_DO_DANGLING(rp->deleteTree(), rp);
VL_DO_DANGLING(rlp->deleteTree(), rlp);
} else if (operandsSame(lrp, rrp)) {
lp->lhsp(nodep);
lp->rhsp(rrp);
nodep->lhsp(llp);
nodep->rhsp(rlp);
rp->deleteTree();
lrp->deleteTree();
VL_DO_DANGLING(rp->deleteTree(), rp);
VL_DO_DANGLING(lrp->deleteTree(), lrp);
} else {
nodep->v3fatalSrc("replaceAndOr on something operandAndOrSame shouldn't have matched");
}
@@ -822,8 +822,8 @@ private:
lp->rhsp(lrp);
nodep->lhsp(llp);
nodep->rhsp(rlp);
rp->deleteTree();
rrp->deleteTree();
VL_DO_DANGLING(rp->deleteTree(), rp);
VL_DO_DANGLING(rrp->deleteTree(), rrp);
//nodep->dumpTree(cout, " repShiftSame_new: ");
}
void replaceConcatSel(AstConcat* nodep) {
@@ -842,9 +842,9 @@ private:
UINFO(5, "merged two adjacent sel "<<lselp <<" and "<<rselp<< " to one "<<newselp<<endl);
nodep->replaceWith(newselp);
lselp->deleteTree(); VL_DANGLING(lselp);
rselp->deleteTree(); VL_DANGLING(rselp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(lselp->deleteTree(), lselp);
VL_DO_DANGLING(rselp->deleteTree(), rselp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceConcatMerge(AstConcat* nodep) {
AstNodeBiop* lp = VN_CAST(nodep->lhsp(), NodeBiop);
@@ -861,8 +861,8 @@ private:
lp->rhsp()->replaceWith(newrp);
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::UNSIGNED);
UINFO(5, "merged "<< nodep <<endl);
rp->unlinkFrBack()->deleteTree(); VL_DANGLING(rp);
nodep->replaceWith(lp->unlinkFrBack()); nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(rp->unlinkFrBack()->deleteTree(), rp);
nodep->replaceWith(lp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep);
iterate(lp->lhsp());
iterate(lp->rhsp());
} else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
@@ -875,7 +875,7 @@ private:
? static_cast<AstNode*>(new AstExtendS(nodep->fileline(), arg0p))
: static_cast<AstNode*>(new AstExtend (nodep->fileline(), arg0p)));
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replacePowShift(AstNodeBiop* nodep) { // Pow or PowS
UINFO(5,"POW(2,b)->SHIFTL(1,b) "<<nodep<<endl);
@@ -885,7 +885,7 @@ private:
rhsp);
newp->dtypeFrom(nodep);
newp->lhsp()->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceMulShift(AstMul* nodep) { // Mul, but not MulS as not simple shift
UINFO(5,"MUL(2^n,b)->SHIFTL(b,n) "<<nodep<<endl);
@@ -894,7 +894,7 @@ private:
AstShiftL* newp = new AstShiftL(nodep->fileline(),
opp, new AstConst(nodep->fileline(), amount));
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceDivShift(AstDiv* nodep) { // Mul, but not MulS as not simple shift
UINFO(5,"DIV(b,2^n)->SHIFTR(b,n) "<<nodep<<endl);
@@ -903,7 +903,7 @@ private:
AstShiftR* newp = new AstShiftR(nodep->fileline(),
opp, new AstConst(nodep->fileline(), amount));
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceModAnd(AstModDiv* nodep) { // Mod, but not ModS as not simple shift
UINFO(5,"MOD(b,2^n)->AND(b,2^n-1) "<<nodep<<endl);
@@ -914,7 +914,7 @@ private:
AstAnd* newp = new AstAnd(nodep->fileline(),
opp, new AstConst(nodep->fileline(), mask));
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceShiftOp(AstNodeBiop* nodep) {
UINFO(5,"SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) "<<nodep<<endl);
@@ -946,8 +946,8 @@ private:
int shift1 = VN_CAST(shift1p, Const)->toUInt();
int shift2 = VN_CAST(shift2p, Const)->toUInt();
int newshift = shift1+shift2;
shift1p->deleteTree(); VL_DANGLING(shift1p);
shift2p->deleteTree(); VL_DANGLING(shift2p);
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
nodep->lhsp(ap);
nodep->rhsp(new AstConst(nodep->fileline(), newshift));
iterate(nodep); // Further reduce, either node may have more reductions.
@@ -958,8 +958,8 @@ private:
int shift2 = VN_CAST(shift2p, Const)->toUInt();
if (VN_IS(nodep, ShiftR)) shift2=-shift2;
int newshift = shift1+shift2;
shift1p->deleteTree(); VL_DANGLING(shift1p);
shift2p->deleteTree(); VL_DANGLING(shift2p);
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
AstNode* newp;
V3Number mask1 (nodep, nodep->width());
V3Number ones (nodep, nodep->width());
@@ -987,11 +987,11 @@ private:
newp,
new AstConst(nodep->fileline(), mask));
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
//newp->dumpTree(cout, " repShiftShift_new: ");
iterate(newp); // Further reduce, either node may have more reductions.
}
lhsp->deleteTree(); VL_DANGLING(lhsp);
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
}
bool replaceAssignMultiSel(AstNodeAssign* nodep) {
@@ -1033,8 +1033,9 @@ private:
new AstConcat(rhs1p->fileline(), rhs1p, rhs2p));
}
//pnewp->dumpTree(cout, "conew: ");
nodep->replaceWith(newp); nodep->deleteTree();
nextp->unlinkFrBack()->deleteTree();
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
VL_DO_DANGLING(nextp->unlinkFrBack()->deleteTree(), nextp);
return true;
}
@@ -1062,7 +1063,7 @@ private:
nodep->v3error("Wire inputs its own output, creating circular logic (wire x=x)");
return false; // Don't delete the assign, or V3Gate will freak out
} else {
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return true;
}
}
@@ -1156,8 +1157,8 @@ private:
if (debug()>=9 && newp) newp->dumpTreeAndNext(cout, " _new: ");
nodep->addNextHere(newp);
// Cleanup
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
conp->deleteTree(); VL_DANGLING(conp);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
VL_DO_DANGLING(conp->deleteTree(), conp);
// Further reduce, either node may have more reductions.
return true;
}
@@ -1170,8 +1171,8 @@ private:
AstNode* streamp = VN_CAST(nodep->rhsp(), StreamR)->unlinkFrBack();
nodep->rhsp(srcp);
// Cleanup
sizep->deleteTree(); VL_DANGLING(sizep);
streamp->deleteTree(); VL_DANGLING(streamp);
VL_DO_DANGLING(sizep->deleteTree(), sizep);
VL_DO_DANGLING(streamp->deleteTree(), streamp);
// Further reduce, any of the nodes may have more reductions.
return true;
}
@@ -1213,8 +1214,8 @@ private:
nodep->lhsp(dstp);
nodep->rhsp(srcp);
// Cleanup
sizep->deleteTree(); VL_DANGLING(sizep);
streamp->deleteTree(); VL_DANGLING(streamp);
VL_DO_DANGLING(sizep->deleteTree(), sizep);
VL_DO_DANGLING(streamp->deleteTree(), streamp);
// Further reduce, any of the nodes may have more reductions.
return true;
}
@@ -1250,7 +1251,7 @@ private:
// widthMin no longer applicable if different C-expanded width
newp->dtypeSetLogicSized(nodep->width(), AstNumeric::UNSIGNED);
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
if (debug()>=9) newp->dumpTree(cout, " _new: ");
}
@@ -1264,7 +1265,7 @@ private:
<<nodep->prettyTypeName()<<endl
<<errorp->warnOther()<<"... Location of non-constant "
<<errorp->prettyTypeName()<<": "<<simvis.whyNotMessage());
replaceZero(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceZero(nodep), nodep);
} else {
// Fetch the result
AstNode* valuep = simvis.fetchValueNull(nodep); // valuep is owned by Simulate
@@ -1274,30 +1275,33 @@ private:
newp->dtypeFrom(nodep);
newp->fileline(nodep->fileline());
UINFO(4, "Simulate->"<<newp<<endl);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
//----------------------------------------
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
// Iterate modules backwards, in bottom-up order. That's faster
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
iterateChildren(nodep);
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
// No ASSIGNW removals under funcs, we've long eliminated INITIALs
// (We should perhaps rename the assignw's to just assigns)
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
// No ASSIGNW removals under scope, we've long eliminated INITIALs
m_scopep = nodep;
m_wremove = false;
@@ -1354,7 +1358,7 @@ private:
// If bp was a concat, then we have this exact same form again!
// Recurse rather then calling node->iterate to prevent 2^n recursion!
if (operandConcatMove(abConcp)) moveConcat(abConcp);
bcConcp->deleteTree(); VL_DANGLING(bcConcp);
VL_DO_DANGLING(bcConcp->deleteTree(), bcConcp);
} else {
AstConcat* abConcp = VN_CAST(nodep->lhsp(), Concat); abConcp->unlinkFrBack();
AstNode* ap = abConcp->lhsp()->unlinkFrBack();
@@ -1365,21 +1369,21 @@ private:
nodep->lhsp(ap);
nodep->rhsp(bcConcp);
if (operandConcatMove(bcConcp)) moveConcat(bcConcp);
abConcp->deleteTree(); VL_DANGLING(abConcp);
VL_DO_DANGLING(abConcp->deleteTree(), abConcp);
}
}
// Special cases
virtual void visit(AstConst* nodep) {} // Already constant
virtual void visit(AstConst* nodep) VL_OVERRIDE {} // Already constant
virtual void visit(AstCell* nodep) {
virtual void visit(AstCell* nodep) VL_OVERRIDE {
if (m_params) {
iterateAndNextNull(nodep->paramsp());
} else {
iterateChildren(nodep);
}
}
virtual void visit(AstPin* nodep) {
virtual void visit(AstPin* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
@@ -1397,7 +1401,7 @@ private:
rhsp->cloneTree(false)),
lhsp->cloneTree(false)));
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceSelSel(AstSel* nodep) {
@@ -1414,8 +1418,8 @@ private:
newlsbp = new AstConst(lsb1p->fileline(),
VN_CAST(lsb1p, Const)->toUInt()
+ VN_CAST(lsb2p, Const)->toUInt());
lsb1p->deleteTree(); VL_DANGLING(lsb1p);
lsb2p->deleteTree(); VL_DANGLING(lsb2p);
VL_DO_DANGLING(lsb1p->deleteTree(), lsb1p);
VL_DO_DANGLING(lsb2p->deleteTree(), lsb2p);
} else {
// Width is important, we need the width of the fromp's
// expression, not the potentially smaller lsb1p's width
@@ -1429,7 +1433,7 @@ private:
newlsbp,
widthp);
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceSelConcat(AstSel* nodep) {
@@ -1469,7 +1473,7 @@ private:
conRhsp->width()-nodep->lsbConst()));
nodep->replaceWith(newp);
}
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
bool operandSelReplicate(AstSel* nodep) {
// SEL(REPLICATE(from,rep),lsb,width) => SEL(from,0,width) as long
@@ -1489,7 +1493,7 @@ private:
new AstConst(lsbp->fileline(), lsbp->toUInt() % fromp->width()),
widthp);
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
return true;
}
bool operandRepRep(AstReplicate* nodep) {
@@ -1505,7 +1509,7 @@ private:
AstReplicate* newp = new AstReplicate(nodep->fileline(),
from2p, cnt1p->toUInt()*cnt2p->toUInt());
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
return true;
}
bool operandConcatSame(AstConcat* nodep) {
@@ -1532,7 +1536,7 @@ private:
from1p->unlinkFrBack();
AstReplicate* newp = new AstReplicate(nodep->fileline(), from1p, cnt1+cnt2);
newp->dtypeFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
return true;
}
void replaceSelIntoBiop(AstSel* nodep) {
@@ -1550,7 +1554,7 @@ private:
fromp->rhsp(new AstSel(nodep->fileline(),
birhsp, lsbp, widthp));
fromp->dtypeFrom(nodep);
nodep->replaceWith(fromp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(fromp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void replaceSelIntoUniop(AstSel* nodep) {
// SEL(NOT(a),1,bit) => NOT(SEL(a,bit))
@@ -1564,17 +1568,17 @@ private:
fromp->lhsp(new AstSel(nodep->fileline(),
bilhsp, lsbp, widthp));
fromp->dtypeFrom(nodep);
nodep->replaceWith(fromp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(fromp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstAttrOf* nodep) {
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
AstAttrOf* oldAttr = m_attrp;
m_attrp = nodep;
iterateChildren(nodep);
m_attrp = oldAttr;
}
virtual void visit(AstArraySel* nodep) {
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->bitp());
if (VN_IS(nodep->bitp(), Const)
&& VN_IS(nodep->fromp(), VarRef)
@@ -1595,12 +1599,12 @@ private:
fromp->dtypeFrom(VN_CAST(fromp->dtypep()->skipRefp(),
NodeArrayDType)->subDTypep());
}
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
m_selp = NULL;
}
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
UASSERT_OBJ(nodep->varp(), nodep, "Not linked");
bool did = false;
@@ -1621,7 +1625,7 @@ private:
if (operandConst(valuep)) {
const V3Number& num = VN_CAST(valuep, Const)->num();
//UINFO(2,"constVisit "<<cvtToHex(valuep)<<" "<<num<<endl);
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
did = true;
}
else if (m_selp && VN_IS(valuep, InitArray)) {
@@ -1631,7 +1635,7 @@ private:
if (VN_IS(itemp, Const)) {
const V3Number& num = VN_CAST(itemp, Const)->num();
//UINFO(2,"constVisit "<<cvtToHex(valuep)<<" "<<num<<endl);
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
did = true;
}
}
@@ -1641,7 +1645,7 @@ private:
// This exception is fairly fragile, i.e. doesn't
// support arrays of arrays or other stuff
AstNode* newp = valuep->cloneTree(false);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
did = true;
}
}
@@ -1651,7 +1655,7 @@ private:
<<nodep->varp()->prettyNameQ());
}
}
virtual void visit(AstEnumItemRef* nodep) {
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
bool did = false;
@@ -1666,7 +1670,7 @@ private:
}
if (AstConst* valuep = VN_CAST(nodep->itemp()->valuep(), Const)) {
const V3Number& num = valuep->num();
replaceNum(nodep, num); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
did = true;
}
}
@@ -1676,7 +1680,7 @@ private:
}
}
// virtual void visit(AstCvtPackString* nodep) {
// virtual void visit(AstCvtPackString* nodep) VL_OVERRIDE {
// Not constant propagated (for today) because AstNodeMath::isOpaque is set
// Someday if lower is constant, convert to quoted "string".
@@ -1684,7 +1688,7 @@ private:
// Only one if it's not in a list
return (!nodep->nextp() && nodep->backp()->nextp() != nodep);
}
virtual void visit(AstSenItem* nodep) {
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_doNConst
&& (VN_IS(nodep->sensp(), Const)
@@ -1694,13 +1698,13 @@ private:
if (nodep->isClocked()) { // A constant can never get a pos/negedge
if (onlySenItemInSenTree(nodep)) {
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
} else { // Otherwise it may compute a result that needs to settle out
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
} else if (m_doNConst && VN_IS(nodep->sensp(), Not)) {
// V3Gate may propagate NOTs into clocks... Just deal with it
@@ -1716,7 +1720,7 @@ private:
AstNodeVarRef* senvarp = VN_CAST(lastSensp->unlinkFrBack(), NodeVarRef);
UASSERT_OBJ(senvarp, sensp, "Non-varref sensitivity variable");
sensp->replaceWith(senvarp);
sensp->deleteTree(); VL_DANGLING(sensp);
VL_DO_DANGLING(sensp->deleteTree(), sensp);
} else if (!m_doNConst // Deal with later when doNConst missing
&& (VN_IS(nodep->sensp(), EnumItemRef)
|| VN_IS(nodep->sensp(), Const))) {
@@ -1726,22 +1730,22 @@ private:
"Null sensitivity variable");
}
}
virtual void visit(AstSenGate* nodep) {
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) {
if (constp->isZero()) {
UINFO(4,"SENGATE(...,0)->NEVER"<<endl);
if (onlySenItemInSenTree(nodep)) {
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
} else {
UINFO(4,"SENGATE(SENITEM,0)->ALWAYS SENITEM"<<endl);
AstNode* senitemp = nodep->sensesp()->unlinkFrBack();
nodep->replaceWith(senitemp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
}
@@ -1778,7 +1782,7 @@ private:
}
};
virtual void visit(AstSenTree* nodep) {
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_doExpensive) {
//cout<<endl; nodep->dumpTree(cout, "ssin: ");
@@ -1787,7 +1791,7 @@ private:
// SENTREE(... SENITEM(x), SENGATE(SENITEM(x),*) ...) => SENITEM(x)
// Do we need the SENITEM's to be identical? No because we're
// ORing between them; we just need to insure that the result is at
// ORing between them; we just need to ensure that the result is at
// least as frequently activating. So we simply
// SENGATE(SENITEM(x)) -> SENITEM(x), then let it collapse with the
// other SENITEM(x).
@@ -1813,7 +1817,8 @@ private:
// Found, push this item up to the top
itemp->unlinkFrBack();
nodep->addSensesp(itemp);
gatep->unlinkFrBack()->deleteTree(); VL_DANGLING(gatep); VL_DANGLING(senp);
VL_DO_DANGLING(gatep->unlinkFrBack()->deleteTree(), gatep);
VL_DANGLING(senp);
}
}
}
@@ -1874,7 +1879,8 @@ private:
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
// Remove redundant node
ritemp->unlinkFrBack()->deleteTree(); VL_DANGLING(ritemp); VL_DANGLING(cmpp);
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
VL_DANGLING(cmpp);
// Try to collapse again
nextp = litemp;
}
@@ -1887,17 +1893,17 @@ private:
//-----
// Zero elimination
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return;
}
virtual void visit(AstAssignAlias* nodep) {
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
// Don't perform any optimizations, keep the alias around
}
virtual void visit(AstAssignVarScope* nodep) {
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
// Don't perform any optimizations, the node won't be linked yet
}
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return;
AstNodeVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); // Not VarXRef, as different refs may set different values to each hierarchy
@@ -1917,14 +1923,14 @@ private:
new AstAssign(nodep->fileline(),
varrefp, exprp));
m_modp->addStmtp(newinitp);
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
// Set the initial value right in the variable so we can constant propagate
AstNode* initvaluep = exprp->cloneTree(false);
varrefp->varp()->valuep(initvaluep);
}
}
virtual void visit(AstNodeIf* nodep) {
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_doNConst) {
if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) {
@@ -1942,13 +1948,13 @@ private:
} else {
nodep->unlinkFrBack();
}
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) {
// Empty block, remove it
// Note if we support more C++ then there might be side
// effects in the condition itself
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (!afterComment(nodep->ifsp())) {
UINFO(4,"IF({x}) NULL {...} => IF(NOT{x}}: "<<nodep<<endl);
@@ -1970,7 +1976,7 @@ private:
AstIf* ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp);
ifp->branchPred(nodep->branchPred().invert());
nodep->replaceWith(ifp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
else if (ifSameAssign(nodep)) {
UINFO(4,"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"<<endl);
@@ -1983,7 +1989,7 @@ private:
ifp->rhsp(new AstCond(truep->fileline(),
condp, truep, falsep));
nodep->replaceWith(ifp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
&& operandIfIf(nodep)) {
@@ -1995,7 +2001,7 @@ private:
nodep->condp(new AstLogAnd(lowerIfp->fileline(),
condp, lowerCondp));
lowerIfp->replaceWith(lowerIfsp);
lowerIfp->deleteTree(); VL_DANGLING(lowerIfp);
VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp);
}
else if (operandBoolShift(nodep->condp())) {
replaceBoolShift(nodep->condp());
@@ -2003,7 +2009,7 @@ private:
}
}
virtual void visit(AstDisplay* nodep) {
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
iterateChildren(nodep);
if (stmtDisplayDisplay(nodep)) return;
@@ -2045,10 +2051,10 @@ private:
if (!prevp->addNewline() && nodep->addNewline()) {
pformatp->text(pformatp->text()+"\n");
}
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return true;
}
virtual void visit(AstSFormatF* nodep) {
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
// Substitute constants into displays. The main point of this is to
// simplify assertion methodologies which call functions with display's.
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
@@ -2069,7 +2075,7 @@ private:
if (!inPct && ch=='%') {
inPct = true;
fmt = ch;
} else if (inPct && (isdigit(ch) || ch=='.')) {
} else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) {
fmt += ch;
} else if (inPct) {
inPct = false;
@@ -2081,13 +2087,13 @@ private:
default: // Most operators, just move to next argument
if (argp) {
AstNode* nextp = argp->nextp();
if (argp && VN_IS(argp, Const)) { // Convert it
if (VN_IS(argp, Const)) { // Convert it
string out = VN_CAST(argp, Const)->num().displayed(nodep, fmt);
UINFO(9," DispConst: "<<fmt<<" -> "<<out
<<" for "<<argp<<endl);
// fmt = out w/ replace % with %% as it must be literal.
fmt = VString::quotePercent(out);
argp->unlinkFrBack()->deleteTree(); VL_DANGLING(argp);
VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp);
}
argp = nextp;
}
@@ -2107,21 +2113,21 @@ private:
&& nodep->name().find('%') == string::npos
&& !nodep->hidden()) {
// Just a simple constant string - the formatting is pointless
replaceConstString(nodep, nodep->name()); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceConstString(nodep, nodep->name()), nodep);
}
}
virtual void visit(AstFuncRef* nodep) {
virtual void visit(AstFuncRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_params) { // Only parameters force us to do constant function call propagation
replaceWithSimulation(nodep);
}
}
virtual void visit(AstArg* nodep) {
virtual void visit(AstArg* nodep) VL_OVERRIDE {
// replaceWithSimulation on the Arg's parent FuncRef replaces these
iterateChildren(nodep);
}
virtual void visit(AstWhile* nodep) {
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
bool oldHasJumpGo = m_hasJumpGo;
m_hasJumpGo = false;
{
@@ -2134,7 +2140,7 @@ private:
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
else if (nodep->condp()->isNeqZero()) {
if (!thisWhileHasJumpGo) {
@@ -2147,27 +2153,27 @@ private:
}
}
}
virtual void visit(AstInitArray* nodep) {
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstInitItem* nodep) {
virtual void visit(AstInitItem* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
// These are converted by V3Param. Don't constify as we don't want the
// from() VARREF to disappear, if any.
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
virtual void visit(AstNodePreSel* nodep) {}
virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE {}
// Ignored, can eliminate early
virtual void visit(AstSysIgnore* nodep) {
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_doNConst) {
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
}
// Simplify
virtual void visit(AstBasicDType* nodep) {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->cvtRangeConst();
}
@@ -2175,7 +2181,7 @@ private:
//-----
// Jump elimination
virtual void visit(AstJumpGo* nodep) {
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
iterateChildren(nodep);
m_hasJumpGo = true;
if (m_doExpensive) {
@@ -2185,7 +2191,7 @@ private:
if (AstJumpLabel* aboveLabelp = VN_CAST(nodep->abovep(), JumpLabel)) {
if (aboveLabelp == nodep->labelp()) {
UINFO(4, "JUMPGO => last remove "<<nodep<<endl);
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
}
@@ -2194,7 +2200,7 @@ private:
}
}
virtual void visit(AstJumpLabel* nodep) {
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
// Because JumpLabels disable many optimizations,
// remove JumpLabels that are not pointed to by any AstJumpGos
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
@@ -2206,7 +2212,7 @@ private:
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
if (underp) nodep->replaceWith(underp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
@@ -2540,7 +2546,7 @@ private:
// Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101
//-----
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// Default: Just iterate
if (m_required) {
if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range)) {
+23 -19
View File
@@ -54,8 +54,8 @@ private:
: m_comment(comment), m_varRefp(vp), m_chgRefp(cp) {}
~ToggleEnt() {}
void cleanup() {
m_varRefp->deleteTree(); m_varRefp = NULL;
m_chgRefp->deleteTree(); m_chgRefp = NULL;
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = NULL);
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = NULL);
}
};
@@ -149,17 +149,21 @@ private:
+"_"+type;
}
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
m_fileps.clear();
iterateChildren(nodep);
m_modp = NULL;
m_inModOff = true;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
bool origInModOff = m_inModOff;
{
m_modp = nodep;
m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
m_fileps.clear();
iterateChildren(nodep);
}
m_modp = origModp;
m_inModOff = origInModOff;
}
// VISITORS - TOGGLE COVERAGE
virtual void visit(AstNodeFTask* nodep) {
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
bool oldtog = m_inToggleOff;
{
m_inToggleOff = true;
@@ -167,7 +171,7 @@ private:
}
m_inToggleOff = oldtog;
}
virtual void visit(AstVar* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_modp && !m_inModOff && !m_inToggleOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) {
@@ -303,7 +307,7 @@ private:
}
// VISITORS - LINE COVERAGE
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
// An else-if. When we iterate the if, use "elsif" marking
@@ -340,7 +344,7 @@ private:
m_checkBlock = true; // Reset as a child may have cleared it
}
}
virtual void visit(AstCaseItem* nodep) {
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
UINFO(4," CASEI: "<<nodep<<endl);
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) {
@@ -353,7 +357,7 @@ private:
m_checkBlock = true; // Reset as a child may have cleared it
}
}
virtual void visit(AstCover* nodep) {
virtual void visit(AstCover* nodep) VL_OVERRIDE {
UINFO(4," COVER: "<<nodep<<endl);
m_checkBlock = true; // Always do cover blocks, even if there's a $stop
iterateChildren(nodep);
@@ -364,21 +368,21 @@ private:
}
m_checkBlock = true; // Reset as a child may have cleared it
}
virtual void visit(AstStop* nodep) {
virtual void visit(AstStop* nodep) VL_OVERRIDE {
UINFO(4," STOP: "<<nodep<<endl);
m_checkBlock = false;
}
virtual void visit(AstPragma* nodep) {
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
// Skip all NEXT nodes under this block, and skip this if/case branch
UINFO(4," OFF: "<<nodep<<endl);
m_checkBlock = false;
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else {
if (m_checkBlock) iterateChildren(nodep);
}
}
virtual void visit(AstBegin* nodep) {
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
// Record the hierarchy of any named begins, so we can apply to user
// coverage points. This is because there may be cov points inside
// generate blocks; each point should get separate consideration.
@@ -398,7 +402,7 @@ private:
}
// VISITORS - BOTH
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// Default: Just iterate
if (m_checkBlock) {
iterateChildren(nodep);
+5 -5
View File
@@ -92,7 +92,7 @@ private:
UINFO(8," new "<<removep->incp()->declp()<<endl);
// Mark the found node as a duplicate of the first node
// (Not vice-versa as we have the iterator for the found node)
removep->unlinkFrBack(); pushDeletep(removep); VL_DANGLING(removep);
removep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(removep), removep);
// Remove node from comparison so don't hit it again
hashed.erase(dupit);
++m_statToggleJoins;
@@ -102,19 +102,19 @@ private:
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
// Find all Coverage's
iterateChildren(nodep);
// Simplify
detectDuplicates();
}
virtual void visit(AstCoverToggle* nodep) {
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
m_toggleps.push_back(nodep);
iterateChildren(nodep);
}
//--------------------
virtual void visit(AstNodeMath* nodep) {} // Accelerate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+46 -33
View File
@@ -57,13 +57,13 @@ private:
// NODE STATE
// ** Shared with DeadVisitor **
// VISITORS
virtual void visit(AstCell* nodep) {
virtual void visit(AstCell* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->modp()->user1Inc(-1);
}
//-----
virtual void visit(AstNodeMath* nodep) {} // Accelerate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -133,20 +133,23 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
}
}
m_modp = NULL;
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc();
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc();
@@ -155,14 +158,14 @@ private:
m_scopesp.push_back(nodep);
}
}
virtual void visit(AstCell* nodep) {
virtual void visit(AstCell* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
m_cellsp.push_back(nodep);
nodep->modp()->user1Inc();
}
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->varScopep()) {
@@ -177,7 +180,7 @@ private:
else nodep->packagep()->user1Inc();
}
}
virtual void visit(AstNodeFTaskRef* nodep) {
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
@@ -185,7 +188,11 @@ private:
else nodep->packagep()->user1Inc();
}
}
virtual void visit(AstRefDType* nodep) {
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
}
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
@@ -194,12 +201,12 @@ private:
else nodep->packagep()->user1Inc();
}
}
virtual void visit(AstNodeDType* nodep) {
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
}
virtual void visit(AstEnumItemRef* nodep) {
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
@@ -208,20 +215,26 @@ private:
}
checkAll(nodep);
}
virtual void visit(AstModport* nodep) {
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref
checkAll(nodep);
}
virtual void visit(AstModport* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_elimCells) {
if (!nodep->varsp()) {
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
}
checkAll(nodep);
}
virtual void visit(AstTypedef* nodep) {
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_elimCells && !nodep->attrPublic()) {
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
checkAll(nodep);
@@ -229,7 +242,7 @@ private:
// Normal modules may disappear, e.g. if they are parameterized then removed
if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
}
virtual void visit(AstVarScope* nodep) {
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc();
@@ -237,7 +250,7 @@ private:
m_vscsp.push_back(nodep);
}
}
virtual void visit(AstVar* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
@@ -245,7 +258,7 @@ private:
m_varsp.push_back(nodep);
}
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
// See if simple assignments to variables may be eliminated because
// that variable is never used.
// Similar code in V3Life
@@ -265,7 +278,7 @@ private:
}
//-----
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
if (nodep->isOutputter()) m_sideEffect = true;
iterateChildren(nodep);
checkAll(nodep);
@@ -289,7 +302,7 @@ private:
if (!modp->dead()) { // If was dead didn't increment user1's
DeadModVisitor visitor(modp);
}
modp->unlinkFrBack()->deleteTree(); VL_DANGLING(modp);
VL_DO_DANGLING(modp->unlinkFrBack()->deleteTree(), modp);
retry = true;
}
}
@@ -299,7 +312,7 @@ private:
return (!nodep->isSigPublic() // Can't elim publics!
&& !nodep->isIO()
&& ((nodep->isTemp() && !nodep->isTrace())
|| (nodep->isParam() && !nodep->isTrace())
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|| m_elimUserVars)); // Post-Trace can kill most anything
}
@@ -317,7 +330,7 @@ private:
if (scp->dtypep()) {
scp->dtypep()->user1Inc(-1);
}
scp->unlinkFrBack()->deleteTree(); VL_DANGLING(scp);
VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp);
*it = NULL;
retry = true;
}
@@ -330,7 +343,7 @@ private:
AstCell* cellp = *it;
if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) {
cellp->modp()->user1Inc(-1);
cellp->unlinkFrBack()->deleteTree(); VL_DANGLING(cellp);
VL_DO_DANGLING(cellp->unlinkFrBack()->deleteTree(), cellp);
}
}
}
@@ -347,11 +360,11 @@ private:
AstNodeAssign* assp = itr->second;
UINFO(4," Dead assign "<<assp<<endl);
assp->dtypep()->user1Inc(-1);
assp->unlinkFrBack()->deleteTree(); VL_DANGLING(assp);
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
}
if (vscp->scopep()) vscp->scopep()->user1Inc(-1);
vscp->dtypep()->user1Inc(-1);
vscp->unlinkFrBack()->deleteTree(); VL_DANGLING(vscp);
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
}
}
for (bool retry=true; retry; ) {
@@ -365,7 +378,7 @@ private:
if (varp->dtypep()) {
varp->dtypep()->user1Inc(-1);
}
varp->unlinkFrBack()->deleteTree(); VL_DANGLING(varp);
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
*it = NULL;
retry = true;
}
@@ -389,7 +402,7 @@ private:
if (!cont)
continue;
}
(*it)->unlinkFrBack()->deleteTree(); VL_DANGLING(*it);
VL_DO_DANGLING((*it)->unlinkFrBack()->deleteTree(), *it);
}
}
}
+12 -12
View File
@@ -348,22 +348,22 @@ private:
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
//VV***** We reset all userp() on the netlist
m_modVarMap.clear();
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
AstNode::user3ClearTree();
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
m_cfuncp = nodep;
iterateChildren(nodep);
m_cfuncp = NULL;
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
m_activep = nodep;
bool oldinit = m_inInitial;
m_inInitial = nodep->hasInitial();
@@ -371,7 +371,7 @@ private:
iterateChildren(nodep);
m_inInitial = oldinit;
}
virtual void visit(AstAssignDly* nodep) {
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
m_inDly = true;
m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
if (m_cfuncp) nodep->v3error("Unsupported: Delayed assignment inside public function/task");
@@ -384,9 +384,9 @@ private:
if (newlhsp) {
nodep->lhsp(newlhsp);
} else {
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
lhsp->deleteTree(); VL_DANGLING(lhsp);
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
}
else {
iterateChildren(nodep);
@@ -395,7 +395,7 @@ private:
m_nextDlyp = NULL;
}
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->lvalue()) {
UINFO(4,"AssignDlyVar: "<<nodep<<endl);
@@ -432,7 +432,7 @@ private:
}
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp); nodep->deleteTree(); VL_DANGLING(nodep);
nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
else if (!m_inDly && nodep->lvalue()) {
//UINFO(9,"NBA "<<nodep<<endl);
@@ -444,10 +444,10 @@ private:
}
}
virtual void visit(AstNodeFor* nodep) {
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin");
}
virtual void visit(AstWhile* nodep) {
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
bool oldloop = m_inLoop;
m_inLoop = true;
iterateChildren(nodep);
@@ -456,7 +456,7 @@ private:
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+17 -14
View File
@@ -82,14 +82,17 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
m_modp = nodep;
m_funcp = NULL;
iterateChildren(nodep);
m_modp = NULL;
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
m_funcp = NULL;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
m_funcp = nodep;
m_depth = 0;
m_maxdepth = 0;
@@ -103,7 +106,7 @@ private:
iterateChildren(nodep);
m_stmtp = NULL;
}
virtual void visit(AstNodeStmt* nodep) {
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
if (!nodep->isStatement()) {
iterateChildren(nodep);
} else {
@@ -111,9 +114,9 @@ private:
}
}
// Operators
virtual void visit(AstNodeTermop* nodep) {
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
}
virtual void visit(AstNodeMath* nodep) {
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
// We have some operator defines that use 2 parens, so += 2.
m_depth += 2;
if (m_depth>m_maxdepth) m_maxdepth = m_depth;
@@ -135,24 +138,24 @@ private:
// (Here instead of new visitor after V3Descope just to avoid another visitor)
void needNonStaticFunc(AstNode* nodep) {
UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function");
if (m_funcp->isStatic().trueU()) {
if (m_funcp->isStatic().trueUnknown()) {
UINFO(5,"Mark non-public due to "<<nodep<<endl);
m_funcp->isStatic(false);
}
}
virtual void visit(AstUCFunc* nodep) {
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
needNonStaticFunc(nodep);
iterateChildren(nodep);
}
virtual void visit(AstUCStmt* nodep) {
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
needNonStaticFunc(nodep);
visitStmt(nodep);
}
//--------------------
// Default: Just iterate
virtual void visit(AstVar* nodep) {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+14 -11
View File
@@ -71,14 +71,17 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
m_modp = nodep;
m_deepNum = 0;
iterateChildren(nodep);
m_modp = NULL;
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
m_deepNum = 0;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
// We recurse into this.
int lastDepth = m_depth;
AstCFunc* lastFuncp = m_funcp;
@@ -93,7 +96,7 @@ private:
void visitStmt(AstNodeStmt* nodep) {
m_depth++;
if (m_depth > v3Global.opt.compLimitBlocks()
&& !VN_IS(nodep, CCall)) { // Already done
&& !VN_IS(nodep, NodeCCall)) { // Already done
UINFO(4, "DeepBlocks "<<m_depth<<" "<<nodep<<endl);
AstNode* backp = nodep->backp(); // Only for debug
if (debug()>=9) backp->dumpTree(cout, "- pre : ");
@@ -106,7 +109,7 @@ private:
}
m_depth--;
}
virtual void visit(AstNodeStmt* nodep) {
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
if (!nodep->isStatement()) {
iterateChildren(nodep);
} else {
@@ -114,11 +117,11 @@ private:
}
}
virtual void visit(AstNodeMath* nodep) {} // Accelerate
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Accelerate
//--------------------
// Default: Just iterate
virtual void visit(AstVar* nodep) {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+85 -91
View File
@@ -44,18 +44,18 @@ private:
// NODE STATE
// Cleared entire netlist
// AstCFunc::user() // bool. Indicates processing completed
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// TYPES
typedef std::multimap<string,AstCFunc*> FuncMmap;
typedef std::multimap<string, AstCFunc*> FuncMmap;
// STATE
AstNodeModule* m_modp; // Current module
AstScope* m_scopep; // Current scope
bool m_modSingleton; // m_modp is only instanced once
bool m_allowThis; // Allow function non-static
bool m_needThis; // Make function non-static
FuncMmap m_modFuncs; // Name of public functions added
AstNodeModule* m_modp; // Current module
AstScope* m_scopep; // Current scope
bool m_modSingleton; // m_modp is only instanced once
bool m_allowThis; // Allow function non-static
bool m_needThis; // Make function non-static
FuncMmap m_modFuncs; // Name of public functions added
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -63,7 +63,7 @@ private:
static bool modIsSingleton(AstNodeModule* modp) {
// True iff there's exactly one instance of this module in the design.
int instances = 0;
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (VN_IS(stmtp, Scope)) {
if (++instances > 1) { return false; }
}
@@ -81,8 +81,7 @@ private:
// Sets 'hierThisr' true if the object is local to this scope
// (and could be made into a function-local later in V3Localize),
// false if the object is in another scope.
string descopedName(const AstScope* scopep, bool& hierThisr,
const AstVar* varp=NULL) {
string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = NULL) {
UASSERT(scopep, "Var/Func not scoped");
hierThisr = (scopep == m_scopep);
@@ -97,7 +96,6 @@ private:
//
// Static functions can't use this
if (!m_allowThis) relativeRefOk = false;
//
// Use absolute refs in top-scoped routines, keep them static.
// The DPI callback registration depends on representing top-level
@@ -106,18 +104,15 @@ private:
//
// V3Combine wouldn't likely be able to combine top-level
// routines anyway, so there's no harm in keeping these static.
if (m_modp->isTop()) {
relativeRefOk = false;
}
UASSERT_OBJ(m_modp, scopep, "Scope not under module");
if (m_modp->isTop()) relativeRefOk = false;
//
// Use absolute refs if this scope is the only instance of the module.
// Saves a bit of overhead on passing the 'this' pointer, and there's no
// need to be nice to V3Combine when we have only a single instance.
// The risk that this prevents combining identical logic from differently-
// named but identical modules seems low.
if (m_modSingleton) {
relativeRefOk = false;
}
if (m_modSingleton) relativeRefOk = false;
if (varp && varp->isFuncLocal()) {
hierThisr = true;
@@ -130,23 +125,21 @@ private:
// Reference to scope of cell directly under this module, can just "cell->"
string name = scopep->name();
string::size_type pos;
if ((pos = name.rfind('.')) != string::npos) {
name.erase(0, pos+1);
}
if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1);
m_needThis = true;
return name+"->";
return name + "->";
} else {
// Reference to something elsewhere, or relative references
// are disabled. Use global variable
UINFO(8," Descope "<<scopep<<endl);
UINFO(8," to "<<scopep->name()<<endl);
UINFO(8," under "<<m_scopep->name()<<endl);
UINFO(8, " Descope " << scopep << endl);
UINFO(8, " to " << scopep->name() << endl);
UINFO(8, " under " << m_scopep->name() << endl);
if (!scopep->aboveScopep()) { // Top
// We could also return "vlSymsp->TOPp->" here, but GCC would
// suspect aliases.
return "vlTOPp->";
} else {
return scopep->nameVlSym()+".";
return scopep->nameVlSym() + ".";
}
}
}
@@ -155,64 +148,64 @@ private:
// We recorded all public functions in m_modFuncs.
// If for any given name only one function exists, we can use that function directly.
// If multiple functions exist, we need to select the appropriate scope.
for (FuncMmap::iterator it = m_modFuncs.begin(); it!=m_modFuncs.end(); ++it) {
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
string name = it->first;
AstCFunc* topFuncp = it->second;
FuncMmap::iterator nextIt1 = it; ++nextIt1;
bool moreOfSame1 = (nextIt1!=m_modFuncs.end() && nextIt1->first == name);
FuncMmap::iterator nextIt1 = it;
++nextIt1;
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
if (moreOfSame1) {
// Multiple functions under this name, need a wrapper function
UINFO(6," Wrapping "<<name<<" multifuncs\n");
UINFO(6, " Wrapping " << name << " multifuncs\n");
AstCFunc* newfuncp = topFuncp->cloneTree(false);
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
newfuncp->name(name);
newfuncp->isStatic(false);
newfuncp->addInitsp(
new AstCStmt(newfuncp->fileline(),
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(),
EmitCBaseVisitor::symTopAssign()+"\n"));
EmitCBaseVisitor::symClassVar() + " = this->__VlSymsp;\n"));
newfuncp->addInitsp(
new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
topFuncp->addNextHere(newfuncp);
// In the body, call each function if it matches the given scope
for (FuncMmap::iterator eachIt = it;
eachIt != m_modFuncs.end() && eachIt->first==name; ++eachIt) {
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
it = eachIt;
AstCFunc* funcp = eachIt->second;
FuncMmap::iterator nextIt2 = eachIt; ++nextIt2;
bool moreOfSame = (nextIt2!=m_modFuncs.end() && nextIt2->first == name);
FuncMmap::iterator nextIt2 = eachIt;
++nextIt2;
bool moreOfSame = (nextIt2 != m_modFuncs.end() && nextIt2->first == name);
UASSERT_OBJ(funcp->scopep(), funcp, "Not scoped");
UINFO(6," Wrapping "<<name<<" "<<funcp<<endl);
UINFO(6," at "<<newfuncp->argTypes()<<" und "<<funcp->argTypes()<<endl);
UINFO(6, " Wrapping " << name << " " << funcp << endl);
UINFO(6, " at " << newfuncp->argTypes()
<< " und " << funcp->argTypes() << endl);
funcp->declPrivate(true);
AstNode* argsp = NULL;
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* newp = new AstVarRef(portp->fileline(),
portp, portp->isWritable());
if (argsp) argsp = argsp->addNextNull(newp);
else argsp = newp;
AstNode* newp
= new AstVarRef(portp->fileline(), portp, portp->isWritable());
argsp = argsp ? argsp->addNextNull(newp) : newp;
}
}
}
AstNode* returnp = new AstCReturn(funcp->fileline(),
new AstCCall(funcp->fileline(),
funcp, argsp));
AstNode* returnp = new AstCReturn(
funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp));
if (moreOfSame) {
AstIf* ifp = new AstIf(funcp->fileline(),
new AstEq(funcp->fileline(),
new AstCMath(funcp->fileline(),
"this", 64),
new AstCMath(funcp->fileline(),
string("&(")
+funcp->scopep()->nameVlSym()
+")", 64)),
returnp, NULL);
AstIf* ifp = new AstIf(
funcp->fileline(),
new AstEq(
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64),
new AstCMath(funcp->fileline(),
string("&(") + funcp->scopep()->nameVlSym() + ")",
64)),
returnp, NULL);
newfuncp->addStmtsp(ifp);
} else {
newfuncp->addStmtsp(returnp);
@@ -220,68 +213,70 @@ private:
}
// Not really any way the user could do this, and we'd need
// to come up with some return value
//newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
// AstDisplayType::DT_WARNING,
// string("%%Error: ")+name+"() called with bad scope", NULL));
//newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
if (debug()>=9) newfuncp->dumpTree(cout, " newfunc: ");
// string("%%Error: ")+name+"() called with bad
// scope", NULL));
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
if (debug() >= 9) newfuncp->dumpTree(cout, " newfunc: ");
} else {
// Only a single function under this name, we can simply rename it
UINFO(6," Wrapping "<<name<<" just one "<<topFuncp<<endl);
UINFO(6, " Wrapping " << name << " just one " << topFuncp << endl);
topFuncp->name(name);
}
}
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_modFuncs.clear();
m_modSingleton = modIsSingleton(m_modp);
iterateChildren(nodep);
makePublicFuncWrappers();
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
m_modFuncs.clear();
m_modSingleton = modIsSingleton(m_modp);
iterateChildren(nodep);
makePublicFuncWrappers();
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
m_scopep = nodep;
iterateChildren(nodep);
m_scopep = NULL;
}
virtual void visit(AstVarScope* nodep) {
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
// Delete the varscope when we're finished
nodep->unlinkFrBack();
pushDeletep(nodep);
}
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Convert the hierch name
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
bool hierThis;
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis/*ref*/,
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis /*ref*/,
nodep->varScopep()->varp()));
nodep->hierThis(hierThis);
nodep->varScopep(NULL);
}
virtual void visit(AstCCall* nodep) {
//UINFO(9," "<<nodep<<endl);
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
// UINFO(9," "<<nodep<<endl);
iterateChildren(nodep);
// Convert the hierch name
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
UASSERT_OBJ(nodep->funcp()->scopep(), nodep, "CFunc not under scope");
bool hierThis;
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis/*ref*/));
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis /*ref*/));
// Can't do this, as we may have more calls later
// nodep->funcp()->scopep(NULL);
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
if (!nodep->user1()) {
m_needThis = false;
m_allowThis = nodep->isStatic().falseU(); // Non-static or unknown if static
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
iterateChildren(nodep);
nodep->user1(true);
if (m_needThis) {
nodep->isStatic(false);
}
if (m_needThis) nodep->isStatic(false);
// If it's under a scope, move it up to the top
if (m_scopep) {
nodep->unlinkFrBack();
@@ -291,23 +286,22 @@ private:
// There may be multiple public functions by the same name;
// record for later correction or making of shells
m_modFuncs.insert(make_pair(nodep->name(), nodep));
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
nodep->name(m_scopep->nameDotless() + "__" + nodep->name());
}
}
}
}
virtual void visit(AstVar*) {}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
}
virtual void visit(AstVar*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit DescopeVisitor(AstNetlist* nodep)
: m_modp(NULL),
m_scopep(NULL),
m_modSingleton(false),
m_allowThis(false),
m_needThis(false) {
: m_modp(NULL)
, m_scopep(NULL)
, m_modSingleton(false)
, m_allowThis(false)
, m_needThis(false) {
iterate(nodep);
}
virtual ~DescopeVisitor() {}
+577 -367
View File
File diff suppressed because it is too large Load Diff
+10 -4
View File
@@ -56,11 +56,17 @@ public:
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
static string symTopAssign() {
return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
static string modClassName(AstNodeModule* modp) { // Return name of current module being processed
if (modp->isTop()) {
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
if (nodep->isConstructor()) return prefixNameProtect(modp);
else if (nodep->isDestructor()) return string("~") + prefixNameProtect(modp);
else return nodep->nameProtect();
}
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule);
if (modp && modp->isTop()) {
return v3Global.opt.prefix();
} else {
return v3Global.opt.modPrefix()+"_"+protect(modp->name());
return v3Global.opt.modPrefix() + "_" + protect(nodep->name());
}
}
static string topClassName() { // Return name of top wrapper module
@@ -108,7 +114,7 @@ private:
// MEMBERS
int m_count; // Number of statements
// VISITORS
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
m_count++;
iterateChildren(nodep);
}
+31 -10
View File
@@ -40,47 +40,68 @@ class EmitCInlines : EmitCBaseVisitor {
void emitInt();
// VISITORS
virtual void visit(AstBasicDType* nodep) {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
if (nodep->keyword() == AstBasicDTypeKwd::STRING) {
// Request #include <string> via verilated_heavy.h when we create symbol file
v3Global.needHeavy(true);
}
}
virtual void visit(AstAssocArrayDType* nodep) {
virtual void visit(AstAssocArrayDType* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstQueueDType* nodep) {
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstValuePlusArgs* nodep) {
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstAtoN* nodep) {
virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstPutcN* nodep) {
virtual void visit(AstValuePlusArgs* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstGetcN* nodep) {
virtual void visit(AstNew* nodep) VL_OVERRIDE {
if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new");
iterateChildren(nodep);
}
virtual void visit(AstAtoN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstSubstrN* nodep) {
virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {
if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstCompareNN* nodep) {
virtual void visit(AstPutcN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstGetcN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstGetcRefN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstSubstrN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstCompareNN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
//---------------------------------------
+4 -4
View File
@@ -125,8 +125,8 @@ class CMakeEmitter {
*of << "\n### Sources...\n";
std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global;
for (AstFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_CAST(nodep->nextp(), File)) {
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source()) {
if (cfilep->support()) {
@@ -160,13 +160,13 @@ class CMakeEmitter {
}
if (v3Global.opt.trace()) {
global.push_back("${VERILATOR_ROOT}/include/"
+ v3Global.opt.traceSourceName()+"_c.cpp");
+ v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
}
global.push_back("${VERILATOR_ROOT}/include/"
+ v3Global.opt.traceSourceName()+"_sc.cpp");
+ v3Global.opt.traceSourceLang() + ".cpp");
}
}
if (v3Global.opt.mtasks()) {
+67 -47
View File
@@ -110,7 +110,10 @@ class EmitCSyms : EmitCBaseVisitor {
void nameCheck(AstNode* nodep) {
// Prevent GCC compile time error; name check all things that reach C++ code
if (nodep->name() != "") {
if (nodep->name() != ""
&& !(VN_IS(nodep, CFunc)
&& (VN_CAST(nodep, CFunc)->isConstructor()
|| VN_CAST(nodep, CFunc)->isDestructor()))) {
string rsvd = m_words.isKeyword(nodep->name());
if (rsvd != "") {
// Generally V3Name should find all of these and throw SYMRSVDWORD.
@@ -244,7 +247,7 @@ class EmitCSyms : EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
// Collect list of scopes
iterateChildren(nodep);
varsExpand();
@@ -268,13 +271,16 @@ class EmitCSyms : EmitCBaseVisitor {
if (!m_dpiHdrOnly) emitDpiImp();
}
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
nameCheck(nodep);
m_modp = nodep;
iterateChildren(nodep);
m_modp = NULL;
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstCellInline* nodep) {
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
if (v3Global.opt.vpi()) {
string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER"
: "SCOPE_MODULE";
@@ -284,18 +290,19 @@ class EmitCSyms : EmitCBaseVisitor {
name_dedot, type)));
}
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
nameCheck(nodep);
m_scopes.push_back(make_pair(nodep, m_modp));
if (v3Global.opt.vpi() && !nodep->isTop()) {
string name_dedot = AstNode::dedotName(nodep->shortName());
m_vpiScopeCandidates.insert(make_pair(nodep->name(),
ScopeData(scopeSymString(nodep->name()),
nodep->name(), "SCOPE_MODULE")));
name_dedot, "SCOPE_MODULE")));
}
}
virtual void visit(AstScopeName* nodep) {
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
string name = nodep->scopeSymName();
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()<<" ss "<<name<<endl);
if (m_scopeNames.find(name) == m_scopeNames.end()) {
@@ -315,7 +322,7 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
}
virtual void visit(AstVar* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
nameCheck(nodep);
iterateChildren(nodep);
if (nodep->isSigUserRdPublic()
@@ -323,13 +330,13 @@ class EmitCSyms : EmitCBaseVisitor {
m_modVars.push_back(make_pair(m_modp, nodep));
}
}
virtual void visit(AstCoverDecl* nodep) {
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
// Assign numbers to all bins, so we know how big of an array to use
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
nodep->binNum(m_coverBins++);
}
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
nameCheck(nodep);
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
m_dpis.push_back(nodep);
@@ -339,9 +346,9 @@ class EmitCSyms : EmitCBaseVisitor {
m_funcp = NULL;
}
// NOPs
virtual void visit(AstConst*) {}
virtual void visit(AstConst*) VL_OVERRIDE {}
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
//---------------------------------------
@@ -383,11 +390,10 @@ void EmitCSyms::emitSymHdr() {
puts("#include \"verilated.h\"\n");
}
// for
puts("\n// INCLUDE MODULE CLASSES\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) {
puts("#include \""+modClassName(nodep)+".h\"\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
if (v3Global.dpi()) {
@@ -411,6 +417,14 @@ void EmitCSyms::emitSymHdr() {
puts("\n// LOCAL STATE\n");
puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert.
if (v3Global.needTraceDumper()) {
// __Vm_dumperp is local, otherwise we wouldn't know what design's eval()
// should call a global dumpperp
puts("bool __Vm_dumping; // Dumping is active\n");
puts("VerilatedMutex __Vm_dumperMutex; // Protect __Vm_dumperp\n");
puts(v3Global.opt.traceClassLang()
+ "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex); /// Trace class for $dump*\n");
}
if (v3Global.opt.trace()) {
puts("bool __Vm_activity; ///< Used by trace routines to determine change occurred\n");
}
@@ -418,20 +432,23 @@ void EmitCSyms::emitSymHdr() {
puts("\n// SUBCELL STATE\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
if (modp->isTop()) {
ofp()->printf("%-30s ", (modClassName(modp)+"*").c_str());
puts(protectIf(scopep->nameDotless()+"p", scopep->protect())+";\n");
}
else {
ofp()->printf("%-30s ", (modClassName(modp)+"").c_str());
puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n");
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str());
puts(protectIf(scopep->nameDotless() + "p", scopep->protect()) + ";\n");
} else {
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "").c_str());
puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
}
}
if (m_coverBins) {
puts("\n// COVERAGE\n");
puts("uint32_t __Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
puts(v3Global.opt.threads() ? "std::atomic<uint32_t>" : "uint32_t");
puts(" __Vcoverage[");
puts(cvtToStr(m_coverBins));
puts("];\n");
}
if (!m_scopeNames.empty()) { // Scope names
@@ -471,7 +488,7 @@ void EmitCSyms::emitSymHdr() {
puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n");
}
puts("\n");
puts("} VL_ATTR_ALIGNED(64);\n");
puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n");
ofp()->putsEndGuard();
}
@@ -480,8 +497,7 @@ void EmitCSyms::closeSplit() {
if (!m_ofp || m_ofp == m_ofpBase) return;
puts("}\n");
delete m_ofp;
m_ofp = NULL;
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
}
void EmitCSyms::checkSplit(bool usesVfinal) {
@@ -522,9 +538,9 @@ void EmitCSyms::emitSymImpPreamble() {
// Includes
puts("#include \""+symClassName()+".h\"\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) {
puts("#include \""+modClassName(nodep)+".h\"\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
}
@@ -574,19 +590,22 @@ void EmitCSyms::emitSymImp() {
puts("\n// FUNCTIONS\n");
puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n");
puts(" // Setup locals\n");
puts(" : __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed
if (v3Global.opt.trace()) {
puts(" , __Vm_activity(false)\n");
puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed
if (v3Global.needTraceDumper()) {
puts(" , __Vm_dumping(false)\n");
puts(" , __Vm_dumperp(NULL)\n");
}
if (v3Global.opt.trace()) puts(" , __Vm_activity(false)\n");
puts(" , __Vm_didInit(false)\n");
puts(" // Setup submodule names\n");
char comma=',';
char comma = ',';
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
if (modp->isTop()) {
} else {
puts(string(" ")+comma+" "+protect(scopep->nameDotless()));
puts("(Verilated::catName(topp->name(),");
puts(string(" ") + comma + " " + protect(scopep->nameDotless()));
puts("(Verilated::catName(topp->name(), ");
// The "." is added by catName
putsQuoted(protectWordsIf(scopep->prettyName(), scopep->protect()));
puts("))\n");
@@ -600,7 +619,8 @@ void EmitCSyms::emitSymImp() {
puts("TOPp = topp;\n");
puts("// Setup each module's pointers to their submodules\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
if (!modp->isTop()) {
checkSplit(false);
string arrow = scopep->name();
@@ -609,10 +629,9 @@ void EmitCSyms::emitSymImp() {
arrow.replace(pos, 1, "->");
}
if (arrow.substr(0, 5) == "TOP->") arrow.replace(0, 5, "TOPp->");
string arrowProt = protectWordsIf(arrow, scopep->protect());
ofp()->printf("%-30s ", arrowProt.c_str());
ofp()->puts(protectWordsIf(arrow, scopep->protect()));
puts(" = &");
puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n");
puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
++m_numStmts;
}
}
@@ -620,7 +639,8 @@ void EmitCSyms::emitSymImp() {
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
puts("TOPp->"+protect("__Vconfigure")+"(this, true);\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
if (!modp->isTop()) {
checkSplit(false);
// first is used by AstCoverDecl's call to __vlCoverInsert
@@ -693,7 +713,7 @@ void EmitCSyms::emitSymImp() {
puts(protect("__Vscope_"+scopep->scopeSymName())+".exportInsert(__Vfinal, ");
putsQuoted(funcp->cname()); // Not protected - user asked for import/export
puts(", (void*)(&");
puts(modClassName(modp));
puts(prefixNameProtect(modp));
puts("::");
puts(funcp->nameProtect());
puts("));\n");
@@ -775,7 +795,7 @@ void EmitCSyms::emitDpiHdr() {
puts("// DESCR" "IPTION: Verilator output: Prototypes for DPI import and export functions.\n");
puts("//\n");
puts("// Verilator includes this file in all generated .cpp files that use DPI functions.\n");
puts("// Manually include this file where DPI .c import functions are declared to insure\n");
puts("// Manually include this file where DPI .c import functions are declared to ensure\n");
puts("// the C functions match the expectations of the DPI imports.\n");
puts("\n");
puts("#include \"svdpi.h\"\n");
+6 -6
View File
@@ -55,7 +55,7 @@ public:
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
of.puts("# Tracing threadeds output mode? 0/1 (from --trace-fst-thread)\n");
of.puts("# Tracing threaded output mode? 0/1 (from --trace-fst-thread)\n");
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
?"1":"0"); of.puts("\n");
@@ -85,12 +85,12 @@ public:
putMakeClassEntry(of, "verilated_cov.cpp");
}
if (v3Global.opt.trace()) {
putMakeClassEntry(of, v3Global.opt.traceSourceName()+"_c.cpp");
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
} else {
putMakeClassEntry(of, v3Global.opt.traceSourceName()+"_sc.cpp");
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
}
}
}
@@ -101,8 +101,8 @@ public:
else if (support==2 && slow) {
}
else {
for (AstFile* nodep = v3Global.rootp()->filesp();
nodep; nodep = VN_CAST(nodep->nextp(), File)) {
for (AstNodeFile* nodep = v3Global.rootp()->filesp();
nodep; nodep = VN_CAST(nodep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source()
&& cfilep->slow()==(slow!=0)
@@ -189,7 +189,7 @@ public:
string cppfile = *it;
of.puts("\t"+V3Os::filenameNonExt(cppfile)+" \\\n");
string dir = V3Os::filenameDir(cppfile);
if (dirs.find(dir) == dirs.end()) dirs.insert(dir);
dirs.insert(dir);
}
of.puts("\n");
+96 -101
View File
@@ -57,15 +57,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstNodeModule* nodep) {
putfs(nodep, nodep->verilogKwd()+" "+modClassName(nodep)+";\n");
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
iterateChildren(nodep);
putqs(nodep, "end"+nodep->verilogKwd()+"\n");
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
}
virtual void visit(AstNodeFTask* nodep) {
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
putfs(nodep, nodep->isFunction() ? "function":"task");
puts(" ");
puts(nodep->prettyName());
@@ -75,8 +75,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putqs(nodep, "end\n");
}
virtual void visit(AstBegin* nodep) {
if (nodep->unnamed()) {
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
if (nodep->name() == "") {
putbs("begin\n");
} else {
putbs("begin : "+nodep->name()+"\n");
@@ -84,22 +84,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateChildren(nodep);
puts("end\n");
}
virtual void visit(AstGenerate* nodep) {
putfs(nodep, "generate\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstFinal* nodep) {
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
putfs(nodep, "final begin\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstInitial* nodep) {
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
putfs(nodep, "initial begin\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
putfs(nodep, "always ");
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
else iterateAndNextNull(nodep->sensesp());
@@ -107,7 +102,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstAlwaysPublic* nodep) {
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
putfs(nodep, "/*verilator public_flat_rw ");
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
else iterateAndNextNull(nodep->sensesp());
@@ -115,37 +110,37 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "*/\n");
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " "+nodep->verilogKwd()+" ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAssignDly* nodep) {
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " <= ");
iterateAndNextNull(nodep->rhsp());
puts(";\n");
}
virtual void visit(AstAssignAlias* nodep) {
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
putbs("alias ");
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " = ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
putfs(nodep, "assign ");
iterateAndNextNull(nodep->lhsp());
putbs(" = ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstBreak* nodep) {
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
putbs("break");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstSenTree* nodep) {
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
// AstSenItem is called for dumping in isolation by V3Order
putfs(nodep, "@(");
for (AstNode* expp=nodep->sensesp(); expp; expp = expp->nextp()) {
@@ -154,16 +149,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(")");
}
virtual void visit(AstSenGate* nodep) {
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp());
}
virtual void visit(AstSenItem* nodep) {
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
putfs(nodep, "");
puts(nodep->edgeType().verilogKwd());
if (nodep->sensp()) puts(" ");
iterateChildren(nodep);
}
virtual void visit(AstNodeCase* nodep) {
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
putfs(nodep, "");
if (const AstCase* casep = VN_CAST(nodep, Case)) {
if (casep->priorityPragma()) puts("priority ");
@@ -184,7 +179,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->itemsp());
putqs(nodep, "endcase\n");
}
virtual void visit(AstCaseItem* nodep) {
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
if (nodep->condsp()) {
iterateAndNextNull(nodep->condsp());
} else putbs("default");
@@ -192,17 +187,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstComment* nodep) {
virtual void visit(AstComment* nodep) VL_OVERRIDE {
puts(string("// ")+nodep->name()+"\n");
iterateChildren(nodep);
}
virtual void visit(AstContinue* nodep) {
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
putbs("continue");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstCoverDecl*) {} // N/A
virtual void visit(AstCoverInc*) {} // N/A
virtual void visit(AstCoverToggle*) {} // N/A
virtual void visit(AstCoverDecl*) VL_OVERRIDE {} // N/A
virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp,
const string& text, AstNode* exprsp) {
@@ -216,28 +211,28 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(");\n");
}
virtual void visit(AstDisable* nodep) {
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
putbs("disable "+nodep->name()+";\n");
}
virtual void visit(AstDisplay* nodep) {
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstElabDisplay* nodep) {
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, NULL, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstFScanF* nodep) {
virtual void visit(AstFScanF* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSScanF* nodep) {
virtual void visit(AstSScanF* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSFormat* nodep) {
virtual void visit(AstSFormat* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstSFormatF* nodep) {
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep) {
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
@@ -247,27 +242,27 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
if (nodep->modep()) iterateAndNextNull(nodep->modep());
puts(");\n");
}
virtual void visit(AstFClose* nodep) {
virtual void visit(AstFClose* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstFFlush* nodep) {
virtual void visit(AstFFlush* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstJumpGo* nodep) {
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
putbs("disable "+cvtToHex(nodep->labelp())+";\n");
}
virtual void visit(AstJumpLabel* nodep) {
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
putbs("begin : "+cvtToHex(nodep)+"\n");
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
puts("end\n");
}
virtual void visit(AstNodeReadWriteMem* nodep) {
virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
@@ -277,17 +272,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
if (nodep->msbp()) { putbs(","); iterateAndNextNull(nodep->msbp()); }
puts(");\n");
}
virtual void visit(AstSysFuncAsTask* nodep) {
virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstSysIgnore* nodep) {
virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
iterateAndNextNull(nodep->exprsp());
puts(");\n");
}
virtual void visit(AstNodeFor* nodep) {
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
putfs(nodep, "for (");
m_suppressSemi = true;
iterateAndNextNull(nodep->initsp());
@@ -300,14 +295,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstRepeat* nodep) {
virtual void visit(AstRepeat* nodep) VL_OVERRIDE {
putfs(nodep, "repeat (");
iterateAndNextNull(nodep->countp());
puts(") begin\n");
iterateAndNextNull(nodep->bodysp());
putfs(nodep, "end\n");
}
virtual void visit(AstWhile* nodep) {
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->precondsp());
putfs(nodep, "while (");
iterateAndNextNull(nodep->condp());
@@ -317,7 +312,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
putfs(nodep, "end\n");
}
virtual void visit(AstNodeIf* nodep) {
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
putfs(nodep, "");
if (const AstIf* ifp = VN_CAST(nodep, If)) {
if (ifp->priorityPragma()) puts("priority ");
@@ -335,7 +330,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
putqs(nodep, "end\n");
}
virtual void visit(AstPast* nodep) {
virtual void visit(AstPast* nodep) VL_OVERRIDE {
putfs(nodep, "$past(");
iterateAndNextNull(nodep->exprp());
if (nodep->ticksp()) {
@@ -344,49 +339,49 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(")");
}
virtual void visit(AstReturn* nodep) {
virtual void visit(AstReturn* nodep) VL_OVERRIDE {
putfs(nodep, "return ");
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstStop* nodep) {
virtual void visit(AstStop* nodep) VL_OVERRIDE {
putfs(nodep, "$stop;\n");
}
virtual void visit(AstFinish* nodep) {
virtual void visit(AstFinish* nodep) VL_OVERRIDE {
putfs(nodep, "$finish;\n");
}
virtual void visit(AstText* nodep) {
virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE {
if (nodep->tracking() || m_trackText) {
puts(nodep->text());
} else {
putsNoTracking(nodep->text());
}
}
virtual void visit(AstTextBlock* nodep) {
visit(VN_CAST(nodep, Text));
virtual void visit(AstTextBlock* nodep) VL_OVERRIDE {
visit(VN_CAST(nodep, NodeSimpleText));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
}
}
virtual void visit(AstScopeName* nodep) {
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
}
virtual void visit(AstCStmt* nodep) {
virtual void visit(AstCStmt* nodep) VL_OVERRIDE {
putfs(nodep, "$_CSTMT(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstCMath* nodep) {
virtual void visit(AstCMath* nodep) VL_OVERRIDE {
putfs(nodep, "$_CMATH(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstUCStmt* nodep) {
virtual void visit(AstUCStmt* nodep) VL_OVERRIDE {
putfs(nodep, "$c(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstUCFunc* nodep) {
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
putfs(nodep, "$c(");
iterateAndNextNull(nodep->bodysp());
puts(")");
@@ -444,19 +439,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
}
virtual void visit(AstNodeTermop* nodep) {
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog());
}
virtual void visit(AstNodeUniop* nodep) {
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
}
virtual void visit(AstNodeBiop* nodep) {
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) {
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
}
virtual void visit(AstAttrOf* nodep) {
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
putfs(nodep, "$_ATTROF(");
iterateAndNextNull(nodep->fromp());
if (nodep->dimp()) {
@@ -465,7 +460,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(")");
}
virtual void visit(AstInitArray* nodep) {
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
putfs(nodep, "`{");
int comma = 0;
const AstInitArray::KeyItemMap& mapr = nodep->map();
@@ -479,13 +474,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts("}");
}
virtual void visit(AstNodeCond* nodep) {
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
putbs("(");
iterateAndNextNull(nodep->condp()); putfs(nodep, " ? ");
iterateAndNextNull(nodep->expr1p()); putbs(" : ");
iterateAndNextNull(nodep->expr2p()); puts(")");
}
virtual void visit(AstRange* nodep) {
virtual void visit(AstRange* nodep) VL_OVERRIDE {
puts("[");
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
@@ -496,7 +491,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->rightp()); puts("]");
}
}
virtual void visit(AstSel* nodep) {
virtual void visit(AstSel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp()); puts("[");
if (VN_IS(nodep->lsbp(), Const)) {
if (nodep->widthp()->isOne()) {
@@ -518,44 +513,44 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts("]");
}
virtual void visit(AstSliceSel* nodep) {
virtual void visit(AstSliceSel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp());
puts(cvtToStr(nodep->declRange()));
}
virtual void visit(AstTypedef* nodep) {
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
putfs(nodep, "typedef ");
iterateAndNextNull(nodep->dtypep()); puts(" ");
puts(nodep->prettyName());
puts(";\n");
}
virtual void visit(AstBasicDType* nodep) {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
if (nodep->isSigned()) putfs(nodep, "signed ");
putfs(nodep, nodep->prettyName());
if (nodep->rangep()) { puts(" "); iterateAndNextNull(nodep->rangep()); puts(" "); }
else if (nodep->isRanged()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); }
}
virtual void visit(AstConstDType* nodep) {
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
putfs(nodep, "const ");
iterate(nodep->subDTypep());
}
virtual void visit(AstNodeArrayDType* nodep) {
virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE {
iterate(nodep->subDTypep());
iterateAndNextNull(nodep->rangep());
}
virtual void visit(AstNodeUOrStructDType* nodep) {
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
puts(nodep->verilogKwd()+" ");
if (nodep->packed()) puts("packed ");
puts("\n");
iterateAndNextNull(nodep->membersp());
puts("}");
}
virtual void visit(AstMemberDType* nodep) {
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
iterate(nodep->subDTypep());
puts(" ");
puts(nodep->name());
puts("}");
}
virtual void visit(AstNodeFTaskRef* nodep) {
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
if (nodep->dotted()!="") {
putfs(nodep, nodep->dotted()); puts("."); puts(nodep->prettyName());
} else { putfs(nodep, nodep->prettyName()); }
@@ -563,11 +558,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->pinsp());
puts(")");
}
virtual void visit(AstArg* nodep) {
virtual void visit(AstArg* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->exprp());
}
// Terminals
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varScopep()) {
putfs(nodep, nodep->varScopep()->prettyName());
} else {
@@ -575,43 +570,43 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(nodep->varp()->prettyName());
}
}
virtual void visit(AstVarXRef* nodep) {
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
putfs(nodep, nodep->dotted());
puts(".");
puts(nodep->varp()->prettyName());
}
virtual void visit(AstConst* nodep) {
virtual void visit(AstConst* nodep) VL_OVERRIDE {
putfs(nodep, nodep->num().ascii(true, true));
}
// Just iterate
virtual void visit(AstTopScope* nodep) {
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstVar* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
puts(" ");
iterate(nodep->dtypep()); puts(" ");
puts(nodep->prettyName());
if (!m_suppressVarSemi) puts(";\n"); else puts("\n");
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
m_sensesp = nodep->sensesp();
iterateAndNextNull(nodep->stmtsp());
m_sensesp = NULL;
}
virtual void visit(AstVarScope*) {}
virtual void visit(AstNodeText*) {}
virtual void visit(AstTraceDecl*) {}
virtual void visit(AstTraceInc*) {}
virtual void visit(AstVarScope*) VL_OVERRIDE {}
virtual void visit(AstNodeText*) VL_OVERRIDE {}
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
// NOPs
virtual void visit(AstPragma*) {}
virtual void visit(AstCell*) {} // Handled outside the Visit class
virtual void visit(AstPragma*) VL_OVERRIDE {}
virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
iterateChildren(nodep);
// Not v3fatalSrc so we keep processing
@@ -757,12 +752,12 @@ void V3EmitV::emitv() {
EmitVFileVisitor visitor (v3Global.rootp(), &of);
} else {
// Process each module in turn
for (AstNodeModule* modp = v3Global.rootp()->modulesp();
modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
V3OutVFile of (v3Global.opt.makeDir()
+"/"+EmitCBaseVisitor::modClassName(modp)+"__Vout.v");
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
V3OutVFile of(v3Global.opt.makeDir() + "/" + EmitCBaseVisitor::prefixNameProtect(modp)
+ "__Vout.v");
of.putsHeader();
EmitVFileVisitor visitor (modp, &of);
EmitVFileVisitor visitor(modp, &of);
}
}
}
@@ -779,8 +774,8 @@ void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os,
void V3EmitV::emitvFiles() {
UINFO(2,__FUNCTION__<<": "<<endl);
for (AstFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), File)) {
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), NodeFile)) {
AstVFile* vfilep = VN_CAST(filep, VFile);
if (vfilep && vfilep->tblockp()) {
V3OutVFile of(vfilep->name());
+31 -23
View File
@@ -71,6 +71,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
void outputTag(AstNode* nodep, string tag) {
if (tag=="") tag = VString::downcase(nodep->typeName());
puts("<"+tag+" "+nodep->fileline()->xml());
puts(" "+nodep->fileline()->xmlDetailedLocation());
if (VN_IS(nodep, NodeDType)) { puts(" id="); outputId(nodep); }
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
if (nodep->tag()!="") { puts(" tag="); putsQuoted(nodep->tag()); }
@@ -94,22 +95,22 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
// VISITORS
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
outputTag(nodep, "contassign"); // IEEE: vpiContAssign
outputChildrenEnd(nodep, "contassign");
}
virtual void visit(AstCell* nodep) {
virtual void visit(AstCell* nodep) VL_OVERRIDE {
outputTag(nodep, "instance"); // IEEE: vpiInstance
puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName
puts(" origName="); putsQuoted(nodep->origName());
outputChildrenEnd(nodep, "instance");
}
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
puts("<netlist>\n");
iterateChildren(nodep);
puts("</netlist>\n");
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" origName="); putsQuoted(nodep->origName());
if (nodep->level()==1 || nodep->level()==2) // ==2 because we don't add wrapper when in XML mode
@@ -117,7 +118,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
if (nodep->modPublic()) puts(" public=\"true\"");
outputChildrenEnd(nodep, "");
}
virtual void visit(AstVar* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
AstVarType typ = nodep->varType();
string kw = nodep->verilogKwd();
string vt = nodep->dtypep()->name();
@@ -131,18 +132,23 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
puts(" origName="); putsQuoted(nodep->origName());
// Attributes
if (nodep->attrClocker()) puts(" clocker=\"true\"");
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES)
puts(" clocker=\"true\"");
else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO)
puts(" clocker=\"false\"");
if (nodep->attrClockEn()) puts(" clock_enable=\"true\"");
if (nodep->attrIsolateAssign()) puts(" isolate_assignments=\"true\"");
if (nodep->isSigPublic()) puts(" public=\"true\"");
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
if (nodep->isGParam()) puts(" param=\"true\"");
else if (nodep->isParam()) puts(" localparam=\"true\"");
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
if (nodep->attrScClocked()) puts(" sc_clock=\"true\"");
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
outputChildrenEnd(nodep, "");
}
virtual void visit(AstPin* nodep) {
virtual void visit(AstPin* nodep) VL_OVERRIDE {
// What we call a pin in verilator is a port in the IEEE spec.
outputTag(nodep, "port"); // IEEE: vpiPort
if (nodep->modVarp()->isIO()) {
@@ -152,26 +158,26 @@ class EmitXmlFileVisitor : public AstNVisitor {
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
outputChildrenEnd(nodep, "port");
}
virtual void visit(AstSenItem* nodep) {
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" edgeType=\""+cvtToStr(nodep->edgeType().ascii())+"\""); // IEEE vpiTopModule
outputChildrenEnd(nodep, "");
}
virtual void visit(AstModportVarRef* nodep) {
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
// Dump direction for Modport references
string kw = nodep->direction().xmlKwd();
outputTag(nodep, "");
puts(" direction="); putsQuoted(kw);
outputChildrenEnd(nodep, "");
}
virtual void visit(AstVarXRef* nodep) {
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" dotted="); putsQuoted(nodep->dotted());
outputChildrenEnd(nodep, "");
}
// Data types
virtual void visit(AstBasicDType* nodep) {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
outputTag(nodep, "basicdtype");
if (nodep->isRanged()) {
puts(" left=\""+cvtToStr(nodep->left())+"\"");
@@ -179,30 +185,30 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
puts("/>\n");
}
virtual void visit(AstIfaceRefDType* nodep) {
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
string mpn;
outputTag(nodep, "");
if (nodep->isModport()) mpn = nodep->modportName();
puts(" modportname="); putsQuoted(mpn);
outputChildrenEnd(nodep, "");
}
virtual void visit(AstDisplay* nodep) {
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, "");
}
virtual void visit(AstElabDisplay* nodep) {
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, "");
}
virtual void visit(AstExtend* nodep) {
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
outputChildrenEnd(nodep, "");
}
virtual void visit(AstExtendS* nodep) {
virtual void visit(AstExtendS* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
@@ -210,7 +216,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
outputTag(nodep, "");
outputChildrenEnd(nodep, "");
}
@@ -237,11 +243,11 @@ private:
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
// Children are iterated backwards to ensure correct compilation order
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Only list modules and interfaces
// Assumes modules and interfaces list is already sorted level wise
if (!nodep->dead()
@@ -251,7 +257,7 @@ private:
}
}
//-----
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// All modules are present at root so no need to iterate on children
}
@@ -288,11 +294,12 @@ private:
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
if (nodep->level() >= 0
&& nodep->level() <=2 ) { // ==2 because we don't add wrapper when in XML mode
m_os<<"<cells>\n";
m_os<<"<cell "<<nodep->fileline()->xml()
<<" "<<nodep->fileline()->xmlDetailedLocation()
<<" name=\""<<nodep->name()<<"\""
<<" submodname=\""<<nodep->name()<<"\""
<<" hier=\""<<nodep->name()<<"\"";
@@ -307,12 +314,13 @@ private:
m_os<<"</cells>\n";
}
}
virtual void visit(AstCell* nodep) {
virtual void visit(AstCell* nodep) VL_OVERRIDE {
if (nodep->modp()->dead()) {
return;
}
if (!m_hasChildren) m_os<<">\n";
m_os<<"<cell "<<nodep->fileline()->xml()
<<" "<<nodep->fileline()->xmlDetailedLocation()
<<" name=\""<<nodep->name()<<"\""
<<" submodname=\""<<nodep->modName()<<"\""
<<" hier=\""<<m_hier+nodep->name()<<"\"";
@@ -329,7 +337,7 @@ private:
m_hasChildren = true;
}
//-----
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+13 -8
View File
@@ -102,6 +102,7 @@ public:
REDEFMACRO, // Redefining existing define macro
SELRANGE, // Selection index out of range
SHORTREAL, // Shortreal not supported
SPLITVAR, // Cannot split the variable
STMTDLY, // Delayed statement
SYMRSVDWORD, // Symbol is Reserved Word
SYNCASYNCNET, // Mixed sync + async reset
@@ -153,7 +154,7 @@ public:
"MULTIDRIVEN", "MULTITOP",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
"REALCVT", "REDEFMACRO",
"SELRANGE", "SHORTREAL", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"TICKCOUNT",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
"UNPACKED", "UNSIGNED", "UNUSED",
@@ -205,11 +206,15 @@ public:
|| m_e==UNDRIVEN
|| m_e==UNUSED
|| m_e==VARHIDDEN ); }
};
inline bool operator==(V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(V3ErrorCode::en lhs, V3ErrorCode rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, V3ErrorCode rhs) { return os<<rhs.ascii(); }
};
inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
return os << rhs.ascii();
}
//######################################################################
@@ -291,8 +296,8 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
// Theses allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
// Note the commas are the comma operator, not separating arguments. These are needed to insure
// evaluation order as otherwise we couldn't insure v3errorPrep is called first.
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
#define v3warnCode(code,msg) \
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
#define v3warnCodeFatal(code,msg) \
+31 -31
View File
@@ -80,7 +80,7 @@ private:
void replaceWithDelete(AstNode* nodep, AstNode* newp) {
newp->user1(1); // Already processed, don't need to re-iterate
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
AstNode* newWordAssign(AstNodeAssign* placep, int word, AstNode* lhsp, AstNode* rhsp) {
AstAssign* newp = new AstAssign(placep->fileline(),
@@ -306,7 +306,7 @@ private:
}
// VISITORS
virtual void visit(AstExtend* nodep) {
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->isWide()) {
@@ -328,7 +328,7 @@ private:
"extending larger thing into smaller?");
lhsp->dtypeFrom(nodep); // Just mark it, else nop
}
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) {
@@ -343,7 +343,7 @@ private:
return true;
}
virtual void visit(AstSel* nodep) {
virtual void visit(AstSel* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
@@ -443,7 +443,7 @@ private:
if (midp) newp = new AstOr(nodep->fileline(), midp, newp);
if (hip) newp = new AstOr(nodep->fileline(), hip, newp);
newp->dtypeFrom(nodep);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
else { // Long/Quad from Long/Quad
UINFO(8," SEL->SHIFT "<<nodep<<endl);
@@ -461,7 +461,7 @@ private:
newp = new AstCCast(newp->fileline(), newp, nodep);
}
newp->dtypeFrom(nodep);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
@@ -553,8 +553,8 @@ private:
rhsp, lsb)));
}
}
rhsp->deleteTree(); VL_DANGLING(rhsp);
destp->deleteTree(); VL_DANGLING(destp);
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
VL_DO_DANGLING(destp->deleteTree(), destp);
} else {
UINFO(8," ASSIGNSEL(const,narrow) "<<nodep<<endl);
if (destp->isQuad() && !rhsp->isQuad()) {
@@ -670,7 +670,7 @@ private:
}
}
virtual void visit(AstConcat* nodep) {
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->isWide()) {
@@ -693,7 +693,7 @@ private:
nodep->width()),
rhsp);
newp->dtypeFrom(nodep); // Unsigned
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) {
@@ -714,7 +714,7 @@ private:
return true;
}
virtual void visit(AstReplicate* nodep) {
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->isWide()) {
@@ -746,10 +746,10 @@ private:
newp);
newp->dtypeFrom(nodep); // Unsigned
}
lhsp->deleteTree(); // Never used
VL_DO_DANGLING(lhsp->deleteTree(), lhsp); // Never used
}
newp->dtypeFrom(nodep); // Unsigned
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) {
@@ -779,7 +779,7 @@ private:
return true;
}
virtual void visit(AstChangeXor* nodep) {
virtual void visit(AstChangeXor* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
@@ -791,7 +791,7 @@ private:
newAstWordSelClone(nodep->rhsp(), w));
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
void visitEqNeq(AstNodeBiop* nodep) {
@@ -816,13 +816,13 @@ private:
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
newp);
}
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
virtual void visit(AstEq* nodep) { visitEqNeq(nodep); }
virtual void visit(AstNeq* nodep) { visitEqNeq(nodep); }
virtual void visit(AstEq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
virtual void visit(AstNeq* nodep) VL_OVERRIDE { visitEqNeq(nodep); }
virtual void visit(AstRedOr* nodep) {
virtual void visit(AstRedOr* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
@@ -836,7 +836,7 @@ private:
newp = new AstNeq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
newp);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} else {
UINFO(8," REDOR->EQ "<<nodep<<endl);
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
@@ -844,10 +844,10 @@ private:
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
longOrQuadWidth(nodep), 0),
lhsp);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
virtual void visit(AstRedAnd* nodep) {
virtual void visit(AstRedAnd* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
@@ -870,17 +870,17 @@ private:
newp = new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(),
~VL_MASK_E(0)), newp);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} else {
UINFO(8," REDAND->EQ "<<nodep<<endl);
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newp = new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), wordMask(lhsp)),
lhsp);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
virtual void visit(AstRedXor* nodep) {
virtual void visit(AstRedXor* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
@@ -893,13 +893,13 @@ private:
}
newp = new AstRedXor(nodep->fileline(), newp);
UINFO(8," Wordize REDXORnew "<<newp<<endl);
replaceWithDelete(nodep, newp); VL_DANGLING(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
// which the inlined function does nicely.
}
virtual void visit(AstNodeStmt* nodep) {
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
if (!nodep->isStatement()) {
iterateChildren(nodep);
@@ -909,7 +909,7 @@ private:
iterateChildren(nodep);
m_stmtp = NULL;
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
m_stmtp = nodep;
iterateChildren(nodep);
@@ -948,15 +948,15 @@ private:
}
// Cleanup common code
if (did) {
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
m_stmtp = NULL;
}
//--------------------
// Default: Just iterate
virtual void visit(AstVar*) {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) {
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't hit varrefs under vars
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+1 -1
View File
@@ -594,7 +594,7 @@ protected:
// Just dispatch to the implementation
VInFilter::VInFilter(const string& command) { m_impp = new VInFilterImp(command); }
VInFilter::~VInFilter() { if (m_impp) delete m_impp; m_impp = NULL; }
VInFilter::~VInFilter() { if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = NULL); }
bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) {
if (!m_impp) v3fatalSrc("readWholefile on invalid filter");
+14 -1
View File
@@ -120,6 +120,7 @@ void VFileContent::pushText(const string& text) {
string VFileContent::getLine(int lineno) const {
// Return error text rather than asserting so the user isn't left without a message
// cppcheck-suppress negativeContainerIndex
if (VL_UNCOVERABLE(lineno < 0 || lineno >= (int)m_lines.size())) {
if (debug() || v3Global.opt.debugCheck()) {
return ("%Error-internal-contents-bad-ct"+cvtToStr(m_id)
@@ -158,6 +159,15 @@ FileLine::FileLine(FileLine::EmptySecret) {
}
}
const string FileLine::xmlDetailedLocation() const {
return "loc=\"" +
cvtToStr(filenameLetters()) + "," +
cvtToStr(firstLineno()) + "," +
cvtToStr(firstColumn()) + "," +
cvtToStr(lastLineno()) + "," +
cvtToStr(lastColumn()) + "\"";
}
string FileLine::lineDirectiveStrg(int enterExit) const {
char numbuf[20]; sprintf(numbuf, "%d", lastLineno());
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
@@ -341,7 +351,10 @@ void FileLine::v3errorEnd(std::ostringstream& str, const string& locationStr) {
if (!locationStr.empty()) {
lstr<<std::setw(ascii().length())<<" "<<": "<<locationStr;
}
if (warnIsOff(V3Error::errorCode())) V3Error::suppressThisWarning();
if (warnIsOff(V3Error::errorCode())
|| V3Config::waive(this, V3Error::errorCode(), str.str())) {
V3Error::suppressThisWarning();
}
else if (!V3Error::errorContexted()) nsstr<<warnContextPrimary();
V3Error::v3errorEnd(nsstr, lstr.str());
}
+3 -2
View File
@@ -119,7 +119,7 @@ private:
return *defFilelinep;
}
public:
FileLine(const string& filename) {
explicit FileLine(const string& filename) {
m_lastLineno = m_firstLineno = 0;
m_lastColumn = m_firstColumn = 0;
m_filenameno = singleton().nameToNumber(filename);
@@ -183,6 +183,7 @@ public:
const string filebasenameNoExt() const;
const string profileFuncname() const;
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lastLineno())+"\""; }
const string xmlDetailedLocation() const;
string lineDirectiveStrg(int enterExit) const;
// Turn on/off warning messages on this line.
@@ -239,7 +240,7 @@ public:
/// When building an error, additional location for additional references
/// Simplified information vs warnContextPrimary() to make dump clearer
string warnContextSecondary() const { return warnContext(true); }
bool operator==(FileLine rhs) const {
bool operator==(const FileLine& rhs) const {
return (m_firstLineno == rhs.m_firstLineno
&& m_firstColumn == rhs.m_firstColumn
&& m_lastLineno == rhs.m_lastLineno
+63 -58
View File
@@ -207,7 +207,7 @@ private:
}
}
// VISITORS
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
++m_ops;
iterateChildren(nodep);
// We only allow a LHS ref for the var being set, and a RHS ref for
@@ -235,7 +235,7 @@ private:
m_rhsVarRefs.push_back(nodep);
}
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
m_substTreep = nodep->rhsp();
if (!VN_IS(nodep->lhsp(), NodeVarRef)) {
clearSimple("ASSIGN(non-VARREF)");
@@ -258,7 +258,7 @@ private:
}
//--------------------
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// *** Special iterator
if (!m_isSimple) return; // Fastpath
if (++m_ops > v3Global.opt.gateStmts()) {
@@ -388,7 +388,7 @@ private:
void decomposeClkVectors();
// VISITORS
virtual void visit(AstNetlist* nodep) {
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
iterateChildren(nodep);
//if (debug()>6) m_graph.dump();
if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre");
@@ -419,20 +419,23 @@ private:
consumedMove();
replaceAssigns();
}
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_activeReducible = true;
iterateChildren(nodep);
m_modp = NULL;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
m_activeReducible = true;
iterateChildren(nodep);
}
m_modp = origModp;
}
virtual void visit(AstScope* nodep) {
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," SCOPE "<<nodep<<endl);
m_scopep = nodep;
m_logicVertexp = NULL;
iterateChildren(nodep);
m_scopep = NULL;
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Create required blocks and add to module
UINFO(4," BLOCK "<<nodep<<endl);
m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible
@@ -443,16 +446,18 @@ private:
m_activep = NULL;
m_activeReducible = true;
}
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
GateVarVertex* vvertexp = makeVarVertex(varscp);
UINFO(5," VARREF to "<<varscp<<endl);
if (m_inSenItem) vvertexp->setIsClock();
// For SYNCASYNCNET
if (m_inSenItem) varscp->user2(true);
if (m_inSenItem) {
vvertexp->setIsClock();
// For SYNCASYNCNET
varscp->user2(true);
}
else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) {
if (varscp->user2()) {
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
@@ -469,19 +474,19 @@ private:
}
}
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
}
virtual void visit(AstAlwaysPublic* nodep) {
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, "AlwaysPublic", NULL);
m_inSlow = lastslow;
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateNewStmt(nodep, "User C Function", "User C Function");
}
virtual void visit(AstSenItem* nodep) {
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
// Note we look at only AstSenItems, not AstSenGate's
// The gating term of a AstSenGate is normal logic
m_inSenItem = true;
@@ -492,33 +497,33 @@ private:
}
m_inSenItem = false;
}
virtual void visit(AstSenGate* nodep) {
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep, "Clock gater", "Clock gater");
}
virtual void visit(AstInitial* nodep) {
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
m_inSlow = lastslow;
}
virtual void visit(AstAssignAlias* nodep) {
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
iterateNewStmt(nodep, NULL, NULL);
}
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
iterateNewStmt(nodep, NULL, NULL);
}
virtual void visit(AstCoverToggle* nodep) {
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
iterateNewStmt(nodep, "CoverToggle", "CoverToggle");
}
virtual void visit(AstTraceInc* nodep) {
virtual void visit(AstTraceInc* nodep) VL_OVERRIDE {
bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, "Tracing", "Tracing");
m_inSlow = lastslow;
}
virtual void visit(AstConcat* nodep) {
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)
&& VN_CAST(nodep->backp(), NodeAssign)->lhsp()==nodep),
nodep, "Concat on LHS of assignment; V3Const should have deleted it");
@@ -527,7 +532,7 @@ private:
//--------------------
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (nodep->isOutputter() && m_logicVertexp) m_logicVertexp->setConsumed("outputter");
}
@@ -666,7 +671,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
varvertexp->propagateAttrClocksFrom(vvertexp);
}
// Remove the edge
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
++m_statRefs;
edgep = vvertexp->outBeginp();
}
@@ -674,7 +679,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
if (removedAllUsages) {
// Remove input links
while (V3GraphEdge* edgep = vvertexp->inBeginp()) {
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
// Clone tree so we remember it for tracing, and keep the pointer
// to the "ALWAYS" part of the tree as part of this statement
@@ -709,7 +714,7 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
it != rhsVarRefs.end(); ++it) {
AstVarScope* vscp = (*it)->varScopep();
if (varscopes.find(vscp) == varscopes.end()) varscopes.insert(vscp);
varscopes.insert(vscp);
}
for (V3GraphEdge* edgep = consumeVertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
GateVarVertex* consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top());
@@ -731,25 +736,25 @@ void GateVisitor::replaceAssigns() {
if (vscp->valuep() && !VN_IS(vscp->valuep(), NodeMath)) {
//if (debug()>9) vscp->dumpTree(cout, "-vscPre: ");
while (AstNode* delp = VN_CAST(vscp->valuep(), Comment)) {
delp->unlinkFrBack()->deleteTree(); VL_DANGLING(delp);
VL_DO_DANGLING(delp->unlinkFrBack()->deleteTree(), delp);
}
if (AstInitial* delp = VN_CAST(vscp->valuep(), Initial)) {
AstNode* bodyp = delp->bodysp();
bodyp->unlinkFrBackWithNext();
delp->replaceWith(bodyp);
delp->deleteTree(); VL_DANGLING(delp);
VL_DO_DANGLING(delp->deleteTree(), delp);
}
if (AstAlways* delp = VN_CAST(vscp->valuep(), Always)) {
AstNode* bodyp = delp->bodysp();
bodyp->unlinkFrBackWithNext();
delp->replaceWith(bodyp);
delp->deleteTree(); VL_DANGLING(delp);
VL_DO_DANGLING(delp->deleteTree(), delp);
}
if (AstNodeAssign* delp = VN_CAST(vscp->valuep(), NodeAssign)) {
AstNode* rhsp = delp->rhsp();
rhsp->unlinkFrBack();
delp->replaceWith(rhsp);
delp->deleteTree(); VL_DANGLING(delp);
VL_DO_DANGLING(delp->deleteTree(), delp);
}
//if (debug()>9) {vscp->dumpTree(cout, "-vscDone: "); cout<<endl;}
if (!VN_IS(vscp->valuep(), NodeMath)
@@ -805,7 +810,7 @@ void GateVisitor::consumedMove() {
// with "tracing-on" sensitivity
UINFO(8," Remove unconsumed "<<nodep<<endl);
nodep->unlinkFrBack();
pushDeletep(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
}
@@ -860,7 +865,7 @@ private:
void hashReplace(AstNode* oldp, AstNode* newp);
// VISITORS
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
if (nodep->varScopep() == m_elimVarScp) {
// Substitute in the new tree
// It's possible we substitute into something that will be reduced more later,
@@ -884,10 +889,10 @@ private:
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false);
hashReplace(nodep, substp);
nodep->replaceWith(substp);
nodep->deleteTree(); VL_DANGLING(nodep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -1066,7 +1071,7 @@ private:
bool m_dedupable; // Determined the assign to be dedupable
// VISITORS
virtual void visit(AstNodeAssign* assignp) {
virtual void visit(AstNodeAssign* assignp) VL_OVERRIDE {
if (m_dedupable) {
// I think we could safely dedupe an always block with multiple
// non-blocking statements, but erring on side of caution here
@@ -1077,7 +1082,7 @@ private:
}
}
}
virtual void visit(AstAlways* alwaysp) {
virtual void visit(AstAlways* alwaysp) VL_OVERRIDE {
if (m_dedupable) {
if (!m_always) {
m_always = true;
@@ -1091,7 +1096,7 @@ private:
// always @(...)
// if (...)
// foo = ...; // or foo <= ...;
virtual void visit(AstNodeIf* ifp) {
virtual void visit(AstNodeIf* ifp) VL_OVERRIDE {
if (m_dedupable) {
if (m_always && !m_ifCondp && !ifp->elsesp()) { //we're under an always, this is the first IF, and there's no else
m_ifCondp = ifp->condp();
@@ -1102,10 +1107,10 @@ private:
}
}
virtual void visit(AstComment*) {} // NOP
virtual void visit(AstComment*) VL_OVERRIDE {} // NOP
//--------------------
// Default
virtual void visit(AstNode*) {
virtual void visit(AstNode*) VL_OVERRIDE {
m_dedupable = false;
}
@@ -1207,7 +1212,7 @@ private:
dupVvertexp->propagateAttrClocksFrom(vvertexp);
// Remove inputs links
while (V3GraphEdge* inedgep = vvertexp->inBeginp()) {
inedgep->unlinkDelete(); VL_DANGLING(inedgep);
VL_DO_DANGLING(inedgep->unlinkDelete(), inedgep);
}
// replaceAssigns() does the deleteTree on lvertexNodep in a later step
AstNode* lvertexNodep = lvertexp->nodep();
@@ -1338,19 +1343,19 @@ private:
UINFO(5, "assemble to new sel: "<<newselp<<endl);
// replace preSel with newSel
preselp->replaceWith(newselp);
preselp->deleteTree(); VL_DANGLING(preselp);
VL_DO_DANGLING(preselp->deleteTree(), preselp);
// create new rhs for pre assignment
AstNode* newrhsp = new AstConcat(
m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false),
assignp->rhsp()->cloneTree(false));
AstNode* oldrhsp = m_assignp->rhsp();
oldrhsp->replaceWith(newrhsp);
oldrhsp->deleteTree(); VL_DANGLING(oldrhsp);
VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp);
m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(),
m_assignp->width()+assignp->width(),
AstNumeric::SIGNED);
// don't need to delete, will be handled
//assignp->unlinkFrBack(); assignp->deleteTree(); VL_DANGLING(assignp);
//assignp->unlinkFrBack(); VL_DO_DANGLING(assignp->deleteTree(), assignp);
// update the graph
{
@@ -1362,11 +1367,11 @@ private:
GateEitherVertex* fromvp
= dynamic_cast<GateEitherVertex*>(oedgep->fromp());
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
oedgep->unlinkDelete(); VL_DANGLING(oedgep);
VL_DO_DANGLING(oedgep->unlinkDelete(), oedgep);
}
}
// delete all outedges to lvertexp, only one
oldedgep->unlinkDelete(); VL_DANGLING(oldedgep);
VL_DO_DANGLING(oldedgep->unlinkDelete(), oldedgep);
}
++m_numMergedAssigns;
} else {
@@ -1425,7 +1430,7 @@ private:
bool m_found; // Offset found
// VISITORS
virtual void visit(AstNodeVarRef* nodep) {
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
UINFO(9,"CLK DECOMP Concat search var (off = "<<m_offset<<") - "<<nodep<<endl);
if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) {
// A concatenation may use the same var multiple times
@@ -1437,14 +1442,14 @@ private:
}
m_offset += nodep->dtypep()->width();
}
virtual void visit(AstConcat* nodep) {
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
UINFO(9,"CLK DECOMP Concat search (off = "<<m_offset<<") - "<<nodep<<endl);
iterate(nodep->rhsp());
iterate(nodep->lhsp());
}
//--------------------
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -1556,7 +1561,7 @@ private:
AstNode* rhsp = assignp->rhsp();
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep; ) {
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1);
m_total_decomposed_clk_vectors++;
@@ -1617,19 +1622,19 @@ void GateVisitor::decomposeClkVectors() {
class GateDeassignVisitor : public GateBaseVisitor {
private:
// VISITORS
virtual void visit(AstVarScope* nodep) {
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
if (AstNodeAssign* assp = VN_CAST(nodep->valuep(), NodeAssign)) {
UINFO(5," Removeassign "<<assp<<endl);
AstNode* valuep = assp->rhsp();
valuep->unlinkFrBack();
assp->replaceWith(valuep);
assp->deleteTree(); VL_DANGLING(assp);
VL_DO_DANGLING(assp->deleteTree(), assp);
}
}
// Speedups
virtual void visit(AstVar* nodep) {}
virtual void visit(AstActive* nodep) {}
virtual void visit(AstNode* nodep) {
virtual void visit(AstVar* nodep) VL_OVERRIDE {}
virtual void visit(AstActive* nodep) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
+15 -15
View File
@@ -83,7 +83,7 @@ private:
}
// VISITORS
virtual void visit(AstTopScope* nodep) {
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
AstNode::user2ClearTree(); // user2p() used on entire tree
AstScope* scopep = nodep->scopep();
@@ -93,7 +93,7 @@ private:
iterateChildren(nodep);
}
//----
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
// Consumption/generation of a variable,
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
@@ -105,23 +105,23 @@ private:
AstVarScope* newvscp = genInpClk(vscp);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
nodep->replaceWith(newrefp);
pushDeletep(nodep); VL_DANGLING(nodep);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterateChildren(nodep->sensesp()); // iterateAndNext?
m_activep = NULL;
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
//-----
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
@@ -152,7 +152,7 @@ private:
AstNodeModule* m_topModp; // Top module
// VISITORS
virtual void visit(AstTopScope* nodep) {
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
AstNode::user1ClearTree(); // user1p() used on entire tree
iterateChildren(nodep);
{
@@ -161,14 +161,14 @@ private:
GenClkRenameVisitor visitor (nodep, m_topModp);
}
}
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Only track the top scopes, not lower level functions
if (nodep->isTop()) {
m_topModp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstCCall* nodep) {
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!nodep->funcp()->entryPoint()) {
// Enter the function and trace it
@@ -176,7 +176,7 @@ private:
iterate(nodep->funcp());
}
}
virtual void visit(AstCFunc* nodep) {
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
if (!m_tracingCall && !nodep->entryPoint()) {
// Only consider logic within a CFunc when looking
// at the call to it, and not when scanning whatever
@@ -188,7 +188,7 @@ private:
}
//----
virtual void visit(AstVarRef* nodep) {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
// Consumption/generation of a variable,
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
@@ -203,13 +203,13 @@ private:
vscp->circular(true);
}
}
virtual void visit(AstNodeAssign* nodep) {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
//UINFO(8,"ASS "<<nodep<<endl);
m_assignp = nodep;
iterateChildren(nodep);
m_assignp = NULL;
}
virtual void visit(AstActive* nodep) {
virtual void visit(AstActive* nodep) VL_OVERRIDE {
UINFO(8,"ACTIVE "<<nodep<<endl);
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
@@ -219,8 +219,8 @@ private:
}
//-----
virtual void visit(AstVar*) {} // Don't want varrefs under it
virtual void visit(AstNode* nodep) {
virtual void visit(AstVar*) VL_OVERRIDE {} // Don't want varrefs under it
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
public:
+86
View File
@@ -0,0 +1,86 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Common implemenetations
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2004-2020 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3Global.h"
#include "V3Ast.h"
#include "V3File.h"
#include "V3LinkCells.h"
#include "V3Parse.h"
#include "V3ParseSym.h"
#include "V3Stats.h"
//######################################################################
// V3 Class -- top level
AstNetlist* V3Global::makeNetlist() {
AstNetlist* newp = new AstNetlist();
newp->addTypeTablep(new AstTypeTable(newp->fileline()));
return newp;
}
void V3Global::checkTree() { rootp()->checkTree(); }
void V3Global::clear() {
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = NULL);
}
void V3Global::readFiles() {
// NODE STATE
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
AstUser4InUse inuser4;
VInFilter filter(v3Global.opt.pipeFilter());
V3ParseSym parseSyms(v3Global.rootp()); // Symbol table must be common across all parsing
V3Parse parser(v3Global.rootp(), &filter, &parseSyms);
// Read top module
const V3StringList& vFiles = v3Global.opt.vFiles();
for (V3StringList::const_iterator it = vFiles.begin(); it != vFiles.end(); ++it) {
string filename = *it;
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, false,
"Cannot find file containing module: ");
}
// Read libraries
// To be compatible with other simulators,
// this needs to be done after the top file is read
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
for (V3StringSet::const_iterator it = libraryFiles.begin(); it != libraryFiles.end(); ++it) {
string filename = *it;
parser.parseFile(new FileLine(FileLine::commandLineFilename()), filename, true,
"Cannot find file containing library module: ");
}
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree"));
V3Error::abortIfErrors();
if (!v3Global.opt.preprocOnly()) {
// Resolve all modules cells refer to
V3LinkCells::link(v3Global.rootp(), &filter, &parseSyms);
}
}
void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool doDump) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(stagename + ".tree", newNumber),
false, doDump);
if (v3Global.opt.stats()) V3Stats::statsStage(stagename);
}
+24 -14
View File
@@ -55,25 +55,32 @@ public:
inline VWidthMinUsage(en _e) : m_e(_e) {}
explicit inline VWidthMinUsage(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
};
inline bool operator==(VWidthMinUsage lhs, VWidthMinUsage rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(VWidthMinUsage lhs, VWidthMinUsage::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(VWidthMinUsage::en lhs, VWidthMinUsage rhs) { return (lhs == rhs.m_e); }
};
inline bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VWidthMinUsage& lhs, VWidthMinUsage::en rhs) {
return lhs.m_e == rhs;
}
inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
return lhs == rhs.m_e;
}
//######################################################################
// V3Global - The top level class for the entire program
class V3Global {
// Globals
AstNetlist* m_rootp; // Root of entire netlist
VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
AstNetlist* m_rootp; // Root of entire netlist
VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
int m_debugFileNumber; // Number to append to debug files created
bool m_assertDTypesResolved; // Tree should have dtypep()'s
bool m_constRemoveXs; // Const needs to strip any Xs
bool m_needHInlines; // Need __Inlines file
bool m_needHeavy; // Need verilated_heavy.h include
bool m_dpi; // Need __Dpi include files
int m_debugFileNumber; // Number to append to debug files created
bool m_assertDTypesResolved; // Tree should have dtypep()'s
bool m_constRemoveXs; // Const needs to strip any Xs
bool m_needTraceDumper; // Need __Vm_dumperp in symbols
bool m_needHInlines; // Need __Inlines file
bool m_needHeavy; // Need verilated_heavy.h include
bool m_dpi; // Need __Dpi include files
public:
// Options
@@ -86,6 +93,7 @@ public:
m_widthMinUsage = VWidthMinUsage::LINT_WIDTH;
m_assertDTypesResolved = false;
m_constRemoveXs = false;
m_needTraceDumper = false;
m_needHInlines = false;
m_needHeavy = false;
m_dpi = false;
@@ -113,10 +121,12 @@ public:
char digits[100]; sprintf(digits, "%03d", m_debugFileNumber);
return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment;
}
bool needTraceDumper() const { return m_needTraceDumper; }
void needTraceDumper(bool flag) { m_needTraceDumper = flag; }
bool needHInlines() const { return m_needHInlines; }
void needHInlines(bool flag) { m_needHInlines=flag; }
void needHInlines(bool flag) { m_needHInlines = flag; }
bool needHeavy() const { return m_needHeavy; }
void needHeavy(bool flag) { m_needHeavy=flag; }
void needHeavy(bool flag) { m_needHeavy = flag; }
bool dpi() const { return m_dpi; }
void dpi(bool flag) { m_dpi = flag; }
};
+2 -2
View File
@@ -224,7 +224,7 @@ void V3Graph::clear() {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) {
V3GraphEdge* nextp = edgep->outNextp();
delete edgep;
VL_DO_DANGLING(delete edgep, edgep);
edgep = nextp;
}
vertexp->outUnlink();
@@ -232,7 +232,7 @@ void V3Graph::clear() {
// Delete the old vertices
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; /*BELOW*/) {
V3GraphVertex* nextp = vertexp->verticesNextp();
delete vertexp;
VL_DO_DANGLING(delete vertexp, vertexp);
vertexp = nextp;
}
verticesUnlink();
+6 -5
View File
@@ -65,15 +65,15 @@ public:
const char* ascii() const {
static const char* const names[] = { "FORWARD", "REVERSE" };
return names[m_e];
};
}
// METHODS unique to this class
GraphWay invert() const { return m_e == FORWARD ? REVERSE : FORWARD; }
bool forward() const { return m_e == FORWARD; }
bool reverse() const { return m_e != FORWARD; }
};
inline bool operator==(GraphWay lhs, GraphWay rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(GraphWay lhs, GraphWay::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(GraphWay::en lhs, GraphWay rhs) { return (lhs == rhs.m_e); }
inline bool operator==(const GraphWay& lhs, const GraphWay& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const GraphWay& lhs, GraphWay::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(GraphWay::en lhs, const GraphWay& rhs) { return lhs == rhs.m_e; }
//============================================================================
@@ -104,6 +104,7 @@ public:
// METHODS
void clear(); // Empty it of all vertices/edges, as if making a new object
void clearColors();
bool empty() const { return m_vertices.empty(); }
V3GraphVertex* verticesBeginp() const { return m_vertices.begin(); }
@@ -270,7 +271,7 @@ class V3GraphEdge {
// Wires/variables aren't edges. Edges have only a single to/from vertex
public:
// ENUMS
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
enum Cutable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
protected:
friend class V3Graph; friend class V3GraphVertex;
friend class GraphAcyc; friend class GraphAcycEdge;
+13 -13
View File
@@ -275,7 +275,7 @@ void GraphAcyc::deleteMarked() {
nextp = vertexp->verticesNextp();
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
if (avertexp->isDelete()) {
avertexp->unlinkDelete(&m_breakGraph); VL_DANGLING(avertexp);
VL_DO_DANGLING(avertexp->unlinkDelete(&m_breakGraph), avertexp);
}
}
}
@@ -291,13 +291,13 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) {
while (V3GraphEdge* edgep = avertexp->outBeginp()) {
V3GraphVertex* otherVertexp = edgep->top();
//UINFO(9," out "<<otherVertexp<<endl);
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(otherVertexp);
}
while (V3GraphEdge* edgep = avertexp->inBeginp()) {
V3GraphVertex* otherVertexp = edgep->fromp();
//UINFO(9," in "<<otherVertexp<<endl);
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(otherVertexp);
}
}
@@ -328,8 +328,8 @@ void GraphAcyc::simplifyOne(GraphAcycVertex* avertexp) {
// cppcheck-suppress leakReturnValNotUsed
edgeFromEdge(templateEdgep, inVertexp, outVertexp);
// Remove old edge
inEdgep->unlinkDelete(); VL_DANGLING(inEdgep);
outEdgep->unlinkDelete(); VL_DANGLING(outEdgep); VL_DANGLING(templateEdgep);
VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep);
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep); VL_DANGLING(templateEdgep);
workPush(inVertexp);
workPush(outVertexp);
}
@@ -363,10 +363,10 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) {
// cppcheck-suppress leakReturnValNotUsed
edgeFromEdge(inEdgep, inVertexp, outVertexp);
// Remove old edge
inEdgep->unlinkDelete(); VL_DANGLING(inEdgep);
VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep);
workPush(inVertexp);
}
outEdgep->unlinkDelete(); VL_DANGLING(outEdgep);
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep);
workPush(outVertexp);
}
}
@@ -389,18 +389,18 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
// !cutable duplicates prev !cutable: we can ignore it, redundant
// cutable duplicates prev !cutable: know it's not a relevant loop, ignore it
UINFO(8," DelDupEdge "<<avertexp<<" -> "<<edgep->top()<<endl);
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
} else if (!edgep->cutable()) {
// !cutable duplicates prev cutable: delete the earlier cutable
UINFO(8," DelDupPrev "<<avertexp<<" -> "<<prevEdgep->top()<<endl);
prevEdgep->unlinkDelete(); VL_DANGLING(prevEdgep);
VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep);
outVertexp->userp(edgep);
} else {
// cutable duplicates prev cutable: combine weights
UINFO(8," DelDupComb "<<avertexp<<" -> "<<edgep->top()<<endl);
prevEdgep->weight(prevEdgep->weight() + edgep->weight());
addOrigEdgep(prevEdgep, edgep);
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
workPush(outVertexp);
workPush(avertexp);
@@ -418,7 +418,7 @@ void GraphAcyc::cutBasic(GraphAcycVertex* avertexp) {
nextp = edgep->outNextp();
if (edgep->cutable() && edgep->top()==avertexp) {
cutOrigEdge(edgep, " Cut Basic");
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(avertexp);
}
}
@@ -439,7 +439,7 @@ void GraphAcyc::cutBackward(GraphAcycVertex* avertexp) {
nextp = edgep->outNextp();
if (edgep->cutable() && edgep->top()->user()) {
cutOrigEdge(edgep, " Cut A->B->A");
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(avertexp);
}
}
@@ -506,7 +506,7 @@ void GraphAcyc::placeTryEdge(V3GraphEdge* edgep) {
// Adding this edge would cause a loop, kill it
edgep->cutable(true); // So graph still looks pretty
cutOrigEdge(edgep, " Cut loop");
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
// Back out the ranks we calculated
while (GraphAcycVertex* vertexp = workBeginp()) {
workPop();
+4 -6
View File
@@ -110,10 +110,10 @@ private:
}
if (saveOld) {
if (m_sumWeights) prevEdgep->weight(prevEdgep->weight() + edgep->weight());
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
} else {
if (m_sumWeights) edgep->weight(prevEdgep->weight() + edgep->weight());
prevEdgep->unlinkDelete(); VL_DANGLING(prevEdgep);
VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep);
outVertexp->userp(edgep);
}
}
@@ -150,9 +150,7 @@ public:
V3GraphEdge* deletep = NULL;
for (V3GraphEdge* edgep = vxp->outBeginp();
edgep; edgep = edgep->outNextp()) {
if (deletep) {
deletep->unlinkDelete(); deletep = NULL;
}
if (deletep) VL_DO_CLEAR(deletep->unlinkDelete(), deletep = NULL);
// It should be safe to modify the graph, despite using
// the GraphPathChecker, as none of the modifications will
// change what can be reached from what, nor should they
@@ -162,7 +160,7 @@ public:
}
}
if (deletep) {
deletep->unlinkDelete(); VL_DANGLING(deletep);
VL_DO_DANGLING(deletep->unlinkDelete(), deletep);
}
}
}
+7 -6
View File
@@ -354,7 +354,7 @@ private:
for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) {
nextp = vertexp->verticesNextp();
if (nfaState(vertexp)) {
vertexp->unlinkDelete(m_graphp); VL_DANGLING(vertexp);
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
}
}
@@ -409,7 +409,7 @@ private:
if (vvertexp->accepting()) {
for (V3GraphEdge* nextp,*edgep = vertexp->outBeginp(); edgep; edgep=nextp) {
nextp = edgep->outNextp();
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
}
}
@@ -445,7 +445,7 @@ private:
for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) {
nextp = vertexp->verticesNextp();
if (!vertexp->user()) {
vertexp->unlinkDelete(m_graphp); VL_DANGLING(vertexp);
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
}
}
}
@@ -487,7 +487,7 @@ private:
}
}
// Transitions to this state removed by the unlink function
vertexp->unlinkDelete(m_graphp); VL_DANGLING(vertexp);
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
}
}
}
@@ -566,7 +566,7 @@ private:
DfaVertex* tovertexp = static_cast<DfaVertex*>(edgep->top());
if (tovertexp->accepting()) {
new DfaEdge(graphp(), vvertexp, m_tempNewerReject, vedgep);
edgep->unlinkDelete(); VL_DANGLING(edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
// NOT of all values goes to accept
@@ -595,10 +595,11 @@ public:
add_complement_edges();
if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_preswap");
m_tempNewerReject->unlinkDelete(graphp()); m_tempNewerReject = NULL;
VL_DO_CLEAR(m_tempNewerReject->unlinkDelete(graphp()), m_tempNewerReject = NULL);
if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_out");
}
~DfaGraphComplement() {}
VL_UNCOPYABLE(DfaGraphComplement);
};
void DfaGraph::dfaComplement() {
+1 -1
View File
@@ -89,7 +89,7 @@ class DfaVertex : public V3GraphVertex {
bool m_accepting; // Accepting state?
public:
// CONSTRUCTORS
DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false)
explicit DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false)
: V3GraphVertex(graphp)
, m_start(start), m_accepting(accepting) {}
using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*)
+1 -1
View File
@@ -73,7 +73,7 @@ GraphPathChecker::~GraphPathChecker() {
for (V3GraphVertex* vxp = m_graphp->verticesBeginp();
vxp; vxp = vxp->verticesNextp()) {
GraphPCNode* nodep = static_cast<GraphPCNode*>(vxp->userp());
delete nodep; VL_DANGLING(nodep);
VL_DO_DANGLING(delete nodep, nodep);
vxp->userp(NULL);
}
}
+2 -2
View File
@@ -42,8 +42,8 @@ class GraphPathChecker : GraphAlg<const V3Graph> {
public:
// CONSTRUCTORS
GraphPathChecker(const V3Graph* graphp,
V3EdgeFuncP edgeFuncp = V3GraphEdge::followAlwaysTrue);
explicit GraphPathChecker(const V3Graph* graphp,
V3EdgeFuncP edgeFuncp = V3GraphEdge::followAlwaysTrue);
~GraphPathChecker();
// METHODS
+3 -3
View File
@@ -95,9 +95,9 @@ private:
public:
// CONSTRUCTORS
GraphStream(const V3Graph* graphp,
GraphWay way = GraphWay::FORWARD,
const T_Compare& lessThan = T_Compare())
explicit GraphStream(const V3Graph* graphp,
GraphWay way = GraphWay::FORWARD,
const T_Compare& lessThan = T_Compare())
// NOTE: Perhaps REVERSE way should also reverse the sense of the
// lessThan function? For now the only usage of REVERSE is not
// sensitive to its lessThan at all, so it doesn't matter.

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