mirror of
https://github.com/verilator/verilator.git
synced 2026-10-04 17:13:40 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfcd412e5f | ||
|
|
307549e8a6 | ||
|
|
09b79a731a | ||
|
|
4544a2fd99 | ||
|
|
e09c918198 | ||
|
|
9bf6135f6d | ||
|
|
d472ef63e9 | ||
|
|
f1c04b5d25 | ||
|
|
1cf29c4d20 | ||
|
|
977a767477 | ||
|
|
771a301f66 | ||
|
|
a9954a71c3 | ||
|
|
967dc24fda | ||
|
|
e1e45cf13c | ||
|
|
bd89c71694 | ||
|
|
633131b984 | ||
|
|
99db18b6c3 | ||
|
|
961a8e190f | ||
|
|
045ff25f80 | ||
|
|
66209d1114 | ||
|
|
3f1fe2d18a | ||
|
|
8b6fb26272 | ||
|
|
881362bb04 | ||
|
|
239ef1ae6d | ||
|
|
9eaec3b5c1 | ||
|
|
dd4aa948ae | ||
|
|
12fa085b26 | ||
|
|
9d6b0d7dd6 | ||
|
|
a1405dac8e | ||
|
|
cb115e1a15 | ||
|
|
1c7eb89df5 | ||
|
|
6e91f82a7d | ||
|
|
17123cd0e0 | ||
|
|
3f0c5b7550 | ||
|
|
f6e0e9adec | ||
|
|
dea1531f40 | ||
|
|
edcfaa888d | ||
|
|
28b9db1903 | ||
|
|
9e64be71a7 | ||
|
|
99a8845a96 | ||
|
|
be4692772c | ||
|
|
4f315d9078 | ||
|
|
f133c4d0b3 | ||
|
|
8490046028 | ||
|
|
d6ac351dcb | ||
|
|
502bd6cbd6 | ||
|
|
d7b6b53c4d | ||
|
|
96725b3431 | ||
|
|
8686ed9b00 | ||
|
|
32e1207782 | ||
|
|
900115bb2d | ||
|
|
3469c78153 | ||
|
|
baa634343b | ||
|
|
1471f5691a | ||
|
|
e556269692 | ||
|
|
d1af69f91d | ||
|
|
fa904f386c | ||
|
|
a4daae66de | ||
|
|
c813026566 | ||
|
|
314cd92129 | ||
|
|
3bc260c55d | ||
|
|
4c0f95af10 |
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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!
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -17,7 +17,7 @@
|
||||
//=========================================================================
|
||||
//
|
||||
// DESCRIPTION: Verilator: Include in verilog files to hide verilator defines
|
||||
|
||||
|
||||
`ifdef _VERILATED_V_ `else
|
||||
`define _VERILATED_V_ 1
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
|
||||
///**** Product and Version name
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
|
||||
#define _VERILATED_DPI_CPP_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
|
||||
#ifndef _VERILATED_DPI_H_
|
||||
#define _VERILATED_DPI_H_ 1 ///< Header Guard
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
|
||||
#ifndef _VERILATED_SC_H_
|
||||
#define _VERILATED_SC_H_ 1 ///< Header Guard
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
|
||||
#ifndef _VERILATEDOS_H_
|
||||
#define _VERILATEDOS_H_ 1 ///< Header Guard
|
||||
|
||||
-1006
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3ACTIVE_H_
|
||||
#define _V3ACTIVE_H_ 1
|
||||
|
||||
|
||||
+2
-2
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3ACTIVETOP_H_
|
||||
#define _V3ACTIVETOP_H_ 1
|
||||
|
||||
|
||||
+9
-9
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3ASSERT_H_
|
||||
#define _V3ASSERT_H_ 1
|
||||
|
||||
|
||||
+2
-2
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3ASSERTPRE_H_
|
||||
#define _V3ASSERTPRE_H_ 1
|
||||
|
||||
|
||||
+10
-4
@@ -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
@@ -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
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3ASTCONSTONLY_H_
|
||||
#define _V3ASTCONSTONLY_H_ 1
|
||||
|
||||
|
||||
+19
-7
@@ -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
@@ -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
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3BEGIN_H_
|
||||
#define _V3BEGIN_H_ 1
|
||||
|
||||
|
||||
+6
-6
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3BRANCH_H_
|
||||
#define _V3BRANCH_H_ 1
|
||||
|
||||
|
||||
+4
-4
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3BROKEN_H_
|
||||
#define _V3BROKEN_H_ 1
|
||||
|
||||
|
||||
+1
-1
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CCTORS_H_
|
||||
#define _V3CCTORS_H_ 1
|
||||
|
||||
|
||||
+7
-7
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CASE_H_
|
||||
#define _V3CASE_H_ 1
|
||||
|
||||
|
||||
+4
-4
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CAST_H_
|
||||
#define _V3CAST_H_ 1
|
||||
|
||||
|
||||
+5
-5
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CDC_H_
|
||||
#define _V3CDC_H_ 1
|
||||
|
||||
|
||||
+3
-3
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CHANGED_H_
|
||||
#define _V3CHANGED_H_ 1
|
||||
|
||||
|
||||
+3
-3
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CLEAN_H_
|
||||
#define _V3CLEAN_H_ 1
|
||||
|
||||
|
||||
+12
-12
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CLOCK_H_
|
||||
#define _V3CLOCK_H_ 1
|
||||
|
||||
|
||||
+3
-3
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3COMBINE_H_
|
||||
#define _V3COMBINE_H_ 1
|
||||
|
||||
|
||||
+2
-2
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CONFIG_H_
|
||||
#define _V3CONFIG_H_ 1
|
||||
|
||||
|
||||
+22
-22
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3CONST_H_
|
||||
#define _V3CONST_H_ 1
|
||||
|
||||
|
||||
+3
-3
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3COVERAGE_H_
|
||||
#define _V3COVERAGE_H_ 1
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3COVERAGEJOIN_H_
|
||||
#define _V3COVERAGEJOIN_H_ 1
|
||||
|
||||
|
||||
+2
-2
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3DEAD_H_
|
||||
#define _V3DEAD_H_ 1
|
||||
|
||||
|
||||
+4
-4
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3DELAYED_H_
|
||||
#define _V3DELAYED_H_ 1
|
||||
|
||||
|
||||
+3
-3
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3DEPTH_H_
|
||||
#define _V3DEPTH_H_ 1
|
||||
|
||||
|
||||
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3DEPTHBLOCK_H_
|
||||
#define _V3DEPTHBLOCK_H_ 1
|
||||
|
||||
|
||||
+2
-2
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3DESCOPE_H_
|
||||
#define _V3DESCOPE_H_ 1
|
||||
|
||||
|
||||
+71
-20
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
|
||||
+290
-88
@@ -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
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3EMITMK_H_
|
||||
#define _V3EMITMK_H_ 1
|
||||
|
||||
|
||||
+28
-3
@@ -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
@@ -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
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _V3EMITXML_H_
|
||||
#define _V3EMITXML_H_ 1
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#include "V3Error.h"
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
# include "V3Ast.h"
|
||||
|
||||
+5
-23
@@ -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
@@ -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
Reference in New Issue
Block a user