Compare commits

...
62 Commits
Author SHA1 Message Date
Wilson Snyder dfcd412e5f Version bump 2019-10-06 09:40:36 -04:00
Wilson Snyder 307549e8a6 Internals: Fix some cppcheck warnings. 2019-10-06 08:20:02 -04:00
Wilson Snyder 09b79a731a Fix more output spacing issues. 2019-10-05 21:52:33 -04:00
Wilson Snyder 4544a2fd99 Fix extra declaration of trace() in submodules. 2019-10-05 20:16:33 -04:00
Wilson Snyder e09c918198 Fix indentation broke in 977a767477. 2019-10-05 18:00:45 -04:00
Wilson Snyder 9bf6135f6d Remove some output tabs. 2019-10-05 17:35:08 -04:00
Wilson Snyder d472ef63e9 Internals: Cleanup some misnamed classes. No functional change. 2019-10-05 08:17:21 -04:00
Wilson Snyder f1c04b5d25 Fix extra space in mtask comment. No functional change. 2019-10-04 22:54:57 -04:00
Wilson Snyder 1cf29c4d20 Fix truncation of comments, broke in f133c4d0b3. 2019-10-04 22:54:17 -04:00
Maarten De Braekeleer 977a767477 Avoid tabs in C output.
Signed-off-by: Wilson Snyder <[email protected]>
2019-10-04 21:10:53 -04:00
Wilson Snyder 771a301f66 Commentary: Remove newlines, upsets some patches. No functional change. 2019-10-04 20:17:11 -04:00
Wilson Snyder a9954a71c3 Fix case statements with strings, bug1536. 2019-10-04 19:13:39 -04:00
Wilson Snyder 967dc24fda Commentary 2019-10-04 17:42:34 -04:00
Wilson Snyder e1e45cf13c Internals: Move option checks to notify(). 2019-10-03 22:18:29 -04:00
Wilson Snyder bd89c71694 Internals: Refactor to avoid V3Global requirements in V3String. No functional change intended. 2019-10-02 21:38:16 -04:00
Stefan Wallentowitz 633131b984 Return vpiModule when it is the scope.
Return the vpiModule when it is searched for by name and not the vpiScope,
now that we actually have it (one step further to supporting vpiModule in
complete).

Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-10-02 18:47:12 -04:00
Wilson Snyder 99db18b6c3 Commentary 2019-10-02 18:47:06 -04:00
Todd Strader 961a8e190f Internals: Remove rogue character. 2019-10-02 08:52:26 -04:00
Stefan Wallentowitz 045ff25f80 Support vpiModule, bug1469.
Add very basic support for vpiModule. Basically it allows to traverse
the module tree to find a variable etc. It does not support more than
vpi_iterate and vpi_scan for vpiModule along basic operations like
vpi_get_str on vpiModule.

The support is added non-intrusively to non-VPI verilator runs. It
essentially:

 - Tracks the creation of cell instances and keeps them alive until
   the emit phase. They are there converted to scopes if modules.

 - Emits empty (don't add anything during construction)
   VerilatedScopes for all inlined modules, only for those inlined
   modules that are on the hierarchical path to public variables.

 - Adds VerilatedHierarchy as abstraction to structure of the
   scopes. It is only created for VPI designs. It allows to traverse
   the hierarchy from the top (NULL).

Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-10-01 21:57:45 -04:00
Wilson Snyder 66209d1114 Tests: Less verbose status. 2019-10-01 21:32:38 -04:00
Todd Strader 3f1fe2d18a Internals: Travis CI environment. 2019-10-01 06:05:11 -04:00
Wilson Snyder 8b6fb26272 Return good exit status on --help. 2019-09-30 23:15:10 -04:00
Wilson Snyder 881362bb04 Fix clang compile warnings. 2019-09-30 21:55:31 -04:00
Wilson Snyder 239ef1ae6d Fix misc bad-syntax crashes, bug1533. 2019-09-30 20:00:30 -04:00
Wilson Snyder 9eaec3b5c1 Fix misc bad-syntax crashes, bug1530. 2019-09-30 19:48:01 -04:00
Wilson Snyder dd4aa948ae Tests: Have driver report ETA. 2019-09-30 19:22:36 -04:00
Wilson Snyder 12fa085b26 Fix misc bad-syntax crashes, bug1529. 2019-09-30 19:22:14 -04:00
Wilson Snyder 9d6b0d7dd6 Tests: Fix broken contributors check. 2019-09-30 18:56:04 -04:00
Wilson Snyder a1405dac8e Fix misc bad-syntax crashes, bug1532. 2019-09-30 18:50:27 -04:00
Todd Strader cb115e1a15 Commentary 2019-09-30 09:33:17 -04:00
Wilson Snyder 1c7eb89df5 Commentary: Update contributing indentation. 2019-09-29 17:11:13 -04:00
Wilson Snyder 6e91f82a7d Commentary: Fix logo rendering 2019-09-29 17:09:03 -04:00
Wilson Snyder 17123cd0e0 Add contributing document. Convert internals to asciidoc format. Part of last commit. 2019-09-29 17:05:13 -04:00
Wilson Snyder 3f0c5b7550 WIP 2019-09-29 17:03:07 -04:00
Wilson Snyder f6e0e9adec Internals: Use SHA256 instead of insecure SHA1. 2019-09-28 13:32:28 -04:00
Wilson Snyder dea1531f40 Commentary 2019-09-28 11:38:23 -04:00
Wilson Snyder edcfaa888d Commentary 2019-09-28 11:13:30 -04:00
Todd Strader 28b9db1903 Add AstVFile and AstTextBlock, towards bug1490. 2019-09-27 04:24:38 -04:00
Todd Strader 9e64be71a7 Add XSim user run flags 2019-09-27 01:12:53 -04:00
Stefan Wallentowitz 99a8845a96 Fix VerilatedVpioVar vpiMemory/vpiReg accessor, bug1528.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-27 00:01:09 -04:00
Wilson Snyder be4692772c Ignore MCD fopenw with --bbox-unsup. 2019-09-26 23:37:22 -04:00
Wilson Snyder 4f315d9078 Fix ugly error on interface misuse, bug1525. 2019-09-25 21:53:01 -04:00
Wilson Snyder f133c4d0b3 Fix mis-indenting AstComments with C++ symbols. 2019-09-24 19:07:22 -04:00
Wilson Snyder 8490046028 Internals: AstComment optional suppression of at. No functional change intended. 2019-09-23 18:44:45 -04:00
Lukasz Dalek d6ac351dcb Add --public-flat-rw switch, bug1511.
This switch exposes VARs, PORTs and WIREs to C++ code. It must be use
with care as it has a significant performance impact and may result in
mis-simulation of generated clocks. Anyhow, it is prefered over
--public and useful for VPI.

Signed-off-by: Lukasz Dalek <[email protected]>
Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-23 07:56:07 -04:00
Stefan Wallentowitz 502bd6cbd6 Tests: Set VM_PREFIX from test script.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-21 08:26:34 -04:00
Philipp Wagner d7b6b53c4d Make callCbs() public.
VerilatedVpi::callCbs() can be used by the user to signal
simulation-related callbacks, e.g.
VerilatedVpi::callCbs(cbStartOfSimulation).

The information if any callbacks have been called may be important to
drive an evaluation until no further changes are observed.

Signed-off-by: Lukasz Dalek <[email protected]>
Signed-off-by: Philipp Wagner <[email protected]>
Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-21 07:43:20 -04:00
Stefan Wallentowitz 96725b3431 Tests: To allow reuse of cpp files, allow to set the PLI filename.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-19 18:46:45 -04:00
Stefan Wallentowitz 8686ed9b00 Fix vpiType accessor, bug1510.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-18 12:24:19 -04:00
Stefan Wallentowitz 32e1207782 Fix vpiType accessor, bug1509.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-18 07:22:59 -04:00
Wilson Snyder 900115bb2d Fix false warning on backward indexing, bug1507. 2019-09-17 15:17:23 -04:00
Wilson Snyder 3469c78153 Fix bad module name. 2019-09-16 21:09:18 -04:00
Wilson Snyder baa634343b Fix config_rev revision detection on old versions. 2019-09-13 07:20:26 -04:00
Wilson Snyder 1471f5691a Fix error on multidimensional cells, bug1505. 2019-09-12 19:06:26 -04:00
Wilson Snyder e556269692 Commentary - Spelling fixes 2019-09-12 07:22:22 -04:00
Todd Strader d1af69f91d Produce man files with 'make all' 2019-09-11 10:01:18 -04:00
Wilson Snyder fa904f386c Commentary - Spelling fixes 2019-09-09 07:50:21 -04:00
Todd Strader a4daae66de -LDLIBS isn't an option 2019-09-06 13:04:47 -04:00
Todd Strader c813026566 Make Syms file honor --output-split-cfuncs, bug1499. 2019-09-04 06:15:41 -04:00
Wilson Snyder 314cd92129 Support $fseek, $ftell, $frewind, bug1496. 2019-09-03 21:28:15 -04:00
Wilson Snyder 3bc260c55d Fix make test with no VERILATOR_ROOT, bug1494. 2019-09-01 11:15:42 -04:00
Wilson Snyder 4c0f95af10 devel release 2019-08-29 19:12:47 -04:00
273 changed files with 3668 additions and 2108 deletions
+28 -1
View File
@@ -2,6 +2,33 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.020 2019-10-06
*** Support $fseek, $ftell, $frewind, bug1496. [Howard Su]
*** Add --public-flat-rw, bug1511. [Stefan Wallentowitz]
*** Support vpiModule, bug1469. [Stefan Wallentowitz]
**** Make Syms file honor --output-split-cfuncs, bug1499. [Todd Strader]
**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy]
**** Fix error on multidimensional cells, bug1505. [Anderson Ignacio Da Silva]
**** Fix config_rev revision detection on old versions.
**** Fix false warning on backward indexing, bug1507. [Hao Shi]
**** Fix vpiType accessor, bug1509, bug1510. [Stefan Wallentowitz]
**** Fix ugly error on interface misuse, bug1525. [Bogdan Vukobratovic]
**** Fix misc bad-syntax crashes, bug1529-bug1533. [Eric Rippey]
**** Fix case statements with strings, bug1536. [Philipp Wagner]
* Verilator 4.018 2019-08-29
** When showing an error, show source code and offer suggestions of replacements.
@@ -3311,7 +3338,7 @@ of input ports exists for tracing.
* Verilator 0.0 1994/7/8
**** First code written.
----------------------------------------------------------------------
This uses outline mode in Emacs. See C-h m [M-x describe-mode].
+10 -24
View File
@@ -107,9 +107,8 @@ SUBDIRS = src test_regress \
examples/hello_world_c examples/hello_world_sc \
examples/tracing_c examples/tracing_sc \
INFOS = README README.html README.pdf internals.txt internals.html \
internals.pdf verilator.txt verilator.html verilator.pdf \
$(VL_INST_MAN_FILES)
INFOS = README README.html README.pdf \
verilator.txt verilator.html verilator.pdf
# Files that can be generated, but should be up to date for a distribution.
DISTDEP = info Makefile
@@ -127,11 +126,13 @@ DISTFILES_INC = $(INFOS) .gitignore \
bin/verilator_includer \
bin/verilator_profcfunc \
docs/.gitignore \
docs/CONTRIBUTING.adoc \
docs/CONTRIBUTORS \
docs/Makefile.in \
docs/TODO \
docs/doxygen-mainpage \
docs/doxygen.config \
docs/internals.adoc \
docs/verilator_logo.png \
install-sh configure *.pod \
include/*.[chv]* \
@@ -192,6 +193,9 @@ 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
default: all
all: all_nomsg msg_test
all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
@@ -275,31 +279,12 @@ README.pdf: README.pod Makefile $(POD2LATEXFIX)
pdflatex README.tex
-rm -f README.toc README.aux README.idx README.out
internals.txt: internals.pod
-rm -f $@
$(POD2TEXT) --loose $< > $@
internals.html: internals.pod
pod2html $< >$@
# PDF needs DIST variables; but having configure.ac as dependency isn't detected
internals.pdf: internals.pod Makefile $(POD2LATEXFIX)
pod2latex --full --out internals.tex $<
$(PERL) $(POD2LATEXFIX) "$(DISTTITLE) Internals Manual" "${DISTDATE}" < internals.tex > internals2.tex
mv internals2.tex internals.tex
pdflatex internals.tex
pdflatex internals.tex
-rm -f internals.toc internals.aux internals.idx internals.out
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \
verilator_coverage verilator_gantt verilator_includer verilator_profcfunc
# Some scripts go into both the search path and pkgdatadir,
# so they can be found by the user, and under $VERILATOR_ROOT.
# 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
VL_INST_INC_BLDDIR_FILES = \
include/verilated_config.h \
include/verilated.mk \
@@ -426,7 +411,8 @@ CPPCHECK_H = $(wildcard \
$(srcdir)/src/*.h )
CPPCHECK = src/cppcheck_filtered
CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
--suppress=nullPointerRedundantCheck
CPPCHECK_FLAGS += --xml
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
@@ -507,7 +493,7 @@ clean mostlyclean distclean maintainer-clean::
rm -rf nodist/obj_dir
distclean maintainer-clean::
rm -f *.info* *.1 $(INFOS)
rm -f *.info* *.1 $(INFOS) $(VL_INST_MAN_FILES)
rm -f Makefile config.status config.cache config.log TAGS
rm -f verilator_bin* verilator_coverage_bin*
rm -f bin/verilator_bin* bin/verilator_coverage_bin*
+3 -3
View File
@@ -32,7 +32,7 @@ The resulting executable will perform the actual simulation.
Verilator is developed and has primary testing on Ubuntu. Versions have
also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
with minor porting on any Linix-ish platform. Verilator also works on
with minor porting on any Linux-ish platform. Verilator also works on
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
output (not Verilator itself) compiles under all the options above, plus
MSVC++ 2008 and newer.
@@ -100,7 +100,7 @@ To use Verilator you will need the C<perl>, C<make> (or C<gmake>), and
C<g++> (or C<clang>) packages. To compile Verilator in addition to the above you need the C<flex>,
C<bison> and C<texi2html> packages installed.
sudo apt-get install git make autoconf g++ flex bisonz # First time prerequisites
sudo apt-get install git make autoconf g++ flex bison # First time prerequisites
sudo apt-get install libgz # Non-Ubuntu (ignore if gives error)
sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
@@ -166,7 +166,7 @@ needed files.
=item 2.
You may eventually be instaling onto a project/company-wide "CAD" tools
You may eventually be installing onto a project/company-wide "CAD" tools
disk that may support multiple versions of every tool.
unset VERILATOR_ROOT # if your shell is bash
+36 -10
View File
@@ -115,7 +115,7 @@ if ($opt_gdb) {
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
}
sub debug {
@@ -321,7 +321,6 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--inhibit-sim Create function to turn off sim
--inline-mult <value> Tune module inlining
-LDFLAGS <flags> Linker pre-object flags for makefile
-LDLIBS <flags> Linker library flags for makefile
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
+libext+<ext>+[ext]... Extensions for finding modules
@@ -355,6 +354,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--prof-threads Enable generating gantt chart data for threads
--private Debugging; see docs
--public Debugging; see docs
--public-flat-rw Mark all variables, etc as public_flat_rw
-pvalue+<name>=<value> Overwrite toplevel parameter
--quiet-exit Don't print the command on failure
--relative-includes Resolve includes relative to current file
@@ -1169,6 +1169,16 @@ inlining. This will also turn off inlining as if all modules had a
/*verilator public_module*/, unless the module specifically enabled it with
/*verilator inline_module*/.
=item --public-flat-rw
Declares all variables, ports and wires public as if they had /*verilator
public_flat_rw*/ comments. This will make them VPI accessible by their
flat name, but not turn off module inlining. This is particularly useful
in combination with --vpi. This may also in some rare cases result in
mis-simulation of generated clocks. Instead of this global switch, marking
only those signals that need public_flat_rw is typically significantly
better performing.
=item -pvalue+I<name>=I<value>
Overwrites the given parameter(s) of the toplevel module. See -G for a
@@ -2917,7 +2927,8 @@ signal should be declared public_flat (see above), but read-only.
Used after an input, output, register, or wire declaration to indicate the
signal should be declared public_flat_rd (see above), and also writable,
where writes should be considered to have the timing specified by the given
sensitivity edge list.
sensitivity edge list. Set for all variables, ports and wires using the
--public-flat-rw switch.
=item /*verilator public_module*/
@@ -4153,17 +4164,32 @@ code to add appropriate prints to see what is going on.
=over 4
=item Does it run under Windows?
=item Can I contribute?
Please contribute! Just file an issue asking for a merge, or ask on the
forums if looking for something to help on. For more information see our
contributor agreement.
=item How commonly is Verilator used?
Verilator is used by many of the largest silicon design companies, and all
the way down to college projects. Verilator is a "big 4" simulator,
meaning one of the 4 main SystemVerilog simulators available, namely the
commercial products Synopsys' VCS (tm), Mentor's ModelSim (tm), Cadence
Incisive/NC-Verilog/NC-Sim, and the open-source Verilator. The three
commercial choices are commonly collectively called the "big 3" simulators.
=item Does Verilator run under Windows?
Yes, using Cygwin. Verilated output also compiles under Microsoft Visual
C++ Version 7 or newer, but this is not tested every release.
C++, but this is not tested every release.
=item Can you provide binaries?
Verilator is available as a RPM for Debian/Ubuntu, SuSE, Fedora, and
perhaps other systems; this is done by porters and may slightly lag the
primary distribution. If there isn't a binary build for your distribution,
how about you set one up? Please contact the authors for assistance.
Verilator is available as a RPM for Debian/Ubuntu, SuSE, Fedora, and other
distributions; this is done by porters and may slightly lag the primary
distribution. If there isn't a binary build for your distribution, how
about you set one up? Please contact the authors for assistance.
Note people sometimes request binaries when they are having problems with
their C++ compiler. Alas, binaries won't help this, as in the end a fully
@@ -4207,7 +4233,7 @@ placed under the Verilator copyright and LGPL/Artistic license. Small test
cases will be released into the public domain so they can be used anywhere,
and large tests under the LGPL/Artistic, unless requested otherwise.
=item Why is Verilation so slow?
=item Why is running Verilator (to create a model) so slow?
Verilator needs more memory than the resulting simulator will require, as
Verilator creates internally all of the state of the resulting generated
+1 -1
View File
@@ -66,7 +66,7 @@ run(verilator_coverage_bin()
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
}
sub debug {
+2 -2
View File
@@ -168,8 +168,8 @@ sub filter {
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
+2 -2
View File
@@ -43,8 +43,8 @@ exit(0);
#######################################################################
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub parameter {
+2 -2
View File
@@ -39,8 +39,8 @@ profcfunc($Opt_File);
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.018 2019-08-29],
AC_INIT([Verilator],[4.020 2019-10-06],
[https://www.veripool.org/verilator],
[verilator],[https://www.veripool.org/verilator])
# When releasing, also update header of Changes file
+82
View File
@@ -0,0 +1,82 @@
= How to contribute to Verilator
Thanks for using Verilator! We welcome your contributions in whatever form.
This contributing document contains some suggestions that may make
contributions flow more efficiently.
==== Did you find a bug?
* Please **Ensure the bug was not already reported** by searching
https://www.veripool.org/projects/verilator/issues[Verilator Issues].
* If you're unable to find an open issue addressing the problem,
https://www.veripool.org/projects/verilator/issues/new[open a new issue].
** Be sure to include a **code sample** or an **executable test case**
demonstrating the bug and expected behavior that is not occurring.
** The ideal example works against other simulators, and is in the
test_regress/t test format, as described in
link:internals.adoc[docs/internals].
==== Did you write a patch that fixes a bug?
* Please https://www.veripool.org/projects/verilator/issues/new[Open a new
issue].
* You may attach a patch to the issue, or (preferred) may point to a github
repository branch within your github account.
** Verilator uses Travis CI to provide continuous integration. You may
want to setup Travis CI on your github branch to ensure your changes
keep the tests passing. See link:internals.adoc[docs/internals].
* Your source-code contributions must be certified as open source, under
the https://developercertificate.org/[Developer Certificate of
Origin]. On your first contribution, you must either:
** Have your patch include the addition of your name to
link:CONTRIBUTORS[docs/CONTRIBUTORS] (preferred).
** Use "git -s" as part of your commit. This adds a "signed-of-by"
attribute which will certify your contribution as described in the
https://github.com/wking/signed-off-by/blob/master/Documentation/SubmittingPatches[Signed-of-By
convention].
** Email, or post in an issue a statement that you certify your
contributions.
** In any of these cases your name will be added to
link:CONTRIBUTORS[docs/CONTRIBUTRORS] and you are agreeing all future
contributions are also certified.
** We occasionally accept contributions where people do not want their
name published. Please email us; you must still certify your
contribution using email.
* Your test contributions are generally considered released into the public
domain, unless you request otherwise or put a GNU/Artistic license on
your test file.
* Most important is we get your patch. If you'd like to clean up
indentation and related issues ahead of our feedback, that is
appreciated; please see the coding conventions in
link:internals.adoc[docs/internals].
==== Do you have questions?
* Please see the
https://www.veripool.org/projects/verilator/wiki/Faq[Verilator FAQ].
* Ask any question in the
https://www.veripool.org/projects/verilator/boards[Verilator forums].
==== Code of Conduct
* Our contributors and participants pledge to make participation in our
project and our community a positive experience for everyone. We follow
the https://www.contributor-covenant.org/version/1/4/code-of-conduct.html[Contributor
Covenant version 1.4].
Thanks!
+4
View File
@@ -6,12 +6,16 @@ Please see the Verilator manual for additional contributors.
Alex Chadwick
Gianfranco Costamagna
Howard Su
Jeremy Bennett
John Coiner
Kanad Kanhere
Lukasz Dalek
Maarten De Braekeleer
Philipp Wagner
Richard Myers
Sebastien Van Cauwenberghe
Stefan Wallentowitz
Todd Strader
Wilson Snyder
Yves Mathieu
+956
View File
@@ -0,0 +1,956 @@
= Verilator Internals Documentation
: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 file discusses internal and programming details for Verilator. It's a
reference for developers and debugging problems.
See also the Verilator internals presentation at http://www.veripool.org.
== Code Flows
=== Verilator Flow
The main flow of Verilator can be followed by reading the Verilator.cpp
`process()` function:
. First, the files specified on the command line are read. Reading
involves preprocessing, then lexical analysis with Flex and parsing with
Bison. This produces an abstract syntax tree (AST) representation of the
design, which is what is visible in the .tree files described below.
. Verilator then makes a series of passes over the AST, progressively
refining and optimizing it.
. Cells in the AST first linked, which will read and parse additional files
as above.
. Functions, variable and other references are linked to their definitions.
. Parameters are resolved and the design is elaborated.
. Verilator then performs many additional edits and optimizations on the
hierarchical design. This includes coverage, assertions, X elimination,
inlining, constant propagation, and dead code elimination.
. References in the design are then pseudo-flattened. Each module's
variables and functions get "Scope" references. A scope reference is an
occurrence of that un-flattened variable in the flattened hierarchy. A
module that occurs only once in the hierarchy will have a single scope and
single VarScope for each variable. A module that occurs twice will have a
scope for each occurrence, and two VarScopes for each variable. This
allows optimizations to proceed across the flattened design, while still
preserving the hierarchy.
. Additional edits and optimizations proceed on the pseudo-flat design.
These include module references, function inlining, loop unrolling,
variable lifetime analysis, lookup table creation, always splitting, and
logic gate simplifications (pushing inverters, etc).
. Verilator orders the code. Best case, this results in a single "eval"
function which has all always statements flowing from top to bottom with no
loops.
. Verilator mostly removes the flattening, so that code may be shared
between multiple invocations of the same module. It localizes variables,
combines identical functions, expands macros to C primitives, adds branch
prediction hints, and performs additional constant propagation.
. Verilator finally writes the C++ modules.
=== Key Classes Used in the Verilator Flow
==== `AstNode`
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).
Each `AstNode` has pointers to up to four children, accessed by the `op1p`
through `op4p` methods. These methods are then abstracted in a specific
Ast* node class to a more specific name. For example with the `AstIf` node
(for `if` statements), `ifsp` calls `op2p` to give the pointer to the AST
for the "then" block, while `elsesp` calls `op3p` to give the pointer to
the AST for the "else" block, or NULL if there is not one.
`AstNode` has the concept of a next and previous AST - for example the next
and previous statements in a block. Pointers to the AST for these
statements (if they exist) can be obtained using the `back` and `next`
methods.
It is useful to remember that the derived class `AstNetlist` is at the top
of the tree, so checking for this class is the standard way to see if you
are at the top of the tree.
By convention, each function/method uses the variable `nodep` as a pointer
to the `AstNode` currently being processed.
==== `AstNVisitor`
The passes are implemented by AST visitor classes. These are implemented
by subclasses of the abstract class, `AstNVisitor`. Each pass creates an
instance of the visitor class, which in turn implements a method to perform
the pass.
==== `V3Graph`
A number of passes use graph algorithms, and the class `V3Graph` is
provided to represent those graphs. Graphs are directed, and algorithms are
provided to manipulate the graphs and to output them in
http://www.graphviz.org/[GraphViz] dot format. `V3Graph.h` provides
documentation of this class.
==== `V3GraphVertex`
`V3GraphVertex` is the base class for vertices in a graph. Vertices have
an associated `fanout`, `color` and `rank`, which may be used in algorithms
for ordering the graph. A generic `user`/`userp` member variable is also
provided.
Virtual methods are provided to specify the name, color, shape and style to
be used in dot output. Typically users provide derived classes from
`V3GraphVertex` which will reimplement these methods.
Iterators are provided to access in and out edges. Typically these are used
in the form:
for (V3GraphEdge *edgep = vertexp->inBeginp();
edgep;
edgep = edgep->inNextp()) {
==== `V3GraphEdge`
`V3GraphEdge` is the base class for directed edges between pairs of
vertices. Edges have an associated `weight` and may also be made
`cutable`. A generic `user`/`userp` member variable is also provided.
Accessors, `fromp` and `top` return the "from" and "to" vertices
respectively.
Virtual methods are provided to specify the label, color and style to be
used in dot output. Typically users provided derived classes from
`V3GraphEdge` which will reimplement these methods.
==== `V3GraphAlg`
This is the base class for graph algorithms. It implements a `bool` method,
`followEdge` which algorithms can use to decide whether an edge is
followed. This method returns true if the graph edge has weight greater
than one and a user function, `edgeFuncp` (supplied in the constructor)
returns `true`.
A number of predefined derived algorithm classes and access methods are
provided and documented in `V3GraphAlg.cpp`.
=== Multithreaded Mode
In `--threads` mode, the frontend of the Verilator pipeline is the same as
serial mode, up until V3Order.
`V3Order` builds a fine-grained, statement-level dependency graph that
governs the ordering of code within a single `eval()` call. In serial mode,
that dependency graph is used to order all statements into a total serial
order. In parallel mode, the same dependency graph is the starting point
for a partitioner (`V3Partition`).
The partitioner's goal is to coarsen the fine-grained graph into a coarser
graph, while maintaining as much available parallelism as possible. Often
the partitioner can transform an input graph with millions of nodes into a
coarsened execution graph with a few dozen nodes, while maintaining enough
parallelism to take advantage of a modern multicore CPU. Runtime
synchronization cost is not prohibitive with so few nodes.
==== Partitioning
Our partitioner is similar to the one Vivek Sarkar described in his 1989
paper _Partitioning and Scheduling Parallel Programs for Multiprocessors_.
Let's define some terms:
==== Par Factor
The available parallelism or "par-factor" of a DAG is the total cost to
execute all nodes, divided by the cost to execute the longest critical path
through the graph. This is the speedup you would get from running the graph
in parallel, if given infinite CPU cores available and communication and
synchronization are zero.
==== Macro Task
When the partitioner coarsens the graph, it combines nodes together. Each
fine-grained node represents an atomic "task"; combined nodes in the
coarsened graph are "macro-tasks". This term comes from Sarkar. Each
macro-task executes from start to end on one processor, without any
synchronization to any other macro-task during its
execution. (Synchronization only happens before the macro-task begins or
after it ends.)
==== Edge Contraction
Verilator's partitioner, like Sarkar's, primarily relies on "edge
contraction" to coarsen the graph. It starts with one macro-task per atomic
task and iteratively combines pairs of edge-connected macro-tasks.
==== Local Critical Path
Each node in the graph has a "local" critical path. That's the critical
path from the start of the graph to the start of the node, plus the node's
cost, plus the critical path from the end of the node to the end of the
graph.
Sarkar calls out an important trade-off: coarsening the graph reduces
runtime synchronization overhead among the macro-tasks, but it tends to
increase the critical path through the graph and thus reduces par-factor.
Sarkar's partitioner, and ours, chooses pairs of macro-tasks to merge such
that the growth in critical path is minimized. Each candidate merge would
result in a new node, which would have some local critical path. We choose
the candidate that would produce the shortest local critical path. Repeat
until par-factor falls to a target threshold. It's a greedy algorithm, and
it's not guaranteed to produce the best partition (which Sarkar proves is
NP-hard).
==== Estimating Logic Costs
To compute the cost of any given path through the graph, Verilator
estimates an execution cost for each task. Each macro-task has an execution
cost which is simply the sum of its tasks' costs. We assume that
communication overhead and synchronization overhead are zero, so the cost
of any given path through the graph is simply the sum of macro-task
execution costs. Sarkar does almost the same thing, except that he has
nonzero estimates for synchronization costs.
Verilator's cost estimates are assigned by `InstrCountCostVisitor`. This
class is perhaps the most fragile piece of the multithread implementation.
It's easy to have a bug where you count something cheap (eg. accessing one
element of a huge array) as if it were expensive (eg. by counting it as if
it were an access to the entire array.) Even without such gross bugs, the
estimates this produce are only loosely predictive of actual runtime cost.
Multithread performance would be better with better runtime costs
estimates. This is an area to improve.
==== Scheduling Macro-Tasks at Runtime
After coarsening the graph, we must schedule the macro-tasks for runtime.
Sarkar describes two options: you can dynamically schedule tasks at
runtime, with a runtime graph follower. Sarkar calls this the
"macro-dataflow model." Verilator does not support this; early experiments
with this approach had poor performance.
The other option is to statically assign macro-tasks to threads, with each
thread running its macro-tasks in a static order. Sarkar describes this in
Chapter 5. Verilator takes this static approach. The only dynamic aspect is
that each macro task may block before starting, to wait until its
prerequisites on other threads have finished.
The synchronization cost is cheap if the prereqs are done. If they're not,
fragmentation (idle CPU cores waiting) is possible. This is the major
source of overhead in this approach. The `--prof-threads` switch and the
`verilator_gantt` script can visualize the time lost to such fragmentation.
==== Locating Variables for Best Spatial Locality
After scheduling all code, we attempt to locate variables in memory such
that variables accessed by a single macro-task are close together in
memory. This provides "spatial locality" -- when we pull in a 64-byte
cache line to access a 2-byte variable, we want the other 62 bytes to be
ones we'll also likely access soon, for best cache performance.
This turns out to be critical for performance. It should allow Verilator to
scale to very large models. We don't rely on our working set fitting in any
CPU cache; instead we essentially "stream" data into caches from
memory. It's not literally streaming, where the address increases
monotonically, but it should have similar performance characteristics, so
long as each macro-task's dataset fits in one core's local caches.
To achieve spatial locality, we tag each variable with the set of
macro-tasks that access it. Let's call this set the "footprint" of that
variable. The variables in a given module have a set of footprints. We can
order those footprints to minimize the distance between them (distance is
the number of macro-tasks that are different across any two footprints) and
then emit all variables into the struct in ordered-footprint order.
The footprint ordering is literally the traveling salesman problem, and we
use a TSP-approximation algorithm to get close to an optimal sort.
This is an old idea. Simulators designed at DEC in the early 1990s used
similar techniques to optimize both single-thread and multi-thread modes.
(Verilator does not optimize variable placement for spatial locality in
serial mode; that is a possible area for improvement.)
==== Improving Multithreaded Performance Further (a TODO list)
===== Wave Scheduling
To allow the Verilated model to run in parallel with the testbench, it
might be nice to support "wave" scheduling, in which work on a cycle begins
before `eval()` is called or continues after `eval()` returns. For now all
work on a cycle happens during the `eval()` call, leaving Verilator's
threads idle while the testbench (everything outside `eval()`) is
working. This would involve fundamental changes within the partitioner,
however, it's probably the best bet for hiding testbench latency.
===== Efficient Dynamic Scheduling
To scale to more than a few threads, we may revisit a fully dynamic
scheduler. For large (>16 core) systems it might make sense to dedicate an
entire core to scheduling, so that scheduler data structures would fit in
its L1 cache and thus the cost of traversing priority-ordered ready lists
would not be prohibitive.
===== Static Scheduling with Runtime Repack
We could modify the static scheduling approach by gathering actual
macro-task execution times at run time, and dynamically re-packing the
macro-tasks into the threads also at run time. Say, re-pack once every
10,000 cycles or something. This has the potential to do better than our
static estimates about macro-task run times. It could potentially react to
CPU cores that aren't performing equally, due to NUMA or thermal throttling
or nonuniform competing memory traffic or whatever.
===== Clock Domain Balancing
Right now Verilator makes no attempt to balance clock domains across
macro-tasks. For a multi-domain model, that could lead to bad gantt chart
fragmentation. This could be improved if it's a real problem in practice.
===== Other Forms of MTask Balancing
The largest source of runtime overhead is idle CPUs, which happens due to
variance between our predicted runtime for each MTask and its actual
runtime. That variance is magnified if MTasks are homogeneous, containing
similar repeating logic which was generally close together in source code
and which is still packed together even after going through Verilator's
digestive tract.
If Verilator could avoid doing that, and instead would take source logic
that was close together and distribute it across MTasks, that would
increase the diversity of any given MTask, and this should reduce variance
in the cost estimates.
One way to do that might be to make various "tie breaker" comparison
routines in the sources to rely more heavily on randomness, and generally
try harder not to keep input nodes together when we have the option to
scramble things.
===== Performance Regression
It would be nice if we had a regression of large designs, with some
diversity of design styles, to test on both single- and multi-threaded
modes. This would help to avoid performance regressions, and also to
evaluate the optimizations while minimizing the impact of parasitic noise.
===== Per-Instance Classes
If we have multiple instances of the same module, and they partition
differently (likely; we make no attempt to partition them the same) then
the variable sort will be suboptimal for either instance. A possible
improvement would be to emit a unique class for each instance of a module,
and sort its variables optimally for that instance's code stream.
=== Verilated Flow
The evaluation loop outputted by Verilator is designed to allow a single
function to perform evaluation under most situations.
On the first evaluation, the Verilated code calls initial blocks, and then
"settles" the modules, by evaluating functions (from always statements)
until all signals are stable.
On other evaluations, the Verilated code detects what input signals have
changes. If any are clocks, it calls the appropriate sequential functions
(from `always @ posedge` statements). Interspersed with sequential functions
it calls combo functions (from `always @*`). After this is complete, it
detects any changes due to combo loops or internally generated clocks, and
if one is found must reevaluate the model again.
For SystemC code, the `eval()` function is wrapped in a SystemC
`SC_METHOD`, sensitive to all inputs. (Ideally it would only be sensitive
to clocks and combo inputs, but tracing requires all signals to cause
evaluation, and the performance difference is small.)
If tracing is enabled, a callback examines all variables in the design for
changes, and writes the trace for each change. To accelerate this process
the evaluation process records a bitmask of variables that might have
changed; if clear, checking those signals for changes may be skipped.
== Coding Conventions
=== Indentation style
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:
+
// -*- mode: C++; c-file-style: "cc-mode" -*-
+
This sets indentation to the `cc-mode` defaults. (Verilator predates a
CC-mode change of several years ago which overrides the defaults with GNU
style indentation; the `c-set-style` undoes that.)
* Use 4 spaces per level, and no tabs.
* Use 2 spaces between the end of source and the beginning of a comment.
* Use "mixedCapsSymbols" instead of "underlined_symbls".
* Comment every member variable.
=== The `astgen` script
Some of the code implementing passes is extremely repetitive, and must be
implemented for each sub-class of `AstNode`. However, while repetitive,
there is more variability than can be handled in C++ macros.
In Verilator this is implemented by using a Perl script, `astgen` to
pre-process the C++ code. For example in `V3Const.cpp` this is used to
implement the `visit()` functions for each binary operation using the
`TREEOP` macro.
The original C++ source code is transformed into C++ code in the `obj_opt`
and `obj_dbg` sub-directories (the former for the optimized version of
Verilator, the latter for the debug version). So for example `V3Const.cpp`
into `V3Const__gen.cpp`.
=== Visitor Functions
Verilator uses the "Visitor" design pattern to implement its refinement and
optimization passes. This allows separation of the pass algorithm from the
AST on which it operates. Wikipedia provides an introduction to the concept
at http://en.wikipedia.org/wiki/Visitor_pattern.
As noted above, all visitors are derived classes of `AstNVisitor`. All
derived classes of `AstNode` implement the `accept` method, which takes as
argument a reference to an instance or a `AstNVisitor` derived class and
applies the visit method of the `AstNVisitor` to the invoking AstNode
instance (i.e. `this`).
One possible difficulty is that a call to `accept` may perform an edit
which destroys the node it receives as argument. The
`acceptSubtreeReturnEdits` method of `AstNode` is provided to apply
`accept` and return the resulting node, even if the original node is
destroyed (if it is not destroyed it will just return the original node).
The behavior of the visitor classes is achieved by overloading the `visit`
function for the different `AstNode` derived classes. If a specific
implementation is not found, the system will look in turn for overloaded
implementations up the inheritance hierarchy. For example calling `accept`
on `AstIf` will look in turn for:
void visit(AstIf* nodep)
void visit(AstNodeIf* nodep)
void visit(AstNodeStmt* nodep)
void visit(AstNode* nodep)
There are three ways data is passed between visitor functions.
1. A visitor-class member variable. This is generally for passing "parent"
information down to children. `m_modp` is a common example. It's set to
NULL in the constructor, where that node (`AstModule` visitor) sets it,
then the children are iterated, then it's cleared. Children under an
`AstModule` will see it set, while nodes elsewhere will see it clear. If
there can be nested items (for example an `AstFor` under an `AstFor`) the
variable needs to be save-set-restored in the `AstFor` visitor, otherwise
exiting the lower for will lose the upper for's setting.
2. User attributes. Each `AstNode` (*Note.* The AST node, not the visitor)
has five user attributes, which may be accessed as an integer using the
`user1()` through `user5()` methods, or as a pointer (of type `AstNUser`)
using the `user1p()` through `user5p()` methods (a common technique lifted
from graph traversal packages).
+
A visitor first clears the one it wants to use by calling
`AstNode::user#ClearTree()`, then it can mark any node's `user#()` with whatever
data it wants. Readers just call `nodep->user()`, but may need to cast
appropriately, so you'll often see `VN_CAST(nodep->userp(), SOMETYPE)`.
At the top of each visitor are comments describing how the `user()` stuff
applies to that visitor class. For example:
+
// NODE STATE
// Cleared entire netlist
// AstModule::user1p() // bool. True to inline this module
+
This says that at the `AstNetlist` `user1ClearTree()` is called. Each
`AstModule`'s `user1()` is used to indicate if we're going to inline it.
+
These comments are important to make sure a `user#()` on a given `AstNode`
type is never being used for two different purposes.
+
Note that calling `user#ClearTree` is fast, it doesn't walk the tree, so
it's ok to call fairly often. For example, it's commonly called on every
module.
3. Parameters can be passed between the visitors in close to the "normal"
function caller to callee way. This is the second `vup` parameter of type
`AstNUser` that is ignored on most of the visitor functions. V3Width does
this, but it proved more messy than the above and is deprecated. (V3Width
was nearly the first module written. Someday this scheme may be removed,
as it slows the program down to have to pass vup everywhere.)
=== Iterators
`AstNVisitor` provides a set of iterators to facilitate walking over the
tree. Each operates on the current `AstNVisitor` class (as this) and takes
an argument type `AstNode*`.
`iterate`::
Applies the `accept` method of the `AstNode` to the visitor function.
`iterateAndNextIgnoreEdit`::
Applies the `accept` method of each `AstNode` in a list (i.e. connected by
`nextp` and `backp` pointers).
`iterateAndNextNull`::
Applies the `accept` method of each `AstNode` in a list, only if the
provided node is non-NULL. If a node is edited by the call to `accept`,
apply `accept` again, until the node does not change.
`iterateListBackwards`::
Applies the `accept` method of each `AstNode` in a list, starting with the
last one.
`iterateChildren`::
Applies the `iterateAndNextNull` method on each child `op1p` through `op4p`
in turn.
`iterateChildrenBackwards`::
Applies the `iterateListBackwards` method on each child `op1p` through
`op4p` in turn.
==== Caution on Using Iterators When Child Changes
Visitors often replace one node with another node; V3Width and V3Const are
major examples. A visitor which is the parent of such a replacement needs
to be aware that calling iteration may cause the children to change. For
example:
// nodep->lhsp() is 0x1234000
iterateAndNextNull(nodep->lhsp()); // and under covers nodep->lhsp() changes
// nodep->lhsp() is 0x5678400
iterateAndNextNull(nodep->lhsp());
Will work fine, as even if the first iterate causes a new node to take the
place of the `lhsp()`, that edit will update `nodep->lhsp()` and the second
call will correctly see the change. Alternatively:
lp = nodep->lhsp();
// nodep->lhsp() is 0x1234000, lp is 0x1234000
iterateAndNextNull(lp); **lhsp=NULL;** // and under covers nodep->lhsp() changes
// nodep->lhsp() is 0x5678400, lp is 0x1234000
iterateAndNextNull(lp);
This will cause bugs or a core dump, as lp is a dangling pointer. Thus it
is advisable to set lhsp=NULL shown in the *'s above to make sure these
dangles are avoided. Another alternative used in special cases mostly in
V3Width is to use acceptSubtreeReturnEdits, which operates on a single node
and returns the new pointer if any. Note acceptSubtreeReturnEdits does not
follow `nextp()` links.
lp = acceptSubtreeReturnEdits(lp)
=== Identifying derived classes
A common requirement is to identify the specific `AstNode` class we are
dealing with. For example a visitor might not implement separate `visit`
methods for `AstIf` and `AstGenIf`, but just a single method for the base
class:
void visit (AstNodeIf* nodep)
However that method might want to specify additional code if it is called
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
possible node type, which returns true if the node is of that type (or
derived from that type). So our `visit` method could use:
if (VN_IS(nodep, AstGenIf) {
<code specific to AstGenIf>
}
Additionally the `VN_CAST` method converts pointers similar to C++
`dynamic_cast`. This either returns a pointer to the object cast to that
type (if it is of class `SOMETYPE`, or a derived class of `SOMETYPE`) or
else NULL. (However, for true/false tests use `VN_IS` as that is faster.)
== Testing
For an overview of how to write a test see the BUGS section of the
Verilator primary manual.
It is important to add tests for failures as well as success (for example
to check that an error message is correctly triggered).
Tests that fail should by convention have the suffix `_bad` in their name,
and include `fails = 1` in either their `compile` or `execute` step as
appropriate.
=== Preparing to Run Tests
For all tests to pass you must install the following packages:
* SystemC to compile the SystemC outputs, see http://systemc.org
* Parallel::Forker from CPAN to run tests in parallel, you can install this
with e.g. "sudo cpan install Parallel::Forker".
* vcddiff to find differences in VCD outputs. See the readme at
https://github.com/veripool/vcddiff
=== 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
For convenience, a summary of the most commonly used features is provided
here. All drivers require a call to `compile` subroutine to compile the
test. For run-time tests, this is followed by a call to the `execute`
subroutine. Both of these functions can optionally be provided with a hash
table as argument specifying additional options.
The test driver assumes by default that the source Verilog file name
matches the PERL driver name. So a test whose driver is `t/t_mytest.pl`
will expect a Verilog source file `t/t_mytest.v`. This can be changed
using the `top_filename` subroutine, for example
top_filename("t/t_myothertest.v");
By default all tests will run with major simulators (Icarus Verilog, NC,
VCS, ModelSim, etc) as well as Verilator, to allow results to be
compared. However if you wish a test only to be used with Verilator, you
can use the following:
scenarios(vlt => 1);
Of the many options that can be set through arguments to `compiler` and
`execute`, the following are particularly useful:
`verilator_flags2`::
A list of flags to be passed to verilator when compiling.
`fails`::
Set to 1 to indicate that the compilation or execution is intended to fail.
For example the following would specify that compilation requires two
defines and is expected to fail.
compile (
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
fails => 1,
);
=== Regression Testing for Developers
Developers will also want to call ./configure with two extra flags:
`--enable-ccwarn`::
Causes the build to stop on warnings as well as errors. A good way to
ensure no sloppy code gets added, however it can be painful when it comes
to testing, since third party code used in the tests (e.g. SystemC) may not
be warning free.
`--enable-longtests`::
In addition to the standard C, SystemC examples, also run the tests in the
`test_regress` directory when using _make test_'. This is disabled by
default as SystemC installation problems would otherwise falsely indicate a
Verilator problem.
When enabling the long tests, some additional PERL modules are needed,
which you can install using cpan.
cpan install Unix::Processors
There are some traps to avoid when running regression tests
* When checking the MANIFEST, the test will barf on unexpected code in the
Verilator tree. So make sure to keep any such code outside the tree.
* Not all Linux systems install Perldoc by default. This is needed for the
`--help_' option to Verilator, and also for regression testing. This can be
installed using cpan:
+
cpan install Pod::Perldoc
+
Many Linux systems also offer a standard package for this. Red
Hat/Fedora/Centos offer _perl-Pod-Perldoc_', while Debian/Ubuntu/Linux Mint
offer `perl-doc'.
* Running regression may exhaust resources on some Linux systems,
particularly file handles and user processes. Increase these to
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.
=== Continuous Integration
Verilator has a https://travis-ci.com/verilator/verilator[Travis CI environment]
which automatically tests the master branch for test failures on new commits. It
also runs a daily cron job to validate all of the tests against different OS and
compiler versions.
Developers can connect Travis CI to their GitHub account so that the CI
enviroment can check their branches too by doing the following:
* Go to https://github.com/marketplace/travis-ci and follow the prompts
* Only the Open Source (FREE) version of Travis CI is required
* Under a Travis CI project click More options > Settings in order to set up a
cron job on a particular branch
== Debugging
=== --debug
When you run with `--debug` there are two primary output file types placed
into the obj_dir, .tree and .dot files.
=== .dot output
Dot files are dumps of internal graphs in
http://www.graphviz.org/[Graphviz] dot format. When a dot file is dumped,
Verilator will also print a line on stdout that can be used to format the
output, for example:
dot -Tps -o ~/a.ps obj_dir/Vtop_foo.dot
You can then print a.ps. You may prefer gif format, which doesn't get
scaled so can be more useful with large graphs.
For dynamic graph viewing consider ZGRViewer
http://zvtm.sourceforge.net/zgrviewer.html. If you know of better
viewers let us know; ZGRViewer isn't great for large graphs.
=== .tree output
Tree files are dumps of the AST Tree and are produced between every major
algorithmic stage. An example:
NETLIST 0x90fb00 <e1> {a0}
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
The following summarizes the above example dump, with more detail on each
field in the section below.
[cols="20%,80%"]
|===
|`1:2:` | indicates the hierarchy of the `VAR` is the `op2p` pointer under
the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
|`VAR` | is the AstNodeType.
| `0x91a780` | is the address of this node.
| `<e74>` | means the 74th edit to the netlist was the last modification to
this node.
| `{a22}` | indicates this node is related to line 22 in the source filename
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
| `@dt=0x...` | indicates the address of the data type this node contains.
| `w32` | indicates the width is 32 bits.
| `out_wide` | is the name of the node, in this case the name of the variable.
| `[O]` | are flags which vary with the type of node, in this case it means the
variable is an output.
|===
In more detail the following fields are dumped common to all nodes. They
are produced by the `AstNode::dump()` method:
Tree Hierarchy::
The dump lines begin with numbers and colons to indicate the child node
hierarchy. As noted above, `AstNode` has lists of items at the same level
in the AST, connected by the `nextp()` and `prevp()` pointers. These appear
as nodes at the same level. For example after inlining:
NETLIST 0x929c1c8 <e1> {a0} w0
1: MODULE 0x92bac80 <e3144> {e14} w0 TOP_t L1 [P]
1:1: CELLINLINE 0x92bab18 <e3686#> {e14} w0 v -> t
1:1: CELLINLINE 0x92bc1d8 <e3688#> {e24} w0 v__DOT__i_test_gen -> test_gen
...
1: MODULE 0x92b9bb0 <e503> {e47} w0 test_gen L3
...
AstNode type::
The textual name of this node AST type (always in capitals). Many of these
correspond directly to Verilog entities (for example `MODULE` and
`TASK`), but others are internal to Verilator (for example `NETLIST` and
`BASICDTYPE`).
Address of the node::
A hexadecimal address of the node in memory. Useful for examining with the
debugger.
Last edit number::
Of the form `<ennnn>` or `<ennnn#>` , where `nnnn` is the number
of the last edit to modify this node. The trailing `#` indicates the node
has been edited since the last tree dump (which typically means in the last
refinement or optimization pass). GDB can watch for this, see << /Debugging >>.
Source file and line::
Of the form `{xxnnnn}`, where C{xx} is the filename letter (or
letters) and `nnnn` is the line number within that file. The first file is
`a`, the 26th is `z`, the 27th is `aa` and so on.
User pointers::
Shows the value of the node's user1p...user5p, if non-NULL.
Data type::
Many nodes have an explicit data type. "@dt=0x..." indicates the address
of the data type (AstNodeDType) this node uses.
+
If a data type is present and is numeric, it then prints the width of the
item. This field is a sequence of flag characters and width data as follows:
+
* `s` if the node is signed.
* `d` if the node is a double (i.e a floating point entity).
* `w` always present, indicating this is the width field.
* `u` if the node is unsized.
* `/nnnn` if the node is unsized, where `nnnn` is the minimum width.
Name of the entity represented by the node if it exists::
For example for a `VAR` it is the name of the variable.
Many nodes follow these fields with additional node specific
information. Thus the `VARREF` node will print either `[LV]` or `[RV]`
to indicate a left value or right value, followed by the node of the
variable being referred to. For example:
1:2:1:1: VARREF 0x92c2598 <e509> {e24} w0 clk [RV] <- VAR 0x92a2e90 <e79> {e18} w0 clk [I] INPUT
In general, examine the `dump()` method in `V3AstNodes.cpp` of the node
type in question to determine additional fields that may be printed.
The `MODULE` has a list of `CELLINLINE` nodes referred to by its
`op1p()` pointer, connected by `nextp()` and `prevp()` pointers.
Similarly the `NETLIST` has a list of modules referred to by its `op1p()`
pointer.
=== Debugging with GDB
The test_regress/driver.pl script accepts `--debug --gdb` to start
Verilator under gdb and break when an error is hit or the program is about
to exit. You can also use `--debug --gdbbt` to just backtrace and then
exit gdb. To debug the Verilated executable, use `--gdbsim`.
If you wish to start Verilator under GDB (or another debugger), then you
can use `--debug` and look at the underlying invocation of
`verilator_dbg`. For example
t/t_alw_dly.pl --debug
shows it invokes the command:
../verilator_bin_dbg --prefix Vt_alw_dly --x-assign unique --debug
-cc -Mdir obj_dir/t_alw_dly --debug-check -f input.vc t/t_alw_dly.v
Start GDB, then `start` with the remaining arguments.
gdb ../verilator_bin_dbg
...
(gdb) start --prefix Vt_alw_dly --x-assign unique --debug -cc -Mdir
obj_dir/t_alw_dly --debug-check -f input.vc t/t_alw_dly.v
> obj_dir/t_alw_dly/vlt_compile.log
...
Temporary breakpoint 1, main (argc=13, argv=0xbfffefa4, env=0xbfffefdc)
at ../Verilator.cpp:615
615 ios::sync_with_stdio();
(gdb)
You can then continue execution with breakpoints as required.
To break at a specific edit number which changed a node (presumably to find
what made a <e####> line in the tree dumps):
watch AstNode::s_editCntGbl==####
To print a node:
pn nodep
# or: call nodep->dumpGdb() # aliased to "pn" in src/.gdbinit
pnt nodep
# or: call nodep->dumpTreeGdb() # aliased to "pnt" in src/.gdbinit
When GDB halts, it is useful to understand that the backtrace will commonly
show the iterator functions between each invocation of `visit` in the
backtrace. You will typically see a frame sequence something like
...
visit()
iterateChildren()
iterateAndNext()
accept()
visit()
...
== Adding a New Feature
Generally what would you do to add a new feature?
. File an issue (if there isn't already) so others know what you're working on.
. Make a testcase in the test_regress/t/t_EXAMPLE format, see << /TESTING >>.
. If grammar changes are needed, look at the git version of VerilogPerl's
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.
. 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
file which you can examine to see if the parsing worked. See also the
sections above on debugging.
. Modify the later visitor functions to process the new feature as needed.
=== Adding a new pass
For more substantial changes you may need to add a new pass. The simplest
way to do this is to copy the `.cpp` and `.h` files from an existing
pass. You'll need to add a call into your pass from the `process()`
function in `src/verilator.cpp`.
To get your pass to build you'll need to add its binary filename to the
list in `src/Makefile_obj.in` and reconfigure.
== Distribution
Copyright 2008-2019 by Wilson Snyder. Verilator 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.
+17 -2
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#define _VERILATED_CPP_
#include "verilatedos.h"
@@ -43,9 +43,13 @@
// Static sanity checks (when get C++11 can use static_assert)
typedef union {
// cppcheck-suppress unusedStructMember // Unused as is assertion
char vluint8_incorrect[(sizeof(vluint8_t) == 1) ? 1:-1];
// cppcheck-suppress unusedStructMember // Unused as is assertion
char vluint16_incorrect[(sizeof(vluint16_t) == 2) ? 1:-1];
// cppcheck-suppress unusedStructMember // Unused as is assertion
char vluint32_incorrect[(sizeof(vluint32_t) == 4) ? 1:-1];
// cppcheck-suppress unusedStructMember // Unused as is assertion
char vluint64_incorrect[(sizeof(vluint64_t) == 8) ? 1:-1];
} vl_static_checks_t;
@@ -1374,6 +1378,7 @@ void VL_WRITEMEM_N(
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;
}
@@ -1511,6 +1516,7 @@ void VL_READMEM_N(
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
@@ -2101,9 +2107,11 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
VerilatedScope::VerilatedScope() {
m_callbacksp = NULL;
m_namep = NULL;
m_identifierp = NULL;
m_funcnumMax = 0;
m_symsp = NULL;
m_varsp = NULL;
m_type = SCOPE_OTHER;
}
VerilatedScope::~VerilatedScope() {
@@ -2116,15 +2124,18 @@ VerilatedScope::~VerilatedScope() {
}
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp,
const char* suffixp) VL_MT_UNSAFE {
const char* suffixp, const char* identifier,
const Type type) VL_MT_UNSAFE {
// Slowpath - called once/scope at construction
// We don't want the space and reference-count access overhead of strings.
m_symsp = symsp;
m_type = type;
char* namep = new char[strlen(prefixp)+strlen(suffixp)+2];
strcpy(namep, prefixp);
if (*prefixp && *suffixp) strcat(namep, ".");
strcat(namep, suffixp);
m_namep = namep;
m_identifierp = identifier;
VerilatedImp::scopeInsert(this);
}
@@ -2229,6 +2240,10 @@ void VerilatedScope::scopeDump() const {
}
}
void VerilatedHierarchy::add(VerilatedScope* fromp, VerilatedScope* top) {
VerilatedImp::hierarchyAdd(fromp, top);
}
//===========================================================================
// VerilatedOneThreaded:: Methods
+20 -3
View File
@@ -23,7 +23,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_H_
#define _VERILATED_H_ 1 ///< Header Guard
@@ -203,6 +203,8 @@ public:
//=========================================================================
/// Base class for all Verilated module classes
class VerilatedScope;
class VerilatedModule {
VL_UNCOPYABLE(VerilatedModule);
private:
@@ -290,6 +292,11 @@ public: // But for internal use only
/// This class is initialized by main thread only. Reading post-init is thread safe.
class VerilatedScope {
public:
typedef enum {
SCOPE_MODULE, SCOPE_OTHER
} Type; // Type of a scope, currently module is only interesting
private:
// Fastpath:
VerilatedSyms* m_symsp; ///< Symbol table
void** m_callbacksp; ///< Callback table pointer (Fastpath)
@@ -297,16 +304,20 @@ class VerilatedScope {
// 4 bytes padding (on -m64), for rent.
VerilatedVarNameMap* m_varsp; ///< Variable map
const char* m_namep; ///< Scope name (Slowpath)
const char* m_identifierp; ///< Identifier of scope (with escapes removed)
Type m_type; ///< Type of the scope
public: // But internals only - called from VerilatedModule's
VerilatedScope();
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp) VL_MT_UNSAFE;
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffix,
const char* identifier, const Type type) VL_MT_UNSAFE;
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
// ACCESSORS
const char* name() const { return m_namep; }
const char* identifier() const { return m_identifierp; }
inline VerilatedSyms* symsp() const { return m_symsp; }
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
@@ -322,6 +333,12 @@ public: // But internals only - called from VerilatedModule's
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
}
}
Type type() const { return m_type; }
};
class VerilatedHierarchy {
public:
void add(VerilatedScope* fromp, VerilatedScope* top);
};
//===========================================================================
@@ -736,7 +753,7 @@ extern double sc_time_stamp();
# define SP_AUTO_COVER3(what,file,line)
#endif
//=========================================================================
// Functional macros/routines
// These all take the form
+1 -1
View File
@@ -17,7 +17,7 @@
//=========================================================================
//
// DESCRIPTION: Verilator: Include in verilog files to hide verilator defines
`ifdef _VERILATED_V_ `else
`define _VERILATED_V_ 1
+1 -1
View File
@@ -19,7 +19,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
///**** Product and Version name
+1 -1
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#define _VERILATED_DPI_CPP_
#include "verilatedos.h"
+1 -1
View File
@@ -23,7 +23,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_DPI_H_
#define _VERILATED_DPI_H_ 1 ///< Header Guard
+1 -1
View File
@@ -24,7 +24,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_HEAVY_H_
#define _VERILATED_HEAVY_H_ 1 ///< Header Guard
+18 -2
View File
@@ -19,12 +19,12 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#ifndef _VERILATED_IMP_H_
#define _VERILATED_IMP_H_ 1 ///< Header Guard
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_)
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_)
# error "verilated_imp.h only to be included by verilated*.cpp internals"
#endif
@@ -187,6 +187,10 @@ class VerilatedImp {
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); ///< Map the represents scope hierarchy
// Slow - somewhat static:
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
@@ -321,6 +325,18 @@ public: // But only for verilated*.cpp
return &s_s.m_nameMap;
}
public: // But only for verilated*.cpp
// METHODS - hierarchy
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
// Slow ok - called at construction for VPI accessible elements
VerilatedLockGuard lock(s_s.m_hierMapMutex);
s_s.m_hierMap[fromp].push_back(top);
}
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
// Thread save only assuming this is called only after model construction completed
return &s_s.m_hierMap;
}
public: // But only for verilated*.cpp
// METHODS - export names
+1 -1
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_SC_H_
#define _VERILATED_SC_H_ 1 ///< Header Guard
+1 -1
View File
@@ -27,7 +27,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_SYM_PROPS_H_
#define _VERILATED_SYM_PROPS_H_ 1 ///< Header Guard
+11 -1
View File
@@ -26,7 +26,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_SYMS_H_
#define _VERILATED_SYMS_H_ 1 ///< Header Guard
@@ -36,6 +36,7 @@
#include "verilated_sym_props.h"
#include <map>
#include <vector>
//======================================================================
/// Types
@@ -63,4 +64,13 @@ public:
~VerilatedVarNameMap() {}
};
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
class VerilatedHierarchyMap
: public std::map<const VerilatedScope*, VerilatedScopeVector> {
public:
VerilatedHierarchyMap() {}
~VerilatedHierarchyMap() {}
};
#endif // Guard
+1
View File
@@ -186,6 +186,7 @@ public:
m_mtaskId = 0;
m_predictTime = 0;
m_startTime = 0;
m_endTime = 0;
m_cpu = getcpu();
}
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
+1 -1
View File
@@ -325,7 +325,7 @@ void VerilatedVcd::printQuad(vluint64_t n) {
void VerilatedVcd::printTime(vluint64_t timeui) {
// VCD file format specification does not allow non-integers for timestamps
// Dinotrace doesn't mind, but Cadence vvision seems to choke
// Dinotrace doesn't mind, but Cadence Vision seems to choke
if (VL_UNLIKELY(timeui < m_timeLastDump)) {
timeui = m_timeLastDump;
static VL_THREAD_LOCAL bool backTime = false;
+82 -10
View File
@@ -24,17 +24,20 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#define _VERILATED_VPI_CPP_
#if VM_SC
# include "verilated_sc.h"
#endif
#include "verilated.h"
#include "verilated_vpi.h"
#include "verilated_imp.h"
#include <list>
#include <map>
#include <set>
#include <sstream>
//======================================================================
// Internal constants
@@ -161,6 +164,7 @@ public:
};
class VerilatedVpioScope : public VerilatedVpio {
protected:
const VerilatedScope* m_scopep;
public:
explicit VerilatedVpioScope(const VerilatedScope* scopep)
@@ -210,7 +214,6 @@ public:
vluint32_t entSize() const { return m_entSize; }
vluint32_t index() { return m_index; }
virtual vluint32_t type() const {
if (varp()->vldir() != vpiNoDirection) return vpiPort;
return (varp()->dims()>1) ? vpiMemory : vpiReg; // but might be wire, logic
}
virtual vluint32_t size() const { return get_range().elements(); }
@@ -308,6 +311,43 @@ public:
}
};
class VerilatedVpioModule : public VerilatedVpioScope {
const char* m_name;
const char* m_fullname;
public:
explicit VerilatedVpioModule(const VerilatedScope* modulep)
: VerilatedVpioScope(modulep) {
m_fullname = m_scopep->name();
if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4;
m_name = m_scopep->identifier();
}
static inline VerilatedVpioModule* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioModule*>((VerilatedVpio*)h); }
virtual vluint32_t type() const { return vpiModule; }
virtual const char* name() const { return m_name; }
virtual const char* fullname() const { return m_fullname; }
};
class VerilatedVpioModuleIter : public VerilatedVpio {
const std::vector<const VerilatedScope*> *m_vec;
std::vector<const VerilatedScope*>::const_iterator m_it;
public:
explicit VerilatedVpioModuleIter(const std::vector<const VerilatedScope*>& vec) : m_vec(&vec) {
m_it = m_vec->begin();
}
virtual ~VerilatedVpioModuleIter() {}
static inline VerilatedVpioModuleIter* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioModuleIter*>((VerilatedVpio*) h); }
virtual vluint32_t type() const { return vpiIterator; }
virtual vpiHandle dovpi_scan() {
if (m_it == m_vec->end()) {
return 0;
}
const VerilatedScope* modp = *m_it++;
return (new VerilatedVpioModule(modp))->castVpiHandle();
}
};
//======================================================================
struct VerilatedVpiTimedCbsCmp {
@@ -390,8 +430,9 @@ public:
}
return ~VL_ULL(0); // maxquad
}
static void callCbs(vluint32_t reason) {
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
bool called = false;
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
@@ -400,7 +441,9 @@ public:
VerilatedVpioCb* vop = *it++;
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback %d %p\n", reason, vop););
(vop->cb_rtnp()) (vop->cb_datap());
called = true;
}
return called;
}
static void callValueCbs() VL_MT_UNSAFE_ONE {
assertOneCheck();
@@ -521,6 +564,10 @@ void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE {
VerilatedVpiImp::callValueCbs();
}
bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
return VerilatedVpiImp::callCbs(reason);
}
//======================================================================
// VerilatedVpiImp implementation
@@ -992,9 +1039,9 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!namep)) return NULL;
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_name %s %p\n", namep, scope););
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
const VerilatedVar* varp;
const VerilatedVar* varp = NULL;
const VerilatedScope* scopep;
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
std::string scopeAndName = namep;
if (voScopep) {
scopeAndName = std::string(voScopep->fullname()) + "." + namep;
@@ -1004,7 +1051,11 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
// This doesn't yet follow the hierarchy in the proper way
scopep = Verilated::scopeFind(namep);
if (scopep) { // Whole thing found as a scope
return (new VerilatedVpioScope(scopep))->castVpiHandle();
if (scopep->type() == VerilatedScope::SCOPE_MODULE) {
return (new VerilatedVpioModule(scopep))->castVpiHandle();
} else {
return (new VerilatedVpioScope(scopep))->castVpiHandle();
}
}
const char* baseNamep = scopeAndName.c_str();
std::string scopename;
@@ -1013,9 +1064,19 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
baseNamep = dotp+1;
scopename = std::string(namep, dotp-namep);
}
scopep = Verilated::scopeFind(scopename.c_str());
if (!scopep) return NULL;
varp = scopep->varFind(baseNamep);
if (scopename.find(".") == std::string::npos) {
// This is a toplevel, hence search in our TOP ports first.
scopep = Verilated::scopeFind("TOP");
if (scopep) {
varp = scopep->varFind(baseNamep);
}
}
if (!varp) {
scopep = Verilated::scopeFind(scopename.c_str());
if (!scopep) return NULL;
varp = scopep->varFind(baseNamep);
}
}
if (!varp) return NULL;
return (new VerilatedVpioVar(varp, scopep))->castVpiHandle();
@@ -1127,6 +1188,14 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
return ((new VerilatedVpioVarIter(vop->scopep()))
->castVpiHandle());
}
case vpiModule: {
VerilatedVpioModule* vop = VerilatedVpioModule::castp(object);
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
const VerilatedScope *mod = vop ? vop->scopep() : NULL;
VerilatedHierarchyMap::const_iterator it = map->find((VerilatedScope*) mod);
if (it == map->end()) return 0;
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
@@ -1154,7 +1223,7 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
return VL_TIME_PRECISION;
}
case vpiType: {
VerilatedVpio* vop = VerilatedVpioVar::castp(object);
VerilatedVpio* vop = VerilatedVpio::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
return vop->type();
}
@@ -1203,6 +1272,9 @@ PLI_BYTE8 *vpi_get_str(PLI_INT32 property, vpiHandle object) {
case vpiDefName: {
return (PLI_BYTE8*)vop->defname();
}
case vpiType: {
return (PLI_BYTE8*) VerilatedVpiError::strFromVpiObjType(vop->type());
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
+4 -1
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#ifndef _VERILATED_VPI_H_
#define _VERILATED_VPI_H_ 1 ///< Header Guard
@@ -45,6 +45,9 @@ public:
/// Call value based callbacks
/// Users should call this from their main loops
static void callValueCbs() VL_MT_UNSAFE_ONE;
/// Call callbacks of arbitrary types
/// Users can call this from their application code
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE;
/// Self test, for internal use only
static void selfTest() VL_MT_UNSAFE_ONE;
};
+1 -1
View File
@@ -25,7 +25,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATEDOS_H_
#define _VERILATEDOS_H_ 1 ///< Header Guard
-1006
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -38,8 +38,8 @@ cwrite("graph_export.cpp");
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
+2 -2
View File
@@ -43,8 +43,8 @@ dotwrite();
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
+2 -1
View File
@@ -22,7 +22,8 @@ Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"help" => sub { print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval => 2, output=>\*STDOUT, -noperldoc=>1); },
pod2usage(-verbose=>2, -exitval => 0,
output=>\*STDOUT, -noperldoc=>1); },
"narrow!" => sub { $Opt_Widen = 0; },
"version" => sub { print "Version $VERSION\n"; exit(0); },
"widen!" => sub { $Opt_Widen = 1; }, # Default, undocumented
+2 -2
View File
@@ -40,8 +40,8 @@ print '(query-replace-regexp "(\\([0-9a-z_]+\\))" "\\1" nil nil nil)',"\n";
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
+11 -11
View File
@@ -29,7 +29,7 @@
// WIRE: Move into SACTIVE(combo)
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -140,7 +140,7 @@ public:
return activep;
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ActiveNamer() {
m_scopep = NULL;
m_iActivep = NULL;
@@ -196,7 +196,7 @@ private:
AstVar* varp = nodep->varp();
if (m_check == CT_SEQ
&& m_assignp
&& !varp->isUsedLoopIdx() // Ignore loop indicies
&& !varp->isUsedLoopIdx() // Ignore loop indices
&& !varp->isTemp()) {
// Allow turning off warnings on the always, or the variable also
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
@@ -214,7 +214,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ActiveDlyVisitor(AstNode* nodep, CheckType check) {
m_alwaysp = nodep;
m_check = check;
@@ -301,7 +301,7 @@ private:
m_namer.scopep()->addActivep(m_scopeFinalp);
}
nodep->unlinkFrBack();
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName()));
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName(), true));
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext());
nodep->deleteTree(); VL_DANGLING(nodep);
}
@@ -320,7 +320,7 @@ private:
return;
}
// Read sensitivitues
// Read sensitivities
m_itemCombo = false;
m_itemSequent = false;
iterateAndNextNull(oldsensesp);
@@ -392,14 +392,14 @@ private:
}
virtual void visit(AstSenGate* nodep) {
AstSenItem* subitemp = nodep->sensesp();
UASSERT_OBJ(subitemp->edgeType() == AstEdgeType::ET_ANYEDGE
|| subitemp->edgeType() == AstEdgeType::ET_POSEDGE
|| subitemp->edgeType() == AstEdgeType::ET_NEGEDGE,
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
nodep, "Strange activity type under SenGate");
iterateChildren(nodep);
}
virtual void visit(AstSenItem* nodep) {
if (nodep->edgeType() == AstEdgeType::ET_ANYEDGE) {
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
m_itemCombo = true;
// Delete the sensitivity
// We'll add it as a generic COMBO SenItem in a moment.
@@ -423,7 +423,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ActiveVisitor(AstNetlist* nodep) {
m_scopeFinalp = NULL;
m_itemCombo = false;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ACTIVE_H_
#define _V3ACTIVE_H_ 1
+2 -2
View File
@@ -26,7 +26,7 @@
// Move SenTree the global SenTree
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -139,7 +139,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ActiveTopVisitor(AstNetlist* nodep) {
m_topscopep = NULL;
iterate(nodep);
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ACTIVETOP_H_
#define _V3ACTIVETOP_H_ 1
+9 -9
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -44,10 +44,10 @@ private:
AstNodeModule* m_modp; // Last module
AstBegin* m_beginp; // Last begin
unsigned m_modPastNum; // Module past numbering
V3Double0 m_statAsCover; // Statistic tracking
V3Double0 m_statAsPsl; // Statistic tracking
V3Double0 m_statAsFull; // Statistic tracking
V3Double0 m_statAsSV; // Statistic tracking
VDouble0 m_statAsCover; // Statistic tracking
VDouble0 m_statAsPsl; // Statistic tracking
VDouble0 m_statAsFull; // Statistic tracking
VDouble0 m_statAsSV; // Statistic tracking
// METHODS
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
@@ -143,7 +143,7 @@ private:
ifp = new AstIf(nodep->fileline(), propp, NULL, stmtsp);
// It's more LIKELY that we'll take the NULL if clause
// than the sim-killing else clause:
ifp->branchPred(AstBranchPred::BP_LIKELY);
ifp->branchPred(VBranchPred::BP_LIKELY);
bodysp = newIfAssertOn(ifp);
} else if (VN_IS(nodep, PslRestrict)) {
// IEEE says simulator ignores these
@@ -182,7 +182,7 @@ private:
AstIf* ifp = new AstIf(nodep->fileline(), propp, passsp, failsp);
AstNode* newp = ifp;
if (VN_IS(nodep, VAssert)) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
if (VN_IS(nodep, VAssert)) ifp->branchPred(VBranchPred::BP_UNLIKELY);
//
// Install it
nodep->replaceWith(newp);
@@ -242,7 +242,7 @@ private:
new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep, "'unique if' statement violated"),
newifp);
checkifp->branchPred(AstBranchPred::BP_UNLIKELY);
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->replaceWith(checkifp);
pushDeletep(nodep);
} else {
@@ -305,7 +305,7 @@ private:
new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"),
NULL);
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
ifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->addNotParallelp(ifp);
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASSERT_H_
#define _V3ASSERT_H_ 1
+2 -2
View File
@@ -20,7 +20,7 @@
// Pre steps:
// Attach clocks to each assertion
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -95,7 +95,7 @@ private:
virtual void visit(AstNodePslCoverOrAssert* nodep) {
if (nodep->sentreep()) return; // Already processed
clearAssertInfo();
// Find PslClocking's burried under nodep->exprsp
// Find PslClocking's buried under nodep->exprsp
iterateChildren(nodep);
nodep->sentreep(newSenTree(nodep));
clearAssertInfo();
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASSERTPRE_H_
#define _V3ASSERTPRE_H_ 1
+10 -4
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -113,7 +113,8 @@ string AstNode::encodeName(const string& namein) {
// a user identifier nor a temp we create in Verilator.
// We also do *NOT* use __DOT__ etc, as we search for those
// in some replacements, and don't want to mangle the user's names.
char hex[10]; sprintf(hex, "__0%02X", pos[0]);
unsigned val = pos[0] & 0xff; // Mask to avoid sign extension
char hex[10]; sprintf(hex, "__0%02X", val);
out += hex;
}
}
@@ -262,7 +263,7 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
UDEBUGONLY(UASSERT_OBJ(!oldtailp->m_nextp, nodep,
"Node had next, but headtail says it shouldn't"););
} else {
// Though inefficent, we are occasionally passed a addNext in the middle of a list.
// Though inefficient, we are occasionally passed a addNext in the middle of a list.
while (oldtailp->m_nextp != NULL) oldtailp = oldtailp->m_nextp;
}
}
@@ -976,23 +977,28 @@ void AstNode::checkTree() {
}
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
cout<<" "; dump(cout); cout<<endl; // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
dumpPtrs(cout); // LCOV_EXCL_LINE
cout<<" Fileline = "<<fileline()<<endl; // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
dumpTree(cout); // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::checkIter() const {
if (m_iterpp) {
dumpPtrs(cout);
@@ -1090,7 +1096,7 @@ string AstNode::locationStr() const {
const AstScope* scopep;
if ((scopep = VN_CAST_CONST(backp, Scope))) {
// The design is flattened and there are no useful scopes
// This is probably because of inilining
// This is probably because of inlining
if (scopep->isTop()) break;
str += scopep->prettyName();
+59 -54
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3AST_H_
#define _V3AST_H_ 1
@@ -73,7 +73,7 @@ public:
// enum en {...};
// const char* ascii() const {...};
enum en m_e;
// cppcheck-suppress uninitVar // responsiblity of each subclass
// cppcheck-suppress uninitVar // responsibility of each subclass
inline AstType() {}
// cppcheck-suppress noExplicitConstructor
inline AstType(en _e) : m_e(_e) {}
@@ -185,7 +185,7 @@ public:
//######################################################################
class AstEdgeType {
class VEdgeType {
public:
// REMEMBER to edit the strings below too
enum en {
@@ -213,7 +213,7 @@ public:
};
return clocked[m_e];
}
AstEdgeType invert() const {
VEdgeType invert() const {
switch (m_e) {
case ET_ANYEDGE: return ET_ANYEDGE;
case ET_BOTHEDGE: return ET_BOTHEDGE;
@@ -223,7 +223,7 @@ public:
case ET_LOWEDGE: return ET_HIGHEDGE;
default: UASSERT_STATIC(0, "Inverting bad edgeType()");
};
return AstEdgeType::ET_ILLEGAL;
return VEdgeType::ET_ILLEGAL;
}
const char* ascii() const {
static const char* const names[] = {
@@ -240,20 +240,20 @@ public:
return names[m_e];
}
// Return true iff this and the other have mutually exclusive transitions
bool exclusiveEdge(const AstEdgeType& other) const {
bool exclusiveEdge(const VEdgeType& other) const {
switch (m_e) {
case AstEdgeType::ET_POSEDGE:
case VEdgeType::ET_POSEDGE:
switch (other.m_e) {
case AstEdgeType::ET_NEGEDGE: // FALLTHRU
case AstEdgeType::ET_LOWEDGE:
case VEdgeType::ET_NEGEDGE: // FALLTHRU
case VEdgeType::ET_LOWEDGE:
return true;
default: {}
}
break;
case AstEdgeType::ET_NEGEDGE:
case VEdgeType::ET_NEGEDGE:
switch (other.m_e) {
case AstEdgeType::ET_POSEDGE: // FALLTHRU
case AstEdgeType::ET_HIGHEDGE:
case VEdgeType::ET_POSEDGE: // FALLTHRU
case VEdgeType::ET_HIGHEDGE:
return true;
default: {}
}
@@ -262,15 +262,15 @@ public:
}
return false;
}
inline AstEdgeType() : m_e(ET_ILLEGAL) {}
inline VEdgeType() : m_e(ET_ILLEGAL) {}
// cppcheck-suppress noExplicitConstructor
inline AstEdgeType(en _e) : m_e(_e) {}
explicit inline AstEdgeType(int _e) : m_e(static_cast<en>(_e)) {}
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==(AstEdgeType lhs, AstEdgeType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstEdgeType lhs, AstEdgeType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstEdgeType::en lhs, AstEdgeType rhs) { return (lhs == rhs.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); }
//######################################################################
@@ -613,7 +613,7 @@ public:
//######################################################################
class AstBranchPred {
class VBranchPred {
public:
enum en {
BP_UNKNOWN=0,
@@ -623,12 +623,15 @@ public:
};
enum en m_e;
// CONSTRUCTOR - note defaults to *UNKNOWN*
inline AstBranchPred() : m_e(BP_UNKNOWN) {}
inline VBranchPred() : m_e(BP_UNKNOWN) {}
// cppcheck-suppress noExplicitConstructor
inline AstBranchPred(en _e) : m_e(_e) {}
explicit inline AstBranchPred(int _e) : m_e(static_cast<en>(_e)) {}
inline VBranchPred(en _e) : m_e(_e) {}
explicit inline VBranchPred(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
AstBranchPred invert() const {
bool unknown() const { return m_e == BP_UNKNOWN; }
bool likely() const { return m_e == BP_LIKELY; }
bool unlikely() const { return m_e == BP_UNLIKELY; }
VBranchPred invert() const {
if (m_e==BP_UNLIKELY) return BP_LIKELY;
else if (m_e==BP_LIKELY) return BP_UNLIKELY;
else return m_e;
@@ -638,14 +641,14 @@ public:
"", "VL_LIKELY", "VL_UNLIKELY"};
return names[m_e]; }
};
inline bool operator==(AstBranchPred lhs, AstBranchPred rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstBranchPred lhs, AstBranchPred::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstBranchPred::en lhs, AstBranchPred rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const AstBranchPred& rhs) { return os<<rhs.ascii(); }
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(); }
//######################################################################
class AstVarAttrClocker {
class VVarAttrClocker {
public:
enum en {
CLOCKER_UNKNOWN=0,
@@ -655,13 +658,13 @@ public:
};
enum en m_e;
// CONSTRUCTOR - note defaults to *UNKNOWN*
inline AstVarAttrClocker() : m_e(CLOCKER_UNKNOWN) {}
inline VVarAttrClocker() : m_e(CLOCKER_UNKNOWN) {}
// cppcheck-suppress noExplicitConstructor
inline AstVarAttrClocker(en _e) : m_e(_e) {}
explicit inline AstVarAttrClocker(int _e) : m_e(static_cast<en>(_e)) {}
inline VVarAttrClocker(en _e) : m_e(_e) {}
explicit inline VVarAttrClocker(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
bool unknown() const { return m_e==CLOCKER_UNKNOWN; }
AstVarAttrClocker invert() const {
VVarAttrClocker invert() const {
if (m_e==CLOCKER_YES) return CLOCKER_NO;
else if (m_e==CLOCKER_NO) return CLOCKER_YES;
else return m_e;
@@ -671,10 +674,10 @@ public:
"", "clker", "non_clker"};
return names[m_e]; }
};
inline bool operator==(AstVarAttrClocker lhs, AstVarAttrClocker rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstVarAttrClocker lhs, AstVarAttrClocker::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstVarAttrClocker::en lhs, AstVarAttrClocker rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const AstVarAttrClocker& rhs) { return os<<rhs.ascii(); }
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(); }
//######################################################################
@@ -753,33 +756,34 @@ public:
//######################################################################
class AstParseRefExp {
class VParseRefExp {
public:
enum en {
PX_NONE, // Used in V3LinkParse only
PX_TEXT // Unknown ID component
};
enum en m_e;
inline AstParseRefExp() : m_e(PX_NONE) {}
inline VParseRefExp() : m_e(PX_NONE) {}
// cppcheck-suppress noExplicitConstructor
inline AstParseRefExp(en _e) : m_e(_e) {}
explicit inline AstParseRefExp(int _e) : m_e(static_cast<en>(_e)) {}
inline VParseRefExp(en _e) : m_e(_e) {}
explicit inline VParseRefExp(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {
"", "TEXT", "PREDOT"};
return names[m_e]; }
};
inline bool operator==(AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator==(AstParseRefExp lhs, AstParseRefExp::en rhs) { return (lhs.m_e == rhs); }
inline bool operator==(AstParseRefExp::en lhs, AstParseRefExp rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const AstParseRefExp& rhs) { return os<<rhs.ascii(); }
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(); }
//######################################################################
// VNumRange - Structure containing numberic range information
// VNumRange - Structure containing numeric range information
// See also AstRange, which is a symbolic version of this
struct VNumRange {
class VNumRange {
public:
int m_hi; // HI part, HI always >= LO
int m_lo; // LO
union {
@@ -834,7 +838,8 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) { rhs.du
//######################################################################
struct VBasicTypeKey {
class VBasicTypeKey {
public:
int m_width; // From AstNodeDType: Bit width of operation
int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
AstNumeric m_numeric; // From AstNodeDType: Node is signed
@@ -910,7 +915,7 @@ public:
//
// AstUser2InUse m_userres;
//
// This will clear the tree, and prevent another visitor from clobering
// This will clear the tree, and prevent another visitor from clobbering
// user2. When the member goes out of scope it will be automagically
// freed up.
@@ -1198,7 +1203,7 @@ public:
void debugTreeChange(const char* prefix, int lineno, bool next);
protected:
// CONSTUCTORS
// CONSTRUCTORS
AstNode() {init(); }
explicit AstNode(FileLine* fileline) {init(); m_fileline = fileline; }
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
@@ -1262,7 +1267,7 @@ public:
static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines
static int instrCountDouble() { return 8; } ///< Instruction cycles to convert or do floats
static int instrCountDoubleDiv() { return 40; } ///< Instruction cycles to divide floats
static int instrCountDoubleTrig() { return 200; } ///< Instruction cycles to do triganomics
static int instrCountDoubleTrig() { return 200; } ///< Instruction cycles to do trigonomics
static int instrCountString() { return 100; } ///< Instruction cycles to do string ops
static int instrCountCall() { return instrCountBranch()+10; } ///< Instruction cycles to call subroutine
static int instrCountTime() { return instrCountCall()+5; } ///< Instruction cycles to determine simulation time
@@ -1754,7 +1759,7 @@ public:
class AstNodeIf : public AstNodeStmt {
private:
AstBranchPred m_branchPred; // Branch prediction as taken/untaken?
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
public:
AstNodeIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
: AstNodeStmt(fl) {
@@ -1772,8 +1777,8 @@ public:
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
void branchPred(AstBranchPred flag) { m_branchPred = flag; }
AstBranchPred branchPred() const { return m_branchPred; }
void branchPred(VBranchPred flag) { m_branchPred = flag; }
VBranchPred branchPred() const { return m_branchPred; }
};
class AstNodeCase : public AstNodeStmt {
@@ -2189,7 +2194,7 @@ class AstNodeModule : public AstNode {
private:
string m_name; // Name of the module
string m_origName; // Name of the module, ignoring name() changes, for dot lookup
string m_hierName; // Hierachical name for errors, etc.
string m_hierName; // Hierarchical name for errors, etc.
bool m_modPublic:1; // Module has public references
bool m_modTrace:1; // Tracing this module
bool m_inLibrary:1; // From a library, no error if not used, never top level
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASTCONSTONLY_H_
#define _V3ASTCONSTONLY_H_ 1
+19 -7
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -120,7 +120,9 @@ int AstNodeClassDType::widthAlignBytes() const {
}
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
} else {
return new AstEq(fl, lhsp, rhsp);
@@ -128,7 +130,9 @@ AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
if (lhsp->isString() && rhsp->isString()) {
return new AstGteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstGteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstGteS(fl, lhsp, rhsp);
@@ -138,7 +142,9 @@ AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
if (lhsp->isString() && rhsp->isString()) {
return new AstLteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstLteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstLteS(fl, lhsp, rhsp);
@@ -148,7 +154,9 @@ AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
} else {
return new AstEqWild(fl, lhsp, rhsp);
@@ -465,7 +473,7 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
string AstVar::mtasksString() const {
std::ostringstream os;
os<<" all: ";
os<<"all: ";
for (MTaskIdSet::const_iterator it = m_mtaskIds.begin();
it != m_mtaskIds.end(); ++it) {
os<<*it<<" ";
@@ -919,9 +927,9 @@ void AstRange::dump(std::ostream& str) {
if (littleEndian()) str<<" [LITTLE]";
}
void AstRefDType::dump(std::ostream& str) {
static bool s_recursing = false;
this->AstNodeDType::dump(str);
if (defp()) {
static bool s_recursing = false;
if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true;
str<<" -> "; defp()->dump(str);
@@ -1155,6 +1163,10 @@ void AstNodeText::dump(std::ostream& str) {
str<<" \""<<out<<"\"";
}
void AstVFile::dump(std::ostream& str) {
this->AstNode::dump(str);
}
void AstCFile::dump(std::ostream& str) {
this->AstNode::dump(str);
if (source()) str<<" [SRC]";
+177 -42
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASTNODES_H_
#define _V3ASTNODES_H_ 1
@@ -334,7 +334,7 @@ public:
};
class AstPackArrayDType : public AstNodeArrayDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Packed array data type, ie "some_dtype [2:0] var_name"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
public:
@@ -538,7 +538,7 @@ public:
bool littleEndian() const { return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); }
bool implicit() const { return keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT; }
VNumRange declRange() const { return isRanged() ? VNumRange(msb(), lsb(), littleEndian()) : VNumRange(); }
void cvtRangeConst() { // Convert to smaller represenation
void cvtRangeConst() { // Convert to smaller representation
if (rangep() && VN_IS(rangep()->msbp(), Const) && VN_IS(rangep()->lsbp(), Const)) {
m.m_nrange.init(rangep()->msbConst(), rangep()->lsbConst(),
rangep()->littleEndian());
@@ -1179,7 +1179,7 @@ private:
bool m_noReset:1; // Do not do automated reset/randomization
bool m_noSubst:1; // Do not substitute out references
bool m_trace:1; // Trace this variable
AstVarAttrClocker m_attrClocker;
VVarAttrClocker m_attrClocker;
MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var
void init() {
@@ -1196,7 +1196,7 @@ private:
m_isStatic = false; m_isPulldown = false; m_isPullup = false;
m_isIfaceParent = false; m_isDpiOpenArray = false;
m_noReset = false; m_noSubst = false; m_trace = false;
m_attrClocker = AstVarAttrClocker::CLOCKER_UNKNOWN;
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
}
public:
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
@@ -1289,7 +1289,7 @@ public:
void ansi(bool flag) { m_ansi = flag; }
void declTyped(bool flag) { m_declTyped = flag; }
void attrClockEn(bool flag) { m_attrClockEn = flag; }
void attrClocker(AstVarAttrClocker flag) { m_attrClocker = flag; }
void attrClocker(VVarAttrClocker flag) { m_attrClocker = flag; }
void attrFileDescr(bool flag) { m_fileDescr = flag; }
void attrScClocked(bool flag) { m_scClocked = flag; }
void attrScBv(bool flag) { m_attrScBv = flag; }
@@ -1374,7 +1374,7 @@ public:
bool attrScClocked() const { return m_scClocked; }
bool attrSFormat() const { return m_attrSFormat; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
AstVarAttrClocker attrClocker() const { return m_attrClocker; }
VVarAttrClocker attrClocker() const { return m_attrClocker; }
virtual string verilogKwd() const;
void propagateAttrFrom(AstVar* fromp) {
// This is getting connected to fromp; keep attributes
@@ -1879,21 +1879,27 @@ public:
class AstCellInline : public AstNode {
// A instantiation cell that was removed by inlining
// For communication between V3Inline and V3LinkDot only
// For communication between V3Inline and V3LinkDot,
// except for VPI runs where it exists until the end.
// It is augmented with the scope in V3Scope for VPI.
// Children: When 2 levels inlined, other CellInline under this
private:
string m_name; // Cell name, possibly {a}__DOT__{b}...
string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup
AstScope* m_scopep; // The scope that the cell is inlined into
public:
AstCellInline(FileLine* fl, const string& name, const string& origModName)
: AstNode(fl)
, m_name(name), m_origModName(origModName) {}
, m_name(name), m_origModName(origModName), m_scopep(NULL) {}
ASTNODE_NODE_FUNCS(CellInline)
virtual void dump(std::ostream& str);
virtual const char* broken() const { BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
virtual void name(const string& name) { m_name = name; }
void scopep(AstScope* scp) { m_scopep = scp; }
AstScope* scopep() const { return m_scopep; }
};
class AstCellRef : public AstNode {
@@ -2004,10 +2010,11 @@ class AstParseRef : public AstNode {
// Parents: math|stmt
// Children: TEXT|DOT|SEL*|TASK|FUNC (or expression under sel)
private:
AstParseRefExp m_expect; // Type we think it should resolve to
string m_name;
VParseRefExp m_expect; // Type we think it should resolve to
string m_name;
public:
AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp)
AstParseRef(FileLine* fl, VParseRefExp expect, const string& name,
AstNode* lhsp, AstNodeFTaskRef* ftaskrefp)
: AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); }
ASTNODE_NODE_FUNCS(ParseRef)
virtual void dump(std::ostream& str);
@@ -2020,8 +2027,8 @@ public:
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual void name(const string& name) { m_name = name; }
AstParseRefExp expect() const { return m_expect; }
void expect(AstParseRefExp exp) { m_expect = exp; }
VParseRefExp expect() const { return m_expect; }
void expect(VParseRefExp exp) { m_expect = exp; }
// op1 = Components
AstNode* lhsp() const { return op1p(); } // op1 = List of statements
AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference
@@ -2133,53 +2140,53 @@ class AstSenItem : public AstNodeSenItem {
// Parents: SENTREE
// Children: (optional) VARREF SENGATE
private:
AstEdgeType m_edgeType; // Edge type
VEdgeType m_edgeType; // Edge type
public:
class Combo {}; // for creator type-overload selection
class Illegal {}; // for creator type-overload selection
class Initial {}; // for creator type-overload selection
class Settle {}; // for creator type-overload selection
class Never {}; // for creator type-overload selection
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNode* varrefp)
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp)
: AstNodeSenItem(fl), m_edgeType(edgeType) {
setOp1p(varrefp);
}
AstSenItem(FileLine* fl, Combo)
: AstNodeSenItem(fl) {
m_edgeType = AstEdgeType::ET_COMBO;
m_edgeType = VEdgeType::ET_COMBO;
}
AstSenItem(FileLine* fl, Illegal)
: AstNodeSenItem(fl) {
m_edgeType = AstEdgeType::ET_ILLEGAL;
m_edgeType = VEdgeType::ET_ILLEGAL;
}
AstSenItem(FileLine* fl, Initial)
: AstNodeSenItem(fl) {
m_edgeType = AstEdgeType::ET_INITIAL;
m_edgeType = VEdgeType::ET_INITIAL;
}
AstSenItem(FileLine* fl, Settle)
: AstNodeSenItem(fl) {
m_edgeType = AstEdgeType::ET_SETTLE;
m_edgeType = VEdgeType::ET_SETTLE;
}
AstSenItem(FileLine* fl, Never)
: AstNodeSenItem(fl) {
m_edgeType = AstEdgeType::ET_NEVER;
m_edgeType = VEdgeType::ET_NEVER;
}
ASTNODE_NODE_FUNCS(SenItem)
virtual void dump(std::ostream& str);
virtual V3Hash sameHash() const { return V3Hash(edgeType()); }
virtual bool same(const AstNode* samep) const {
return edgeType()==static_cast<const AstSenItem*>(samep)->edgeType(); }
AstEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge
void edgeType(AstEdgeType type) { m_edgeType = type; editCountInc(); } // * = Posedge/negedge
VEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge
void edgeType(VEdgeType type) { m_edgeType = type; editCountInc(); } // * = Posedge/negedge
AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized
AstNodeVarRef* varrefp() const { return VN_CAST(op1p(), NodeVarRef); } // op1 = Signal sensitized
//
virtual bool isClocked() const { return edgeType().clockedStmt(); }
virtual bool isCombo() const { return edgeType()==AstEdgeType::ET_COMBO; }
virtual bool isInitial() const { return edgeType()==AstEdgeType::ET_INITIAL; }
virtual bool isIllegal() const { return edgeType()==AstEdgeType::ET_ILLEGAL; }
virtual bool isSettle() const { return edgeType()==AstEdgeType::ET_SETTLE; }
virtual bool isNever() const { return edgeType()==AstEdgeType::ET_NEVER; }
virtual bool isCombo() const { return edgeType()==VEdgeType::ET_COMBO; }
virtual bool isInitial() const { return edgeType()==VEdgeType::ET_INITIAL; }
virtual bool isIllegal() const { return edgeType()==VEdgeType::ET_ILLEGAL; }
virtual bool isSettle() const { return edgeType()==VEdgeType::ET_SETTLE; }
virtual bool isNever() const { return edgeType()==VEdgeType::ET_NEVER; }
bool hasVar() const { return !(isCombo()||isInitial()||isSettle()||isNever()); }
};
@@ -2387,15 +2394,17 @@ class AstComment : public AstNodeStmt {
// Parents: {statement list}
// Children: none
private:
bool m_showAt; // Show "at <fileline>"
string m_name; // Text of comment
public:
AstComment(FileLine* fl, const string& name)
AstComment(FileLine* fl, const string& name, bool showAt=false)
: AstNodeStmt(fl)
, m_name(name) {}
, m_showAt(showAt), m_name(name) {}
ASTNODE_NODE_FUNCS(Comment)
virtual string name() const { return m_name; } // * = Text
virtual V3Hash sameHash() const { return V3Hash(); } // Ignore name in comments
virtual bool same(const AstNode* samep) const { return true; } // Ignore name in comments
virtual bool showAt() const { return m_showAt; }
};
class AstCond : public AstNodeCond {
@@ -2876,6 +2885,86 @@ public:
void countp(AstNode* nodep) { setNOp4p(nodep); }
};
class AstFRewind : public AstNodeMath {
// Parents: stmtlist
// Children: file which must be a varref
public:
AstFRewind(FileLine* fileline, AstNode* filep)
: AstNodeMath(fileline) {
setNOp2p(filep);
}
ASTNODE_NODE_FUNCS(FRewind)
virtual string verilogKwd() const { return "$frewind"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool isUnlikely() const { return true; }
virtual bool cleanOut() { return false; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op2p(); }
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
};
class AstFTell : public AstNodeMath {
// Parents: stmtlist
// Children: file which must be a varref
public:
AstFTell(FileLine* fileline, AstNode* filep)
: AstNodeMath(fileline) {
setNOp2p(filep);
}
ASTNODE_NODE_FUNCS(FTell)
virtual string verilogKwd() const { return "$ftell"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool isUnlikely() const { return true; }
virtual bool cleanOut() { return false; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op2p(); }
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
};
class AstFSeek : public AstNodeMath {
// Parents: expr
// Children: file which must be a varref
// Children: offset
// Children: operation
public:
AstFSeek(FileLine* fileline, AstNode* filep,
AstNode* offset, AstNode* operation)
: AstNodeMath(fileline) {
setOp2p(filep);
setNOp3p(offset);
setNOp4p(operation);
}
ASTNODE_NODE_FUNCS(FSeek)
virtual string verilogKwd() const { return "$fseek"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering
virtual bool isOutputter() const { return true; } // SPECIAL: makes output
virtual bool cleanOut() { return false; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op2p(); }
void filep(AstNode* nodep) { setOp2p(nodep); }
AstNode* offset() const { return op3p(); }
void offset(AstNode* nodep) { setNOp3p(nodep); }
AstNode* operation() const { return op4p(); }
void operation(AstNode* nodep) { setNOp4p(nodep); }
};
class AstFScanF : public AstNodeMath {
// Parents: expr
// Children: file which must be a varref
@@ -3112,7 +3201,7 @@ public:
ASTNODE_NODE_FUNCS(Repeat)
AstNode* countp() const { return op2p(); } // op2 = condition to continue
AstNode* bodysp() const { return op3p(); } // op3 = body of loop
virtual bool isGateOptimizable() const { return false; } // Not releavant - converted to FOR
virtual bool isGateOptimizable() const { return false; } // Not relevant - converted to FOR
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
@@ -5690,6 +5779,23 @@ public:
bool tracking() const { return m_tracking; }
};
class AstTextBlock : public AstText {
private:
bool m_commas; // Comma separate emitted children
public:
AstTextBlock(FileLine* fl, const string& textp="", bool tracking=false,
bool commas=false)
: AstText(fl, textp, tracking), m_commas(commas) {}
ASTNODE_NODE_FUNCS(TextBlock)
void commas(bool flag) { m_commas = flag; }
bool commas() const { return m_commas; }
AstNode* nodesp() const { return op1p(); }
void addNodep(AstNode* nodep) { addOp1p(nodep); }
void addText(FileLine* fl, const string& textp, bool tracking=false) {
addNodep(new AstText(fl, textp, tracking));
}
};
class AstScCtor : public AstNodeText {
public:
AstScCtor(FileLine* fl, const string& textp)
@@ -5762,29 +5868,58 @@ public:
};
//======================================================================
// Emit C nodes
// Emitted file nodes
class AstCFile : public AstNode {
// C++ output file
class AstFile : public AstNode {
// Emitted Otput file
// Parents: NETLIST
// Children: nothing yet
// Children: AstTextBlock
private:
string m_name; ///< Filename
public:
AstFile(FileLine* fl, const string& name)
: AstNode(fl) {
m_name = name;
}
ASTNODE_BASE_FUNCS(File)
virtual string name() const { return m_name; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
void tblockp(AstTextBlock* tblockp) { setOp1p(tblockp); }
AstTextBlock* tblockp() { return VN_CAST(op1p(), TextBlock); }
};
//======================================================================
// Emit V nodes
class AstVFile : public AstFile {
// Verilog output file
// Parents: NETLIST
public:
AstVFile(FileLine* fl, const string& name)
: AstFile(fl, name) { }
ASTNODE_NODE_FUNCS(VFile)
virtual void dump(std::ostream& str=std::cout);
};
//======================================================================
// Emit C nodes
class AstCFile : public AstFile {
// C++ output file
// Parents: NETLIST
private:
bool m_slow:1; ///< Compile w/o optimization
bool m_source:1; ///< Source file (vs header file)
bool m_support:1; ///< Support file (non systemc)
public:
AstCFile(FileLine* fl, const string& name)
: AstNode(fl) {
m_name = name;
: AstFile(fl, name) {
m_slow = false;
m_source = false;
m_support = false;
}
ASTNODE_NODE_FUNCS(CFile)
virtual string name() const { return m_name; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
virtual void dump(std::ostream& str=std::cout);
bool slow() const { return m_slow; }
void slow(bool flag) { m_slow = flag; }
@@ -6150,8 +6285,8 @@ public:
AstNodeModule* topModulep() const { // * = Top module in hierarchy (first one added, for now)
return VN_CAST(op1p(), NodeModule); }
void addModulep(AstNodeModule* modulep) { addOp1p(modulep); }
AstCFile* filesp() const { return VN_CAST(op2p(), CFile);} // op2 = List of files
void addFilesp(AstCFile* filep) { addOp2p(filep); }
AstFile* filesp() const { return VN_CAST(op2p(), File);} // op2 = List of files
void addFilesp(AstFile* filep) { addOp2p(filep); }
AstNode* miscsp() const { return op3p(); } // op3 = List of dtypes etc
void addMiscsp(AstNode* nodep) { addOp3p(nodep); }
AstTypeTable* typeTablep() { return m_typeTablep; }
+3 -3
View File
@@ -28,7 +28,7 @@
// Unnamed BEGINs change only variable, not $display("%m") scope.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -227,7 +227,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
BeginVisitor(AstNetlist* nodep, BeginState* statep) {
m_statep = statep;
m_modp = NULL;
@@ -276,7 +276,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) {
iterate(nodep);
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3BEGIN_H_
#define _V3BEGIN_H_ 1
+6 -6
View File
@@ -26,7 +26,7 @@
// Then, if FTASK is called only once, add inline attribute
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -87,10 +87,10 @@ private:
int elseUnlikely = m_unlikely;
// Compute
int likeness = ifLikely - ifUnlikely - (elseLikely - elseUnlikely);
if (likeness>0) {
nodep->branchPred(AstBranchPred::BP_LIKELY);
} else if (likeness<0) {
nodep->branchPred(AstBranchPred::BP_UNLIKELY);
if (likeness > 0) {
nodep->branchPred(VBranchPred::BP_LIKELY);
} else if (likeness < 0) {
nodep->branchPred(VBranchPred::BP_UNLIKELY);
} // else leave unknown
}
m_likely = lastLikely;
@@ -122,7 +122,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit BranchVisitor(AstNetlist* nodep) {
reset();
iterateChildren(nodep);
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3BRANCH_H_
#define _V3BRANCH_H_ 1
+4 -4
View File
@@ -24,7 +24,7 @@
// Check all links point to marked nodes
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -179,7 +179,7 @@ public:
}
}
public:
// CONSTUCTORS
// CONSTRUCTORS
BrokenTable() {}
virtual ~BrokenTable() {}
};
@@ -213,7 +213,7 @@ private:
processAndIterate(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit BrokenMarkVisitor(AstNetlist* nodep) {
iterate(nodep);
}
@@ -269,7 +269,7 @@ private:
processAndIterate(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) {
iterate(nodep);
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3BROKEN_H_
#define _V3BROKEN_H_ 1
+1 -1
View File
@@ -134,7 +134,7 @@ void V3CCtors::evalAsserts() {
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
new AstCStmt(varp->fileline(),
"Verilated::overWidthError(\""+varp->prettyName()+"\");"));
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
ifp->branchPred(VBranchPred::BP_UNLIKELY);
newp = ifp;
funcp->addStmtsp(newp);
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CCTORS_H_
#define _V3CCTORS_H_ 1
+7 -7
View File
@@ -37,7 +37,7 @@
// <000000001_000000000 at midpoint.)
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -110,7 +110,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) {
m_caseExprp = NULL;
iterate(nodep);
@@ -129,8 +129,8 @@ private:
AstUser3InUse m_inuser3;
// STATE
V3Double0 m_statCaseFast; // Statistic tracking
V3Double0 m_statCaseSlow; // Statistic tracking
VDouble0 m_statCaseFast; // Statistic tracking
VDouble0 m_statCaseSlow; // Statistic tracking
// Per-CASE
int m_caseWidth; // Width of valueItems
@@ -210,7 +210,7 @@ private:
return false;
}
}
if (m_caseItems <= 3) return false; // Not worth simplifing
if (m_caseItems <= 3) return false; // Not worth simplifying
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
@@ -223,7 +223,7 @@ private:
if (msb<0) {
// There's no space for a IF. We know upperValue is thus down to a specific
// exact value, so just return the tree value
// Note can't clone here, as we're going to check for equivelence above
// Note can't clone here, as we're going to check for equivalence above
return m_valueItem[upperValue];
}
else {
@@ -474,7 +474,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CaseVisitor(AstNetlist* nodep) {
m_caseWidth = 0;
m_caseItems = 0;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CASE_H_
#define _V3CASE_H_ 1
+4 -4
View File
@@ -40,7 +40,7 @@
// even if assigning to a unsigned.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -94,7 +94,7 @@ private:
// 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
// less than has undeterministic signedness.
// less than has nondeterministic signedness.
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
&& !VN_IS(nodep->lhsp(), CCast)) {
insertCast(nodep->lhsp(), VL_WORDSIZE);
@@ -154,7 +154,7 @@ private:
nodep->user1(1);
}
virtual void visit(AstConst* nodep) {
// Constants are of unknown size if smaller than 33 bits, becase
// Constants are of unknown size if smaller than 33 bits, because
// we're too lazy to wrap every constant in the universe in
// ((IData)#).
nodep->user1(nodep->isQuad() || nodep->isWide());
@@ -170,7 +170,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CastVisitor(AstNetlist* nodep) {
iterate(nodep);
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CAST_H_
#define _V3CAST_H_ 1
+5 -5
View File
@@ -24,7 +24,7 @@
// Trace back to previous flop
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -154,7 +154,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix) {
m_ofp = ofp;
m_prefix = prefix;
@@ -181,7 +181,7 @@ private:
}
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CdcWidthVisitor(AstNode* nodep) {
m_maxLineno = 0;
m_maxFilenameLen = 0;
@@ -682,7 +682,7 @@ private:
}
virtual void visit(AstSenGate* nodep) {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is delt with as logic
// The logic gating term is dealt with as logic
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep) {
@@ -729,7 +729,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CdcVisitor(AstNode* nodep) {
m_logicVertexp = NULL;
m_scopep = NULL;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CDC_H_
#define _V3CDC_H_ 1
+3 -3
View File
@@ -29,7 +29,7 @@
// we need to indicate a new clock has been created.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -193,7 +193,7 @@ private:
<<m_vscp->varp()->prettyNameQ());
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
m_statep = statep;
m_vscp = vscp;
@@ -296,7 +296,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ChangedVisitor(AstNetlist* nodep, ChangedState* statep) {
m_statep = statep;
iterate(nodep);
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CHANGED_H_
#define _V3CHANGED_H_ 1
+3 -3
View File
@@ -26,7 +26,7 @@
// Copy all width() values to widthMin() so RANGE, etc can still see orig widths
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -72,7 +72,7 @@ private:
int width = cppWidth(nodep); // widthMin is unchanged
if (old_dtypep->width() != width) {
// Since any given dtype's cppWidth() is the same, we can just
// remember one convertion for each, and reuse it
// remember one conversion for each, and reuse it
if (AstNodeDType* new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
nodep->dtypep(new_dtypep);
} else {
@@ -285,7 +285,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CleanVisitor(AstNetlist* nodep) {
m_modp = NULL;
iterate(nodep);
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CLEAN_H_
#define _V3CLEAN_H_ 1
+12 -12
View File
@@ -30,7 +30,7 @@
// Create global calling function for any per-scope functions. (For FINALs).
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -110,14 +110,14 @@ private:
// HIGHEDGE: var
// LOWEDGE: ~var
AstNode* newp = NULL;
if (nodep->edgeType()==AstEdgeType::ET_ILLEGAL) {
if (nodep->edgeType()==VEdgeType::ET_ILLEGAL) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error("Unsupported: Complicated event expression in sensitive activity list");
}
return NULL;
}
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
if (nodep->edgeType()==AstEdgeType::ET_POSEDGE) {
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(nodep->fileline(),
new AstVarRef(nodep->fileline(),
@@ -125,23 +125,23 @@ private:
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(),
lastVscp, false)));
} else if (nodep->edgeType()==AstEdgeType::ET_NEGEDGE) {
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(nodep->fileline(),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(),
nodep->varrefp()->varScopep(), false)),
new AstVarRef(nodep->fileline(), lastVscp, false));
} else if (nodep->edgeType()==AstEdgeType::ET_BOTHEDGE) {
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstXor(nodep->fileline(),
new AstVarRef(nodep->fileline(),
nodep->varrefp()->varScopep(), false),
new AstVarRef(nodep->fileline(), lastVscp, false));
} else if (nodep->edgeType()==AstEdgeType::ET_HIGHEDGE) {
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
newp = new AstVarRef(nodep->fileline(),
clkvscp, false);
} else if (nodep->edgeType()==AstEdgeType::ET_LOWEDGE) {
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
newp = new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(),
clkvscp, false));
@@ -271,7 +271,7 @@ private:
m_scopep = NULL;
}
virtual void visit(AstAlways* nodep) {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
@@ -280,7 +280,7 @@ private:
nodep->deleteTree(); VL_DANGLING(nodep);
}
virtual void visit(AstAlwaysPost* nodep) {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
@@ -301,7 +301,7 @@ private:
changep),
incp, NULL);
// We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though verus a potential memory miss.
// It's another whole branch though versus a potential memory miss.
// We'll go with the miss.
newp->addIfsp(new AstAssign(nodep->fileline(),
changep->cloneTree(false),
@@ -309,7 +309,7 @@ private:
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
}
virtual void visit(AstInitial* nodep) {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
nodep->replaceWith(cmtp);
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
@@ -431,7 +431,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ClockVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_evalFuncp = NULL;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CLOCK_H_
#define _V3CLOCK_H_ 1
+3 -3
View File
@@ -68,7 +68,7 @@ protected:
// Note this is disabled, it still needed work
// Also repair it for DPI functions; when make __common need to insure 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 danginling reference.
// get split between functions causing the text to have a dangling reference.
bool statementCombine() { return false; } // duplicateFunctionCombine();
};
@@ -189,7 +189,7 @@ private:
// STATE
typedef enum {STATE_IDLE, STATE_HASH, STATE_DUP} CombineState;
V3Double0 m_statCombs; // Statistic tracking
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state; // Major state
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function
@@ -461,7 +461,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CombineVisitor(AstNetlist* nodep) {
m_state = STATE_IDLE;
m_modp = NULL;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3COMBINE_H_
#define _V3COMBINE_H_ 1
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -35,7 +35,7 @@ class V3ConfigLine {
public:
int m_lineno; // Line number to make change at
V3ErrorCode m_code; // Error code
bool m_on; // True to enaable message
bool m_on; // True to enable message
V3ConfigLine(V3ErrorCode code, int lineno, bool on)
: m_lineno(lineno), m_code(code), m_on(on) {}
~V3ConfigLine() {}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CONFIG_H_
#define _V3CONFIG_H_ 1
+22 -22
View File
@@ -23,7 +23,7 @@
// Attempt to convert operands to constants
// If operands are constant, replace this node with constant.
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -53,7 +53,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ConstVarMarkVisitor(AstNode* nodep) {
AstNode::user4ClearTree(); // Check marked InUse before we're called
iterate(nodep);
@@ -75,7 +75,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ConstVarFindVisitor(AstNode* nodep) {
m_found = false;
iterateAndNextNull(nodep);
@@ -97,7 +97,7 @@ private:
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
// STATE
bool m_params; // If true, propogate parameterized and true numbers only
bool m_params; // If true, propagate parameterized and true numbers only
bool m_required; // If true, must become a constant
bool m_wremove; // Inside scope, no assignw removal
bool m_warn; // Output warnings
@@ -557,7 +557,7 @@ private:
return false;
}
bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp) {
// determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantagous
// determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantageous
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (lhsp->type() != rhsp->type()) return false;
if (!ifConcatMergeableBiop(lhsp)) return false;
@@ -677,21 +677,21 @@ private:
// NODE(..., CHILD(...)) -> CHILD(...)
childp->unlinkFrBackWithNext();
// If replacing a SEL for example, the data type comes from the parent (is less wide).
// This may adversly affect the operation of the node being replaced.
// This may adversely affect the operation of the node being replaced.
childp->dtypeFrom(nodep);
nodep->replaceWith(childp);
nodep->deleteTree(); VL_DANGLING(nodep);
}
//! Replace a ternary node with its RHS after iterating
//! Used with short-circuting, where the RHS has not yet been iterated.
//! Used with short-circuiting, where the RHS has not yet been iterated.
void replaceWIteratedRhs(AstNodeTriop* nodep) {
if (AstNode* rhsp = nodep->rhsp()) iterateAndNextNull(rhsp);
replaceWChild(nodep, nodep->rhsp()); // May have changed
}
//! Replace a ternary node with its THS after iterating
//! Used with short-circuting, where the THS has not yet been iterated.
//! Used with short-circuiting, where the THS has not yet been iterated.
void replaceWIteratedThs(AstNodeTriop* nodep) {
if (AstNode* thsp = nodep->thsp()) iterateAndNextNull(thsp);
replaceWChild(nodep, nodep->thsp()); // May have changed
@@ -1268,7 +1268,7 @@ private:
}
void swapSides(AstNodeBiCom* nodep) {
// COMMUNATIVE({a},CONST) -> COMMUNATIVE(CONST,{a})
// COMMUTATIVE({a},CONST) -> COMMUTATIVE(CONST,{a})
// This simplifies later optimizations
AstNode* lhsp = nodep->lhsp()->unlinkFrBackWithNext();
AstNode* rhsp = nodep->rhsp()->unlinkFrBackWithNext();
@@ -1597,7 +1597,7 @@ private:
if (initarp->defaultp()) {
itemp = initarp->defaultp();
} else {
initarp->v3fatalSrc("Not enough values in array initalizement");
initarp->v3fatalSrc("Not enough values in array initialization");
}
}
}
@@ -1658,7 +1658,7 @@ private:
|| VN_IS(nodep->sensp(), EnumItemRef)
|| (nodep->varrefp() && nodep->varrefp()->varp()->isParam()))) {
// Constants in sensitivity lists may be removed (we'll simplify later)
if (nodep->isClocked()) { // A constant can never get a pos/negexge
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);
@@ -1830,16 +1830,16 @@ private:
|| (!litemp->varrefp() && !ritemp->varrefp())) {
// We've sorted in the order ANY, BOTH, POS, NEG,
// so we don't need to try opposite orders
if (( litemp->edgeType()==AstEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
|| (litemp->edgeType()==AstEdgeType::ET_BOTHEDGE) // BOTH or {POS|NEG} -> BOTH
|| (litemp->edgeType()==AstEdgeType::ET_POSEDGE // POS or NEG -> BOTH
&& ritemp->edgeType()==AstEdgeType::ET_NEGEDGE)
|| (litemp->edgeType()==ritemp->edgeType()) // Identical edges
if (( litemp->edgeType() == VEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
|| (litemp->edgeType() == VEdgeType::ET_BOTHEDGE) // BOTH or {POS|NEG} -> BOTH
|| (litemp->edgeType() == VEdgeType::ET_POSEDGE // POS or NEG -> BOTH
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
|| (litemp->edgeType() == ritemp->edgeType()) // Identical edges
) {
// Fix edge of old node
if (litemp->edgeType()==AstEdgeType::ET_POSEDGE
&& ritemp->edgeType()==AstEdgeType::ET_NEGEDGE)
litemp->edgeType(AstEdgeType::ET_BOTHEDGE);
if (litemp->edgeType() == VEdgeType::ET_POSEDGE
&& ritemp->edgeType() == VEdgeType::ET_NEGEDGE)
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
// Remove redundant node
ritemp->unlinkFrBack()->deleteTree(); VL_DANGLING(ritemp); VL_DANGLING(cmpp);
// Try to collapse again
@@ -2192,7 +2192,7 @@ private:
// v--- *1* These ops are always first, as we warn before replacing
// v--- *V* This op is a verilog op, only in m_doV mode
// v--- *C* This op works on all constant children, allowed in m_doConst mode
// v--- *S* This op specifies a type should use short-circuting of its lhs op
// v--- *S* This op specifies a type should use short-circuiting of its lhs op
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
// Generic constants on both side. Do this first to avoid other replacements
@@ -2518,7 +2518,7 @@ public:
PROC_CPP
};
// CONSTUCTORS
// CONSTRUCTORS
explicit ConstVisitor(ProcMode pmode) {
m_params = false;
m_required = false;
@@ -2586,7 +2586,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
//! trigger warnings when we deal with the width. It is possible that these
//! are spurious, existing within sub-expressions that will not actually be
//! generated. Since such occurrences, must be constant, in order to be
//! someting a generate block can depend on, we can wait until later to do the
//! something a generate block can depend on, we can wait until later to do the
//! width check.
//! @return Pointer to the edited node.
AstNode* V3Const::constifyGenerateParamsEdit(AstNode* nodep) {
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CONST_H_
#define _V3CONST_H_ 1
+3 -3
View File
@@ -27,7 +27,7 @@
// for that if/else/case.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -262,7 +262,7 @@ private:
}
}
else if (AstUnionDType* adtypep = VN_CAST(dtypep, UnionDType)) {
// Arbitrarially handle only the first member of the union
// Arbitrarily handle only the first member of the union
if (AstMemberDType* itemp = adtypep->membersp()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
ToggleEnt newent (above.m_comment+string(".")+itemp->name(),
@@ -380,7 +380,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) {
// Operate on all modules
m_checkBlock = true;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3COVERAGE_H_
#define _V3COVERAGE_H_ 1
+3 -3
View File
@@ -20,7 +20,7 @@
// COVERAGEJOIN TRANSFORMATIONS:
// If two COVERTOGGLEs have same VARSCOPE, combine them
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -50,7 +50,7 @@ private:
// STATE
ToggleList m_toggleps; // List of of all AstCoverToggle's
V3Double0 m_statToggleJoins; // Statistic tracking
VDouble0 m_statToggleJoins; // Statistic tracking
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -119,7 +119,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CoverageJoinVisitor(AstNetlist* nodep) {
iterate(nodep);
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3COVERAGEJOIN_H_
#define _V3COVERAGEJOIN_H_ 1
+2 -2
View File
@@ -37,7 +37,7 @@
// here after scoping to allow more dead node
// removal.
// *************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -407,7 +407,7 @@ public:
iterate(nodep);
deadCheckVar();
// We only elimate scopes when in a flattened structure
// We only eliminate scopes when in a flattened structure
// Otherwise we have no easy way to know if a scope is used
if (elimScopes) deadCheckScope();
if (elimCells) deadCheckCells();
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3DEAD_H_
#define _V3DEAD_H_ 1
+4 -4
View File
@@ -51,7 +51,7 @@
// ASSIGNW (BITSEL(ARRAYSEL(VARREF(x), __Vdlyvdim_x), __Vdlyvlsb_x), __Vdlyvval_x)
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -99,10 +99,10 @@ private:
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
bool m_inDly; // True in delayed assignments
bool m_inLoop; // True in for loops
bool m_inInitial; // True in intial blocks
bool m_inInitial; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*,string>,AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
V3Double0 m_statSharedSet;// Statistic tracking
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<AstVarScope*,int> ScopeVecMap;
ScopeVecMap m_scopeVecMap; // Next var number for each scope
@@ -461,7 +461,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit DelayedVisitor(AstNetlist* nodep) {
m_inDly = false;
m_activep = NULL;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3DELAYED_H_
#define _V3DELAYED_H_ 1
+3 -3
View File
@@ -26,7 +26,7 @@
// Any statements that need "this" are marked non-static
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -132,7 +132,7 @@ private:
//--------------------
// Marking of non-static functions (because they might need "this")
// (Here instead of new vistor after V3Descope just to avoid another visitor)
// (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()) {
@@ -157,7 +157,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit DepthVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_funcp = NULL;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3DEPTH_H_
#define _V3DEPTH_H_ 1
+2 -2
View File
@@ -23,7 +23,7 @@
// For each deep block, create cfunc including that block.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -123,7 +123,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit DepthBlockVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_funcp = NULL;
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3DEPTHBLOCK_H_
#define _V3DEPTHBLOCK_H_ 1
+2 -2
View File
@@ -25,7 +25,7 @@
// This allows for better V3Combine'ing.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -136,7 +136,7 @@ private:
m_needThis = true;
return name+"->";
} else {
// Reference to something elsewhere, or relative refences
// Reference to something elsewhere, or relative references
// are disabled. Use global variable
UINFO(8," Descope "<<scopep<<endl);
UINFO(8," to "<<scopep->name()<<endl);
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3DESCOPE_H_
#define _V3DESCOPE_H_ 1
+71 -20
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -236,7 +236,9 @@ public:
nodep->v3fatalSrc("Case statements should have been reduced out");
}
virtual void visit(AstComment* nodep) {
putsDecoration(string("// ")+nodep->name()+" at "+nodep->fileline()->ascii()+"\n");
string at;
if (nodep->showAt()) at = " at "+nodep->fileline()->ascii();
putsDecoration(string("// ")+nodep->name()+at+"\n");
iterateChildren(nodep);
}
virtual void visit(AstCoverDecl* nodep) {
@@ -246,7 +248,7 @@ public:
// If this isn't the first instantiation of this module under this
// design, don't really count the bucket, and rely on verilator_cov to
// aggregate counts. This is because Verilator combines all
// hiearchies itself, and if verilator_cov also did it, you'd end up
// hierarchies itself, and if verilator_cov also did it, you'd end up
// with (number-of-instant) times too many counts in this bin.
puts(", first"); // Enable, passed from __Vconfigure parameter
puts(", "); putsQuoted(nodep->fileline()->filename());
@@ -395,6 +397,25 @@ public:
puts(")); }\n");
}
}
virtual void visit(AstFSeek* nodep) {
puts("(fseek(VL_CVT_I_FP(");
iterateAndNextNull(nodep->filep());
puts("),");
iterateAndNextNull(nodep->offset());
puts(",");
iterateAndNextNull(nodep->operation());
puts(")==-1?-1:0)");
}
virtual void visit(AstFTell* nodep) {
puts("ftell(VL_CVT_I_FP(");
iterateAndNextNull(nodep->filep());
puts("))");
}
virtual void visit(AstFRewind* nodep) {
puts("(fseek(VL_CVT_I_FP(");
iterateAndNextNull(nodep->filep());
puts("), 0, 0)==-1?-1:0)");
}
virtual void visit(AstFRead* nodep) {
puts("VL_FREAD_I(");
puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width
@@ -484,11 +505,11 @@ public:
}
virtual void visit(AstNodeIf* nodep) {
puts("if (");
if (nodep->branchPred() != AstBranchPred::BP_UNKNOWN) {
if (!nodep->branchPred().unknown()) {
puts(nodep->branchPred().ascii()); puts("(");
}
iterateAndNextNull(nodep->condp());
if (nodep->branchPred() != AstBranchPred::BP_UNKNOWN) puts(")");
if (!nodep->branchPred().unknown()) puts(")");
puts(") {\n");
iterateAndNextNull(nodep->ifsp());
if (nodep->elsesp()) {
@@ -512,12 +533,19 @@ public:
puts(",\"\");\n");
}
virtual void visit(AstText* nodep) {
if (nodep->tracking()) {
if (nodep->tracking() || m_trackText) {
puts(nodep->text());
} else {
ofp()->putsNoTracking(nodep->text());
}
}
virtual void visit(AstTextBlock* nodep) {
visit(VN_CAST(nodep, Text));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
}
}
virtual void visit(AstCStmt* nodep) {
putbs("");
iterateAndNextNull(nodep->bodysp());
@@ -825,6 +853,7 @@ public:
virtual void visit(AstTraceDecl*) {} // Handled outside the Visit class
virtual void visit(AstTraceInc*) {} // Handled outside the Visit class
virtual void visit(AstCFile*) {} // Handled outside the Visit class
virtual void visit(AstCellInline*) {} // Handled outside the Visit class (EmitCSyms)
// Default
virtual void visit(AstNode* nodep) {
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
@@ -832,13 +861,23 @@ public:
nodep->v3fatalSrc("Unknown node type reached emitter: "<<nodep->prettyTypeName());
}
public:
EmitCStmts() {
void init() {
m_suppressSemi = false;
m_wideTempRefp = NULL;
m_splitSize = 0;
m_splitFilenum = 0;
}
public:
EmitCStmts() {
init();
}
EmitCStmts(AstNode* nodep, V3OutCFile* ofp, bool trackText=false) {
init();
m_ofp = ofp;
m_trackText = trackText;
iterate(nodep);
}
virtual ~EmitCStmts() {}
};
@@ -1704,7 +1743,7 @@ void EmitCImp::emitVarReset(AstVar* varp) {
for (AstNode* itemp = initarp->initsp(); itemp; ++pos, itemp=itemp->nextp()) {
int index = initarp->posIndex(pos);
UASSERT_OBJ(initarp->defaultp() || index==pos, initarp,
"Not enough values in array initalizement");
"Not enough values in array initialization");
emitSetVarConstant(varp->name()+"["+cvtToStr(index)+"]", VN_CAST(itemp, Const));
}
} else {
@@ -1846,7 +1885,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
//
// For example: suppose models A and B are each compiled to run on
// 4 threads. The client might create a single thread pool with 3
// threads and pass it to both models. If the client can ensure tht
// threads and pass it to both models. If the client can ensure that
// A.eval() and B.eval() do NOT run concurrently, there will be no
// contention for the threads. This mode is missing for now. (Is
// there demand for such a setup?)
@@ -1921,14 +1960,13 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
for (int de=0; de<2; ++de) {
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string writeread = de ? "read" : "write";
string op = de ? ">>" : "<<";
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
puts("void "+modClassName(modp)+"::"+funcname+"("+classname+"& os) {\n");
// Place a computed checksum to insure proper structure save/restore formatting
// OK if this hash includes some things we won't dump, since
// just looking for loading the wrong model
VHashSha1 hash;
VHashSha256 hash;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
hash.insert(varp->name());
@@ -2520,7 +2558,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (modp->isTop()) puts("// Public to allow access to /*verilator_public*/ items;\n");
if (modp->isTop()) puts("// otherwise the application code can consider these internals.\n");
}
ofp()->putsCellDecl(modClassName(cellp->modp()), cellp->name());
puts(modClassName(cellp->modp())+"* "+cellp->name()+";\n");
}
}
}
@@ -2607,10 +2645,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (modp->isTop()) puts("/// Destroy the model; called (often implicitly) by application code\n");
puts("~"+modClassName(modp)+"();\n");
}
if (v3Global.opt.trace()) {
if (modp->isTop()) puts("/// Trace signals in the model; called by application code\n");
if (v3Global.opt.trace() && modp->isTop()) {
puts("/// Trace signals in the model; called by application code\n");
puts("void trace("+v3Global.opt.traceClassBase()+"C* tfp, int levels, int options=0);\n");
if (modp->isTop() && optSystemC()) {
if (optSystemC()) {
puts("/// SC tracing; avoid overloaded virtual function lint warning\n");
puts("virtual void trace(sc_trace_file* tfp) const { ::sc_core::sc_module::trace(tfp); }\n");
}
@@ -2839,7 +2877,7 @@ class EmitCTrace : EmitCStmts {
puts("void "+topClassName()+"::traceInit("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
putsDecoration("// Callback from vcd->open()\n");
puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n");
puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n");
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
puts("if (!Verilated::calcUnusedSigs()) {\n");
puts( "VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
@@ -2853,7 +2891,7 @@ class EmitCTrace : EmitCStmts {
puts("void "+topClassName()+"::traceFull("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
putsDecoration("// Callback from vcd->dump()\n");
puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n");
puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n");
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
puts("t->traceFullThis(vlSymsp, vcdp, code);\n");
puts("}\n");
@@ -2868,7 +2906,7 @@ class EmitCTrace : EmitCStmts {
puts("void "+topClassName()+"::traceChg("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
putsDecoration("// Callback from vcd->dump()\n");
puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n");
puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n");
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
puts("if (vlSymsp->getClearActivity()) {\n");
puts("t->traceChgThis(vlSymsp, vcdp, code);\n");
@@ -3084,7 +3122,7 @@ class EmitCTrace : EmitCStmts {
}
// VISITORS
using EmitCStmts::visit; // Suppress hidden overloaded virtual function warnng
using EmitCStmts::visit; // Suppress hidden overloaded virtual function warning
virtual void visit(AstNetlist* nodep) {
// Top module only
iterate(nodep->topModulep());
@@ -3208,3 +3246,16 @@ void V3EmitC::emitcTrace() {
{ EmitCTrace fast(false); fast.main(); }
}
}
void V3EmitC::emitcFiles() {
UINFO(2,__FUNCTION__<<": "<<endl);
for (AstFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), File)) {
AstCFile* cfilep = VN_CAST(filep, CFile);
if (cfilep && cfilep->tblockp()) {
V3OutCFile of(cfilep->name());
of.puts("// DESCR" "IPTION: Verilator generated C++\n");
EmitCStmts visitor(cfilep->tblockp(), &of, true);
}
}
}
+2 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3EMITC_H_
#define _V3EMITC_H_ 1
@@ -35,6 +35,7 @@ public:
static void emitcInlines();
static void emitcSyms(bool dpiHdrOnly = false);
static void emitcTrace();
static void emitcFiles();
};
#endif // Guard
+4 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3EMITCBASE_H_
#define _V3EMITCBASE_H_ 1
@@ -38,6 +38,7 @@ class EmitCBaseVisitor : public AstNVisitor {
public:
// STATE
V3OutCFile* m_ofp;
bool m_trackText; // Always track AstText nodes
// METHODS
V3OutCFile* ofp() const { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
@@ -88,6 +89,7 @@ public:
// CONSTRUCTORS
EmitCBaseVisitor() {
m_ofp = NULL;
m_trackText = false;
}
virtual ~EmitCBaseVisitor() {}
};
@@ -105,7 +107,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit EmitCBaseCounterVisitor(AstNode* nodep) {
m_count = 0;
iterate(nodep);
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
+290 -88
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -43,9 +43,9 @@ class EmitCSyms : EmitCBaseVisitor {
AstUser1InUse m_inuser1;
// TYPES
struct ScopeNameData { string m_symName; string m_prettyName;
ScopeNameData(const string& symName, const string& prettyName)
: m_symName(symName), m_prettyName(prettyName) {}
struct ScopeData { string m_symName; string m_prettyName; string m_type;
ScopeData(const string& symName, const string& prettyName, const string& type)
: m_symName(symName), m_prettyName(prettyName), m_type(type) {}
};
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
@@ -60,9 +60,11 @@ class EmitCSyms : EmitCBaseVisitor {
};
typedef std::map<string,ScopeFuncData> ScopeFuncs;
typedef std::map<string,ScopeVarData> ScopeVars;
typedef std::map<string,ScopeNameData> ScopeNames;
typedef std::map<string,ScopeData> ScopeNames;
typedef std::pair<AstScope*,AstNodeModule*> ScopeModPair;
typedef std::pair<AstNodeModule*,AstVar*> ModVarPair;
typedef std::vector<string> ScopeNameList;
typedef std::map<string, ScopeNameList> ScopeNameHierarchy;
struct CmpName {
inline bool operator() (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
return lhsp.first->name() < rhsp.first->name();
@@ -81,19 +83,28 @@ class EmitCSyms : EmitCBaseVisitor {
// STATE
AstCFunc* m_funcp; // Current function
AstNodeModule* m_modp; // Current module
std::vector<ScopeModPair> m_scopes; // Every scope by module
std::vector<ScopeModPair> m_scopes; // Every scope by module
std::vector<AstCFunc*> m_dpis; // DPI functions
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
ScopeNames m_scopeNames; // Each unique AstScopeName
ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func}
ScopeVars m_scopeVars; // Each {scope,public-var}
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
V3LanguageWords m_words; // Reserved word detector
int m_coverBins; // Coverage bin number
int m_labelNum; // Next label number
bool m_dpiHdrOnly; // Only emit the DPI header
int m_numStmts; // Number of statements output
int m_funcNum; // CFunc split function number
V3OutCFile* m_ofpBase; // Base (not split) C file
std::map<int,bool> m_usesVfinal; // Split method uses __Vfinal
// METHODS
void emitSymHdr();
void checkSplit(bool usesVfinal);
void closeSplit();
void emitSymImpPreamble();
void emitSymImp();
void emitDpiHdr();
void emitDpiImp();
@@ -112,8 +123,59 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
string scopeSymString(const string& scpname) {
string out = scpname;
string::size_type pos;
while ((pos = out.find("__PVT__")) != string::npos) {
out.replace(pos, 7, "");
}
if (out.substr(0, 10) == "TOP__DOT__") out.replace(0, 10, "");
if (out.substr(0, 4) == "TOP.") out.replace(0, 4, "");
while ((pos = out.find('.')) != string::npos) {
out.replace(pos, 1, "__");
}
while ((pos = out.find("__DOT__")) != string::npos) {
out.replace(pos, 7, "__");
}
return out;
}
string scopeDecodeIdentifier(const string& scpname) {
string out = scpname;
// Remove hierarchy
string::size_type pos = out.rfind(".");
if (pos != std::string::npos) out.erase(0, pos + 1);
// Decode all escaped characters
while ((pos = out.find("__0")) != string::npos) {
unsigned int x;
std::stringstream ss;
ss << std::hex << out.substr(pos+3, 2);
ss >> x;
out.replace(pos, 5, 1, (char) x);
}
return out;
}
void varHierarchyScopes(string scp) {
while (!scp.empty()) {
ScopeNames::const_iterator scpit = m_vpiScopeCandidates.find(scp);
if ((scpit != m_vpiScopeCandidates.end())
&& (m_scopeNames.find(scp) == m_scopeNames.end())) {
m_scopeNames.insert(make_pair(scpit->second.m_symName, scpit->second));
}
string::size_type pos = scp.rfind("__DOT__");
if (pos == string::npos) {
pos = scp.rfind(".");
if (pos == string::npos) {
break;
}
}
scp.resize(pos);
}
}
void varsExpand() {
// We didn'e have all m_scopes loaded when we encountered variables, so expand them now
// We didn't have all m_scopes loaded when we encountered variables, so expand them now
// It would be less code if each module inserted its own variables.
// Someday. For now public isn't common.
for (std::vector<ScopeModPair>::iterator itsc = m_scopes.begin();
@@ -142,26 +204,14 @@ class EmitCSyms : EmitCBaseVisitor {
//UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl);
string varBasePretty = AstNode::prettyName(varBase);
string scpPretty = AstNode::prettyName(scpName);
string scpSym;
{
string out = scpName;
string::size_type pos;
while ((pos = out.find("__PVT__")) != string::npos) {
out.replace(pos, 7, "");
}
if (out.substr(0, 10) == "TOP__DOT__") out.replace(0, 10, "");
if (out.substr(0, 4) == "TOP.") out.replace(0, 4, "");
while ((pos = out.find('.')) != string::npos) {
out.replace(pos, 1, "__");
}
while ((pos = out.find("__DOT__")) != string::npos) {
out.replace(pos, 7, "__");
}
scpSym = out;
}
string scpSym = scopeSymString(scpName);
//UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
if (v3Global.opt.vpi()) {
varHierarchyScopes(scpName);
}
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty)));
m_scopeNames.insert(make_pair(scpSym, ScopeData(scpSym, scpPretty,
"SCOPE_OTHER")));
}
m_scopeVars.insert(
make_pair(scpSym + " " + varp->name(),
@@ -171,20 +221,48 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
void buildVpiHierarchy() {
for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
if (it->second.m_type != "SCOPE_MODULE") continue;
string name = it->second.m_prettyName;
if (name.substr(0, 4) == "TOP.") name.replace(0, 4, "");
string above = name;
while (!above.empty()) {
string::size_type pos = above.rfind(".");
if (pos == string::npos) {
break;
}
above.resize(pos);
if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) {
m_vpiScopeHierarchy[above].push_back(name);
break;
}
}
m_vpiScopeHierarchy[name] = std::vector<string>();
}
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
// Collect list of scopes
iterateChildren(nodep);
varsExpand();
if (v3Global.opt.vpi()) {
buildVpiHierarchy();
}
// Sort by names, so line/process order matters less
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
// Output
if (!m_dpiHdrOnly) {
emitSymHdr();
// Must emit implementation first to determine number of splits
emitSymImp();
emitSymHdr();
}
if (v3Global.dpi()) {
emitDpiHdr();
@@ -198,15 +276,33 @@ class EmitCSyms : EmitCBaseVisitor {
iterateChildren(nodep);
m_modp = NULL;
}
virtual void visit(AstCellInline* nodep) {
if (v3Global.opt.vpi()) {
string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER"
: "SCOPE_MODULE";
string name = nodep->scopep()->name() + "__DOT__" + nodep->name();
string name_dedot = AstNode::dedotName(name);
m_vpiScopeCandidates.insert(make_pair(name, ScopeData(scopeSymString(name),
name_dedot, type)));
}
}
virtual void visit(AstScope* nodep) {
nameCheck(nodep);
m_scopes.push_back(make_pair(nodep, m_modp));
if (v3Global.opt.vpi() && !nodep->isTop()) {
m_vpiScopeCandidates.insert(make_pair(nodep->name(),
ScopeData(scopeSymString(nodep->name()),
nodep->name(), "SCOPE_MODULE")));
}
}
virtual void visit(AstScopeName* nodep) {
string name = nodep->scopeSymName();
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()<<" ss "<<name<<endl);
if (m_scopeNames.find(name) == m_scopeNames.end()) {
m_scopeNames.insert(make_pair(name, ScopeNameData(name, nodep->scopePrettySymName())));
m_scopeNames.insert(make_pair(name, ScopeData(name, nodep->scopePrettySymName(),
"SCOPE_OTHER")));
}
if (nodep->dpiExport()) {
UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function");
@@ -215,8 +311,9 @@ class EmitCSyms : EmitCBaseVisitor {
} else {
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
m_scopeNames.insert(make_pair(nodep->scopeDpiName(),
ScopeNameData(nodep->scopeDpiName(),
nodep->scopePrettyDpiName())));
ScopeData(nodep->scopeDpiName(),
nodep->scopePrettyDpiName(),
"SCOPE_OTHER")));
}
}
}
@@ -263,6 +360,9 @@ public:
m_modp = NULL;
m_coverBins = 0;
m_labelNum = 0;
m_numStmts = 0;
m_funcNum = 0;
m_ofpBase = NULL;
iterate(nodep);
}
};
@@ -343,21 +443,33 @@ void EmitCSyms::emitSymHdr() {
puts("uint32_t __Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
}
{ // Scope names
bool did = false;
if (!m_scopeNames.empty()) { // Scope names
puts("\n// SCOPE NAMES\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
if (!did) {
did = true;
puts("\n// SCOPE NAMES\n");
}
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
}
}
if (v3Global.opt.vpi()) {
puts("\n// SCOPE HIERARCHY\n");
puts("VerilatedHierarchy __Vhier;\n");
}
puts("\n// CREATORS\n");
puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n");
puts(string("~")+symClassName()+"() {}\n");
for (std::map<int,bool>::iterator it = m_usesVfinal.begin();
it != m_usesVfinal.end(); ++it) {
puts("void "+symClassName()+"_"+cvtToStr(it->first)+"(");
if (it->second) {
puts("int __Vfinal");
} else {
puts(topClassName()+"* topp");
}
puts(");\n");
}
puts("\n// METHODS\n");
puts("inline const char* name() { return __Vm_namep; }\n");
if (v3Global.opt.trace()) {
@@ -373,13 +485,46 @@ void EmitCSyms::emitSymHdr() {
puts("#endif // guard\n");
}
void EmitCSyms::emitSymImp() {
UINFO(6,__FUNCTION__<<": "<<endl);
string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp";
void EmitCSyms::closeSplit() {
if (!m_ofp || m_ofp == m_ofpBase) return;
puts("}\n");
delete m_ofp;
m_ofp = NULL;
}
void EmitCSyms::checkSplit(bool usesVfinal) {
if (m_ofp && (!v3Global.opt.outputSplitCFuncs() ||
m_numStmts < v3Global.opt.outputSplitCFuncs())) return;
m_numStmts = 0;
string filename = v3Global.opt.makeDir()+"/"+symClassName()+"__"+cvtToStr(++m_funcNum)+".cpp";
AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/);
cfilep->support(true);
V3OutCFile cf (filename);
m_ofp = &cf;
m_usesVfinal[m_funcNum] = usesVfinal;
closeSplit();
m_ofp = new V3OutCFile(filename);
m_ofpBase->puts(symClassName()+"_"+cvtToStr(m_funcNum)+"(");
if (usesVfinal) {
m_ofpBase->puts("__Vfinal");
} else {
m_ofpBase->puts("topp");
}
m_ofpBase->puts(");\n");
emitSymImpPreamble();
puts("void "+symClassName()+"::"+symClassName()+"_"+cvtToStr(m_funcNum)+"(");
if (usesVfinal) {
puts("int __Vfinal");
} else {
puts(topClassName()+"* topp");
}
puts(") {\n");
}
void EmitCSyms::emitSymImpPreamble() {
ofp()->putsHeader();
puts("// DESCR" "IPTION: Verilator output: Symbol table implementation internals\n");
puts("\n");
@@ -390,30 +535,71 @@ void EmitCSyms::emitSymImp() {
nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) {
puts("#include \""+modClassName(nodep)+".h\"\n");
}
}
void EmitCSyms::emitSymImp() {
UINFO(6,__FUNCTION__<<": "<<endl);
string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp";
AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/);
cfilep->support(true);
V3OutCFile cf (filename);
m_ofp = &cf;
m_ofpBase = m_ofp;
emitSymImpPreamble();
//puts("\n// GLOBALS\n");
puts("\n");
if (v3Global.opt.savable() ) {
puts("\n");
for (int de=0; de<2; ++de) {
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string op = de ? ">>" : "<<";
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n");
puts( "// LOCAL STATE\n");
// __Vm_namep presumably already correct
if (v3Global.opt.trace()) {
puts( "os"+op+"__Vm_activity;\n");
}
puts( "os"+op+"__Vm_didInit;\n");
puts( "// 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;
if (!modp->isTop()) {
puts( scopep->nameDotless()+"."+funcname+"(os);\n");
}
}
puts("}\n");
}
}
puts("\n");
puts("\n// FUNCTIONS\n");
puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n");
puts("\t// Setup locals\n");
puts("\t: __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed
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("\t, __Vm_activity(false)\n");
puts(" , __Vm_activity(false)\n");
}
puts("\t, __Vm_didInit(false)\n");
puts("\t// Setup submodule names\n");
puts(" , __Vm_didInit(false)\n");
puts(" // Setup submodule names\n");
char comma=',';
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (modp->isTop()) {
} else {
string nameDl = scopep->nameDotless();
ofp()->printf("\t%c %-30s ", comma, nameDl.c_str());
puts(string(" ")+comma+" "+scopep->nameDotless());
puts("(Verilated::catName(topp->name(),");
// The "." is added by catName
putsQuoted(scopep->prettyName());
puts("))\n");
comma=',';
comma = ',';
++m_numStmts;
}
}
puts("{\n");
@@ -424,6 +610,7 @@ void EmitCSyms::emitSymImp() {
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (!modp->isTop()) {
checkSplit(false);
string arrow = scopep->name();
string::size_type pos;
while ((pos = arrow.find('.')) != string::npos) {
@@ -433,6 +620,7 @@ void EmitCSyms::emitSymImp() {
ofp()->printf("%-30s ", arrow.c_str());
puts(" = &");
puts(scopep->nameDotless()+";\n");
++m_numStmts;
}
}
@@ -441,36 +629,72 @@ void EmitCSyms::emitSymImp() {
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (!modp->isTop()) {
checkSplit(false);
// first is used by AstCoverDecl's call to __vlCoverInsert
bool first = !modp->user1();
modp->user1(true);
puts(scopep->nameDotless()+".__Vconfigure(this, "
+(first?"true":"false")
+");\n");
++m_numStmts;
}
}
{ // Setup scope names
bool did = false;
if (!m_scopeNames.empty()) { // Setup scope names
puts("// Setup scopes\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
if (!did) {
did = true;
puts("// Setup scope names\n");
}
checkSplit(false);
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
putsQuoted(it->second.m_prettyName);
puts(");\n");
puts(", ");
putsQuoted(scopeDecodeIdentifier(it->second.m_prettyName));
puts(", VerilatedScope::"+it->second.m_type+");\n");
++m_numStmts;
}
}
if (v3Global.opt.vpi()) {
puts("\n// Setup scope hierarchy\n");
for (ScopeNames::const_iterator it = m_scopeNames.begin();
it != m_scopeNames.end(); ++it) {
string name = it->second.m_prettyName;
if (it->first == "TOP") continue;
name = name.replace(0, 4, ""); // Remove the "TOP."
if ((name.find(".") == string::npos) && (it->second.m_type == "SCOPE_MODULE")) {
puts("__Vhier.add(0, &__Vscope_" + it->second.m_symName + ");\n");
}
}
for (ScopeNameHierarchy::const_iterator it = m_vpiScopeHierarchy.begin();
it != m_vpiScopeHierarchy.end(); ++it) {
for (ScopeNameList::const_iterator lit = it->second.begin();
lit != it->second.end(); ++lit) {
string fromname = scopeSymString(it->first);
string toname = scopeSymString(*lit);
ScopeNames::const_iterator from = m_scopeNames.find(fromname);
ScopeNames::const_iterator to = m_scopeNames.find(toname);
UASSERT(from != m_scopeNames.end(), fromname+" not in m_scopeNames");
UASSERT(to != m_scopeNames.end(), toname+" not in m_scopeNames");
puts("__Vhier.add(");
puts("&__Vscope_"+from->second.m_symName+", ");
puts("&__Vscope_"+to->second.m_symName+");\n");
}
}
puts("\n");
}
// Everything past here is in the __Vfinal loop, so start a new split file if needed
closeSplit();
if (v3Global.dpi()) {
puts("// Setup export functions\n");
puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
m_ofpBase->puts("// Setup export functions\n");
m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstScopeName* scopep = it->second.m_scopep;
AstCFunc* funcp = it->second.m_funcp;
AstNodeModule* modp = it->second.m_modp;
if (funcp->dpiExport()) {
checkSplit(true);
puts("__Vscope_"+scopep->scopeSymName()+".exportInsert(__Vfinal,");
putsQuoted(funcp->cname());
puts(", (void*)(&");
@@ -478,11 +702,13 @@ void EmitCSyms::emitSymImp() {
puts("::");
puts(funcp->name());
puts("));\n");
++m_numStmts;
}
}
// It would be less code if each module inserted its own variables.
// Someday. For now public isn't common.
for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
checkSplit(true);
AstNodeModule* modp = it->second.m_modp;
AstScope* scopep = it->second.m_scopep;
AstVar* varp = it->second.m_varp;
@@ -531,37 +757,13 @@ void EmitCSyms::emitSymImp() {
puts(cvtToStr(pdim+udim));
puts(bounds);
puts(");\n");
++m_numStmts;
}
puts("}\n");
m_ofpBase->puts("}\n");
}
puts("}\n");
if (v3Global.opt.savable() ) {
puts("\n");
for (int de=0; de<2; ++de) {
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string op = de ? ">>" : "<<";
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n");
puts( "// LOCAL STATE\n");
// __Vm_namep presumably already correct
if (v3Global.opt.trace()) {
puts( "os"+op+"__Vm_activity;\n");
}
puts( "os"+op+"__Vm_didInit;\n");
puts( "// 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;
if (!modp->isTop()) {
puts( scopep->nameDotless()+"."+funcname+"(os);\n");
}
}
puts("}\n");
}
}
m_ofpBase->puts("}\n");
closeSplit();
}
//######################################################################
@@ -595,12 +797,12 @@ void EmitCSyms::emitDpiHdr() {
if (nodep->dpiExportWrapper()) {
if (!firstExp++) puts("\n// DPI EXPORTS\n");
puts("// DPI export at "+nodep->fileline()->ascii()+"\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+");\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+");\n");
}
else if (nodep->dpiImport()) {
if (!firstImp++) puts("\n// DPI IMPORTS\n");
puts("// DPI import at "+nodep->fileline()->ascii()+"\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+");\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+");\n");
}
}
@@ -643,7 +845,7 @@ void EmitCSyms::emitDpiImp() {
if (nodep->dpiExportWrapper()) {
puts("#ifndef _VL_DPIDECL_"+nodep->name()+"\n");
puts("#define _VL_DPIDECL_"+nodep->name()+"\n");
puts(nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+") {\n");
puts(nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+") {\n");
puts("// DPI Export at "+nodep->fileline()->ascii()+"\n");
puts("return "+topClassName()+"::"+nodep->name()+"(");
string args;
+8 -6
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -107,11 +107,13 @@ public:
else if (support==2 && slow) {
}
else {
for (AstCFile* nodep = v3Global.rootp()->filesp();
nodep; nodep = VN_CAST(nodep->nextp(), CFile)) {
if (nodep->source() && nodep->slow()==(slow!=0)
&& nodep->support()==(support!=0)) {
putMakeClassEntry(of, nodep->name());
for (AstFile* nodep = v3Global.rootp()->filesp();
nodep; nodep = VN_CAST(nodep->nextp(), File)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source()
&& cfilep->slow()==(slow!=0)
&& cfilep->support()==(support!=0)) {
putMakeClassEntry(of, cfilep->name());
}
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3EMITMK_H_
#define _V3EMITMK_H_ 1
+28 -3
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -356,7 +356,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$finish;\n");
}
virtual void visit(AstText* nodep) {
putsNoTracking(nodep->text());
if (nodep->tracking() || m_trackText) {
puts(nodep->text());
} else {
putsNoTracking(nodep->text());
}
}
virtual void visit(AstTextBlock* nodep) {
visit(VN_CAST(nodep, Text));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
}
}
virtual void visit(AstScopeName* nodep) {
}
@@ -628,8 +639,9 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
virtual void putqs(AstNode*, const string& str) { putbs(str); }
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp) {
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText=false) {
m_ofp = ofp;
m_trackText = trackText;
iterate(nodep);
}
virtual ~EmitVFileVisitor() {}
@@ -758,3 +770,16 @@ void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os,
AstSenTree* domainp, bool user3mark) {
EmitVPrefixedVisitor(nodep, os, prefix, flWidth, domainp, user3mark);
}
void V3EmitV::emitvFiles() {
UINFO(2,__FUNCTION__<<": "<<endl);
for (AstFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), File)) {
AstVFile* vfilep = VN_CAST(filep, VFile);
if (vfilep && vfilep->tblockp()) {
V3OutVFile of(vfilep->name());
of.puts("// DESCR" "IPTION: Verilator generated Verilog\n");
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true);
}
}
}
+2 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3EMITV_H_
#define _V3EMITV_H_ 1
@@ -36,6 +36,7 @@ public:
static void verilogPrefixedTree(AstNode* nodep, std::ostream& os,
const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark);
static void emitvFiles();
};
#endif // Guard
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3EMITXML_H_
#define _V3EMITXML_H_ 1
+1 -1
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "V3Error.h"
#ifndef _V3ERROR_NO_GLOBAL_
# include "V3Ast.h"
+5 -23
View File
@@ -17,13 +17,16 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ERROR_H_
#define _V3ERROR_H_ 1
#include "config_build.h"
#include "verilatedos.h"
// Limited V3 headers here - this is a base class for Vlc etc
#include "V3String.h"
#include <bitset>
#include <cassert>
#include <deque>
@@ -77,7 +80,7 @@ public:
ENDLABEL, // End lable name mismatch
GENCLK, // Generated Clock
IFDEPTH, // If statements too deep
IGNOREDRETURN, // Ignoring return value (funcation as task)
IGNOREDRETURN, // Ignoring return value (function as task)
IMPERFECTSCH, // Imperfect schedule (disabled by default)
IMPLICIT, // Implicit wire
IMPORTSTAR, // Import::* in $unit
@@ -345,25 +348,4 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
//----------------------------------------------------------------------
template <class T> std::string cvtToStr(const T& t) {
std::ostringstream os; os<<t; return os.str();
}
template <class T> std::string cvtToHex(const T* tp) {
std::ostringstream os; os<<static_cast<const void*>(tp); return os.str();
}
inline uint32_t cvtToHash(const void* vp) {
// We can shove a 64 bit pointer into a 32 bit bucket
// On 32-bit systems, lower is always 0, but who cares?
union { const void* up; struct {uint32_t upper; uint32_t lower;} l;} u;
u.l.upper = 0; u.l.lower = 0; u.up = vp;
return u.l.upper^u.l.lower;
}
inline string ucfirst(const string& text) {
string out = text;
out[0] = toupper(out[0]);
return out;
}
#endif // Guard
+3 -3
View File
@@ -28,7 +28,7 @@
// propagation across signals.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -700,7 +700,7 @@ private:
// Lhs or Rhs may be word, long, or quad.
// newAstWordSelClone nicely abstracts the difference.
int rhsshift = rhsp->rhsp()->widthMin();
// Sometimes doing the words backwards is preferrable.
// Sometimes doing the words backwards is preferable.
// When we have x={x,foo} backwards is better, when x={foo,x} forward is better
// However V3Subst tends to rip this up, so not worth optimizing now.
for (int w=0; w<rhsp->widthWords(); w++) {
@@ -956,7 +956,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ExpandVisitor(AstNetlist* nodep) {
m_stmtp = NULL;
iterate(nodep);

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