mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 00:23:35 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95c4b6aaba | ||
|
|
1c1319079b | ||
|
|
328fef8190 | ||
|
|
e2dec043a0 | ||
|
|
bd42e31b2a | ||
|
|
6d73237b27 | ||
|
|
6c6d70a5e5 | ||
|
|
6f49f802b1 | ||
|
|
808c958d42 | ||
|
|
961ac49c5c | ||
|
|
2d52f525c5 | ||
|
|
e70cba77e6 | ||
|
|
8054fc47ea | ||
|
|
e673875b3b | ||
|
|
29923b78fd | ||
|
|
135cbcd79a | ||
|
|
75ecad591a | ||
|
|
c108f5def9 | ||
|
|
dab1cb610a | ||
|
|
fd656f6cc1 | ||
|
|
a7e65379fa | ||
|
|
905067d13f | ||
|
|
30a33a6104 | ||
|
|
0ca0e07354 | ||
|
|
aac02acf92 | ||
|
|
082c9e0b1d | ||
|
|
a7bd934fe3 | ||
|
|
e98a380b44 | ||
|
|
4878fe3a1f | ||
|
|
c6b755a12e | ||
|
|
991d81cd0a | ||
|
|
c06a97a221 | ||
|
|
6131bcdbb0 | ||
|
|
68b6a0b667 | ||
|
|
4c438bbc67 | ||
|
|
5b83484f20 | ||
|
|
93ac79981b | ||
|
|
c9b74847d1 | ||
|
|
23eb96579c | ||
|
|
8319ea6c73 | ||
|
|
60f82961b4 | ||
|
|
f7d1c6ca72 | ||
|
|
4b4f10f5e6 | ||
|
|
120f62fe85 | ||
|
|
db6ecbd57e | ||
|
|
28e19cef90 | ||
|
|
18f8cd0529 | ||
|
|
02786b3f09 | ||
|
|
70358e8587 | ||
|
|
95b66feeb8 | ||
|
|
890cecc15b | ||
|
|
f7bad37e88 | ||
|
|
134b5efd70 | ||
|
|
0d6ebf21b3 | ||
|
|
2d1b804e80 | ||
|
|
77f1b3eef4 | ||
|
|
609a5dc26d | ||
|
|
0aabe6ce00 | ||
|
|
20cc4e57d5 | ||
|
|
f3ebdc40c6 | ||
|
|
2ca9f73b31 | ||
|
|
73f5e3f808 | ||
|
|
8d3dad510f | ||
|
|
2576c136f6 | ||
|
|
a8ad97eef2 | ||
|
|
ee7da1e690 | ||
|
|
969a46faf6 | ||
|
|
820df28ad9 | ||
|
|
50fb7fc8b4 | ||
|
|
119162912a | ||
|
|
80d94891e1 | ||
|
|
f00ff61559 | ||
|
|
2d195ebae5 | ||
|
|
9a6bc3ddcf | ||
|
|
d218f1746c | ||
|
|
8d8eb1b9f3 | ||
|
|
d4614c290e | ||
|
|
027cce35c0 | ||
|
|
9fd81b2c6b | ||
|
|
5430e4ac9b | ||
|
|
619214b48f | ||
|
|
68fa82fb14 | ||
|
|
cac50282eb | ||
|
|
b50ef9ff39 | ||
|
|
8a8f1135b7 | ||
|
|
f0b2336345 | ||
|
|
52907e7b02 | ||
|
|
ef5250f0ca | ||
|
|
eafed88a6e | ||
|
|
d64e6b3f9c | ||
|
|
d68ffba8cd | ||
|
|
f0f370490f | ||
|
|
708fd36563 | ||
|
|
a4e8d39932 | ||
|
|
8f0e8e0696 | ||
|
|
11380bc3b2 | ||
|
|
7ab2bdb6bb | ||
|
|
5d037c3c8c | ||
|
|
c5d04631d1 | ||
|
|
957c1d606b | ||
|
|
48dd358c03 | ||
|
|
220daa5f33 | ||
|
|
d76b5b7823 | ||
|
|
4266d31443 | ||
|
|
fbdf5f2dad | ||
|
|
8e26bdd098 | ||
|
|
22088c907f | ||
|
|
d87648c258 | ||
|
|
abf3850d08 | ||
|
|
4a122fd0f2 | ||
|
|
0352ceea44 | ||
|
|
e8ff191a17 | ||
|
|
5ae09daf5b | ||
|
|
1acff950d0 | ||
|
|
f28d837930 | ||
|
|
1dd9a74b6c | ||
|
|
165833a97c | ||
|
|
18e837336a | ||
|
|
835f668aaa | ||
|
|
09199f79a6 | ||
|
|
2f4954ca68 | ||
|
|
7024ea8cb6 | ||
|
|
623c4ec103 | ||
|
|
023526ad4b | ||
|
|
e2ba1c041f | ||
|
|
b41b9417b9 | ||
|
|
4443ab34fd | ||
|
|
e9a309ea8d | ||
|
|
81e8127168 | ||
|
|
47803c3591 | ||
|
|
af38e8d387 | ||
|
|
67bb0c78c8 | ||
|
|
918df2e618 | ||
|
|
7bed17b14b | ||
|
|
fad465abf1 | ||
|
|
98fb7ec193 | ||
|
|
b71eb76252 | ||
|
|
1d2a7b2f41 | ||
|
|
cd38e88fb8 | ||
|
|
a15aa0b82b | ||
|
|
fe94f9891b | ||
|
|
fe9cf9bd42 |
@@ -17,6 +17,7 @@
|
||||
README
|
||||
TAGS
|
||||
autom4te.cache
|
||||
compile_commands.json
|
||||
config.cache
|
||||
config.status
|
||||
configure
|
||||
|
||||
+11
-3
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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/> +++ • Accepts synthesizable Verilog or SystemVerilog
|
||||
+++ <br/> +++ • Performs lint code-quality checks
|
||||
+++ <br/> +++ • Compiles into multithreaded {cpp}, SystemC, or (soon) {cpp}-under-Python
|
||||
+++ <br/> +++ • Compiles into multithreaded {cpp}, or SystemC
|
||||
+++ <br/> +++ • 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/> +++ • 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/> +++ • Guided by the https://chipsalliance.org/[CHIPS Alliance] and https://www.linuxfoundation.org/[Linux Foundation]
|
||||
+++ <br/> +++ • Open, and free as in both speech and beer
|
||||
+++ <br/> +++ • More simulation for your verification budget
|
||||
|
||||
^.^| *Commercial Support Available*
|
||||
+++ <br/> +++ • Commercial support contracts
|
||||
+++ <br/> +++ • Design support contracts
|
||||
+++ <br/> +++ • 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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Executable
+12
@@ -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
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+22
-22
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+10
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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*)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user