mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0478dbdd1f | ||
|
|
38b0e8a777 | ||
|
|
fe9f1add6f | ||
|
|
ae9179f412 | ||
|
|
4c35a76cdb | ||
|
|
8ca3428fb6 | ||
|
|
7369500bb7 | ||
|
|
45702e319b | ||
|
|
813468bfe6 | ||
|
|
78192308e1 | ||
|
|
cb72390b57 | ||
|
|
71b2eeef67 | ||
|
|
57c8590b21 | ||
|
|
f8ad0a0923 | ||
|
|
7c443ab108 | ||
|
|
0d645757e7 | ||
|
|
dd37c2ea86 | ||
|
|
d3032bfc21 | ||
|
|
bd6ecdfa6f | ||
|
|
3558e70722 | ||
|
|
a579e9273b | ||
|
|
21369bec95 | ||
|
|
d119d10569 | ||
|
|
38988c005c | ||
|
|
8cc4b588b2 | ||
|
|
12607abb33 | ||
|
|
562f17ea4b | ||
|
|
0aea9b7709 | ||
|
|
c0afe96b80 | ||
|
|
5c919cd0de | ||
|
|
f555c93c11 | ||
|
|
cbb7cd16d0 | ||
|
|
4d074b5414 | ||
|
|
dfd22b2b07 | ||
|
|
6edaef9598 | ||
|
|
f63e946f04 | ||
|
|
add5cc8b56 | ||
|
|
2a4e830bee | ||
|
|
eb87232472 | ||
|
|
52c3031a82 | ||
|
|
df471e87eb | ||
|
|
ec6fae5d1a | ||
|
|
cb422a9a02 | ||
|
|
f91bac7b31 | ||
|
|
d542921ff7 | ||
|
|
ad693d67b2 | ||
|
|
350932e9c0 | ||
|
|
4e98d96755 | ||
|
|
c17a9eb5f1 | ||
|
|
252ed4c1ae | ||
|
|
f9fd634fae | ||
|
|
c17c81254e | ||
|
|
5ead61dc7b | ||
|
|
e403db5877 | ||
|
|
32874fa848 | ||
|
|
b90f383cfe | ||
|
|
eb65984368 | ||
|
|
10e0d34140 | ||
|
|
f4b00d3c64 | ||
|
|
cc0b780412 | ||
|
|
fbbbe4ec87 | ||
|
|
1372d62186 | ||
|
|
a69936de74 | ||
|
|
f5dfa1e9c3 | ||
|
|
5fb21c2159 | ||
|
|
132f61e900 | ||
|
|
0e9be8eea0 | ||
|
|
96f5f66c26 | ||
|
|
bbed4d50ab | ||
|
|
4b7ee8267b | ||
|
|
f6a745a4c2 | ||
|
|
a23a5505c4 | ||
|
|
21030f0a4f | ||
|
|
d21824cbae | ||
|
|
124786ad1b | ||
|
|
f81daac9c0 | ||
|
|
db8e8392fa | ||
|
|
5bc2f87d3e | ||
|
|
de35c90847 | ||
|
|
bc813fddcc | ||
|
|
13c91f5fce | ||
|
|
ac4690d74b | ||
|
|
a1a8f17617 | ||
|
|
12be852a43 | ||
|
|
440fbef79b | ||
|
|
e1c221a4d5 | ||
|
|
e1f1c82d4e | ||
|
|
3c1b82255e | ||
|
|
6bd47b54df | ||
|
|
3261a45ec1 | ||
|
|
0ac116bb4e | ||
|
|
221e4ff6fe | ||
|
|
fe80499f9c | ||
|
|
d3d1f3ab60 | ||
|
|
264b888ef2 | ||
|
|
ba270e09a4 | ||
|
|
8281ee1520 | ||
|
|
75aab4e9d2 | ||
|
|
b532a47e4a | ||
|
|
77a3d683e3 | ||
|
|
c132d0e1fe | ||
|
|
1a6348f113 | ||
|
|
89ac6ab594 | ||
|
|
3d1012b73b | ||
|
|
c98ad79e68 | ||
|
|
82460b0da3 | ||
|
|
0bdc57a14a | ||
|
|
33780a09df | ||
|
|
a9c9d5ca4b | ||
|
|
ab07dbdb9d | ||
|
|
6dd6750985 | ||
|
|
59aa0f43d5 | ||
|
|
04ca6a4307 | ||
|
|
c7cbe11ba4 | ||
|
|
4794093aba | ||
|
|
46e300b2c5 | ||
|
|
c693e52f6c | ||
|
|
4e2ec09f9a | ||
|
|
cdbae456d5 |
@@ -2,6 +2,69 @@ Revision history for Verilator
|
||||
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 3.916 2017-11-25
|
||||
|
||||
*** Support self-recursive modules, bug659. [Sean Moore, et al]
|
||||
|
||||
*** Support $error/$warning in elaboration time blocks.
|
||||
|
||||
*** Support $size/$bits/etc on type references.
|
||||
|
||||
*** Add error when driving input-only modport, bug1110. [Trevor Elbourne]
|
||||
|
||||
*** Add BSSPACE and COLONPLUS lint warnings.
|
||||
|
||||
**** Detect MSB overflow when under VL_DEBUG, bug1238. [Junyi Xi]
|
||||
|
||||
**** Add data types to --xml. [Rui Terra]
|
||||
|
||||
**** Fix partial slicing with pattern assignments, bug991. [Johan Bjork]
|
||||
|
||||
**** Fix false unused warning on interfaces, bug1241. [Laurens van Dam]
|
||||
|
||||
**** Fix error on "unique case" with no cases.
|
||||
|
||||
**** Fix MacOS portability, bug1232. [Jeff Bush]
|
||||
|
||||
|
||||
* Verilator 3.914 2017-10-14
|
||||
|
||||
** Added new examples/ directory with appropriate examples. This replaces the
|
||||
old test_c and test_sc directories.
|
||||
|
||||
*** Add --getenv option for simplifying Makefiles.
|
||||
|
||||
*** Add --x-initial option for specifying initial value assignment behavior.
|
||||
|
||||
*** Add --no-relative-cfuncs and related default optimization, bug1224. [John Coiner]
|
||||
|
||||
*** Add /*verilator tag*/ for XML extraction applications. [Chris Randall]
|
||||
|
||||
**** The internal test_verilated test directory is moved to be part of test_regress.
|
||||
|
||||
**** The experimental VL_THREADED setting (only, not normal mode) now requires C++11.
|
||||
|
||||
**** Fix over-aggressive inlining, bug1223. [John Coiner]
|
||||
|
||||
**** Fix Ubuntu 17.10 issues, bug1223 partial. [John Coiner]
|
||||
|
||||
**** Fix compiler warning when WIDTH warning ignored on large compare.
|
||||
|
||||
**** Fix memory leak in VerilatedVcd dumps, bug1222 partial. [Shareef Jalloq]
|
||||
|
||||
**** Fix unnecessary Vdly variables, bug1224 partial. [John Coiner]
|
||||
|
||||
**** Fix conditional slices and add related optimizations.
|
||||
|
||||
**** Fix `` expansion of `defines, bug1225, bug1227, bug1228. [Odd Magne Reitan]
|
||||
|
||||
**** Fix -E duplicating output, bug1226. [Odd Magne Reitan]
|
||||
|
||||
**** Fix float-conversion warning, bug1229. [Robert Henry]
|
||||
|
||||
**** Fix MacOS portability, bug1230, bug1231. [Jeff Bush]
|
||||
|
||||
|
||||
* Verilator 3.912 2017-09-23
|
||||
|
||||
** Verilated headers no longer "use namespace std;"
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
/cov_work/
|
||||
/logs/
|
||||
^Makefile$
|
||||
bin/verilator_bin.*
|
||||
bin/verilator_coverage_bin.*
|
||||
src/Makefile$
|
||||
src/Makefile_obj$
|
||||
include/verilated.mk$
|
||||
@@ -39,5 +41,6 @@ nodist/
|
||||
/vc_hdrs.h$
|
||||
/csrc/
|
||||
doxygen-doc/.*
|
||||
obj_dir/.*
|
||||
TAGS
|
||||
.*~
|
||||
|
||||
+67
-43
@@ -92,6 +92,7 @@ datarootdir = @datarootdir@
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
CFG_WITH_THREADED = @CFG_WITH_THREADED@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
@@ -101,7 +102,9 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SUBDIRS = src test_verilated test_c test_sc test_regress
|
||||
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 \
|
||||
@@ -114,7 +117,11 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
*.in *.ac \
|
||||
Changes TODO \
|
||||
MANIFEST.SKIP \
|
||||
bin/* \
|
||||
bin/verilator \
|
||||
bin/verilator_coverage \
|
||||
bin/verilator_difftree \
|
||||
bin/verilator_includer \
|
||||
bin/verilator_profcfunc \
|
||||
doxygen-mainpage doxygen.config veripool-logo.png \
|
||||
install-sh configure mkinstalldirs *.pod \
|
||||
include/*.[chv]* \
|
||||
@@ -127,9 +134,10 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
src/vlcovgen \
|
||||
src/.gdbinit \
|
||||
src/*.pl src/*.pod \
|
||||
examples/*/.*ignore examples/*/Makefile* \
|
||||
examples/*/*.[chv]* examples/*/*.pl \
|
||||
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
|
||||
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \
|
||||
test_verilated/vgen*.pl \
|
||||
test_regress/t/t*/*.sv* \
|
||||
test_regress/t/t*/*.v* \
|
||||
test_regress/t/t*/*/*.sv* \
|
||||
@@ -153,9 +161,9 @@ INST_PROJ_FILES = \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
INST_PROJ_BIN_FILES = \
|
||||
verilator_bin \
|
||||
verilator_bin_dbg \
|
||||
verilator_coverage_bin_dbg \
|
||||
bin/verilator_bin \
|
||||
bin/verilator_bin_dbg \
|
||||
bin/verilator_coverage_bin_dbg \
|
||||
|
||||
DISTFILES := $(DISTFILES_INC)
|
||||
|
||||
@@ -182,33 +190,33 @@ verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg:
|
||||
msg_test: all_nomsg
|
||||
@echo "Build complete!"
|
||||
@echo
|
||||
@echo "Type 'make test' to test."
|
||||
@echo "Now type 'make test' to test."
|
||||
@echo
|
||||
|
||||
.PHONY:test
|
||||
.PHONY: test
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
test: test_c test_sc test_verilated test_regress
|
||||
test: smoke-test examples test_regress
|
||||
else
|
||||
test: test_c test_sc
|
||||
test: smoke-test examples
|
||||
endif
|
||||
@echo "Tests passed!"
|
||||
@echo
|
||||
@echo "Type 'make install' to install documentation."
|
||||
@echo "Now type 'make install' to install."
|
||||
@echo "Or type 'make' inside an examples subdirectory."
|
||||
@echo
|
||||
|
||||
test_c: all_nomsg
|
||||
@(cd test_c && $(MAKE))
|
||||
test_c_debug: all_nomsg
|
||||
@(cd test_c && $(MAKE) test_debug)
|
||||
test_sc: all_nomsg
|
||||
@(cd test_sc && $(MAKE))
|
||||
test_sc_debug: all_nomsg
|
||||
@(cd test_sc && $(MAKE) test_debug)
|
||||
test_verilated: all_nomsg
|
||||
@(cd test_verilated && $(MAKE))
|
||||
smoke-test: all_nomsg
|
||||
test_regress/t/t_a_first_cc.pl
|
||||
test_regress/t/t_a_first_sc.pl
|
||||
|
||||
test_regress: all_nomsg
|
||||
@(cd test_regress && $(MAKE))
|
||||
|
||||
examples: all_nomsg
|
||||
for p in examples/* ; do \
|
||||
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
|
||||
done
|
||||
|
||||
info: $(INFOS)
|
||||
|
||||
# Use --no-split to avoid creating filenames > 14 chars.
|
||||
@@ -281,18 +289,16 @@ VL_INST_INC_SRCDIR_FILES = \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
VL_INST_DATA_SRCDIR_FILES = \
|
||||
test_v/*.[chv]* \
|
||||
test_c/*.[chv]* test_c/Makefile test_c/Makefile_obj \
|
||||
test_sc/*.[chv]* test_sc/Makefile test_sc/Makefile_obj \
|
||||
examples/*/*.[chv]* examples/*/Makefile* \
|
||||
|
||||
installbin:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage $(DESTDIR)$(bindir)/verilator_coverage )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
|
||||
( $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin )
|
||||
( $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg )
|
||||
( $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg )
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
|
||||
|
||||
@@ -314,12 +320,13 @@ installdata:
|
||||
; for p in $(VL_INST_INC_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/hello_world_c
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/hello_world_sc
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/tracing_c
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/tracing_sc
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgconfigdir)
|
||||
$(INSTALL_DATA) verilator.pc $(DESTDIR)$(pkgconfigdir)
|
||||
@@ -331,15 +338,15 @@ uninstall:
|
||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_BLDDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_SRCDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_SRCDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_DATA_SRCDIR_FILES)
|
||||
-rm $(DESTDIR)$(pkgconfigdir)/verilator.pc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/bin
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/hello_world_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/hello_world_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/tracing_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/tracing_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||
-rmdir $(DESTDIR)$(pkgconfigdir)
|
||||
@@ -358,8 +365,8 @@ INST_PROJ_CVS = cp_if_cvs_diff
|
||||
|
||||
install-project: dist
|
||||
@echo "Install-project to $(DIRPROJECT)"
|
||||
strip verilator_bin*
|
||||
strip verilator_coverage_bin*
|
||||
strip bin/verilator_bin*
|
||||
strip bin/verilator_coverage_bin*
|
||||
$(MAKE) install-project-quick
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||
@@ -382,8 +389,8 @@ endif
|
||||
|
||||
install-cadtools: dist
|
||||
@echo "Install-project to $(CAD_DIR)"
|
||||
strip verilator_bin*
|
||||
strip verilator_coverage_bin*
|
||||
strip bin/verilator_bin*
|
||||
strip bin/verilator_coverage_bin*
|
||||
$(MAKE) install-cadtools-quick
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
@@ -421,12 +428,23 @@ CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
|
||||
|
||||
cppcheck: $(CPPCHECK_DEP)
|
||||
%.cppcheck: %.cpp
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 $(CPPCHECK_INC) $<
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $<
|
||||
|
||||
analyzer-src:
|
||||
-rm -rf src/obj_dbg
|
||||
scan-build $(MAKE) -k verilator_coverage_bin_dbg verilator_bin_dbg
|
||||
|
||||
analyzer-include:
|
||||
-rm -rf examples/*/obj*
|
||||
scan-build $(MAKE) -k examples
|
||||
|
||||
ftp: info
|
||||
|
||||
install-msg:
|
||||
@echo "Installed!"
|
||||
@echo
|
||||
@echo "Installed binaries to $(DESTDIR)$(bindir)/verilator"
|
||||
@echo "Installed man to $(DESTDIR)$(mandir)/man1"
|
||||
@echo "Installed examples to $(DESTDIR)$(pkgdatadir)/examples"
|
||||
@echo
|
||||
@echo "For documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see http://www.veripool.org/verilator"
|
||||
@@ -454,7 +472,7 @@ endif
|
||||
maintainer-clean::
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "rebuilding the deleted files requires makeinfo."
|
||||
rm -f *.info* $(INFOS) configure
|
||||
rm -f *.info* *.1 $(INFOS) configure
|
||||
|
||||
clean mostlyclean distclean maintainer-clean maintainer-copy::
|
||||
for dir in $(SUBDIRS); do \
|
||||
@@ -468,10 +486,13 @@ clean mostlyclean distclean maintainer-clean::
|
||||
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx
|
||||
rm -f *.ev *.evs *.ov *.ovs *.cv *.cvs *.ma *.mas
|
||||
rm -f *.tex
|
||||
rm -rf test_*/obj_dir
|
||||
rm -rf examples/*/obj_dir examples/*/logs
|
||||
|
||||
distclean maintainer-clean::
|
||||
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*
|
||||
rm -f include/verilated.mk include/verilated_config.h
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
@@ -493,6 +514,9 @@ dist-file-list:
|
||||
@echo $(wildcard $(DISTFILES))
|
||||
@echo "end-dist-file-list:"; # Scripts look for this
|
||||
|
||||
print-cfg-with-threaded:
|
||||
@echo $(CFG_WITH_THREADED)
|
||||
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
|
||||
+7
-4
@@ -169,6 +169,9 @@ have the verilator binary directory in your PATH (this should already be
|
||||
true if using the default configure), and make sure VERILATOR_ROOT is not
|
||||
set.
|
||||
|
||||
You may now wish to consult the examples directory. Type C<make> inside any
|
||||
example directory to run the example.
|
||||
|
||||
=back
|
||||
|
||||
=head1 USAGE DOCUMENTATION
|
||||
@@ -190,10 +193,10 @@ The directories in the kit after de-taring are as follows:
|
||||
include/verilated.v => Stub defines for linting
|
||||
include/verilated.mk => Common makefile
|
||||
src/ => Translator source code
|
||||
test_v => Example Verilog code for other test dirs
|
||||
test_c => Example Verilog->C++ conversion
|
||||
test_sc => Example Verilog->SystemC conversion
|
||||
test_verilated => Internal tests
|
||||
examples/hello_world_c => Example simple Verilog->C++ conversion
|
||||
examples/hello_world_sc => Example simple Verilog->SystemC conversion
|
||||
examples/tracing_c => Example Verilog->C++ with tracing
|
||||
examples/tracing_sc => Example Verilog->SystemC with tracing
|
||||
test_regress => Internal tests
|
||||
|
||||
=head1 LIMITATIONS
|
||||
|
||||
+223
-122
@@ -183,8 +183,8 @@ sub run {
|
||||
}
|
||||
if ($status & 127) {
|
||||
if (($status & 127) == 4 # SIGILL
|
||||
|| ($status & 127) == 8 # SIGFPA
|
||||
|| ($status & 127) == 11) { # SIGSEGV
|
||||
|| ($status & 127) == 8 # SIGFPA
|
||||
|| ($status & 127) == 11) { # SIGSEGV
|
||||
warn "%Error: Verilator internal fault, sorry. Consider trying --debug --gdbbt\n" if !$Debug;
|
||||
} elsif (($status & 127) == 6) { # SIGABRT
|
||||
warn "%Error: Verilator aborted. Consider trying --debug --gdbbt\n" if !$Debug;
|
||||
@@ -286,6 +286,7 @@ descriptions in the next sections for more information.
|
||||
-G<name>=<value> Overwrite toplevel parameter
|
||||
--gdb Run Verilator under GDB interactively
|
||||
--gdbbt Run Verilator under GDB for backtrace
|
||||
--getenv <var> Get environment variable with defaults
|
||||
--help Display this help
|
||||
-I<dir> Directory to search for includes
|
||||
--if-depth <value> Tune IFDEPTH warning
|
||||
@@ -327,6 +328,7 @@ descriptions in the next sections for more information.
|
||||
--public Debugging; see docs
|
||||
-pvalue+<name>=<value> Overwrite toplevel parameter
|
||||
--relative-includes Resolve includes relative to current file
|
||||
--no-relative-cfuncs Disallow 'this->' in generated functions
|
||||
--report-unoptflat Extra diagnostics for UNOPTFLAT
|
||||
--savable Enable model save-restore
|
||||
--sc Create SystemC output
|
||||
@@ -358,7 +360,8 @@ descriptions in the next sections for more information.
|
||||
-Wno-lint Disable all lint warnings
|
||||
-Wno-style Disable all style warnings
|
||||
-Wno-fatal Disable fatal exit on warnings
|
||||
--x-assign <mode> Initially assign Xs to this value
|
||||
--x-assign <mode> Assign non-initial Xs to this value
|
||||
--x-initial <mode> Assign initial Xs to this value
|
||||
--x-initial-edge Enable initial X->0 and X->1 edge triggers
|
||||
-y <dir> Directory to search for modules
|
||||
|
||||
@@ -428,9 +431,6 @@ C<+1364-1995ext+> etc. specify both the syntax I<and> semantics to be used.
|
||||
|
||||
Enable all assertions.
|
||||
|
||||
See also --x-assign and --x-initial-edge; setting "--x-assign unique"
|
||||
and/or "--x-initial-edge" may be desirable.
|
||||
|
||||
=item --autoflush
|
||||
|
||||
After every $display or $fdisplay, flush the output stream. This insures
|
||||
@@ -547,7 +547,7 @@ Coverage analysis adds statements at each code flow change point, which are
|
||||
the branches of IF and CASE statements, a super-set of normal Verilog Line
|
||||
Coverage. At each such branch a unique counter is incremented. At the end
|
||||
of a test, the counters along with the filename and line number
|
||||
corresponding to each counter are written into logs/coverage.pl.
|
||||
corresponding to each counter are written into logs/coverage.dat.
|
||||
|
||||
Verilator automatically disables coverage of branches that have a $stop in
|
||||
them, as it is assumed $stop branches contain an error check that should
|
||||
@@ -762,6 +762,14 @@ backtrace on exit, then exit GDB immediately. Without --debug or if GDB
|
||||
doesn't seem to work, this flag is ignored. Intended for easy creation of
|
||||
backtraces by users; otherwise see the --gdb flag.
|
||||
|
||||
=item --getenv I<variable>
|
||||
|
||||
If the variable is declared in the environment, print it and exit
|
||||
immediately. Otherwise, if it's built into Verilator (e.g. VERILATOR_ROOT),
|
||||
print that and exit immediately. Otherwise, print a newline and exit
|
||||
immediately. This can be useful in makefiles. See also -V, and the various
|
||||
*.mk files.
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
@@ -873,6 +881,22 @@ change the ultimate model's performance, but may in some cases.
|
||||
|
||||
Backward compatible alias for "--pins-bv 33".
|
||||
|
||||
=item --no-relative-cfuncs
|
||||
|
||||
Disable 'this->' references in generated functions, and instead Verilator
|
||||
will generate absolute references starting from 'vlTOPp->'. This prevents
|
||||
V3Combine from merging functions from multiple instances of the same
|
||||
module, so it can grow the instruction stream.
|
||||
|
||||
This is a work around for old compilers. Don't set this if your C++
|
||||
compiler supports __restrict__ properly, as GCC 4.5.x and newer do. For
|
||||
older compilers, test if this switch gives you better performance or not.
|
||||
|
||||
Compilers which don't honor __restrict__ will suspect that 'this->'
|
||||
references and 'vlTOPp->' references may alias, and may write slow code
|
||||
with extra loads and stores to handle the (imaginary) aliasing. Using only
|
||||
'vlTOPp->' references allows these old compilers to produce tight code.
|
||||
|
||||
=item --no-skip-identical
|
||||
|
||||
Rarely needed. Disables skipping execution of Verilator if all source
|
||||
@@ -1181,7 +1205,7 @@ Setting it to "" disables matching.
|
||||
=item -V
|
||||
|
||||
Shows the verbose version, including configuration information compiled
|
||||
into Verilator. (Similar to perl -V.)
|
||||
into Verilator. (Similar to perl -V.) See also --getenv.
|
||||
|
||||
=item -v I<filename>
|
||||
|
||||
@@ -1227,11 +1251,11 @@ directives in the source, i.e. the warning will still not be printed.
|
||||
=item -Wno-lint
|
||||
|
||||
Disable all lint related warning messages, and all style warnings. This is
|
||||
equivalent to "-Wno-ALWCOMBORDER -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP
|
||||
-Wno-CASEX -Wno-CASEWITHX -Wno-CMPCONST -Wno-ENDLABEL -Wno-IMPLICIT
|
||||
-Wno-LITENDIAN -Wno-PINCONNECTEMPTY -Wno-PINMISSING -Wno-SYNCASYNCNET
|
||||
-Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED -Wno-WIDTH" plus the list shown for
|
||||
Wno-style.
|
||||
equivalent to "-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE
|
||||
-Wno-CASEOVERLAP -Wno-CASEX -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS
|
||||
-Wno-ENDLABEL -Wno-IMPLICIT -Wno-LITENDIAN -Wno-PINCONNECTEMPTY
|
||||
-Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED
|
||||
-Wno-WIDTH" plus the list shown for Wno-style.
|
||||
|
||||
It is strongly recommended you cleanup your code rather than using this
|
||||
option, it is only intended to be use when running test-cases of code
|
||||
@@ -1260,10 +1284,10 @@ Enables the specified warning message.
|
||||
|
||||
Enable all lint related warning messages (note by default they are already
|
||||
enabled), but do not affect style messages. This is equivalent to
|
||||
"-Wwarn-ALWCOMBORDER -Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX
|
||||
-Wwarn-CASEWITHX -Wwarn-CMPCONST -Wwarn-ENDLABEL -Wwarn-IMPLICIT
|
||||
-Wwarn-LITENDIAN -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED
|
||||
-Wwarn-WIDTH".
|
||||
"-Wwarn-ALWCOMBORDER -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE
|
||||
-Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASEWITHX -Wwarn-CMPCONST
|
||||
-Wwarn-COLONPLUS -Wwarn-ENDLABEL -Wwarn-IMPLICIT -Wwarn-LITENDIAN
|
||||
-Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH".
|
||||
|
||||
=item -Wwarn-style
|
||||
|
||||
@@ -1298,7 +1322,30 @@ enable rerunning with that same seed so you can reproduce bugs.
|
||||
B<Note.> This option applies only to variables which are explicitly assigned
|
||||
to X in the Verilog source code. Initial values of clocks are set to 0 unless
|
||||
--x-initial-edge is specified. Initial values of all other state holding
|
||||
variables are set as though --x-assign unique had been specified.
|
||||
variables are controlled with --x-initial.
|
||||
|
||||
=item --x-initial 0
|
||||
|
||||
=item --x-initial fast
|
||||
|
||||
=item --x-initial unique (default)
|
||||
|
||||
Controls the two-state value that is used to initialize variables that are
|
||||
not otherwise initialized.
|
||||
|
||||
--x-initial=0, initializes all otherwise uninitialized variables to zero.
|
||||
|
||||
--x-initial=unique, the default, initializes variables using a function,
|
||||
which determines the value to use each initialization. This gives greatest
|
||||
flexibility and allows finding reset bugs. See L</"Unknown states">
|
||||
|
||||
--x-initial=fast, is best for performance, and initializes all variables to
|
||||
a state Verilator determines is optimal. This may allow further code
|
||||
optimizations, but will likely hide any code bugs relating to missing
|
||||
resets.
|
||||
|
||||
B<Note.> This option applies only to initial values of variables. Initial
|
||||
values of clocks are set to 0 unless --x-initial-edge is specified.
|
||||
|
||||
=item --x-initial-edge
|
||||
|
||||
@@ -1360,7 +1407,7 @@ We'll compile this example into C++.
|
||||
cat <<EOF >sim_main.cpp
|
||||
#include "Vour.h"
|
||||
#include "verilated.h"
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int main(int argc, char** argv, char** env) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vour* top = new Vour;
|
||||
while (!Verilated::gotFinish()) { top->eval(); }
|
||||
@@ -1409,8 +1456,8 @@ And we get as output
|
||||
|
||||
Really, you're better off writing a Makefile to do all this for you. Then,
|
||||
when your source changes it will automatically run all of these steps; to
|
||||
aid this Verilator can create a makefile dependency file. See the test_c
|
||||
directory in the distribution for an example.
|
||||
aid this Verilator can create a makefile dependency file. See the examples
|
||||
directory in the distribution.
|
||||
|
||||
|
||||
=head1 EXAMPLE SYSTEMC EXECUTION
|
||||
@@ -1487,15 +1534,16 @@ And we get the same output as the C++ example:
|
||||
|
||||
Really, you're better off using a Makefile to do all this for you. Then,
|
||||
when your source changes it will automatically run all of these steps. See
|
||||
the test_sc directory in the distribution for an example.
|
||||
the examples directory in the distribution.
|
||||
|
||||
|
||||
=head1 BENCHMARKING & OPTIMIZATION
|
||||
|
||||
For best performance, run Verilator with the "-O3 --x-assign=fast
|
||||
--noassert" flags. The -O3 flag will require longer compile times, and
|
||||
--x-assign=fast may increase the risk of reset bugs in trade for
|
||||
performance; see the above documentation for these flags.
|
||||
--x-initial=fast --noassert" flags. The -O3 flag will require longer
|
||||
compile times, and --x-assign=fast --x-initial=fast may increase the risk
|
||||
of reset bugs in trade for performance; see the above documentation for
|
||||
these flags.
|
||||
|
||||
Minor Verilog code changes can also give big wins. You should not have any
|
||||
UNOPTFLAT warnings from Verilator. Fixing these warnings can result in
|
||||
@@ -1686,7 +1734,7 @@ Verilator RPM as the hardcoded value should be correct.
|
||||
=head1 CONNECTING TO C++
|
||||
|
||||
Verilator creates a .h and .cpp file for the top level module and all
|
||||
modules under it. See the test_c directory in the kit for an example.
|
||||
modules under it. See the examples directory in the kit for examples.
|
||||
|
||||
After the modules are completed, there will be a I<module>.mk file that may
|
||||
be used with Make to produce a I<module>__ALL.a file with all required
|
||||
@@ -1973,7 +2021,7 @@ accesses the above signal "readme" would be:
|
||||
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int main(int argc, char** argv, char** env) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vour* top = new Vour;
|
||||
Verilated::internalsDump(); // See scopes to help debug
|
||||
@@ -2301,7 +2349,7 @@ Verilator configuration commands.
|
||||
|
||||
Switch back to processing Verilog code after a `systemc_... mode switch.
|
||||
The Verilog code returns to the last language mode specified with
|
||||
`begin_keywords, or SystemVerilog if none were specified.
|
||||
`begin_keywords, or SystemVerilog if none was specified.
|
||||
|
||||
=item /*verilator clock_enable*/
|
||||
|
||||
@@ -2418,6 +2466,13 @@ lint_restore*/. For example:
|
||||
If SOME_WARNING was on before the lint_off, it will now be restored to on,
|
||||
and if it was off before the lint_off it will remain off.
|
||||
|
||||
=item /*verilator no_inline_module*/
|
||||
|
||||
Specifies the module the comment appears in should not be inlined into any
|
||||
modules that use this module. This is useful especially at the top level
|
||||
module to reduce the size of the interface class, to aid compile time at a
|
||||
small performance loss.
|
||||
|
||||
=item /*verilator no_inline_task*/
|
||||
|
||||
Used in a function or task variable definition section to specify the
|
||||
@@ -2526,6 +2581,12 @@ indicate the function or task should pass all remaining arguments through
|
||||
$sformatf. This allows creation of DPI functions with $display like
|
||||
behavior. See the test_regress/t/t_dpi_display.v file for an example.
|
||||
|
||||
=item /*verilator tag <text...>*/
|
||||
|
||||
Attached after a variable or structure member to indicate opaque (to
|
||||
Verilator) text that should be passed through to the XML output as a tag,
|
||||
for use by downstream applications.
|
||||
|
||||
=item /*verilator tracing_off*/
|
||||
|
||||
Disable waveform tracing for all future signals that are declared in this
|
||||
@@ -2638,24 +2699,25 @@ value (see the --x-assign switch.) Thus if the value is actually used, the
|
||||
random value should cause downstream errors. Integers also randomize, even
|
||||
though the Verilog 2001 specification says they initialize to zero.
|
||||
|
||||
All variables are randomly initialized using a function. By running
|
||||
several random simulation runs you can determine that reset is working
|
||||
correctly. On the first run, the function initializes variables to zero.
|
||||
On the second, have it initialize variables to one. On the third and
|
||||
following runs have it initialize them randomly. If the results match,
|
||||
reset works. (Note this is what the hardware will really do.) In
|
||||
practice, just setting all variables to one at startup finds most problems.
|
||||
All variables, depending on --x-initial setting, are typically randomly
|
||||
initialized using a function. By running several random simulation runs
|
||||
you can determine that reset is working correctly. On the first run, the
|
||||
function initializes variables to zero. On the second, have it initialize
|
||||
variables to one. On the third and following runs have it initialize them
|
||||
randomly. If the results match, reset works. (Note this is what the
|
||||
hardware will really do.) In practice, just setting all variables to one
|
||||
at startup finds most problems (since typically control signals are
|
||||
active-high).
|
||||
|
||||
B<Note.> --x-assign applies to variables explicitly initialized or assigned to
|
||||
X. Uninitialized clocks are initialized to zero, while all other state holding
|
||||
variables are initialized to a random value.
|
||||
|
||||
Event driven simulators will generally trigger an edge on a transition from X
|
||||
to 1 (C<posedge>) or X to 0 (C<negedge>). However, by default, since clocks
|
||||
are initialized to zero, Verilator will not trigger an initial negedge. Some
|
||||
code (particularly for reset) may rely on X->0 triggering an edge. Verilator
|
||||
provides a switch (see --x-initial-edge) to enable this behavior. Comparing
|
||||
runs with and without this switch will find such problems.
|
||||
--x-assign applies to variables explicitly initialized or assigned to
|
||||
X. Uninitialized clocks are initialized to zero, while all other state
|
||||
holding variables are initialized to a random value. Event driven
|
||||
simulators will generally trigger an edge on a transition from X to 1
|
||||
(C<posedge>) or X to 0 (C<negedge>). However, by default, since clocks are
|
||||
initialized to zero, Verilator will not trigger an initial negedge. Some
|
||||
code (particularly for reset) may rely on X->0 triggering an edge. The
|
||||
--x-initial-edge switch enables this behavior. Comparing runs with and
|
||||
without this switch will find such problems.
|
||||
|
||||
|
||||
=head2 Tri/Inout
|
||||
@@ -3019,6 +3081,17 @@ generally unrolls small loops. You may want to try increasing
|
||||
--unroll-count (and occasionally --unroll-stmts) which will raise the small
|
||||
loop bar to avoid this error.
|
||||
|
||||
=item BSSPACE
|
||||
|
||||
Warns that a backslash is followed by a space then a newline. Likely the
|
||||
intent was to have a backslash directly followed by a newline (e.g. when
|
||||
making a `define) and there's accidentally whitespace at the end of the
|
||||
line. If the space is not accidental, suggest removing the backslash in
|
||||
the code as it serves no function.
|
||||
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
|
||||
=item CASEINCOMPLETE
|
||||
|
||||
Warns that inside a case statement there is a stimulus pattern for which
|
||||
@@ -3058,6 +3131,15 @@ instead intended is to use a casez with C<?>.
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
|
||||
=item COLONPLUS
|
||||
|
||||
Warns that a :+ is seen. Likely the intent was to use +: to select a range
|
||||
of bits. If the intent was a range that is explicitly positive, suggest
|
||||
adding a space, e.g. use ": +".
|
||||
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
|
||||
=item CDCRSTLOGIC
|
||||
|
||||
With --cdc only, warns that asynchronous flop reset terms come from other
|
||||
@@ -3589,24 +3671,24 @@ program above:
|
||||
|
||||
=item Does it run under Windows?
|
||||
|
||||
Yes, using Cygwin. Verilated output should also compile under Microsoft
|
||||
Visual C++ Version 7 or newer, but this is not tested by the author.
|
||||
Yes, using Cygwin. Verilated output also compiles under Microsoft Visual
|
||||
C++ Version 7 or newer, but this is not tested every release.
|
||||
|
||||
=item Can you provide binaries?
|
||||
|
||||
Verilator is available as a RPM for 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
|
||||
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.
|
||||
|
||||
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
|
||||
working C++ compiler is required to compile the output of Verilator.
|
||||
|
||||
=item How can it be faster than (name-the-simulator)?
|
||||
=item How can it be faster than (name-the-commercial-simulator)?
|
||||
|
||||
Generally, the implied part of the question is "... with all of their
|
||||
manpower they can put into it."
|
||||
Generally, the implied part is of the question is "... with all of the
|
||||
manpower they can put into developing it."
|
||||
|
||||
Most commercial simulators have to be Verilog compliant, meaning event
|
||||
driven. This prevents them from being able to reorder blocks and make
|
||||
@@ -3639,17 +3721,18 @@ source code available.
|
||||
As is standard with Open Source, contributions back to Verilator will be
|
||||
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,
|
||||
large tests under the LGPL/Artistic, unless requested otherwise.
|
||||
and large tests under the LGPL/Artistic, unless requested otherwise.
|
||||
|
||||
=item Why is Verilation so slow?
|
||||
|
||||
Verilator needs more memory than the resulting simulator will require, as
|
||||
Verilator creates internally all of the state of the resulting simulator in
|
||||
order to optimize it. If it takes more than a minute or so (and you're not
|
||||
using --debug since debug is disk bound), see if your machine is paging;
|
||||
most likely you need to run it on a machine with more memory. Verilator is
|
||||
a full 64-bit application and may use more than 4GB, but about 1GB is the
|
||||
maximum typically needed.
|
||||
Verilator creates internally all of the state of the resulting generated
|
||||
simulator in order to optimize it. If it takes more than a minute or so
|
||||
(and you're not using --debug since debug is disk bound), see if your
|
||||
machine is paging; most likely you need to run it on a machine with more
|
||||
memory. Verilator is a full 64-bit application and may use more than 4GB,
|
||||
but about 1GB is the maximum typically needed, and very large commercial
|
||||
designs have topped 16GB.
|
||||
|
||||
=item How do I generate waveforms (traces) in C++?
|
||||
|
||||
@@ -3659,7 +3742,7 @@ Add the --trace switch to Verilator, and in your top level C code, call
|
||||
Verilated::traceEverOn(true). Then create a VerilatedVcdC object, and
|
||||
in your main loop call "trace_object->dump(time)" every time step, and
|
||||
finally call "trace_object->close()". For an example, see below and the
|
||||
test_c/sim_main.cpp file of the distribution.
|
||||
examples/tracing_c/sim_main.cpp file of the distribution.
|
||||
|
||||
You also need to compile verilated_vcd_c.cpp and add it to your link,
|
||||
preferably by adding the dependencies in $(VK_GLOBAL_OBJS) to your
|
||||
@@ -3671,7 +3754,7 @@ trace file if you want all data to land in the same output file.
|
||||
|
||||
#include "verilated_vcd_c.h"
|
||||
...
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int main(int argc, char** argv, char** env) {
|
||||
...
|
||||
Verilated::traceEverOn(true);
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
@@ -3691,7 +3774,7 @@ Add the --trace switch to Verilator, and in your top level C sc_main code,
|
||||
include verilated_vcd_sc.h. Then call Verilated::traceEverOn(true). Then
|
||||
create a VerilatedVcdSc object as you would create a normal SystemC trace
|
||||
file. For an example, see the call to VerilatedVcdSc in the
|
||||
test_sc/sc_main.cpp file of the distribution, and below.
|
||||
examples/tracing_sc/sc_main.cpp file of the distribution, and below.
|
||||
|
||||
Alternatively you may use the C++ trace mechanism described in the previous
|
||||
question, however the timescale and timeprecision will not inherited from
|
||||
@@ -3707,7 +3790,7 @@ trace file if you want all data to land in the same output file.
|
||||
|
||||
#include "verilated_vcd_sc.h"
|
||||
...
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int main(int argc, char** argv, char** env) {
|
||||
...
|
||||
Verilated::traceEverOn(true);
|
||||
VerilatedVcdSc* tfp = new VerilatedVcdSc;
|
||||
@@ -3722,8 +3805,8 @@ trace file if you want all data to land in the same output file.
|
||||
=item How do I view waveforms (traces)?
|
||||
|
||||
Verilator makes standard VCD (Value Change Dump) files. They are viewable
|
||||
with the public domain Dinotrace or GtkWave programs, or any of the many
|
||||
commercial offerings.
|
||||
with the public domain GtkWave (recommended) or Dinotrace (legacy)
|
||||
programs, or any of the many commercial offerings.
|
||||
|
||||
=item How do I reduce the size of large waveform (trace) files?
|
||||
|
||||
@@ -3737,8 +3820,8 @@ want to trace (such as perhaps library cells). Finally, use the
|
||||
--trace-depth option to limit the depth of tracing, for example
|
||||
--trace-depth 1 to see only the top level signals.
|
||||
|
||||
Also be sure you write your trace files to a local disk, instead of to a
|
||||
network disk. Network disks are generally far slower.
|
||||
Also be sure you write your trace files to a local solid-state disk,
|
||||
instead of to a network disk. Network disks are generally far slower.
|
||||
|
||||
=item How do I do coverage analysis?
|
||||
|
||||
@@ -3753,14 +3836,14 @@ At the end of your test, call VerilatedCov::write passing the name of the
|
||||
coverage data file (typically "logs/coverage.dat").
|
||||
|
||||
Run each of your tests in different directories. Each test will create a
|
||||
logs/coverage.pl file.
|
||||
logs/coverage.dat file.
|
||||
|
||||
After running all of your tests, verilator_coverage is executed.
|
||||
Verilator_coverage reads the logs/coverage.pl file(s), and creates an
|
||||
Verilator_coverage reads the logs/coverage.dat file(s), and creates an
|
||||
annotated source code listing showing code coverage details.
|
||||
|
||||
For an example, after running 'make test' in the Verilator distribution,
|
||||
see the test_sc/logs directory. Grep for lines starting
|
||||
see the examples/tracing_c/logs directory. Grep for lines starting
|
||||
with '%' to see what lines Verilator believes need more coverage.
|
||||
|
||||
=item Where is the translate_off command? (How do I ignore a construct?)
|
||||
@@ -3774,6 +3857,8 @@ the "VERILATOR" define for you, so just wrap the code in an ifndef region:
|
||||
Something_Verilator_Dislikes;
|
||||
`endif
|
||||
|
||||
Most synthesis tools similarly define SYNTHESIS for you.
|
||||
|
||||
=item Why do I get "unexpected `do'" or "unexpected `bit'" errors?
|
||||
|
||||
Do, bit, ref, return, and other words are now SystemVerilog keywords. You
|
||||
@@ -3810,7 +3895,7 @@ simulator knows the current time. See the "CONNECTING TO C++" examples.
|
||||
You need to link your compiled Verilated code against the verilated.cpp
|
||||
file found in the include directory of the Verilator kit. This is one
|
||||
target in the $(VK_GLOBAL_OBJS) make variable, which should be part of your
|
||||
Makefile's link rule.
|
||||
Makefile's link rule. If you use --exe, this is done for you.
|
||||
|
||||
=item Is the PLI supported?
|
||||
|
||||
@@ -3832,13 +3917,20 @@ test_regress/t/t_extend_class files show an example of how to do this.
|
||||
|
||||
=item How do I get faster build times?
|
||||
|
||||
Between GCC 3.0 to 3.3, each compiled progressively slower, thus if you can
|
||||
use GCC 2.95, or GCC 3.4 you'll have faster builds. Two ways to cheat are
|
||||
to compile on parallel machines and avoid compilations altogether. See the
|
||||
--output-split option, and the web for the ccache, distcc and icecream
|
||||
packages. ccache will skip GCC runs between identical source builds, even
|
||||
across different users. You can use the OBJCACHE environment variable to
|
||||
use these CC wrappers.
|
||||
Use a recent compiler. Newer compilers tend do be faster, with the
|
||||
now relatively old GCC 3.0 to 3.3 being horrible.
|
||||
|
||||
Compile in parallel on many machines and use caching; see the web for the
|
||||
ccache, distcc and icecream packages. ccache will skip GCC runs between
|
||||
identical source builds, even across different users. You can use the
|
||||
OBJCACHE environment variable to use these CC wrappers. Also see the
|
||||
--output-split option.
|
||||
|
||||
To reduce the compile time of classes that use a Verilated module (e.g. a
|
||||
top CPP file) you may wish to add /*verilator no_inline_module*/ to your
|
||||
top level module. This will decrease the amount of code in the model's
|
||||
Verilated class, improving compile times of any instantiating top level C++
|
||||
code, at a relatively small cost of execution performance.
|
||||
|
||||
=item Why do so many files need to recompile when I add a signal?
|
||||
|
||||
@@ -3978,7 +4070,7 @@ License.)
|
||||
In 2001, Wilson Snyder took the kit, and added a SystemC mode, and
|
||||
called it Verilator2. This was the first packaged public release.
|
||||
|
||||
In 2002, Wilson Snyder created Verilator3 by rewriting Verilator from
|
||||
In 2002, Wilson Snyder created Verilator 3.000 by rewriting Verilator from
|
||||
scratch in C++. This added many optimizations, yielding about a 2-5x
|
||||
performance gain.
|
||||
|
||||
@@ -4010,50 +4102,59 @@ Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
|
||||
and SiCortex Inc.
|
||||
|
||||
The people who have contributed major functionality are Byron Bradley,
|
||||
Jeremy Bennett, Jie Xu, Lane Brooks, Duane Galbi, Paul Wasson, and Wilson
|
||||
Snyder. Major testers include Jeff Dutton, Jonathon Donaldson, Ralf Karge,
|
||||
David Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov, Sebastien Van
|
||||
Cauwenberghe, Gene Weber, and Clifford Wolf.
|
||||
Jeremy Bennett, Jie Xu, Lane Brooks, John Coiner, Duane Galbi, Paul Wasson,
|
||||
and Wilson Snyder. Major testers included Jeff Dutton, Jonathon Donaldson,
|
||||
Ralf Karge, David Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov,
|
||||
Sebastien Van Cauwenberghe, Gene Weber, and Clifford Wolf.
|
||||
|
||||
Some of the people who have provided ideas and feedback for Verilator
|
||||
include: Yves Mathieu, David Addison, Nikana Anastasiadis, Hans Van
|
||||
Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad Bagri, Andrew Bardsley,
|
||||
Geoff Barrett, J Baxter, Julius Baxter, Jeremy Bennett, Michael Berman,
|
||||
David Binderman, David Black, Daniel Bone, Gregg Bouchard, Christopher
|
||||
Boumenot, Nick Bowler, Byron Bradley, Bryan Brady, Charlie Brej, Lane
|
||||
Brooks, John Brownlee, Jeff Bush, Lawrence Butcher, Ted Campbell, Chris
|
||||
Candler, Lauren Carlson, Donal Casey, Terry Chen, Robert A. Clark, Allan
|
||||
Cochrane, Gunter Dannoritzer, Ashutosh Das, Bernard Deadman, Mike Denio,
|
||||
John Deroo, Philip Derrick, John Dickol, R. Diez, Ruben Diez, Danny Ding,
|
||||
Ivan Djordjevic, Jonathon Donaldson, Alex Duller, Jeff Dutton, Chandan
|
||||
Egbert, Joe Eiler, Ahmed El-Mahmoudy, Robert Farrell, Eugen Fekete,
|
||||
Fabrizio Ferrandi, Andrea Foletto, Bob Fredieu, Christian Gelinek, Glen
|
||||
Gibb, Shankar Giri, Sam Gladstone, Amir Gonnen, Chitlesh Goorah, Neil
|
||||
Hamilton, Junji Hashimoto, Thomas Hawkins, David Hewson, Hiroki Honda, Alex
|
||||
Hornung, Jae Hossell, Ben Jackson, Krzysztof Jankowski, HyungKi Jeong,
|
||||
Iztok Jeras, James Johnson, Christophe Joly, Franck Jullien, Mike Kagen,
|
||||
Kaalia Kahn, Guy-Armand Kamendje, Vasu Kandadi, Patricio Kaplan, Ralf
|
||||
Karge, Dan Katz, Sol Katzman, Jonathan Kimmitt, Sobhan Klnv, Gernot Koch,
|
||||
Soon Koh, Steve Kolecki, Brett Koonce, Wojciech Koszek, Varun Koyyalagunta,
|
||||
David Kravitz, Roland Kruse, Ed Lander, Steve Lang, Stephane Laurent,
|
||||
Walter Lavino, Christian Leber, Igor Lesik, John Li, Eivind Liland, Charlie
|
||||
Lind, Andrew Ling, Paul Liu, Derek Lockhart, Arthur Low, Stefan Ludwig, Dan
|
||||
Lussier, Fred Ma, Duraid Madina, Mark Marshall, Jason McMullan, Wim
|
||||
Michiels, Wai Sum Mong, Sean Moore, Dennis Muhlestein, John Murphy, Richard
|
||||
Myers, Dimitris Nalbantis, Bob Newgard, Cong Van Nguyen, Paul Nitza, Pete
|
||||
Nixon, Lisa Noack, Mark Nodine, Andreas Olofsson, Brad Parker, David
|
||||
Pierce, Dominic Plunkett, David Poole, Rich Porter, Niranjan Prabhu, Usha
|
||||
Priyadharshini, Mark Jackson Pulver, Prateek Puri, Chris Randall, Frederic
|
||||
Requin, Alberto Del Rio, Oleg Rodionov, Jan Egil Ruud, John Sanguinetti,
|
||||
Salman Sheikh, Mike Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Rodney
|
||||
Sinclair, Steven Slatter, Brian Small, Wilson Snyder, Alex Solomatnikov,
|
||||
Art Stamness, John Stevenson, Todd Strader, John Stroebel, Emerson
|
||||
include: Ahmed El-Mahmoudy, David Addison, Tariq B. Ahmad, Nikana
|
||||
Anastasiadis, Hans Van Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad
|
||||
Bagri, Andrew Bardsley, Matthew Barr, Geoff Barrett, Julius Baxter, Jeremy
|
||||
Bennett, Michael Berman, David Binderman, Johan Bjork, David Black, Daniel
|
||||
Bone, Gregg Bouchard, Christopher Boumenot, Nick Bowler, Byron Bradley,
|
||||
Bryan Brady, Charlie Brej, J Briquet, Lane Brooks, John Brownlee, Jeff
|
||||
Bush, Lawrence Butcher, Ted Campbell, Chris Candler, Lauren Carlson, Donal
|
||||
Casey, Terry Chen, Enzo Chi, Robert A. Clark, Allan Cochrane, John Coiner,
|
||||
Gunter Dannoritzer, Ashutosh Das, Bernard Deadman, John Demme, Mike Denio,
|
||||
John Deroo, Philip Derrick, John Dickol, Ruben Diez, Danny Ding, Ivan
|
||||
Djordjevic, Jonathon Donaldson, Sebastian Dressler, Alex Duller, Jeff
|
||||
Dutton, Usuario Eda, Chandan Egbert, Joe Eiler, Ahmed El-Mahmoudy, Robert
|
||||
Farrell, Eugen Fekete, Fabrizio Ferrandi, Brian Flachs, Andrea Foletto, Bob
|
||||
Fredieu, Christian Gelinek, Glen Gibb, Shankar Giri, Dan Gisselquist, Sam
|
||||
Gladstone, Amir Gonnen, Chitlesh Goorah, Xuan Guo, Neil Hamilton, Jannis
|
||||
Harder, Junji Hashimoto, Thomas Hawkins, Robert Henry, David Hewson, Jamey
|
||||
Hicks, Hiroki Honda, Alex Hornung, David Horton, Jae Hossell, Alan Hunter,
|
||||
Jamie Iles, Ben Jackson, Shareef Jalloq, Krzysztof Jankowski, HyungKi
|
||||
Jeong, Iztok Jeras, James Johnson, Christophe Joly, Franck Jullien, Mike
|
||||
Kagen, Arthur Kahlich, Kaalia Kahn, Guy-Armand Kamendje, Vasu Kandadi,
|
||||
Patricio Kaplan, Ralf Karge, Dan Katz, Sol Katzman, Jonathan Kimmitt, Olof
|
||||
Kindgren, Sobhan Klnv, Gernot Koch, Soon Koh, Steve Kolecki, Brett Koonce,
|
||||
Wojciech Koszek, Varun Koyyalagunta, David Kravitz, Roland Kruse, Sergey
|
||||
Kvachonok, Ed Lander, Steve Lang, Stephane Laurent, Walter Lavino,
|
||||
Christian Leber, Igor Lesik, John Li, Eivind Liland, Charlie Lind, Andrew
|
||||
Ling, Paul Liu, Derek Lockhart, Arthur Low, Stefan Ludwig, Dan Lussier,
|
||||
Fred Ma, Duraid Madina, Mark Marshall, Alfonso Martinez, Yves Mathieu,
|
||||
Patrick Maupin, Jason McMullan, Elliot Mednick, Wim Michiels, Miodrag
|
||||
Milanovic, Wai Sum Mong, Sean Moore, Dennis Muhlestein, John Murphy,
|
||||
Richard Myers, Dimitris Nalbantis, Bob Newgard, Cong Van Nguyen, Paul
|
||||
Nitza, Pete Nixon, Lisa Noack, Mark Nodine, Andreas Olofsson, James
|
||||
Pallister, Brad Parker, Maciej Piechotka, David Pierce, Dominic Plunkett,
|
||||
David Poole, Mike Popoloski, Rich Porter, Niranjan Prabhu, Usha
|
||||
Priyadharshini, Mark Jackson Pulver, Prateek Puri, Chris Randall, Anton
|
||||
Rapp, Odd Magne Reitan, Frederic Requin, Alberto Del Rio, Oleg Rodionov,
|
||||
Paul Rolfe, Jan Egil Ruud, John Sanguinetti, Galen Seitz, Salman Sheikh,
|
||||
Mike Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Rodney Sinclair, Steven
|
||||
Slatter, Brian Small, Alex Solomatnikov, Wei Song, Art Stamness, John
|
||||
Stevenson, Rob Stoddard, Todd Strader, John Stroebel, Sven Stucki, Emerson
|
||||
Suguimoto, Gene Sullivan, Renga Sundararajan, Yutetsu Takatsukasa, Peter
|
||||
Tengstrand, Stefan Thiede, Gary Thomas, Kevin Thompson, Mike Thyer, Steve
|
||||
Tong, Holger Waechtler, Stefan Wallentowitz, Shawn Wang, Greg Waters,
|
||||
Thomas Watts, Eugene Weber, David Welch, Leon Wildman, Gerald Williams,
|
||||
Trevor Williams, Jeff Winston, Joshua Wise, Clifford Wolf, Johan Wouters,
|
||||
Ding Xiaoliang, Jie Xu, and Amir Yazdanbakhsh.
|
||||
Tengstrand, Wesley Terpstra, Stefan Thiede, Gary Thomas, Kevin Thompson,
|
||||
Ian Thompson, Mike Thyer, Hans Tichelaar, Steve Tong, Michael Tresidder,
|
||||
Holger Waechtler, Stefan Wallentowitz, Shawn Wang, Greg Waters, Thomas
|
||||
Watts, Eugene Weber, David Welch, Thomas J Whatson, Leon Wildman, Gerald
|
||||
Williams, Trevor Williams, Jeff Winston, Joshua Wise, Clifford Wolf, Johan
|
||||
Wouters, Ding Xiaoliang, Jie Xu, Mandy Xu, Luke Yang, and Amir
|
||||
Yazdanbakhsh.
|
||||
|
||||
Thanks to them, and all those we've missed including above.
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ additional points.
|
||||
Additional Verilog-standard arguments specify the search paths necessary to
|
||||
find the source code that the coverage analysis was performed on.
|
||||
|
||||
To get correct coverage percentages, you may wish to read logs/coverage.pl
|
||||
To get correct coverage percentages, you may wish to read logs/coverage.dat
|
||||
into Emacs and do a M-x keep-lines to include only those statistics of
|
||||
interest.
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ use warnings;
|
||||
print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
|
||||
foreach my $param (@ARGV) {
|
||||
if ($param =~ /^-D([^=]+)=(.*)/) {
|
||||
print "#define $1 $2\n"
|
||||
print "#define $1 $2\n"
|
||||
} else {
|
||||
print "#include \"$param\"\n"
|
||||
print "#include \"$param\"\n"
|
||||
}
|
||||
}
|
||||
|
||||
+91
-24
@@ -6,7 +6,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[3.912 2017-09-23])
|
||||
AC_INIT([Verilator],[3.916 2017-11-25])
|
||||
# When releasing, also update header of Changes file
|
||||
# and commit using "devel release" or "Version bump" message
|
||||
|
||||
@@ -43,7 +43,7 @@ AC_ARG_ENABLE([ccwarn],
|
||||
x) CFG_WITH_CCWARN=no ;;
|
||||
*) CFG_WITH_CCWARN=yes ;;
|
||||
esac]
|
||||
)
|
||||
)
|
||||
AC_SUBST(CFG_WITH_CCWARN)
|
||||
AC_MSG_RESULT($CFG_WITH_CCWARN)
|
||||
|
||||
@@ -61,7 +61,7 @@ AC_ARG_ENABLE([longtests],
|
||||
x) CFG_WITH_LONGTESTS=no ;;
|
||||
*) CFG_WITH_LONGTESTS=yes ;;
|
||||
esac]
|
||||
)
|
||||
)
|
||||
AC_SUBST(CFG_WITH_LONGTESTS)
|
||||
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
||||
|
||||
@@ -79,10 +79,10 @@ AC_PROG_INSTALL
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING([that C++ compiler can compile simple program])
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_SOURCE([int main() { return 0; }])],
|
||||
AC_MSG_RESULT(yes),
|
||||
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]),
|
||||
AC_MSG_RESULT(yes))
|
||||
[AC_LANG_SOURCE([int main() { return 0; }])],
|
||||
AC_MSG_RESULT(yes),
|
||||
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]),
|
||||
AC_MSG_RESULT(yes))
|
||||
|
||||
AC_PATH_PROG(PERL,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
@@ -106,44 +106,91 @@ AC_TYPE_SIZE_T
|
||||
# Checks for compiler characteristics.
|
||||
AC_C_INLINE
|
||||
|
||||
AC_DEFUN([_MY_CXX_CHECK_OPT],
|
||||
[# _MY_CXX_CHECK_OPT(flag) -- Check if compiler supports specific options
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <new>], [[int* a=new int; delete a; ]])],
|
||||
[], [AC_MSG_ERROR([$CXX does not seem to successfully compile a simple C++ program])])
|
||||
|
||||
AC_DEFUN([_MY_CXX_CHECK_FLAG],
|
||||
[# _MY_CXX_CHECK_FLAG(flag) -- Check if compiler supports specific options
|
||||
# Set $_my_result appropriately
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
# -Werror needed otherwise unknown -Wno-div-by-zero won't report problems
|
||||
CXXFLAGS="$CXXFLAGS $2 -Werror"
|
||||
AC_MSG_CHECKING([whether $CXX accepts $2])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([],[])],
|
||||
[_my_result=yes
|
||||
if test -s conftest.err; then
|
||||
if grep -e "$2" conftest.err >/dev/null; then
|
||||
_my_result=no
|
||||
fi
|
||||
fi],
|
||||
[_my_result=no])
|
||||
# new/delete is needed to find -faligned-new link problem on Darwin
|
||||
CXXFLAGS="$CXXFLAGS $1 -Werror"
|
||||
AC_MSG_CHECKING([whether $CXX accepts $1])
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <new>], [[int* a=new int; delete a; ]])],
|
||||
[_my_result=yes
|
||||
if test -s conftest.err; then
|
||||
if grep -e "$1" conftest.err >/dev/null; then
|
||||
_my_result=no
|
||||
fi
|
||||
fi],
|
||||
[_my_result=no])
|
||||
# GCC is annoying, trying to be helpful, it postpones unknown -Wno-
|
||||
# options if there's no error We want to see them regardless, so try
|
||||
# forcing an error and see if we get a gcc warning
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([[an_error "intentional-error-for-test.h"
|
||||
]],[])],
|
||||
]],[])],
|
||||
[], # Ignore ok exit
|
||||
[if test -s conftest.err; then
|
||||
if grep -e "$2" conftest.err >/dev/null; then
|
||||
if grep -e "$1" conftest.err >/dev/null; then
|
||||
_my_result=no
|
||||
fi
|
||||
fi])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_CXX_CHECK_SET],
|
||||
[# _MY_CXX_CHECK_SET(variable,flag) -- Check if compiler supports specific options
|
||||
# If it does, set variable to flag, only if not previously set
|
||||
if test "$$1" = ""; then
|
||||
_MY_CXX_CHECK_FLAG($2)
|
||||
if test "$_my_result" = "yes" ; then
|
||||
$1="$2"
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_CXX_CHECK_OPT],
|
||||
[# _MY_CXX_CHECK_OPT(flag) -- Check if compiler supports specific options
|
||||
# If it does, append flag to variable
|
||||
_MY_CXX_CHECK_FLAG($2)
|
||||
if test "$_my_result" = "yes" ; then
|
||||
$1="$$1 $2"
|
||||
fi
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
])# _MY_CXX_CHECK_OPT
|
||||
])
|
||||
|
||||
# Flag to select newest language standard supported
|
||||
# Macros work such that first option that passes is the one we take
|
||||
# gnu++14 is the newest that Verilator supports
|
||||
# std++03 is the oldest that Verilator supports
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++14)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++11)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++03)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++14)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++11)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++03)
|
||||
AC_SUBST(CFG_CXXFLAGS_STD_NEWEST)
|
||||
# And likewise oldest standard (same list above, backwards)
|
||||
# This is used for internal testing
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=std++03)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=std++11)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=std++14)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++03)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++11)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++14)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++17)
|
||||
AC_SUBST(CFG_CXXFLAGS_STD_OLDEST)
|
||||
|
||||
# Flags for compiling Verilator internals including parser, and Verilated files
|
||||
# These turn on extra warnings and are only used with 'configure --enable-ccwarn'
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wextra)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wfloat-conversion)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wlogical-op)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
|
||||
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
||||
|
||||
# Flags for compiling Verilator internals including parser always
|
||||
@@ -180,7 +227,27 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-variable)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-shadow)
|
||||
AC_SUBST(CFG_CXXFLAGS_NO_UNUSED)
|
||||
|
||||
# Set CFG_WITH_THREADED if can support threading
|
||||
AC_MSG_CHECKING(whether $CXX supports Verilated threads)
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST $CFG_CXXFLAGS_NO_UNUSED"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <thread>], [[ ]])],
|
||||
[_my_result=yes
|
||||
if test -s conftest.err; then
|
||||
if grep -e "$1" conftest.err >/dev/null; then
|
||||
_my_result=no
|
||||
fi
|
||||
fi],
|
||||
[_my_result=no])
|
||||
CFG_WITH_THREADED=$_my_result
|
||||
AC_SUBST(CFG_WITH_THREADED)
|
||||
AC_MSG_RESULT($CFG_WITH_THREADED)
|
||||
|
||||
# Checks for library functions.
|
||||
AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
|
||||
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
|
||||
[], [#include <sys/stat.h>])
|
||||
|
||||
# Checks for system services
|
||||
|
||||
|
||||
+1
-2
@@ -635,8 +635,7 @@ INPUT = doxygen-mainpage \
|
||||
test_c \
|
||||
test_regress \
|
||||
test_sc \
|
||||
test_v \
|
||||
test_verilated
|
||||
test_v
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
*.csrc
|
||||
*.vcd
|
||||
obj_*
|
||||
project
|
||||
logs
|
||||
@@ -0,0 +1,52 @@
|
||||
######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Small Makefile
|
||||
#
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
######################################################################
|
||||
# Check for sanity to avoid later confusion
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
|
||||
# This is intended to be a minimal example. Before copying this to start a
|
||||
# real project, it is better to start with a more complete example,
|
||||
# e.g. examples/tracing_c.
|
||||
|
||||
# If $VERILATOR_ROOT isn't in the enviornment, we assume it is part of a
|
||||
# package inatall, and verilator is in your path. Otherwise find the
|
||||
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
|
||||
ifeq ($(VERILATOR_ROOT),)
|
||||
VERILATOR = verilator
|
||||
else
|
||||
export VERILATOR_ROOT
|
||||
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
endif
|
||||
|
||||
default:
|
||||
@echo "-- Verilator hello-world simple example"
|
||||
@echo "-- VERILATE ----------------"
|
||||
$(VERILATOR) -cc --exe top.v sim_main.cpp
|
||||
@echo "-- COMPILE -----------------"
|
||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
@echo "-- RUN ---------------------"
|
||||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "Note: Once this example is understood, see examples/tracing_c."
|
||||
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
|
||||
|
||||
######################################################################
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_dir *.log *.dmp *.vpd core
|
||||
@@ -0,0 +1,41 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
//======================================================================
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
// See a similar example walkthrough in the verilator manpage.
|
||||
|
||||
// This is intended to be a minimal example. Before copying this to start a
|
||||
// real project, it is better to start with a more complete example,
|
||||
// e.g. examples/c_tracing.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv && env) {}
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop;
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
|
||||
// Evaluate model
|
||||
top->eval();
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
top->final();
|
||||
|
||||
// Destroy model
|
||||
delete top;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
|
||||
// See also the EXAMPLE section in the verilator manpage/document.
|
||||
module top;
|
||||
initial begin
|
||||
$display("Hello World!");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -1,8 +1,6 @@
|
||||
*.old
|
||||
*.dmp
|
||||
*.log
|
||||
*.csrc
|
||||
*.vcd
|
||||
obj_*
|
||||
logs
|
||||
project
|
||||
@@ -0,0 +1,67 @@
|
||||
######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Small Makefile
|
||||
#
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
######################################################################
|
||||
# Check for sanity to avoid later confusion
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
|
||||
# This is intended to be a minimal example. Before copying this to start a
|
||||
# real project, it is better to start with a more complete example,
|
||||
# e.g. examples/tracing_sc.
|
||||
|
||||
# If $VERILATOR_ROOT isn't in the enviornment, we assume it is part of a
|
||||
# package inatall, and verilator is in your path. Otherwise find the
|
||||
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
|
||||
ifeq ($(VERILATOR_ROOT),)
|
||||
VERILATOR = verilator
|
||||
else
|
||||
export VERILATOR_ROOT
|
||||
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
endif
|
||||
|
||||
# Check if SC exists via a verilator call (empty if not)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --getenv SYSTEMC_INCLUDE)
|
||||
|
||||
ifneq ($(SYSTEMC_EXISTS),)
|
||||
default: run
|
||||
else
|
||||
default: nosc
|
||||
endif
|
||||
|
||||
run:
|
||||
@echo "-- Verilator hello-world simple example"
|
||||
@echo "-- VERILATE ----------------"
|
||||
$(VERILATOR) -sc --exe top.v sc_main.cpp
|
||||
@echo "-- COMPILE -----------------"
|
||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
@echo "-- RUN ---------------------"
|
||||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "Note: Once this example is understood, see examples/tracing_sc."
|
||||
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
|
||||
|
||||
######################################################################
|
||||
|
||||
nosc:
|
||||
@echo
|
||||
@echo "%Skip: SYSTEMC_INCLUDE not in environment"
|
||||
@echo "(If you have SystemC see the README, and rebuild Verilator)"
|
||||
@echo
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_dir *.log *.dmp *.vpd core
|
||||
@@ -0,0 +1,51 @@
|
||||
// -*- SystemC -*-
|
||||
// DESCRIPTION: Verilator Example: Top level main for invoking SystemC model
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
//======================================================================
|
||||
|
||||
// SystemC global header
|
||||
#include <systemc.h>
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// See a similar example walkthrough in the verilator manpage.
|
||||
|
||||
// This is intended to be a minimal example. Before copying this to start a
|
||||
// real project, it is better to start with a more complete example,
|
||||
// e.g. examples/c_tracing.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv) {}
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop("top");
|
||||
|
||||
// Initialize SC model
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
top->final();
|
||||
|
||||
// Fin
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
|
||||
// See also the EXAMPLE section in the verilator manpage/document.
|
||||
module top;
|
||||
initial begin
|
||||
$display("Hello World!");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,6 @@
|
||||
*.dmp
|
||||
*.log
|
||||
*.csrc
|
||||
*.vcd
|
||||
obj_*
|
||||
logs
|
||||
@@ -0,0 +1,96 @@
|
||||
######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Small Makefile
|
||||
#
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
######################################################################
|
||||
# Check for sanity to avoid later confusion
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# Set up variables
|
||||
|
||||
# If $VERILATOR_ROOT isn't in the enviornment, we assume it is part of a
|
||||
# package inatall, and verilator is in your path. Otherwise find the
|
||||
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
|
||||
ifeq ($(VERILATOR_ROOT),)
|
||||
VERILATOR = verilator
|
||||
VERILATOR_COVERAGE = verilator_coverage
|
||||
else
|
||||
export VERILATOR_ROOT
|
||||
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
|
||||
endif
|
||||
|
||||
VERILATOR_FLAGS =
|
||||
# Generate C++ in executable form
|
||||
VERILATOR_FLAGS += -cc --exe
|
||||
# Generate makefile dependencies (not shown as complicates the Makefile)
|
||||
#VERILATOR_FLAGS += -MMD
|
||||
# Optimize
|
||||
VERILATOR_FLAGS += -O2 -x-assign 0
|
||||
# Warn abount lint issues; may not want this on less solid designs
|
||||
VERILATOR_FLAGS += -Wall
|
||||
# Make waveforms
|
||||
VERILATOR_FLAGS += --trace
|
||||
# Check SystemVerilog assertions
|
||||
VERILATOR_FLAGS += --assert
|
||||
# Generate coverage analysis
|
||||
VERILATOR_FLAGS += --coverage
|
||||
# Run Verilator in debug mode
|
||||
#VERILATOR_FLAGS += --debug
|
||||
# Add this trace to get a backtrace in gdb
|
||||
#VERILATOR_FLAGS += --gdbbt
|
||||
|
||||
######################################################################
|
||||
default: run
|
||||
|
||||
run:
|
||||
@echo
|
||||
@echo "-- Verilator tracing example"
|
||||
|
||||
@echo
|
||||
@echo "-- VERILATE ----------------"
|
||||
$(VERILATOR) $(VERILATOR_FLAGS) -f input.vc top.v sim_main.cpp
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
# To compile, we can either just do what Verilator asks,
|
||||
# or call a submakefile where we can override the rules ourselves
|
||||
# $(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
$(MAKE) -j 4 -C obj_dir -f ../Makefile_obj
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
@mkdir -p logs
|
||||
obj_dir/Vtop +trace
|
||||
|
||||
@echo
|
||||
@echo "-- COVERAGE ----------------"
|
||||
$(VERILATOR_COVERAGE) --annotate logs/annotated logs/coverage.dat
|
||||
|
||||
@echo
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "To see waveforms, open vlt_dump.vcd in a waveform viewer"
|
||||
@echo
|
||||
|
||||
|
||||
######################################################################
|
||||
# Other targets
|
||||
|
||||
show-config:
|
||||
$(VERILATOR) -V
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_dir logs *.log *.dmp *.vpd coverage.dat core
|
||||
@@ -0,0 +1,55 @@
|
||||
# -*- Makefile -*-
|
||||
#######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Makefile for inside object directory
|
||||
#
|
||||
# This is executed in the object directory, and called by ../Makefile
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
default: Vtop
|
||||
|
||||
# Include the rules made by Verilator
|
||||
include Vtop.mk
|
||||
|
||||
#######################################################################
|
||||
# Compile flags
|
||||
|
||||
# Override some default compile flags
|
||||
CPPFLAGS += -MMD -MP
|
||||
CPPFLAGS += -DVL_DEBUG=1
|
||||
# Turn on some more flags (when configured appropriately)
|
||||
# For testing inside Verilator, "configure --enable-ccwarn" will do this
|
||||
# automatically; otherwise you may want this unconditionally enabled
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
USER_CPPFLAGS_WALL += -W -Werror -Wall
|
||||
endif
|
||||
|
||||
# See the benchmarking section of bin/verilator.
|
||||
# Support class optimizations. This includes the tracing and symbol table.
|
||||
# SystemC takes minutes to optimize, thus it is off by default.
|
||||
OPT_SLOW =
|
||||
# Fast path optimizations. Most time is spent in these classes.
|
||||
OPT_FAST = -O2 -fstrict-aliasing
|
||||
#OPT_FAST = -O
|
||||
#OPT_FAST =
|
||||
|
||||
#######################################################################
|
||||
# Linking final exe -- presumes have a sim_main.cpp
|
||||
|
||||
# Special compile rule
|
||||
sim_main.o: sim_main.cpp $(VM_PREFIX).h
|
||||
|
||||
######################################################################
|
||||
######################################################################
|
||||
# Automatically understand dependencies
|
||||
|
||||
DEPS := $(wildcard *.d)
|
||||
ifneq ($(DEPS),)
|
||||
include $(DEPS)
|
||||
endif
|
||||
@@ -0,0 +1,2 @@
|
||||
// This file typically lists flags required by a large project, e.g. include directories
|
||||
+librescan +libext+.v+.sv+.vh+.svh -y .
|
||||
@@ -0,0 +1,119 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
//======================================================================
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
|
||||
#include <sys/stat.h> // mkdir
|
||||
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
// If "verilator --trace" is used, include the tracing class
|
||||
#if VM_TRACE
|
||||
# include <verilated_vcd_c.h>
|
||||
#endif
|
||||
|
||||
// Current simulation time (64-bit unsigned)
|
||||
vluint64_t main_time = 0;
|
||||
// Called by $time in Verilog
|
||||
double sc_time_stamp () {
|
||||
return main_time; // Note does conversion to real, to match SystemC
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
// This is a more complicated example, please also see the simpler examples/hello_world_c.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv && env) {}
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Set debug level, 0 is off, 9 is highest presently used
|
||||
Verilated::debug(0);
|
||||
|
||||
// Randomization reset policy
|
||||
Verilated::randReset(2);
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
|
||||
|
||||
#if VM_TRACE
|
||||
// If verilator was invoked with --trace argument,
|
||||
// and if at run time passed the +trace argument, turn on tracing
|
||||
VerilatedVcdC* tfp = NULL;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0==strcmp(flag, "+trace")) {
|
||||
Verilated::traceEverOn(true); // Verilator must compute traced signals
|
||||
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
|
||||
tfp = new VerilatedVcdC;
|
||||
top->trace(tfp, 99); // Trace 99 levels of hierarchy
|
||||
mkdir("logs", 0777);
|
||||
tfp->open("logs/vlt_dump.vcd"); // Open the dump file
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set some inputs
|
||||
top->reset_l = !0;
|
||||
top->fastclk = 0;
|
||||
top->clk = 0;
|
||||
top->in_small = 1;
|
||||
top->in_quad = 0x1234;
|
||||
top->in_wide[0] = 0x11111111;
|
||||
top->in_wide[1] = 0x22222222;
|
||||
top->in_wide[2] = 0x3;
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
main_time++; // Time passes...
|
||||
|
||||
// Toggle clocks and such
|
||||
top->fastclk = !top->fastclk;
|
||||
if ((main_time % 10) == 3) {
|
||||
top->clk = 1;
|
||||
}
|
||||
if ((main_time % 10) == 8) {
|
||||
top->clk = 0;
|
||||
}
|
||||
if (main_time > 1 && main_time < 10) {
|
||||
top->reset_l = !1; // Assert reset
|
||||
} else {
|
||||
top->reset_l = !0; // Deassert reset
|
||||
}
|
||||
|
||||
// Assign some other inputs
|
||||
top->in_quad += 0x12;
|
||||
|
||||
// Evaluate model
|
||||
top->eval();
|
||||
|
||||
// Read outputs
|
||||
VL_PRINTF ("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
||||
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
||||
main_time, top->clk, top->reset_l, top->in_quad,
|
||||
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
top->final();
|
||||
|
||||
// Close trace if opened
|
||||
#if VM_TRACE
|
||||
if (tfp) { tfp->close(); }
|
||||
#endif
|
||||
|
||||
// Coverage analysis (since test passed)
|
||||
#if VM_COVERAGE
|
||||
mkdir("logs", 0777);
|
||||
VerilatedCov::write("logs/coverage.dat");
|
||||
#endif
|
||||
|
||||
// Destroy model
|
||||
delete top; top = NULL;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
// ======================================================================
|
||||
|
||||
module sub
|
||||
(
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l
|
||||
);
|
||||
|
||||
// Example counter/flop
|
||||
reg [31:0] count_f;
|
||||
always_ff @ (posedge fastclk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
count_f <= 32'h0;
|
||||
// End of automatics
|
||||
end
|
||||
else begin
|
||||
count_f <= count_f + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// Another example flop
|
||||
reg [31:0] count_c;
|
||||
always_ff @ (posedge clk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
count_c <= 32'h0;
|
||||
// End of automatics
|
||||
end
|
||||
else begin
|
||||
count_c <= count_c + 1;
|
||||
if (count_c >= 3) begin
|
||||
$display("[%0t] fastclk is %0d times faster than clk\n",
|
||||
$time, count_f/count_c);
|
||||
// This write is a magic value the Makefile uses to make sure the
|
||||
// test completes successfully.
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert (!reset_l || count_c<100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
cover property (@(posedge clk) count_c==3);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,42 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
// ======================================================================
|
||||
|
||||
// This is intended to be a complex example of several features, please also
|
||||
// see the simpler examples/hello_world_c.
|
||||
|
||||
module top
|
||||
(
|
||||
// Declare some signals so we can see how I/O works
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l,
|
||||
|
||||
output [1:0] out_small,
|
||||
output [39:0] out_quad,
|
||||
output [69:0] out_wide,
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
);
|
||||
|
||||
// Connect up the outputs, using some trivial logic
|
||||
wire [1:0] out_small = ~reset_l ? '0 : (in_small + 2'b1);
|
||||
wire [39:0] out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
|
||||
wire [69:0] out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
|
||||
|
||||
// And an example sub module. The submodule will print stuff.
|
||||
sub sub (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.fastclk (fastclk),
|
||||
.reset_l (reset_l));
|
||||
|
||||
// Print some stuff as an example
|
||||
initial begin
|
||||
$display("[%0t] Model running...\n", $time);
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,6 @@
|
||||
*.dmp
|
||||
*.log
|
||||
*.csrc
|
||||
*.vcd
|
||||
obj_*
|
||||
logs
|
||||
@@ -0,0 +1,109 @@
|
||||
######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Small Makefile
|
||||
#
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
######################################################################
|
||||
# Check for sanity to avoid later confusion
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# Set up variables
|
||||
|
||||
# If $VERILATOR_ROOT isn't in the enviornment, we assume it is part of a
|
||||
# package inatall, and verilator is in your path. Otherwise find the
|
||||
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
|
||||
ifeq ($(VERILATOR_ROOT),)
|
||||
VERILATOR = verilator
|
||||
VERILATOR_COVERAGE = verilator_coverage
|
||||
else
|
||||
export VERILATOR_ROOT
|
||||
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
|
||||
endif
|
||||
|
||||
VERILATOR_FLAGS =
|
||||
# Generate SystemC in executable form
|
||||
VERILATOR_FLAGS += -sc --exe
|
||||
# Generate makefile dependencies (not shown as complicates the Makefile)
|
||||
#VERILATOR_FLAGS += -MMD
|
||||
# Optimize
|
||||
VERILATOR_FLAGS += -O2 -x-assign 0
|
||||
# Warn abount lint issues; may not want this on less solid designs
|
||||
VERILATOR_FLAGS += -Wall
|
||||
# Make waveforms
|
||||
VERILATOR_FLAGS += --trace
|
||||
# Check SystemVerilog assertions
|
||||
VERILATOR_FLAGS += --assert
|
||||
# Generate coverage analysis
|
||||
VERILATOR_FLAGS += --coverage
|
||||
# Run Verilator in debug mode
|
||||
#VERILATOR_FLAGS += --debug
|
||||
# Add this trace to get a backtrace in gdb
|
||||
#VERILATOR_FLAGS += --gdbbt
|
||||
|
||||
# Check if SC exists via a verilator call (empty if not)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --getenv SYSTEMC_INCLUDE)
|
||||
|
||||
######################################################################
|
||||
|
||||
ifneq ($(SYSTEMC_EXISTS),)
|
||||
default: run
|
||||
else
|
||||
default: nosc
|
||||
endif
|
||||
|
||||
run:
|
||||
@echo
|
||||
@echo "-- Verilator tracing example"
|
||||
|
||||
@echo
|
||||
@echo "-- VERILATE ----------------"
|
||||
$(VERILATOR) $(VERILATOR_FLAGS) -f input.vc top.v sc_main.cpp
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE ----------------="
|
||||
# To compile, we can either just do what Verilator asks,
|
||||
# or call a submakefile where we can override the rules ourselves
|
||||
# $(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
$(MAKE) -j 4 -C obj_dir -f ../Makefile_obj
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
@mkdir -p logs
|
||||
obj_dir/Vtop +trace
|
||||
|
||||
@echo
|
||||
@echo "-- COVERAGE ----------------"
|
||||
$(VERILATOR_COVERAGE) --annotate logs/annotated logs/coverage.dat
|
||||
|
||||
@echo
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "To see waveforms, open vlt_dump.vcd in a waveform viewer"
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
# Other targets
|
||||
|
||||
nosc:
|
||||
@echo
|
||||
@echo "%Skip: SYSTEMC_INCLUDE not in environment"
|
||||
@echo "(If you have SystemC see the README, and rebuild Verilator)"
|
||||
@echo
|
||||
|
||||
show-config:
|
||||
$(VERILATOR) -V
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_dir logs *.log *.dmp *.vpd coverage.dat core
|
||||
@@ -0,0 +1,63 @@
|
||||
# -*- Makefile -*-
|
||||
#######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Makefile for inside object directory
|
||||
#
|
||||
# This is executed in the object directory, and called by ../Makefile
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
default: Vtop
|
||||
|
||||
# Include the rules made by Verilator
|
||||
include Vtop.mk
|
||||
|
||||
#######################################################################
|
||||
# Compile flags
|
||||
|
||||
# Override some default compile flags
|
||||
CPPFLAGS += -MMD -MP
|
||||
CPPFLAGS += -DVL_DEBUG=1
|
||||
# SystemC isn't too clean
|
||||
CPPFLAGS += -Wno-deprecated
|
||||
# Turn on some more flags (when configured appropriately)
|
||||
# For testing inside Verilator, "configure --enable-ccwarn" will do this
|
||||
# automatically; otherwise you may want this unconditionally enabled
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
USER_CPPFLAGS_WALL += -W -Werror -Wall
|
||||
endif
|
||||
|
||||
# If you build your own rules from scratch, note you need to include
|
||||
# SystemC as follows (Vtop.mk file includes verilated.mk with these
|
||||
# already).
|
||||
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
|
||||
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
|
||||
|
||||
# See the benchmarking section of bin/verilator.
|
||||
# Support class optimizations. This includes the tracing and symbol table.
|
||||
# SystemC takes minutes to optimize, thus it is off by default.
|
||||
OPT_SLOW =
|
||||
# Fast path optimizations. Most time is spent in these classes.
|
||||
OPT_FAST = -O2 -fstrict-aliasing
|
||||
#OPT_FAST = -O
|
||||
#OPT_FAST =
|
||||
|
||||
#######################################################################
|
||||
# Linking final exe -- presumes have a sim_main.cpp
|
||||
|
||||
# Special compile rule
|
||||
sim_main.o: sim_main.cpp $(VM_PREFIX).h
|
||||
|
||||
######################################################################
|
||||
######################################################################
|
||||
# Automatically understand dependencies
|
||||
|
||||
DEPS := $(wildcard *.d)
|
||||
ifneq ($(DEPS),)
|
||||
include $(DEPS)
|
||||
endif
|
||||
@@ -0,0 +1,2 @@
|
||||
// This file typically lists flags required by a large project, e.g. include directories
|
||||
+librescan +libext+.v+.sv+.vh+.svh -y .
|
||||
@@ -0,0 +1,141 @@
|
||||
// -*- SystemC -*-
|
||||
// DESCRIPTION: Verilator Example: Top level main for invoking SystemC model
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
//======================================================================
|
||||
|
||||
// SystemC global header
|
||||
#include <systemc.h>
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
#if VM_TRACE
|
||||
#include <verilated_vcd_sc.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h> // mkdir
|
||||
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// This is a more complicated example, please also see the simpler examples/hello_world_c.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv) {}
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Set debug level, 0 is off, 9 is highest presently used
|
||||
Verilated::debug(0);
|
||||
|
||||
// Randomization reset policy
|
||||
Verilated::randReset(2);
|
||||
|
||||
// General logfile
|
||||
ios::sync_with_stdio();
|
||||
|
||||
// Defaults time
|
||||
#if (SYSTEMC_VERSION>20011000)
|
||||
#else
|
||||
sc_time dut(1.0, sc_ns);
|
||||
sc_set_default_time_unit(dut);
|
||||
#endif
|
||||
|
||||
// Define clocks
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_clock clk ("clk", 10,SC_NS, 0.5, 3,SC_NS, true);
|
||||
sc_clock fastclk ("fastclk", 2,SC_NS, 0.5, 2,SC_NS, true);
|
||||
#else
|
||||
sc_clock clk ("clk", 10, 0.5, 3, true);
|
||||
sc_clock fastclk ("fastclk", 2, 0.5, 2, true);
|
||||
#endif
|
||||
|
||||
// Define interconnect
|
||||
sc_signal<bool> reset_l;
|
||||
sc_signal<vluint32_t> in_small;
|
||||
sc_signal<vluint64_t> in_quad;
|
||||
sc_signal<sc_bv<70> > in_wide;
|
||||
sc_signal<vluint32_t> out_small;
|
||||
sc_signal<vluint64_t> out_quad;
|
||||
sc_signal<sc_bv<70> > out_wide;
|
||||
|
||||
// Construct the Verilated model, from inside Vtop.h
|
||||
Vtop* top = new Vtop("top");
|
||||
// Attach signals to the model
|
||||
top->clk (clk);
|
||||
top->fastclk (fastclk);
|
||||
top->reset_l (reset_l);
|
||||
top->in_small (in_small);
|
||||
top->in_quad (in_quad);
|
||||
top->in_wide (in_wide);
|
||||
top->out_small (out_small);
|
||||
top->out_quad (out_quad);
|
||||
top->out_wide (out_wide);
|
||||
|
||||
#if VM_TRACE
|
||||
// Before any evaluation, need to know to calculate those signals only used for tracing
|
||||
Verilated::traceEverOn(true);
|
||||
#endif
|
||||
|
||||
// You must do one evaluation before enabling waves, in order to allow
|
||||
// SystemC to interconnect everything for testing.
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
// If verilator was invoked with --trace argument,
|
||||
// and if at run time passed the +trace argument, turn on tracing
|
||||
VerilatedVcdSc* tfp = NULL;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0==strcmp(flag, "+trace")) {
|
||||
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
||||
VerilatedVcdSc* tfp = new VerilatedVcdSc;
|
||||
top->trace (tfp, 99);
|
||||
mkdir("logs", 0777);
|
||||
tfp->open ("logs/vlt_dump.vcd");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
#if VM_TRACE
|
||||
// Flush the wave files each cycle so we can immediately see the output
|
||||
// Don't do this in "real" programs, do it in an abort() handler instead
|
||||
if (tfp) tfp->flush();
|
||||
// Apply inputs
|
||||
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
|
||||
reset_l = !1; // Assert reset
|
||||
} else if (VL_TIME_Q() > 1) {
|
||||
reset_l = !0; // Deassert reset
|
||||
}
|
||||
#endif
|
||||
// Simulate 1ns
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Close Waves
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
// Final model cleanup
|
||||
top->final();
|
||||
|
||||
// Coverage analysis (since test passed)
|
||||
#if VM_COVERAGE
|
||||
mkdir("logs", 0777);
|
||||
VerilatedCov::write("logs/coverage.dat");
|
||||
#endif
|
||||
|
||||
// Fin
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
// ======================================================================
|
||||
|
||||
module sub
|
||||
(
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l
|
||||
);
|
||||
|
||||
// Example counter/flop
|
||||
reg [31:0] count_f;
|
||||
always_ff @ (posedge fastclk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
count_f <= 32'h0;
|
||||
// End of automatics
|
||||
end
|
||||
else begin
|
||||
count_f <= count_f + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// Another example flop
|
||||
reg [31:0] count_c;
|
||||
always_ff @ (posedge clk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
count_c <= 32'h0;
|
||||
// End of automatics
|
||||
end
|
||||
else begin
|
||||
count_c <= count_c + 1;
|
||||
if (count_c >= 3) begin
|
||||
$display("[%0t] fastclk is %0d times faster than clk\n",
|
||||
$time, count_f/count_c);
|
||||
// This write is a magic value the Makefile uses to make sure the
|
||||
// test completes successfully.
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert (!reset_l || count_c<100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
cover property (@(posedge clk) count_c==3);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,42 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
// ======================================================================
|
||||
|
||||
// This is intended to be a complex example of several features, please also
|
||||
// see the simpler examples/hello_world_c.
|
||||
|
||||
module top
|
||||
(
|
||||
// Declare some signals so we can see how I/O works
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l,
|
||||
|
||||
output [1:0] out_small,
|
||||
output [39:0] out_quad,
|
||||
output [69:0] out_wide,
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
);
|
||||
|
||||
// Connect up the outputs, using some trivial logic
|
||||
wire [1:0] out_small = ~reset_l ? '0 : (in_small + 2'b1);
|
||||
wire [39:0] out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
|
||||
wire [69:0] out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
|
||||
|
||||
// And an example sub module. The submodule will print stuff.
|
||||
sub sub (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.fastclk (fastclk),
|
||||
.reset_l (reset_l));
|
||||
|
||||
// Print some stuff as an example
|
||||
initial begin
|
||||
$display("[%0t] Model running...\n", $time);
|
||||
end
|
||||
|
||||
endmodule
|
||||
+401
-169
File diff suppressed because it is too large
Load Diff
+444
-269
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,10 @@ RANLIB = ranlib
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
|
||||
# Select newest language
|
||||
CFG_CXXFLAGS_STD_NEWEST = @CFG_CXXFLAGS_STD_NEWEST@
|
||||
# Select oldest language (for Verilator internal testing only)
|
||||
CFG_CXXFLAGS_STD_OLDEST = @CFG_CXXFLAGS_STD_OLDEST@
|
||||
# Compiler flags to use to turn off unused and generated code warnings, such as -Wno-div-by-zero
|
||||
CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
|
||||
# Compiler flags that turn on extra warnings
|
||||
@@ -105,6 +109,16 @@ ifeq ($(VM_SC),1)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
##### Threaded builds
|
||||
|
||||
ifneq ($(VM_THREADS),0)
|
||||
ifneq ($(VM_THREADS),)
|
||||
# Need C++11 at least, so always default to newest
|
||||
CPPFLAGS += -DVL_THREADED $(CFG_CXXFLAGS_STD_NEWEST)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
##### Stub
|
||||
|
||||
|
||||
+67
-51
@@ -96,13 +96,14 @@ private:
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
ValueIndexMap m_valueIndexes; ///< For each key/value a unique arbitrary index value
|
||||
IndexValueMap m_indexValues; ///< For each key/value a unique arbitrary index value
|
||||
ItemList m_items; ///< List of all items
|
||||
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
|
||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||
|
||||
VerilatedCovImpItem* m_insertp; ///< Item about to insert
|
||||
const char* m_insertFilenamep; ///< Filename about to insert
|
||||
int m_insertLineno; ///< Line number about to insert
|
||||
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert
|
||||
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert
|
||||
int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedCovImp() {
|
||||
@@ -110,16 +111,17 @@ private:
|
||||
m_insertFilenamep = NULL;
|
||||
m_insertLineno = 0;
|
||||
}
|
||||
VL_UNCOPYABLE(VerilatedCovImp);
|
||||
public:
|
||||
~VerilatedCovImp() { clear(); }
|
||||
static VerilatedCovImp& imp() {
|
||||
~VerilatedCovImp() { clearGuts(); }
|
||||
static VerilatedCovImp& imp() VL_MT_SAFE {
|
||||
static VerilatedCovImp s_singleton;
|
||||
return s_singleton;
|
||||
}
|
||||
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
int valueIndex(const std::string& value) {
|
||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||
static int nextIndex = KEY_UNDEF+1;
|
||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
@@ -128,7 +130,7 @@ private:
|
||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||
return nextIndex;
|
||||
}
|
||||
std::string dequote(const std::string& text) {
|
||||
static std::string dequote(const std::string& text) VL_PURE {
|
||||
// Quote any special characters
|
||||
std::string rtn;
|
||||
for (const char* pos = text.c_str(); *pos; ++pos) {
|
||||
@@ -141,7 +143,7 @@ private:
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
bool legalKey(const std::string& key) {
|
||||
static bool legalKey(const std::string& key) VL_PURE {
|
||||
// Because we compress long keys to a single letter, and
|
||||
// don't want applications to either get confused if they use
|
||||
// a letter differently, nor want them to rely on our compression...
|
||||
@@ -150,7 +152,7 @@ private:
|
||||
if (key.length()==2 && isdigit(key[1])) return false;
|
||||
return true;
|
||||
}
|
||||
std::string keyValueFormatter (const std::string& key, const std::string& value) {
|
||||
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
|
||||
std::string name;
|
||||
if (key.length()==1 && isalpha(key[0])) {
|
||||
name += std::string("\001")+key;
|
||||
@@ -160,7 +162,7 @@ private:
|
||||
name += std::string("\002")+dequote(value);
|
||||
return name;
|
||||
}
|
||||
std::string combineHier (const std::string& old, const std::string& add) {
|
||||
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
||||
// (foo.a.x, foo.b.x) => foo.*.x
|
||||
// (foo.a.x, foo.b.y) => foo.*
|
||||
// (foo.a.x, foo.b) => foo.*
|
||||
@@ -194,7 +196,7 @@ private:
|
||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
||||
return out;
|
||||
}
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) {
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
// We don't compare keys, only values
|
||||
@@ -206,22 +208,19 @@ private:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void selftest() {
|
||||
static void selftest() VL_MT_SAFE {
|
||||
// Little selftest
|
||||
if (combineHier ("a.b.c","a.b.c") !="a.b.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.b.c","a.b") !="a.b*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.x.c","a.y.c") !="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("z","a") !="*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.a","q.b") !="q.*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.za","q.zb") !="q.z*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
}
|
||||
|
||||
public:
|
||||
// PUBLIC METHODS
|
||||
void clear() {
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
void clearGuts() VL_REQUIRES(m_mutex) {
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
delete itemp;
|
||||
}
|
||||
@@ -229,7 +228,17 @@ public:
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
}
|
||||
void clearNonMatch (const char* matchp) {
|
||||
|
||||
public:
|
||||
// PUBLIC METHODS
|
||||
void clear() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
clearGuts();
|
||||
}
|
||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
@@ -243,23 +252,28 @@ public:
|
||||
m_items = newlist;
|
||||
}
|
||||
}
|
||||
void zero() {
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
void zero() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
}
|
||||
|
||||
// We assume there's always call to i/f/p in that order
|
||||
void inserti (VerilatedCovImpItem* itemp) {
|
||||
void inserti (VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
assert(!m_insertp);
|
||||
m_insertp = itemp;
|
||||
}
|
||||
void insertf (const char* filenamep, int lineno) {
|
||||
void insertf (const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
m_insertFilenamep = filenamep;
|
||||
m_insertLineno = lineno;
|
||||
}
|
||||
void insertp (const char* ckeyps[MAX_KEYS],
|
||||
const char* valps[MAX_KEYS]) {
|
||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
assert(m_insertp);
|
||||
// First two key/vals are filename
|
||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||
@@ -303,7 +317,7 @@ public:
|
||||
addKeynum++;
|
||||
if (!legalKey(key)) {
|
||||
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,16 +326,18 @@ public:
|
||||
m_insertp = NULL;
|
||||
}
|
||||
|
||||
void write (const char* filename) {
|
||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
#ifndef VM_COVERAGE
|
||||
vl_fatal("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
#endif
|
||||
selftest();
|
||||
|
||||
std::ofstream os (filename);
|
||||
if (os.fail()) {
|
||||
std::string msg = (std::string)"%Error: Can't write '"+filename+"'";
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
return;
|
||||
}
|
||||
os << "# SystemC::Coverage-3\n";
|
||||
@@ -372,7 +388,7 @@ public:
|
||||
}
|
||||
|
||||
// Output body
|
||||
for (EventMap::iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||
os<<"C '"<<std::dec;
|
||||
os<<it->first;
|
||||
if (it->second.first != "") os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
|
||||
@@ -385,25 +401,25 @@ public:
|
||||
//=============================================================================
|
||||
// VerilatedCov
|
||||
|
||||
void VerilatedCov::clear() {
|
||||
void VerilatedCov::clear() VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().clear();
|
||||
}
|
||||
void VerilatedCov::clearNonMatch (const char* matchp) {
|
||||
void VerilatedCov::clearNonMatch(const char* matchp) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().clearNonMatch(matchp);
|
||||
}
|
||||
void VerilatedCov::zero() {
|
||||
void VerilatedCov::zero() VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().zero();
|
||||
}
|
||||
void VerilatedCov::write (const char* filenamep) {
|
||||
void VerilatedCov::write(const char* filenamep) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().write(filenamep);
|
||||
}
|
||||
void VerilatedCov::_inserti (vluint32_t* itemp) {
|
||||
void VerilatedCov::_inserti(vluint32_t* itemp) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint32_t>(itemp));
|
||||
}
|
||||
void VerilatedCov::_inserti (vluint64_t* itemp) {
|
||||
void VerilatedCov::_inserti(vluint64_t* itemp) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
|
||||
}
|
||||
void VerilatedCov::_insertf (const char* filename, int lineno) {
|
||||
void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().insertf(filename,lineno);
|
||||
}
|
||||
|
||||
@@ -413,7 +429,7 @@ void VerilatedCov::_insertf (const char* filename, int lineno) {
|
||||
#define N(n) "","" // Null argument list
|
||||
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19),
|
||||
A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) {
|
||||
A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) VL_MT_SAFE {
|
||||
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
|
||||
= {NULL,NULL,NULL, // filename,lineno,page
|
||||
key0,key1,key2,key3,key4,key5,key6,key7,key8,key9,
|
||||
@@ -428,20 +444,20 @@ void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
}
|
||||
|
||||
// And versions with fewer arguments (oh for a language with named parameters!)
|
||||
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) {
|
||||
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
|
||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
}
|
||||
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) {
|
||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
|
||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
}
|
||||
// Backward compatibility for Verilator
|
||||
void VerilatedCov::_insertp (A(0), A(1), K(2),int val2, K(3),int val3,
|
||||
K(4),const std::string& val4, A(5),A(6)) {
|
||||
K(4),const std::string& val4, A(5),A(6)) VL_MT_SAFE {
|
||||
std::string val2str = vlCovCvtToStr(val2);
|
||||
std::string val3str = vlCovCvtToStr(val3);
|
||||
_insertp(C(0),C(1),
|
||||
|
||||
+11
-9
@@ -73,7 +73,7 @@
|
||||
//=============================================================================
|
||||
/// Convert VL_COVER_INSERT value arguments to strings
|
||||
|
||||
template< class T> std::string vlCovCvtToStr (const T& t) {
|
||||
template< class T> std::string vlCovCvtToStr (const T& t) VL_PURE {
|
||||
std::ostringstream os; os<<t; return os.str();
|
||||
}
|
||||
|
||||
@@ -82,23 +82,25 @@ template< class T> std::string vlCovCvtToStr (const T& t) {
|
||||
/// Verilator coverage global class
|
||||
////
|
||||
/// Global class with methods affecting all coverage data.
|
||||
/// All public methods in this class are thread safe.
|
||||
|
||||
class VerilatedCov {
|
||||
VL_UNCOPYABLE(VerilatedCov);
|
||||
public:
|
||||
// GLOBAL METHODS
|
||||
/// Return default filename
|
||||
static const char* defaultFilename() { return "coverage.dat"; }
|
||||
static const char* defaultFilename() VL_PURE { return "coverage.dat"; }
|
||||
/// Write all coverage data to a file
|
||||
static void write (const char* filenamep = defaultFilename());
|
||||
static void write (const char* filenamep = defaultFilename()) VL_MT_SAFE;
|
||||
/// Insert a coverage item
|
||||
/// We accept from 1-30 key/value pairs, all as strings.
|
||||
/// Call _insert1, followed by _insert2 and _insert3
|
||||
/// Do not call directly; use VL_COVER_INSERT or higher level macros instead
|
||||
// _insert1: Remember item pointer with count. (Not const, as may add zeroing function)
|
||||
static void _inserti (vluint32_t* itemp);
|
||||
static void _inserti (vluint64_t* itemp);
|
||||
static void _inserti (vluint32_t* itemp) VL_MT_SAFE;
|
||||
static void _inserti (vluint64_t* itemp) VL_MT_SAFE;
|
||||
// _insert2: Set default filename and line number
|
||||
static void _insertf (const char* filename, int lineno);
|
||||
static void _insertf (const char* filename, int lineno) VL_MT_SAFE;
|
||||
// _insert3: Set parameters
|
||||
// We could have just the maximum argument version, but this compiles
|
||||
// much slower (nearly 2x) than having smaller versions also. However
|
||||
@@ -120,11 +122,11 @@ public:
|
||||
#undef A
|
||||
#undef D
|
||||
/// Clear coverage points (and call delete on all items)
|
||||
static void clear();
|
||||
static void clear() VL_MT_SAFE;
|
||||
/// Clear items not matching the provided string
|
||||
static void clearNonMatch (const char* matchp);
|
||||
static void clearNonMatch (const char* matchp) VL_MT_SAFE;
|
||||
/// Zero coverage points
|
||||
static void zero();
|
||||
static void zero() VL_MT_SAFE;
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -63,12 +63,6 @@ VLCOVGEN_ITEM("name=>'row2', short=>'r2', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'row3', short=>'r3', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr=>'For totaling items, weight of this item'")
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovKey
|
||||
/// Verilator coverage global class
|
||||
////
|
||||
/// Global class with methods affecting all coverage data.
|
||||
|
||||
// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
|
||||
#define VL_CIK_COL0 "c0"
|
||||
#define VL_CIK_COL0_NAME "C0"
|
||||
@@ -102,9 +96,14 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
|
||||
#define VL_CIK_WEIGHT "w"
|
||||
// VLCOVGEN_CIK_AUTO_EDIT_END
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovKey
|
||||
/// Verilator coverage global class.
|
||||
/// This class is thread safe.
|
||||
|
||||
class VerilatedCovKey {
|
||||
public:
|
||||
static std::string shortKey(const std::string& key) {
|
||||
static std::string shortKey(const std::string& key) VL_PURE {
|
||||
// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
|
||||
if (key == "col0") return VL_CIK_COL0;
|
||||
if (key == "col0_name") return VL_CIK_COL0_NAME;
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
|
||||
// On MSVC++ we need svdpi.h to declare exports, not imports
|
||||
#define DPI_PROTOTYPES
|
||||
#undef XXTERN
|
||||
#define XXTERN DPI_EXTERN DPI_DLLESPEC
|
||||
#undef EETERN
|
||||
#define EETERN DPI_EXTERN DPI_DLLESPEC
|
||||
|
||||
#include "vltstd/svdpi.h"
|
||||
@@ -40,11 +42,11 @@
|
||||
|
||||
// Not supported yet
|
||||
#define _VL_SVDPI_UNIMP() \
|
||||
vl_fatal(__FILE__,__LINE__,"",(std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str())
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"",(std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str())
|
||||
|
||||
// Function requires a "context" in the import declaration
|
||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||
VL_PRINTF("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
VL_PRINTF_MT("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
@@ -261,13 +263,13 @@ svScope svGetScope() {
|
||||
|
||||
svScope svSetScope(const svScope scope) {
|
||||
const VerilatedScope* prevScopep = Verilated::dpiScope();
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
const VerilatedScope* vscopep = reinterpret_cast<const VerilatedScope*>(scope);
|
||||
Verilated::dpiScope(vscopep);
|
||||
return (svScope)prevScopep;
|
||||
}
|
||||
|
||||
const char* svGetNameFromScope(const svScope scope) {
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
const VerilatedScope* vscopep = reinterpret_cast<const VerilatedScope*>(scope);
|
||||
return vscopep->name();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
/// \file
|
||||
/// \brief Verilator: Common include for all Verilated C files that use DPI
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates where DPI is used. It contains
|
||||
/// DPI interface functions required by the Verilated code.
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates where DPI is used. It contains
|
||||
/// DPI interface functions required by the Verilated code.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
@@ -35,23 +35,23 @@
|
||||
// SETTING OPERATORS
|
||||
|
||||
/// Return svBitVecVal from WData
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) {
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) {
|
||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) {
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
// Note we ignore X/Z in svLogicVecVal
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i].aval;
|
||||
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) {
|
||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||
// Note we don't create X/Z in svLogicVecVal
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words; ++i) owp[i].bval=0;
|
||||
|
||||
+20
-20
@@ -16,10 +16,10 @@
|
||||
/// \file
|
||||
/// \brief Verilator: String include for all Verilated C files
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates. It is used when strings or other
|
||||
/// heavyweight types are required; these contents are not part of
|
||||
/// verilated.h to save compile time when such types aren't used.
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates. It is used when strings or other
|
||||
/// heavyweight types are required; these contents are not part of
|
||||
/// verilated.h to save compile time when such types aren't used.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
@@ -36,49 +36,49 @@
|
||||
//======================================================================
|
||||
// Conversion functions
|
||||
|
||||
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
|
||||
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) {
|
||||
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE;
|
||||
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
|
||||
WData lw[2]; VL_SET_WQ(lw, lhs);
|
||||
return VL_CVT_PACK_STR_NW(2, lw);
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) {
|
||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE {
|
||||
return lhs;
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NI(IData lhs) {
|
||||
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
|
||||
WData lw[1]; lw[0] = lhs;
|
||||
return VL_CVT_PACK_STR_NW(1, lw);
|
||||
}
|
||||
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) {
|
||||
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
|
||||
return lhs+rhs;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) {
|
||||
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) VL_PURE {
|
||||
std::string out; out.reserve(lhs.length() * rep);
|
||||
for (unsigned times=0; times<rep; ++times) out += lhs;
|
||||
return out;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const std::string& lhs, IData rep) {
|
||||
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const std::string& lhs, IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
|
||||
}
|
||||
|
||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode);
|
||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
const std::string& ofilename, void* memp, IData start, IData end);
|
||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...);
|
||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...);
|
||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rdp);
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) {
|
||||
const std::string& ofilename, void* memp, IData start, IData end) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rdp) VL_MT_SAFE;
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
|
||||
WData rwp[2]; // WData must always be at least 2
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
|
||||
if (got) rdr = rwp[0];
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) {
|
||||
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) VL_MT_SAFE {
|
||||
WData rwp[2];
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
|
||||
if (got) rdr = VL_SET_QW(rwp);
|
||||
return got;
|
||||
}
|
||||
extern IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr);
|
||||
extern IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_SAFE;
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+251
-59
@@ -34,14 +34,131 @@
|
||||
#include "verilated_syms.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#ifdef VL_THREADED
|
||||
# include <functional>
|
||||
# include <queue>
|
||||
#endif
|
||||
|
||||
class VerilatedScope;
|
||||
|
||||
//======================================================================
|
||||
// Types
|
||||
// Threaded message passing
|
||||
|
||||
#ifdef VL_THREADED
|
||||
/// Message, enqueued on a train, and consumed on the main eval thread
|
||||
class VerilatedMsg {
|
||||
public:
|
||||
// TYPES
|
||||
struct Cmp {
|
||||
bool operator() (const VerilatedMsg& a, const VerilatedMsg& b) {
|
||||
return a.trainId() < b.trainId(); }
|
||||
};
|
||||
private:
|
||||
// MEMBERS
|
||||
vluint32_t m_trainId; ///< Train that did enqueue
|
||||
std::function<void()> m_cb; ///< Lambda to execute when message received
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedMsg(const std::function<void()>& cb)
|
||||
: m_trainId(Verilated::trainId()), m_cb(cb) {}
|
||||
~VerilatedMsg() {}
|
||||
// METHODS
|
||||
vluint32_t trainId() const { return m_trainId; }
|
||||
/// Execute the lambda function
|
||||
void run() const { m_cb(); }
|
||||
};
|
||||
|
||||
/// Each thread has a queue it pushes to
|
||||
/// This assumes no thread starts pushing the next tick until the previous has drained.
|
||||
/// If more aggressiveness is needed, a double-buffered scheme might work well.
|
||||
class VerilatedEvalMsgQueue {
|
||||
typedef std::multiset<VerilatedMsg, VerilatedMsg::Cmp> VerilatedThreadQueue;
|
||||
|
||||
std::atomic<vluint64_t> m_depth; ///< Current depth of queue (see comments below)
|
||||
|
||||
VerilatedMutex m_mutex; ///< Mutex protecting queue
|
||||
VerilatedThreadQueue m_queue VL_GUARDED_BY(m_mutex); ///< Message queue
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedEvalMsgQueue() : m_depth(0) { }
|
||||
~VerilatedEvalMsgQueue() { }
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
|
||||
public:
|
||||
// METHODS
|
||||
//// Add message to queue (called by producer)
|
||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::endOfEvalReqdInc(); // No mutex, threadsafe
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||
++m_depth;
|
||||
}
|
||||
/// Service queue until completion (called by consumer)
|
||||
void process() VL_EXCLUDES(m_mutex) {
|
||||
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
||||
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
||||
while (m_depth) {
|
||||
// Wait for a message to be added to the queue
|
||||
// We don't use unique_lock as want to unlock with the message copy still in scope
|
||||
m_mutex.lock();
|
||||
assert(!m_queue.empty()); // Otherwise m_depth is wrong
|
||||
// Unfortunately to release the lock we need to copy the message
|
||||
// (Or have the message be a pointer, but then new/delete cost on each message)
|
||||
// We assume messages are small, so copy
|
||||
auto it = m_queue.begin();
|
||||
const VerilatedMsg msg = *(it);
|
||||
m_queue.erase(it);
|
||||
m_mutex.unlock();
|
||||
m_depth--; // Ok if outside critical section as only this code checks the value
|
||||
Verilated::endOfEvalReqdDec(); // No mutex, threadsafe
|
||||
{
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from trainId=%d\n", msg.trainId()););
|
||||
msg.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Each thread has a local queue to build up messages until the end of the eval() call
|
||||
class VerilatedThreadMsgQueue {
|
||||
std::queue<VerilatedMsg> m_queue;
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedThreadMsgQueue() { }
|
||||
~VerilatedThreadMsgQueue() {
|
||||
// The only call of this with a non-empty queue is a fatal error.
|
||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||
}
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||
// METHODS
|
||||
static VerilatedThreadMsgQueue& threadton() {
|
||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
}
|
||||
public:
|
||||
/// Add message to queue, called by producer
|
||||
static void post(const VerilatedMsg& msg) VL_MT_SAFE {
|
||||
Verilated::endOfEvalReqdInc();
|
||||
threadton().m_queue.push(msg); // Pass by value to copy the message into queue
|
||||
}
|
||||
/// Push all messages to the eval's queue
|
||||
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
while (!threadton().m_queue.empty()) {
|
||||
evalMsgQp->post(threadton().m_queue.front());
|
||||
threadton().m_queue.pop();
|
||||
Verilated::endOfEvalReqdDec();
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // VL_THREADED
|
||||
|
||||
//======================================================================
|
||||
// VerilatedImp
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
@@ -56,86 +173,115 @@ class VerilatedImp {
|
||||
|
||||
// Nothing here is save-restored; users expected to re-register appropriately
|
||||
|
||||
ArgVec m_argVec; ///< Argument list (NOT save-restored, may want different results)
|
||||
bool m_argVecLoaded; ///< Ever loaded argument list
|
||||
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
|
||||
VerilatedScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
|
||||
VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded
|
||||
ArgVec m_argVec VL_GUARDED_BY(m_argMutex); ///< Argument list (NOT save-restored, may want different results)
|
||||
bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list
|
||||
|
||||
VerilatedMutex m_userMapMutex; ///< Protect m_userMap
|
||||
UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData>
|
||||
|
||||
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
||||
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
|
||||
// Slow - somewhat static:
|
||||
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
|
||||
int m_exportNext; ///< Next export funcnum
|
||||
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
||||
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
|
||||
int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum
|
||||
|
||||
// File I/O
|
||||
std::vector<FILE*> m_fdps; ///< File descriptors
|
||||
std::deque<IData> m_fdFree; ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
|
||||
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
||||
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
|
||||
// Threads
|
||||
VerilatedMutex m_threadMutex; ///< Protect m_numThreads, etc
|
||||
bool m_spawned VL_GUARDED_BY(m_threadMutex); ///< Already called spawnThreads()
|
||||
unsigned m_numThreads VL_GUARDED_BY(m_threadMutex); ///< Number of threads user requested, 0x0=all cpus
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {
|
||||
VerilatedImp()
|
||||
: m_argVecLoaded(false), m_exportNext(0), m_spawned(false), m_numThreads(0) {
|
||||
m_fdps.resize(3);
|
||||
m_fdps[0] = stdin;
|
||||
m_fdps[1] = stdout;
|
||||
m_fdps[2] = stderr;
|
||||
}
|
||||
~VerilatedImp() {}
|
||||
static void internalsDump() {
|
||||
VL_PRINTF("internalsDump:\n");
|
||||
VL_PRINTF(" Argv:");
|
||||
for (ArgVec::iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
VL_PRINTF(" %s",it->c_str());
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedImp);
|
||||
public:
|
||||
static void internalsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
VL_PRINTF_MT("internalsDump:\n");
|
||||
VL_PRINTF_MT(" Argv:");
|
||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
VL_PRINTF_MT(" %s",it->c_str());
|
||||
}
|
||||
VL_PRINTF("\n");
|
||||
VL_PRINTF(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||
VL_PRINTF_MT("\n");
|
||||
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||
scopesDump();
|
||||
exportsDump();
|
||||
userDump();
|
||||
}
|
||||
|
||||
// METHODS - arguments
|
||||
static void commandArgs(int argc, const char** argv) {
|
||||
public:
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
s_s.m_argVec.clear(); // Always clear
|
||||
commandArgsAdd(argc, argv);
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
static void commandArgsAdd(int argc, const char** argv) {
|
||||
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; ++i) s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
static std::string argPlusMatch(const char* prefixp) {
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
vl_fatal("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
VL_FATAL_MT("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0]=='+') {
|
||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private:
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
|
||||
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; ++i) s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
|
||||
public:
|
||||
// METHODS - user scope tracking
|
||||
// We implement this as a single large map instead of one map per scope
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) {
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) {
|
||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) {
|
||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
@@ -144,44 +290,50 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
static void userDump() {
|
||||
static void userDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
bool first = true;
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF(" userDump:\n"); first=false; }
|
||||
VL_PRINTF(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||
it->first.first, it->first.second, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) {
|
||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at construction
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) {
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(namep);
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) {
|
||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at destruction
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
||||
userEraseScope(scopep);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
}
|
||||
static void scopesDump() {
|
||||
VL_PRINTF(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||
static void scopesDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
||||
VL_PRINTF_MT(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF("\n");
|
||||
VL_PRINTF_MT("\n");
|
||||
}
|
||||
static const VerilatedScopeNameMap* scopeNameMap() {
|
||||
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
return &s_s.m_nameMap;
|
||||
}
|
||||
|
||||
@@ -194,8 +346,9 @@ public: // But only for verilated*.cpp
|
||||
// in the design that also happen to have our same callback function.
|
||||
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) {
|
||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||
// Slow ok - called once/function at creation
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||
@@ -204,26 +357,29 @@ public: // But only for verilated*.cpp
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) {
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||
+" but no such DPI export function name exists in ANY model");
|
||||
vl_fatal("unknown",0,"", msg.c_str());
|
||||
VL_FATAL_MT("unknown",0,"", msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
static const char* exportName(int funcnum) {
|
||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
for (ExportNameMap::iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
static void exportsDump() {
|
||||
static void exportsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
bool first = true;
|
||||
for (ExportNameMap::iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF(" exportDump:\n"); first=false; }
|
||||
VL_PRINTF(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
}
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
@@ -231,31 +387,67 @@ public: // But only for verilated*.cpp
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
static IData fdNew(FILE* fp) {
|
||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
VerilatedLockGuard guard(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
size_t start = s_s.m_fdps.size();
|
||||
s_s.m_fdps.resize(start*2);
|
||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back((IData)i);
|
||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
||||
}
|
||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
||||
s_s.m_fdps[idx] = fp;
|
||||
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
||||
}
|
||||
static void fdDelete(IData fdi) {
|
||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard guard(s_s.m_fdMutex);
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||
s_s.m_fdps[idx] = NULL;
|
||||
s_s.m_fdFree.push_back(idx);
|
||||
}
|
||||
static inline FILE* fdToFp(IData fdi) {
|
||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard guard(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||
return s_s.m_fdps[idx];
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - Threading
|
||||
static void numThreads(unsigned threads) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
||||
if (!s_s.m_spawned) s_s.m_numThreads = threads;
|
||||
}
|
||||
static unsigned numThreads() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
||||
#ifdef VL_THREADED
|
||||
unsigned threads = s_s.m_numThreads;
|
||||
if (threads == 0x0) {
|
||||
threads = std::thread::hardware_concurrency(); // Or 0=unknown, C++11
|
||||
}
|
||||
if (threads<1) threads = 1;
|
||||
return threads;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
static void spawnThreads() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
||||
if (!s_s.m_spawned) {
|
||||
// Convert numThreads from 0 to the spawned number
|
||||
numThreads(numThreads());
|
||||
s_s.m_spawned = true;
|
||||
#ifdef VL_THREADED
|
||||
// THREADED-TODO startup threads
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+28
-24
@@ -40,15 +40,15 @@
|
||||
#endif
|
||||
|
||||
// CONSTANTS
|
||||
static const char* VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||
static const char* VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Searalization
|
||||
|
||||
bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t size) {
|
||||
bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
bufferCheck();
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
vluint8_t miss = 0;
|
||||
@@ -58,17 +58,17 @@ bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t siz
|
||||
return (miss!=0);
|
||||
}
|
||||
|
||||
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) {
|
||||
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(readDiffers(datap,size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = (std::string)"Can't deserialize save-restore file as was made from different model";
|
||||
vl_fatal(fn.c_str(), 0, "", msg.c_str());
|
||||
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
|
||||
void VerilatedSerialize::header() {
|
||||
void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
|
||||
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
|
||||
assert((strlen(VLTSAVE_HEADER_STR) & 7) == 0); // Keep aligned
|
||||
os.write(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR));
|
||||
@@ -78,29 +78,29 @@ void VerilatedSerialize::header() {
|
||||
os.write(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||
}
|
||||
|
||||
void VerilatedDeserialize::header() {
|
||||
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = (std::string)"Can't deserialize; file has wrong header signature";
|
||||
vl_fatal(fn.c_str(), 0, "", msg.c_str());
|
||||
std::string msg = std::string("Can't deserialize; file has wrong header signature");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||
}
|
||||
|
||||
void VerilatedSerialize::trailer() {
|
||||
void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
|
||||
assert((strlen(VLTSAVE_TRAILER_STR) & 7) == 0); // Keep aligned
|
||||
os.write(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR));
|
||||
}
|
||||
|
||||
void VerilatedDeserialize::trailer() {
|
||||
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = (std::string)"Can't deserialize; file has wrong end-of-file signature";
|
||||
vl_fatal(fn.c_str(), 0, "", msg.c_str());
|
||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -110,9 +110,10 @@ void VerilatedDeserialize::trailer() {
|
||||
//=============================================================================
|
||||
// Opening/Closing
|
||||
|
||||
void VerilatedSave::open (const char* filenamep) {
|
||||
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_PRINTF("-vltSave: opening save file %s\n",filenamep););
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n",filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
@@ -132,9 +133,10 @@ void VerilatedSave::open (const char* filenamep) {
|
||||
header();
|
||||
}
|
||||
|
||||
void VerilatedRestore::open (const char* filenamep) {
|
||||
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_PRINTF("-vltRestore: opening restore file %s\n",filenamep););
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n",filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
@@ -155,7 +157,7 @@ void VerilatedRestore::open (const char* filenamep) {
|
||||
header();
|
||||
}
|
||||
|
||||
void VerilatedSave::close () {
|
||||
void VerilatedSave::close() VL_MT_UNSAFE_ONE {
|
||||
if (!isOpen()) return;
|
||||
trailer();
|
||||
flush();
|
||||
@@ -163,7 +165,7 @@ void VerilatedSave::close () {
|
||||
::close(m_fd); // May get error, just ignore it
|
||||
}
|
||||
|
||||
void VerilatedRestore::close () {
|
||||
void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
|
||||
if (!isOpen()) return;
|
||||
trailer();
|
||||
flush();
|
||||
@@ -174,7 +176,8 @@ void VerilatedRestore::close () {
|
||||
//=============================================================================
|
||||
// Buffer management
|
||||
|
||||
void VerilatedSave::flush() {
|
||||
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
vluint8_t* wp = m_bufp;
|
||||
while (1) {
|
||||
@@ -188,7 +191,7 @@ void VerilatedSave::flush() {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
@@ -197,7 +200,8 @@ void VerilatedSave::flush() {
|
||||
m_cp = m_bufp; // Reset buffer
|
||||
}
|
||||
|
||||
void VerilatedRestore::fill() {
|
||||
void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
|
||||
vluint8_t* rp = m_bufp;
|
||||
@@ -216,7 +220,7 @@ void VerilatedRestore::fill() {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
|
||||
+76
-59
@@ -27,64 +27,43 @@
|
||||
#include <string>
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSerialBase - internal base class for common code between VerilatedSerialize and VerilatedDeserialize
|
||||
// VerilatedSerialize - convert structures to a stream representation
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedSerialBase {
|
||||
class VerilatedSerialize {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
std::string m_filename;
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||
|
||||
// CREATORS
|
||||
VerilatedSerialBase() {
|
||||
void header() VL_MT_UNSAFE_ONE;
|
||||
void trailer() VL_MT_UNSAFE_ONE;
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSerialize);
|
||||
public:
|
||||
VerilatedSerialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
}
|
||||
private:
|
||||
VerilatedSerialBase(const VerilatedSerialBase& ); ///< N/A, no copy constructor
|
||||
public:
|
||||
// CREATORS
|
||||
virtual ~VerilatedSerialBase() {
|
||||
virtual ~VerilatedSerialize() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
std::string filename() const { return m_filename; }
|
||||
virtual void close() { flush(); }
|
||||
virtual void flush() {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSerialize - convert structures to a stream representation
|
||||
|
||||
class VerilatedSerialize : public VerilatedSerialBase {
|
||||
protected:
|
||||
virtual void close() { flush(); }
|
||||
virtual void flush() {}
|
||||
void header();
|
||||
void trailer();
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedSerialize() {}
|
||||
virtual ~VerilatedSerialize() { close(); }
|
||||
// METHODS
|
||||
VerilatedSerialize& bufferCheck() {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||
flush();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
inline VerilatedSerialize& write (const void* __restrict datap, size_t size) {
|
||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
@@ -95,23 +74,58 @@ public:
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
private:
|
||||
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||
flush();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedDeserial - load structures from a stream representation
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedDeserialize : public VerilatedSerialBase {
|
||||
class VerilatedDeserialize {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||
|
||||
virtual void fill() = 0;
|
||||
void header();
|
||||
void trailer();
|
||||
void header() VL_MT_UNSAFE_ONE;
|
||||
void trailer() VL_MT_UNSAFE_ONE;
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedDeserialize);
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedDeserialize() { m_endp = NULL; }
|
||||
virtual ~VerilatedDeserialize() { close(); }
|
||||
VerilatedDeserialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
m_endp = NULL;
|
||||
}
|
||||
virtual ~VerilatedDeserialize() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
}
|
||||
// METHODS
|
||||
inline VerilatedDeserialize& read (void* __restrict datap, size_t size) {
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
std::string filename() const { return m_filename; }
|
||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
@@ -123,10 +137,11 @@ public:
|
||||
return *this; // For function chaining
|
||||
}
|
||||
// Read a datum and compare with expected value
|
||||
bool readDiffers (const void* __restrict datap, size_t size);
|
||||
VerilatedDeserialize& readAssert (const void* __restrict datap, size_t size);
|
||||
VerilatedDeserialize& readAssert (vluint64_t data) { return readAssert(&data, sizeof(data)); }
|
||||
VerilatedDeserialize& bufferCheck() {
|
||||
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE { return readAssert(&data, sizeof(data)); }
|
||||
private:
|
||||
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
||||
@@ -138,40 +153,42 @@ public:
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSave - serialize to a file
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedSave : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
VerilatedSave() { m_fd=-1; }
|
||||
virtual ~VerilatedSave() { close(); }
|
||||
// METHODS
|
||||
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) { open(filename.c_str()); }
|
||||
virtual void close();
|
||||
virtual void flush();
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedRestore - deserialize from a file
|
||||
// This class is not thread safe, it must be called by a single thread
|
||||
|
||||
class VerilatedRestore : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
VerilatedRestore() { m_fd=-1; }
|
||||
virtual ~VerilatedRestore() { close(); }
|
||||
|
||||
// METHODS
|
||||
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) { open(filename.c_str()); }
|
||||
virtual void close();
|
||||
virtual void flush() {}
|
||||
virtual void fill();
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
/// \file
|
||||
/// \brief Verilator: Common include for all Verilated SystemC files
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all SystemC files it generates.
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all SystemC files it generates.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
@@ -35,13 +35,14 @@
|
||||
// We want to get a pointer to m_data in the sc_bv_base class,
|
||||
// but it is protected. So make an exposing class, then use
|
||||
// cast magic to get at it. Saves patching get_datap in SystemC.
|
||||
// This class is thread safe (though most of SystemC is not).
|
||||
|
||||
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
|
||||
class VlScBvExposer : public sc_bv_base {
|
||||
public:
|
||||
static vluint32_t* sp_datap(const sc_bv_base& base) {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp(); }
|
||||
vluint32_t* sp_datatp() const { return (vluint32_t*)(m_data); }
|
||||
static const vluint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp(); }
|
||||
const vluint32_t* sp_datatp() const { return reinterpret_cast<vluint32_t*>(m_data); }
|
||||
// Above reads this protected element in sc_bv_base:
|
||||
// sc_digit* m_data; // data array
|
||||
};
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
/// the symbol table. It is not included in verilated.h
|
||||
/// as it requires some heavyweight C++ classes.
|
||||
///
|
||||
/// These classes are thread safe on read only. It is constructed
|
||||
/// only when a model is built (from the main thread).
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
@@ -34,6 +37,7 @@
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator range
|
||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
||||
|
||||
// See also V3Ast::VNumRange
|
||||
class VerilatedRange {
|
||||
@@ -53,6 +57,7 @@ public:
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator variable
|
||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
||||
|
||||
class VerilatedVar {
|
||||
void* m_datap; // Location of data
|
||||
@@ -71,7 +76,7 @@ public:
|
||||
~VerilatedVar() {}
|
||||
void* datap() const { return m_datap; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
VerilatedVarFlags vldir() const { return (VerilatedVarFlags)((int)m_vlflags & VLVF_MASK_DIR); }
|
||||
VerilatedVarFlags vldir() const { return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR); }
|
||||
vluint32_t entSize() const;
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
const VerilatedRange& range() const { return m_range; }
|
||||
|
||||
+80
-37
@@ -46,6 +46,40 @@
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdImp
|
||||
/// Base class to hold some static state
|
||||
/// This is an internally used class
|
||||
|
||||
class VerilatedVcdSingleton {
|
||||
private:
|
||||
typedef std::vector<VerilatedVcd*> VcdVec;
|
||||
struct Singleton {
|
||||
VerilatedMutex s_vcdMutex; ///< Protect the singleton
|
||||
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
|
||||
};
|
||||
static Singleton& singleton() { static Singleton s; return s; }
|
||||
public:
|
||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
||||
singleton().s_vcdVecp.push_back(vcdp);
|
||||
}
|
||||
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
||||
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
||||
}
|
||||
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
||||
// Thread safety: Although this function is protected by a mutex so perhaps
|
||||
// in the future we can allow tracing in separate threads, vcdp->flush() assumes call from single thread
|
||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
||||
for (VcdVec::const_iterator it=singleton().s_vcdVecp.begin(); it!=singleton().s_vcdVecp.end(); ++it) {
|
||||
VerilatedVcd* vcdp = *it;
|
||||
vcdp->flush();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdCallInfo
|
||||
/// Internal callback routines for each module being traced.
|
||||
@@ -62,11 +96,12 @@ protected:
|
||||
VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
|
||||
void* m_userthis; ///< Fake "this" for caller
|
||||
vluint32_t m_code; ///< Starting code number
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
VerilatedVcdCallInfo (VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb,
|
||||
VerilatedVcdCallback_t changecb,
|
||||
void* ut, vluint32_t code)
|
||||
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {};
|
||||
~VerilatedVcdCallInfo() {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -74,16 +109,16 @@ protected:
|
||||
//=============================================================================
|
||||
// VerilatedVcdFile
|
||||
|
||||
bool VerilatedVcdFile::open(const std::string& name) {
|
||||
bool VerilatedVcdFile::open(const std::string& name) VL_MT_UNSAFE {
|
||||
m_fd = ::open(name.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK, 0666);
|
||||
return (m_fd>=0);
|
||||
}
|
||||
|
||||
void VerilatedVcdFile::close() {
|
||||
void VerilatedVcdFile::close() VL_MT_UNSAFE {
|
||||
::close(m_fd);
|
||||
}
|
||||
|
||||
ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) {
|
||||
ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE {
|
||||
return ::write(m_fd, bufp, len);
|
||||
}
|
||||
|
||||
@@ -112,11 +147,12 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
|
||||
}
|
||||
|
||||
void VerilatedVcd::open (const char* filename) {
|
||||
m_assertOne.check();
|
||||
if (isOpen()) return;
|
||||
|
||||
// Set member variables
|
||||
m_filename = filename;
|
||||
singleton().s_vcdVecp.push_back(this);
|
||||
VerilatedVcdSingleton::pushVcd(this);
|
||||
|
||||
// SPDIFF_OFF
|
||||
// Set callback so an early exit will flush us
|
||||
@@ -142,6 +178,7 @@ void VerilatedVcd::open (const char* filename) {
|
||||
void VerilatedVcd::openNext (bool incFilename) {
|
||||
// Open next filename in concat sequence, mangle filename if
|
||||
// incFilename is true.
|
||||
m_assertOne.check();
|
||||
closePrev(); // Close existing
|
||||
if (incFilename) {
|
||||
// Find _0000.{ext} in filename
|
||||
@@ -190,7 +227,7 @@ void VerilatedVcd::makeNameMap() {
|
||||
m_namemapp = new NameMap;
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
cip->m_code = nextCode();
|
||||
cip->m_code = m_nextCode;
|
||||
(cip->m_initcb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
|
||||
@@ -199,13 +236,13 @@ void VerilatedVcd::makeNameMap() {
|
||||
// If no scope was specified, prefix everything with a "top"
|
||||
// This comes from user instantiations with no name - IE Vtop("").
|
||||
bool nullScope = false;
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
for (NameMap::const_iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const std::string& hiername = it->first;
|
||||
if (hiername.size() >= 1 && hiername[0] == '\t') nullScope=true;
|
||||
}
|
||||
if (nullScope) {
|
||||
NameMap* newmapp = new NameMap;
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
for (NameMap::const_iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const std::string& hiername = it->first;
|
||||
const std::string& decl = it->second;
|
||||
std::string newname = std::string("top");
|
||||
@@ -228,12 +265,15 @@ VerilatedVcd::~VerilatedVcd() {
|
||||
if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; }
|
||||
deleteNameMap();
|
||||
if (m_filep && m_fileNewed) { delete m_filep; m_filep = NULL; }
|
||||
// Remove from list of traces
|
||||
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), this);
|
||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
||||
for (CallbackVec::const_iterator it=m_callbacks.begin(); it!=m_callbacks.end(); ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
m_callbacks.clear();
|
||||
VerilatedVcdSingleton::removeVcd(this);
|
||||
}
|
||||
|
||||
void VerilatedVcd::closePrev () {
|
||||
// This function is on the flush() call path
|
||||
if (!isOpen()) return;
|
||||
|
||||
bufferFlush();
|
||||
@@ -242,6 +282,7 @@ void VerilatedVcd::closePrev () {
|
||||
}
|
||||
|
||||
void VerilatedVcd::closeErr () {
|
||||
// This function is on the flush() call path
|
||||
// Close due to an error. We might abort before even getting here,
|
||||
// depending on the definition of vl_fatal.
|
||||
if (!isOpen()) return;
|
||||
@@ -252,6 +293,8 @@ void VerilatedVcd::closeErr () {
|
||||
}
|
||||
|
||||
void VerilatedVcd::close() {
|
||||
// This function is on the flush() call path
|
||||
m_assertOne.check();
|
||||
if (!isOpen()) return;
|
||||
if (m_evcd) {
|
||||
printStr("$vcdclose ");
|
||||
@@ -280,10 +323,10 @@ void VerilatedVcd::printTime (vluint64_t timeui) {
|
||||
// Dinotrace doesn't mind, but Cadence vvision seems to choke
|
||||
if (VL_UNLIKELY(timeui < m_timeLastDump)) {
|
||||
timeui = m_timeLastDump;
|
||||
static bool backTime = false;
|
||||
static VL_THREAD_LOCAL bool backTime = false;
|
||||
if (!backTime) {
|
||||
backTime = true;
|
||||
VL_PRINTF("VCD time is moving backwards, wave file may be incorrect.\n");
|
||||
VL_PRINTF_MT("%%Warning: VCD time is moving backwards, wave file may be incorrect.\n");
|
||||
}
|
||||
}
|
||||
m_timeLastDump = timeui;
|
||||
@@ -304,10 +347,12 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::bufferFlush () {
|
||||
void VerilatedVcd::bufferFlush () VL_MT_UNSAFE_ONE {
|
||||
// This function is on the flush() call path
|
||||
// We add output data to m_writep.
|
||||
// When it gets nearly full we dump it using this routine which calls write()
|
||||
// This is much faster than using buffered I/O
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
char* wp = m_wrBufp;
|
||||
while (1) {
|
||||
@@ -321,8 +366,8 @@ void VerilatedVcd::bufferFlush () {
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = (std::string)"VerilatedVcd::bufferFlush: "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
std::string msg = std::string("VerilatedVcd::bufferFlush: ")+strerror(errno);
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
closeErr();
|
||||
break;
|
||||
}
|
||||
@@ -349,7 +394,7 @@ void VerilatedVcd::set_time_resolution (const char* unitp) {
|
||||
double VerilatedVcd::timescaleToDouble (const char* unitp) {
|
||||
char* endp;
|
||||
double value = strtod(unitp, &endp);
|
||||
if (!value) value=1; // On error so we allow just "ns" to return 1e-9.
|
||||
if (value==0.0 && endp==unitp) value=1; // On error so we allow just "ns" to return 1e-9.
|
||||
unitp=endp;
|
||||
while (*unitp && isspace(*unitp)) unitp++;
|
||||
switch (*unitp) {
|
||||
@@ -411,7 +456,7 @@ void VerilatedVcd::dumpHeader () {
|
||||
|
||||
// Print the signal names
|
||||
const char* lastName = "";
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
for (NameMap::const_iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const std::string& hiernamestr = it->first;
|
||||
const std::string& decl = it->second;
|
||||
|
||||
@@ -468,19 +513,20 @@ void VerilatedVcd::dumpHeader () {
|
||||
}
|
||||
|
||||
void VerilatedVcd::module (const std::string& name) {
|
||||
m_assertOne.check();
|
||||
m_modName = name;
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
if (!code) { vl_fatal(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
|
||||
if (!code) { VL_FATAL_MT(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
|
||||
|
||||
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
|
||||
int codesNeeded = 1+int(bits/32);
|
||||
if (tri) codesNeeded *= 2; // Space in change array for __en signals
|
||||
|
||||
// Make sure array is large enough
|
||||
m_nextCode = std::max(nextCode(), code+codesNeeded);
|
||||
m_nextCode = std::max(m_nextCode, code+codesNeeded);
|
||||
if (m_sigs.capacity() <= m_nextCode) {
|
||||
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
|
||||
}
|
||||
@@ -566,7 +612,7 @@ void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum
|
||||
|
||||
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
(*((double*)&m_sigs_oldvalp[code])) = newval;
|
||||
(*(reinterpret_cast<double*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
// Buffer can't overflow before sprintf; we sized during declaration
|
||||
sprintf(m_writep, "r%.16g", newval);
|
||||
m_writep += strlen(m_writep);
|
||||
@@ -575,9 +621,9 @@ void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
|
||||
}
|
||||
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
(*((float*)&m_sigs_oldvalp[code])) = newval;
|
||||
(*(reinterpret_cast<float*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
// Buffer can't overflow before sprintf; we sized during declaration
|
||||
sprintf(m_writep, "r%.16g", (double)newval);
|
||||
sprintf(m_writep, "r%.16g", static_cast<double>(newval));
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
@@ -586,15 +632,16 @@ void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
|
||||
//=============================================================================
|
||||
// Callbacks
|
||||
|
||||
void VerilatedVcd::addCallback (
|
||||
void VerilatedVcd::addCallback VL_MT_UNSAFE_ONE (
|
||||
VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb,
|
||||
void* userthis)
|
||||
{
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(isOpen())) {
|
||||
std::string msg = (std::string)"Internal: "+__FILE__+"::"+__FUNCTION__+" called with already open file";
|
||||
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
||||
std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__+" called with already open file";
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"",msg.c_str());
|
||||
}
|
||||
VerilatedVcdCallInfo* vci = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, nextCode());
|
||||
VerilatedVcdCallInfo* vci = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, m_nextCode);
|
||||
m_callbacks.push_back(vci);
|
||||
}
|
||||
|
||||
@@ -602,15 +649,17 @@ void VerilatedVcd::addCallback (
|
||||
// Dumping
|
||||
|
||||
void VerilatedVcd::dumpFull (vluint64_t timeui) {
|
||||
m_assertOne.check();
|
||||
dumpPrep (timeui);
|
||||
Verilated::quiesce();
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
(cip->m_fullcb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
dumpDone ();
|
||||
}
|
||||
|
||||
void VerilatedVcd::dump (vluint64_t timeui) {
|
||||
m_assertOne.check();
|
||||
if (!isOpen()) return;
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No need for more full dumps
|
||||
@@ -622,11 +671,11 @@ void VerilatedVcd::dump (vluint64_t timeui) {
|
||||
if (!isOpen()) return;
|
||||
}
|
||||
dumpPrep (timeui);
|
||||
Verilated::quiesce();
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
(cip->m_changecb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
dumpDone();
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpPrep (vluint64_t timeui) {
|
||||
@@ -635,17 +684,11 @@ void VerilatedVcd::dumpPrep (vluint64_t timeui) {
|
||||
printStr("\n");
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpDone () {
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Static members
|
||||
|
||||
void VerilatedVcd::flush_all() {
|
||||
for (vluint32_t ent = 0; ent< singleton().s_vcdVecp.size(); ent++) {
|
||||
VerilatedVcd* vcdp = singleton().s_vcdVecp[ent];
|
||||
vcdp->flush();
|
||||
}
|
||||
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE {
|
||||
VerilatedVcdSingleton::flush_all();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
+57
-54
@@ -24,6 +24,7 @@
|
||||
#define _VERILATED_VCD_C_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -44,9 +45,9 @@ public:
|
||||
// METHODS
|
||||
VerilatedVcdFile() : m_fd(0) {}
|
||||
virtual ~VerilatedVcdFile() {}
|
||||
virtual bool open(const std::string& name);
|
||||
virtual void close();
|
||||
virtual ssize_t write(const char* bufp, ssize_t len);
|
||||
virtual bool open(const std::string& name) VL_MT_UNSAFE;
|
||||
virtual void close() VL_MT_UNSAFE;
|
||||
virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -96,20 +97,18 @@ private:
|
||||
vluint64_t m_wrChunkSize; ///< Output buffer size
|
||||
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
||||
std::vector<VerilatedVcdSig> m_sigs; ///< Pointer to signal information
|
||||
std::vector<VerilatedVcdCallInfo*> m_callbacks; ///< Routines to perform dumping
|
||||
typedef std::map<std::string,std::string> NameMap;
|
||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
||||
typedef std::vector<VerilatedVcdSig> SigVec;
|
||||
SigVec m_sigs; ///< Pointer to signal information
|
||||
typedef std::vector<VerilatedVcdCallInfo*> CallbackVec;
|
||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
||||
typedef std::map<std::string,std::string> NameMap;
|
||||
NameMap* m_namemapp; ///< List of names for the header
|
||||
|
||||
typedef std::vector<VerilatedVcd*> VcdVec;
|
||||
struct Singleton {
|
||||
VcdVec s_vcdVecp; ///< List of all created traces
|
||||
};
|
||||
static Singleton& singleton() { static Singleton s; return s; }
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
void bufferResize(vluint64_t minsize);
|
||||
void bufferFlush();
|
||||
void bufferFlush() VL_MT_UNSAFE_ONE;
|
||||
inline void bufferCheck() {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
@@ -135,33 +134,26 @@ private:
|
||||
// cppcheck-suppress functionConst
|
||||
void dumpDone ();
|
||||
inline void printCode (vluint32_t code) {
|
||||
if (code>=(94*94*94)) *m_writep++ = ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) *m_writep++ = ((char)((code/94/94)%94+33));
|
||||
if (code>=(94)) *m_writep++ = ((char)((code/94)%94+33));
|
||||
*m_writep++ = ((char)((code)%94+33));
|
||||
if (code>=(94*94*94)) *m_writep++ = static_cast<char>((code/94/94/94)%94+33);
|
||||
if (code>=(94*94)) *m_writep++ = static_cast<char>((code/94/94)%94+33);
|
||||
if (code>=(94)) *m_writep++ = static_cast<char>((code/94)%94+33);
|
||||
*m_writep++ = static_cast<char>((code)%94+33);
|
||||
}
|
||||
static std::string stringCode (vluint32_t code) {
|
||||
static std::string stringCode (vluint32_t code) VL_PURE {
|
||||
std::string out;
|
||||
if (code>=(94*94*94)) out += ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) out += ((char)((code/94/94)%94+33));
|
||||
if (code>=(94)) out += ((char)((code/94)%94+33));
|
||||
return out + ((char)((code)%94+33));
|
||||
if (code>=(94*94*94)) out += static_cast<char>((code/94/94/94)%94+33);
|
||||
if (code>=(94*94)) out += static_cast<char>((code/94/94)%94+33);
|
||||
if (code>=(94)) out += static_cast<char>((code/94)%94+33);
|
||||
return out + static_cast<char>((code)%94+33);
|
||||
}
|
||||
|
||||
VerilatedVcd(const VerilatedVcd& ); ///< N/A, no copy constructor
|
||||
|
||||
protected:
|
||||
// METHODS
|
||||
void evcd(bool flag) { m_evcd = flag; }
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcd);
|
||||
public:
|
||||
// CREATORS
|
||||
explicit VerilatedVcd(VerilatedVcdFile* filep=NULL);
|
||||
~VerilatedVcd();
|
||||
|
||||
// ACCESSORS
|
||||
/// Inside dumping routines, return next VCD signal code
|
||||
vluint32_t nextCode() const {return m_nextCode;}
|
||||
/// Set size in megabytes after which new file should be created
|
||||
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB=rolloverMB; };
|
||||
/// Is file open?
|
||||
@@ -172,11 +164,13 @@ public:
|
||||
inline bool isScopeEscape(char c) { return isspace(c) || c==m_scopeEscape; }
|
||||
|
||||
// METHODS
|
||||
void open (const char* filename); ///< Open the file; call isOpen() to see if errors
|
||||
void open(const char* filename) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
void openNext (bool incFilename); ///< Open next data-only file
|
||||
void flush() { bufferFlush(); } ///< Flush any remaining data
|
||||
static void flush_all(); ///< Flush any remaining data from all files
|
||||
void close (); ///< Close the file
|
||||
void close() VL_MT_UNSAFE_ONE; ///< Close the file
|
||||
/// Flush any remaining data to this file
|
||||
void flush() VL_MT_UNSAFE_ONE { bufferFlush(); }
|
||||
/// Flush any remaining data from all files
|
||||
static void flush_all() VL_MT_UNSAFE_ONE;
|
||||
|
||||
void set_time_unit (const char* unit); ///< Set time units (s/ms, defaults to ns)
|
||||
void set_time_unit (const std::string& unit) { set_time_unit(unit.c_str()); }
|
||||
@@ -190,12 +184,12 @@ public:
|
||||
/// Inside dumping routines, called each cycle to make the dump
|
||||
void dump (vluint64_t timeui);
|
||||
/// Call dump with a absolute unscaled time in seconds
|
||||
void dumpSeconds (double secs) { dump((vluint64_t)(secs * m_timeRes)); }
|
||||
void dumpSeconds (double secs) { dump(static_cast<vluint64_t>(secs * m_timeRes)); }
|
||||
|
||||
/// Inside dumping routines, declare callbacks for tracings
|
||||
void addCallback (VerilatedVcdCallback_t init, VerilatedVcdCallback_t full,
|
||||
VerilatedVcdCallback_t change,
|
||||
void* userthis);
|
||||
void* userthis) VL_MT_UNSAFE_ONE;
|
||||
|
||||
/// Inside dumping routines, declare a module
|
||||
void module (const std::string& name);
|
||||
@@ -216,7 +210,7 @@ public:
|
||||
void fullBit (vluint32_t code, const vluint32_t newval) {
|
||||
// Note the &1, so we don't require clean input -- makes more common no change case faster
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
*m_writep++=('0'+(char)(newval&1)); printCode(code); *m_writep++='\n';
|
||||
*m_writep++=('0'+static_cast<char>(newval&1)); printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullBus (vluint32_t code, const vluint32_t newval, int bits) {
|
||||
@@ -229,7 +223,7 @@ public:
|
||||
bufferCheck();
|
||||
}
|
||||
void fullQuad (vluint32_t code, const vluint64_t newval, int bits) {
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code])) = newval;
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++=((newval&(1ULL<<bit))?'1':'0');
|
||||
@@ -268,8 +262,8 @@ public:
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code])) = newval;
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code+1])) = newtri;
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) = newtri;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit)&1ULL)
|
||||
@@ -333,7 +327,7 @@ public:
|
||||
}
|
||||
}
|
||||
inline void chgQuad (vluint32_t code, const vluint64_t newval, int bits) {
|
||||
vluint64_t diff = (*((vluint64_t*)&m_sigs_oldvalp[code])) ^ newval;
|
||||
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==64 || (diff & ((1ULL<<bits)-1) ))) {
|
||||
fullQuad(code, newval, bits);
|
||||
@@ -368,8 +362,8 @@ public:
|
||||
}
|
||||
}
|
||||
inline void chgTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
|
||||
vluint64_t diff = ( ((*((vluint64_t*)&m_sigs_oldvalp[code])) ^ newval)
|
||||
| ((*((vluint64_t*)&m_sigs_oldvalp[code+1])) ^ newtri));
|
||||
vluint64_t diff = ( ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) ^ newval)
|
||||
| ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==64 || (diff & ((1ULL<<bits)-1) ))) {
|
||||
fullTriQuad(code, newval, newtri, bits);
|
||||
@@ -387,28 +381,37 @@ public:
|
||||
}
|
||||
inline void chgDouble (vluint32_t code, const double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY((*((double*)&m_sigs_oldvalp[code])) != newval)) {
|
||||
if (VL_UNLIKELY((*(reinterpret_cast<double*>(&m_sigs_oldvalp[code]))) != newval)) {
|
||||
fullDouble (code, newval);
|
||||
}
|
||||
}
|
||||
inline void chgFloat (vluint32_t code, const float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY((*((float*)&m_sigs_oldvalp[code])) != newval)) {
|
||||
if (VL_UNLIKELY((*(reinterpret_cast<float*>(&m_sigs_oldvalp[code]))) != newval)) {
|
||||
fullFloat (code, newval);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// METHODS
|
||||
void evcd(bool flag) { m_evcd = flag; }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdC
|
||||
/// Create a VCD dump file in C standalone (no SystemC) simulations.
|
||||
/// Also derived for use in SystemC simulations.
|
||||
/// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE
|
||||
|
||||
class VerilatedVcdC {
|
||||
VerilatedVcd m_sptrace; ///< Trace file being created
|
||||
public:
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdC);
|
||||
public:
|
||||
explicit VerilatedVcdC(VerilatedVcdFile* filep=NULL) : m_sptrace(filep) {}
|
||||
~VerilatedVcdC() {}
|
||||
public:
|
||||
// ACCESSORS
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_sptrace.isOpen(); }
|
||||
@@ -416,24 +419,24 @@ public:
|
||||
/// Open a new VCD file
|
||||
/// This includes a complete header dump each time it is called,
|
||||
/// just as if this object was deleted and reconstructed.
|
||||
void open (const char* filename) { m_sptrace.open(filename); }
|
||||
void open(const char* filename) VL_MT_UNSAFE_ONE { m_sptrace.open(filename); }
|
||||
/// Continue a VCD dump by rotating to a new file name
|
||||
/// The header is only in the first file created, this allows
|
||||
/// "cat" to be used to combine the header plus any number of data files.
|
||||
void openNext (bool incFilename=true) { m_sptrace.openNext(incFilename); }
|
||||
void openNext(bool incFilename=true) VL_MT_UNSAFE_ONE { m_sptrace.openNext(incFilename); }
|
||||
/// Set size in megabytes after which new file should be created
|
||||
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); };
|
||||
/// Close dump
|
||||
void close() { m_sptrace.close(); }
|
||||
void close() VL_MT_UNSAFE_ONE { m_sptrace.close(); }
|
||||
/// Flush dump
|
||||
void flush() { m_sptrace.flush(); }
|
||||
void flush() VL_MT_UNSAFE_ONE { m_sptrace.flush(); }
|
||||
/// Write one cycle of dump data
|
||||
void dump (vluint64_t timeui) { m_sptrace.dump(timeui); }
|
||||
/// Write one cycle of dump data - backward compatible and to reduce
|
||||
/// conversion warnings. It's better to use a vluint64_t time instead.
|
||||
void dump (double timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (vluint32_t timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (int timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (double timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
void dump (vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
void dump (int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
/// Set time units (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
void set_time_unit (const char* unit) { m_sptrace.set_time_unit(unit); }
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
/// \file
|
||||
/// \brief Verilator tracing in VCD format
|
||||
///
|
||||
/// This class is not threadsafe, as the SystemC kernel is not threadsafe.
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
@@ -37,6 +39,8 @@ class VerilatedVcdSc
|
||||
: sc_trace_file
|
||||
, public VerilatedVcdC
|
||||
{
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdSc);
|
||||
public:
|
||||
VerilatedVcdSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
@@ -56,8 +60,9 @@ public:
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
# endif
|
||||
}
|
||||
|
||||
virtual ~VerilatedVcdSc() {}
|
||||
|
||||
// METHODS
|
||||
/// Called by SystemC simulate()
|
||||
virtual void cycle (bool delta_cycle) {
|
||||
# if (SYSTEMC_VERSION>20011000)
|
||||
|
||||
+591
-86
File diff suppressed because it is too large
Load Diff
+10
-456
@@ -16,8 +16,8 @@
|
||||
/// \file
|
||||
/// \brief Verilator: VPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the VPI.
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the VPI.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
@@ -29,470 +29,24 @@
|
||||
#include "verilated.h"
|
||||
#include "verilated_syms.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
//======================================================================
|
||||
// From IEEE 1800-2009 annex K
|
||||
|
||||
#include "vltstd/vpi_user.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal constants
|
||||
|
||||
#define VL_DEBUG_IF_PLI VL_DEBUG_IF
|
||||
#define VL_VPI_LINE_SIZE 8192
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
#define _VL_VPI_INTERNAL VerilatedVpi::error_info()->setMessage(vpiInternal)->setMessage
|
||||
#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage
|
||||
#define _VL_VPI_ERROR VerilatedVpi::error_info()->setMessage(vpiError )->setMessage
|
||||
#define _VL_VPI_WARNING VerilatedVpi::error_info()->setMessage(vpiWarning )->setMessage
|
||||
#define _VL_VPI_NOTICE VerilatedVpi::error_info()->setMessage(vpiNotice )->setMessage
|
||||
#define _VL_VPI_ERROR_RESET VerilatedVpi::error_info()->resetError
|
||||
|
||||
// Not supported yet
|
||||
#define _VL_VPI_UNIMP() \
|
||||
_VL_VPI_ERROR(__FILE__,__LINE__,Verilated::catName("Unsupported VPI function: ",VL_FUNC));
|
||||
|
||||
//======================================================================
|
||||
// Implementation
|
||||
|
||||
// Base VPI handled object
|
||||
class VerilatedVpio {
|
||||
// MEM MANGLEMENT
|
||||
static vluint8_t* s_freeHead;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedVpio() {}
|
||||
virtual ~VerilatedVpio() {}
|
||||
inline static void* operator new(size_t size) {
|
||||
// We new and delete tons of vpi structures, so keep them around
|
||||
// To simplify our free list, we use a size large enough for all derived types
|
||||
// We reserve word zero for the next pointer, as that's safer in case a
|
||||
// dangling reference to the original remains around.
|
||||
static size_t chunk = 96;
|
||||
if (VL_UNLIKELY(size>chunk)) vl_fatal(__FILE__,__LINE__,"", "increase chunk");
|
||||
if (VL_LIKELY(s_freeHead)) {
|
||||
vluint8_t* newp = s_freeHead;
|
||||
s_freeHead = *((vluint8_t**)newp);
|
||||
return newp+8;
|
||||
} else {
|
||||
// +8: 8 bytes for next
|
||||
vluint8_t* newp = (vluint8_t*)(::operator new(chunk+8));
|
||||
return newp+8;
|
||||
}
|
||||
}
|
||||
inline static void operator delete(void* obj, size_t size) {
|
||||
vluint8_t* oldp = ((vluint8_t*)obj)-8;
|
||||
*((void**)oldp) = s_freeHead;
|
||||
s_freeHead = oldp;
|
||||
}
|
||||
// MEMBERS
|
||||
static inline VerilatedVpio* castp(vpiHandle h) { return dynamic_cast<VerilatedVpio*>((VerilatedVpio*)h); }
|
||||
inline vpiHandle castVpiHandle() { return (vpiHandle)(this); }
|
||||
// ACCESSORS
|
||||
virtual const char* name() { return "<null>"; }
|
||||
virtual const char* fullname() { return "<null>"; }
|
||||
virtual const char* defname() { return "<null>"; }
|
||||
virtual vluint32_t type() { return 0; }
|
||||
virtual vluint32_t size() const { return 0; }
|
||||
virtual const VerilatedRange* rangep() const { return NULL; }
|
||||
virtual vpiHandle dovpi_scan() { return 0; }
|
||||
};
|
||||
|
||||
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *);
|
||||
|
||||
class VerilatedVpioCb : public VerilatedVpio {
|
||||
t_cb_data m_cbData;
|
||||
s_vpi_value m_value;
|
||||
QData m_time;
|
||||
public:
|
||||
// cppcheck-suppress uninitVar // m_value
|
||||
VerilatedVpioCb(const t_cb_data* cbDatap, QData time)
|
||||
: m_cbData(*cbDatap), m_time(time) {
|
||||
m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal;
|
||||
m_cbData.value = &m_value;
|
||||
}
|
||||
virtual ~VerilatedVpioCb() {}
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiCallback; }
|
||||
vluint32_t reason() const { return m_cbData.reason; }
|
||||
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
|
||||
t_cb_data* cb_datap() { return &(m_cbData); }
|
||||
QData time() const { return m_time; }
|
||||
};
|
||||
|
||||
class VerilatedVpioConst : public VerilatedVpio {
|
||||
vlsint32_t m_num;
|
||||
public:
|
||||
explicit VerilatedVpioConst(vlsint32_t num) : m_num(num) {}
|
||||
virtual ~VerilatedVpioConst() {}
|
||||
static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiUndefined; }
|
||||
vlsint32_t num() const { return m_num; }
|
||||
};
|
||||
|
||||
class VerilatedVpioRange : public VerilatedVpio {
|
||||
const VerilatedRange* m_range;
|
||||
vlsint32_t m_iteration;
|
||||
public:
|
||||
explicit VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
|
||||
virtual ~VerilatedVpioRange() {}
|
||||
static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiRange; }
|
||||
virtual vluint32_t size() const { return m_range->elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return m_range; }
|
||||
int iteration() const { return m_iteration; }
|
||||
void iterationInc() { ++m_iteration; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (!iteration()) {
|
||||
VerilatedVpioRange* nextp = new VerilatedVpioRange(*this);
|
||||
nextp->iterationInc();
|
||||
return ((nextp)->castVpiHandle());
|
||||
} else {
|
||||
return 0; // End of list - only one deep
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioScope : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
public:
|
||||
explicit VerilatedVpioScope(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep) {}
|
||||
virtual ~VerilatedVpioScope() {}
|
||||
static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiScope; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
virtual const char* name() { return m_scopep->name(); }
|
||||
virtual const char* fullname() { return m_scopep->name(); }
|
||||
};
|
||||
|
||||
class VerilatedVpioVar : public VerilatedVpio {
|
||||
const VerilatedVar* m_varp;
|
||||
const VerilatedScope* m_scopep;
|
||||
vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange
|
||||
union {
|
||||
vluint8_t u8[4];
|
||||
vluint32_t u32;
|
||||
} m_mask; // memoized variable mask
|
||||
vluint32_t m_entSize; // memoized variable size
|
||||
protected:
|
||||
void* m_varDatap; // varp()->datap() adjusted for array entries
|
||||
vlsint32_t m_index;
|
||||
const VerilatedRange& get_range() const {
|
||||
// Determine number of dimensions and return outermost
|
||||
return (m_varp->dims()>1) ? m_varp->array() : m_varp->range();
|
||||
}
|
||||
public:
|
||||
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
|
||||
: m_varp(varp), m_scopep(scopep), m_index(0) {
|
||||
m_prevDatap = NULL;
|
||||
m_mask.u32 = VL_MASK_I(varp->range().elements());
|
||||
m_entSize = varp->entSize();
|
||||
m_varDatap = varp->datap();
|
||||
}
|
||||
virtual ~VerilatedVpioVar() {
|
||||
if (m_prevDatap) { delete [] m_prevDatap; m_prevDatap = NULL; }
|
||||
}
|
||||
static inline VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVar*>((VerilatedVpio*)h); }
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
vluint32_t mask() const { return m_mask.u32; }
|
||||
vluint8_t mask_byte(int idx) { return m_mask.u8[idx & 3]; }
|
||||
vluint32_t entSize() const { return m_entSize; }
|
||||
vluint32_t index() { return m_index; }
|
||||
virtual vluint32_t type() {
|
||||
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(); }
|
||||
virtual const VerilatedRange* rangep() const { return &get_range(); }
|
||||
virtual const char* name() { return m_varp->name(); }
|
||||
virtual const char* fullname() {
|
||||
VL_STATIC_OR_THREAD std::string out;
|
||||
out = std::string(m_scopep->name())+"."+name();
|
||||
return out.c_str();
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
void* varDatap() const { return m_varDatap; }
|
||||
void createPrevDatap() {
|
||||
if (VL_UNLIKELY(!m_prevDatap)) {
|
||||
m_prevDatap = new vluint8_t [entSize()];
|
||||
memcpy(prevDatap(), varp()->datap(), entSize());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWord : public VerilatedVpioVar {
|
||||
public:
|
||||
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep,
|
||||
vlsint32_t index, int offset)
|
||||
: VerilatedVpioVar(varp, scopep) {
|
||||
m_index = index;
|
||||
m_varDatap = ((vluint8_t*)varp->datap()) + entSize()*offset;
|
||||
}
|
||||
virtual ~VerilatedVpioMemoryWord() {}
|
||||
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiMemoryWord; }
|
||||
virtual vluint32_t size() const { return varp()->range().elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return &(varp()->range()); }
|
||||
virtual const char* fullname() {
|
||||
VL_STATIC_OR_THREAD std::string out;
|
||||
char num[20]; sprintf(num,"%d",m_index);
|
||||
out = std::string(scopep()->name())+"."+name()+"["+num+"]";
|
||||
return out.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioVarIter : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
VerilatedVarNameMap::iterator m_it;
|
||||
bool m_started;
|
||||
public:
|
||||
explicit VerilatedVpioVarIter(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep), m_started(false) { }
|
||||
virtual ~VerilatedVpioVarIter() {}
|
||||
static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiIterator; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (VL_LIKELY(m_scopep->varsp())) {
|
||||
VerilatedVarNameMap* varsp = m_scopep->varsp();
|
||||
if (VL_UNLIKELY(!m_started)) { m_it = varsp->begin(); m_started=true; }
|
||||
else if (VL_UNLIKELY(m_it == varsp->end())) return 0;
|
||||
else ++m_it;
|
||||
if (m_it == varsp->end()) return 0;
|
||||
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))
|
||||
->castVpiHandle());
|
||||
} else {
|
||||
return 0; // End of list - only one deep
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWordIter : public VerilatedVpio {
|
||||
const vpiHandle m_handle;
|
||||
const VerilatedVar* m_varp;
|
||||
vlsint32_t m_iteration;
|
||||
vlsint32_t m_direction;
|
||||
bool m_done;
|
||||
public:
|
||||
VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp)
|
||||
: m_handle(handle), m_varp(varp), m_iteration(varp->array().right()), m_direction(VL_LIKELY(varp->array().left()>varp->array().right())?1:-1), m_done(false) { }
|
||||
virtual ~VerilatedVpioMemoryWordIter() {}
|
||||
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiIterator; }
|
||||
void iterationInc() { if (!(m_done = (m_iteration == m_varp->array().left()))) m_iteration+=m_direction; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
vpiHandle result;
|
||||
if (m_done) return 0;
|
||||
result = vpi_handle_by_index(m_handle, m_iteration);
|
||||
iterationInc();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
struct VerilatedVpiTimedCbsCmp {
|
||||
/// Ordering sets keyed by time, then callback descriptor
|
||||
bool operator() (const std::pair<QData,VerilatedVpioCb*>& a,
|
||||
const std::pair<QData,VerilatedVpioCb*>& b) const {
|
||||
if (a.first < b.first) return 1;
|
||||
if (a.first > b.first) return 0;
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpiError;
|
||||
|
||||
class VerilatedVpi {
|
||||
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason
|
||||
typedef std::list<VerilatedVpioCb*> VpioCbList;
|
||||
typedef std::set<std::pair<QData,VerilatedVpioCb*>,VerilatedVpiTimedCbsCmp > VpioTimedCbs;
|
||||
|
||||
struct product_info {
|
||||
PLI_BYTE8* product;
|
||||
};
|
||||
|
||||
VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
|
||||
VpioTimedCbs m_timedCbs; // Time based callbacks
|
||||
VerilatedVpiError* m_errorInfop; // Container for vpi error info
|
||||
|
||||
static VerilatedVpi s_s; // Singleton
|
||||
|
||||
public:
|
||||
VerilatedVpi() { m_errorInfop=NULL; }
|
||||
~VerilatedVpi() {}
|
||||
static void cbReasonAdd(VerilatedVpioCb* vop) {
|
||||
if (vop->reason() == cbValueChange) {
|
||||
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
|
||||
varop->createPrevDatap();
|
||||
}
|
||||
}
|
||||
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) vl_fatal(__FILE__,__LINE__,"", "vpi bb reason too large");
|
||||
s_s.m_cbObjLists[vop->reason()].push_back(vop);
|
||||
}
|
||||
static void cbTimedAdd(VerilatedVpioCb* vop) {
|
||||
s_s.m_timedCbs.insert(std::make_pair(vop->time(), vop));
|
||||
}
|
||||
static void cbReasonRemove(VerilatedVpioCb* cbp) {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[cbp->reason()];
|
||||
// We do not remove it now as we may be iterating the list,
|
||||
// instead set to NULL and will cleanup later
|
||||
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end(); ++it) {
|
||||
if (*it == cbp) *it = NULL;
|
||||
}
|
||||
}
|
||||
static void cbTimedRemove(VerilatedVpioCb* cbp) {
|
||||
VpioTimedCbs::iterator it=s_s.m_timedCbs.find(std::make_pair(cbp->time(),cbp));
|
||||
if (VL_LIKELY(it != s_s.m_timedCbs.end())) {
|
||||
s_s.m_timedCbs.erase(it);
|
||||
}
|
||||
}
|
||||
static void callTimedCbs() {
|
||||
QData time = VL_TIME_Q();
|
||||
for (VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); it!=s_s.m_timedCbs.end(); ) {
|
||||
if (VL_UNLIKELY(it->first <= time)) {
|
||||
VerilatedVpioCb* vop = it->second;
|
||||
++it; // iterator may be deleted by callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: timed_callback %p\n",vop););
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
else { ++it; }
|
||||
}
|
||||
}
|
||||
static QData cbNextDeadline() {
|
||||
VpioTimedCbs::iterator it=s_s.m_timedCbs.begin();
|
||||
if (VL_LIKELY(it!=s_s.m_timedCbs.end())) {
|
||||
return it->first;
|
||||
} else {
|
||||
return ~VL_ULL(0); // maxquad
|
||||
}
|
||||
}
|
||||
static void callCbs(vluint32_t reason) {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
|
||||
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
|
||||
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
continue;
|
||||
}
|
||||
VerilatedVpioCb* vop = *it++;
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: reason_callback %d %p\n",reason,vop););
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
static void callValueCbs() {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
|
||||
typedef std::set<VerilatedVpioVar*> VpioVarSet;
|
||||
VpioVarSet update; // set of objects to update after callbacks
|
||||
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
|
||||
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
continue;
|
||||
}
|
||||
VerilatedVpioCb* vop = *it++;
|
||||
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
|
||||
void* newDatap = varop->varDatap();
|
||||
void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_test %s v[0]=%d/%d %p %p\n",
|
||||
varop->fullname(), *((CData*)newDatap), *((CData*)prevDatap),
|
||||
newDatap, prevDatap););
|
||||
if (memcmp(prevDatap, newDatap, varop->entSize())) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n",
|
||||
vop,varop->fullname(), *((CData*)newDatap)););
|
||||
update.insert(varop);
|
||||
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (VpioVarSet::iterator it=update.begin(); it!=update.end(); ++it) {
|
||||
memcpy((*it)->prevDatap(), (*it)->varDatap(), (*it)->entSize());
|
||||
}
|
||||
}
|
||||
|
||||
static VerilatedVpiError* error_info(); // getter for vpi error info
|
||||
/// Call timed callbacks
|
||||
/// Users should call this from their main loops
|
||||
static void callTimedCbs() VL_MT_UNSAFE_ONE;
|
||||
/// Call value based callbacks
|
||||
/// Users should call this from their main loops
|
||||
static void callValueCbs() VL_MT_UNSAFE_ONE;
|
||||
/// Self test, for internal use only
|
||||
static void selfTest() VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
#define _VL_VPI_ERROR_SET \
|
||||
do { \
|
||||
va_list args; \
|
||||
va_start(args, message); \
|
||||
VL_VSNPRINTF(m_buff, sizeof(m_buff), message.c_str(), args); \
|
||||
va_end(args); \
|
||||
} while (0)
|
||||
|
||||
class VerilatedVpiError {
|
||||
//// Container for vpi error info
|
||||
|
||||
t_vpi_error_info m_errorInfo;
|
||||
bool m_flag;
|
||||
char m_buff[VL_VPI_LINE_SIZE];
|
||||
void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) {
|
||||
m_errorInfo.message = message;
|
||||
m_errorInfo.file = file;
|
||||
m_errorInfo.line = line;
|
||||
m_errorInfo.code = code;
|
||||
do_callbacks();
|
||||
}
|
||||
void do_callbacks() {
|
||||
if (getError()->level >= vpiError && Verilated::fatalOnVpiError()) {
|
||||
// Stop on vpi error/unsupported
|
||||
vpi_unsupported();
|
||||
}
|
||||
// We need to run above code first because in the case that the callback executes further vpi
|
||||
// functions we will loose the error as it will be overwritten.
|
||||
VerilatedVpi::callCbs(cbPLIError);
|
||||
}
|
||||
public:
|
||||
|
||||
VerilatedVpiError() : m_flag(false) {
|
||||
m_buff[0] = '\0';
|
||||
m_errorInfo.product = (PLI_BYTE8*)Verilated::productName();
|
||||
}
|
||||
~VerilatedVpiError() {}
|
||||
static void selfTest();
|
||||
VerilatedVpiError* setMessage(PLI_INT32 level) {
|
||||
m_flag=true;
|
||||
m_errorInfo.level = level;
|
||||
return this;
|
||||
}
|
||||
void setMessage(std::string file, PLI_INT32 line, std::string message, ...) {
|
||||
static VL_THREAD std::string filehold;
|
||||
_VL_VPI_ERROR_SET;
|
||||
m_errorInfo.state = vpiPLI;
|
||||
filehold = file;
|
||||
setError((PLI_BYTE8*)m_buff, NULL, (PLI_BYTE8*)filehold.c_str(), line);
|
||||
}
|
||||
p_vpi_error_info getError() {
|
||||
if (m_flag) return &m_errorInfo;
|
||||
return NULL;
|
||||
}
|
||||
void resetError() {
|
||||
m_flag=false;
|
||||
}
|
||||
static void vpi_unsupported() {
|
||||
// Not supported yet
|
||||
p_vpi_error_info error_info_p = VerilatedVpi::error_info()->getError();
|
||||
if (error_info_p) {
|
||||
vl_fatal(error_info_p->file, error_info_p->line, "", error_info_p->message);
|
||||
return;
|
||||
}
|
||||
vl_fatal(__FILE__, __LINE__, "", "vpi_unsupported called without error info set");
|
||||
}
|
||||
static const char* strFromVpiVal(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiObjType(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiMethod(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiProp(PLI_INT32 vpiVal);
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+88
-20
@@ -42,52 +42,100 @@
|
||||
# else
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, fmtArgNum, fmtArgNum+1)))
|
||||
# endif
|
||||
# define VL_ATTR_PURE __attribute__ ((pure))
|
||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||
# define VL_FUNC __func__
|
||||
# if defined(__clang__) && defined(VL_THREADED)
|
||||
# define VL_ACQUIRE(...) __attribute__ ((acquire_capability(__VA_ARGS__)))
|
||||
# define VL_ACQUIRE_SHARED(...) __attribute__ ((acquire_shared_capability(__VA_ARGS__)))
|
||||
# define VL_RELEASE(...) __attribute__ ((release_capability(__VA_ARGS__)))
|
||||
# define VL_RELEASE_SHARED(...) __attribute__ ((release_shared_capability(__VA_ARGS__)))
|
||||
# define VL_TRY_ACQUIRE(...) __attribute__ ((try_acquire_capability(__VA_ARGS__)))
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__ ((try_acquire_shared_capability(__VA_ARGS__)))
|
||||
# define VL_CAPABILITY(x) __attribute__ ((capability(x)))
|
||||
# define VL_REQUIRES(x) __attribute__ ((requires_capability(x)))
|
||||
# define VL_GUARDED_BY(x) __attribute__ ((guarded_by(x)))
|
||||
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
|
||||
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
|
||||
# endif
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define VL_UNREACHABLE __builtin_unreachable();
|
||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
||||
#elif defined(_MSC_VER)
|
||||
# define VL_ATTR_ALIGNED(alignment)
|
||||
# define VL_ATTR_ALWINLINE
|
||||
# define VL_ATTR_NORETURN
|
||||
# define VL_ATTR_PRINTF(fmtArgNum)
|
||||
# define VL_ATTR_UNUSED
|
||||
# define VL_FUNC __FUNCTION__
|
||||
# define VL_LIKELY(x) (!!(x))
|
||||
# define VL_UNLIKELY(x) (!!(x))
|
||||
# define VL_UNREACHABLE
|
||||
# define VL_PREFETCH_RD(p)
|
||||
# define VL_PREFETCH_RW(p)
|
||||
#else
|
||||
#endif
|
||||
|
||||
// Defaults for unsupported compiler features
|
||||
#ifndef VL_ATTR_ALIGNED
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
#endif
|
||||
#ifndef VL_ATTR_ALWINLINE
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
#endif
|
||||
#ifndef VL_ATTR_NORETURN
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
#endif
|
||||
#ifndef VL_ATTR_PRINTF
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
#endif
|
||||
#ifndef VL_ATTR_PURE
|
||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||
#endif
|
||||
#ifndef VL_ATTR_UNUSED
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
#endif
|
||||
#ifndef VL_FUNC
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
#endif
|
||||
#ifndef VL_CAPABILITY
|
||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||
#endif
|
||||
#ifndef VL_LIKELY
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
#endif
|
||||
#ifndef VL_UNREACHABLE
|
||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||
#endif
|
||||
#ifndef VL_PREFETCH_RD
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
#endif
|
||||
#ifndef VL_PREFETCH_RW
|
||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||
#endif
|
||||
|
||||
#ifdef VL_THREADED
|
||||
# ifdef __GNUC__
|
||||
# define VL_THREAD __thread ///< Storage class for thread-local storage
|
||||
# if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING)
|
||||
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
|
||||
# endif
|
||||
# else
|
||||
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
||||
# endif
|
||||
# define VL_STATIC_OR_THREAD ///< Static if unthreaded, as some strings can be faster
|
||||
// ///< if non-dynamic and can't do "static VL_THREAD string"
|
||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||
#else
|
||||
# define VL_THREAD ///< Storage class for thread-local storage
|
||||
# define VL_STATIC_OR_THREAD static ///< Static if unthreaded, as some strings can be faster
|
||||
// ///< if non-dynamic and can't do "static VL_THREAD string"
|
||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||
#endif
|
||||
#define VL_THREAD ///< Deprecated
|
||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
|
||||
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only during normal operation (post-init)
|
||||
#define VL_MT_UNSAFE ///< Comment tag that function is not threadsafe when VL_THREADED
|
||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
||||
@@ -96,7 +144,7 @@
|
||||
#endif
|
||||
|
||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||
#define VL_UL(c) ((IData)(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
||||
# define VL_DANGLING(v)
|
||||
@@ -108,10 +156,22 @@
|
||||
// C++-2011
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define VL_EQ_DELETE = delete
|
||||
# define VL_HAS_UNIQUE_PTR
|
||||
# define VL_UNIQUE_PTR unique_ptr
|
||||
# define VL_HAS_UNORDERED_MAP
|
||||
# define VL_HAS_UNORDERED_SET
|
||||
# define vl_unique_ptr std::unique_ptr
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
#else
|
||||
# define VL_UNIQUE_PTR auto_ptr
|
||||
# define VL_EQ_DELETE
|
||||
# define vl_unique_ptr std::auto_ptr
|
||||
# define vl_unordered_map std::map
|
||||
# define vl_unordered_set std::set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <set>
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
@@ -251,6 +311,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
/// Words this number of bits needs (1 bit=1 word)
|
||||
#define VL_WORDS_I(nbits) (((nbits)+(VL_WORDSIZE-1))/VL_WORDSIZE)
|
||||
|
||||
//=========================================================================
|
||||
// Class definition helpers
|
||||
|
||||
// Used to declare a class as uncopyable; put after a private:
|
||||
#define VL_UNCOPYABLE(Type) \
|
||||
Type(const Type& other) VL_EQ_DELETE; \
|
||||
Type& operator= (const Type&) VL_EQ_DELETE
|
||||
|
||||
//=========================================================================
|
||||
// Verilated function size macros
|
||||
|
||||
|
||||
@@ -105,10 +105,12 @@ typedef unsigned char PLI_UBYTE8;
|
||||
|
||||
/* object is defined imported by the application */
|
||||
|
||||
#undef XXTERN
|
||||
#define XXTERN PLI_EXTERN PLI_DLLISPEC
|
||||
|
||||
/* object is exported by the application */
|
||||
|
||||
#undef EETERN
|
||||
#define EETERN PLI_EXTERN PLI_DLLESPEC
|
||||
#endif
|
||||
|
||||
|
||||
+8
-8
@@ -237,10 +237,10 @@ implementation is not found, the system will look in turn for overloaded
|
||||
implementations up the inheritance hierarchy. For example calling C<accept>
|
||||
on C<AstIf> will look in turn for:
|
||||
|
||||
void visit (AstIf* nodep, AstNUser* vup)
|
||||
void visit (AstNodeIf* nodep, AstNUser* vup)
|
||||
void visit (AstNodeStmt* nodep, AstNUser* vup)
|
||||
void visit (AstNode* nodep, AstNUser* vup)
|
||||
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.
|
||||
|
||||
@@ -485,10 +485,10 @@ be warning free.
|
||||
|
||||
=item --enable-longtests
|
||||
|
||||
In addition to the standard C, SystemC tests also run the tests in the
|
||||
C<test_verilated> and C<test_regress> directories when using I<make test>.
|
||||
This is disabled by default as SystemC installation problems would
|
||||
otherwise falsely indicate a Verilator problem.
|
||||
In addition to the standard C, SystemC examples, also run the tests in the
|
||||
C<test_regress> directory when using I<make test>. This is disabled by
|
||||
default as SystemC installation problems would otherwise falsely indicate a
|
||||
Verilator problem.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
+7
-7
@@ -48,25 +48,25 @@ obj_dbg:
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
.PHONY: ../verilator_bin ../verilator_bin_dbg ../verilator_coverage_bin_dbg
|
||||
.PHONY: ../bin/verilator_bin ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
|
||||
|
||||
opt: ../verilator_bin
|
||||
opt: ../bin/verilator_bin
|
||||
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
|
||||
../verilator_bin: ../verilator_bin_dbg
|
||||
../bin/verilator_bin: ../bin/verilator_bin_dbg
|
||||
-rm -rf $@ $@.exe
|
||||
-cp -p $<$(EXEEXT) $@$(EXEEXT)
|
||||
else
|
||||
../verilator_bin: obj_opt prefiles
|
||||
../bin/verilator_bin: obj_opt prefiles
|
||||
cd obj_opt && $(MAKE) -j 1 TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj
|
||||
endif
|
||||
|
||||
dbg: ../verilator_bin_dbg ../verilator_coverage_bin_dbg
|
||||
../verilator_bin_dbg: obj_dbg prefiles
|
||||
dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
|
||||
../bin/verilator_bin_dbg: obj_dbg prefiles
|
||||
cd obj_dbg && $(MAKE) -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
|
||||
|
||||
../verilator_coverage_bin_dbg: obj_dbg prefiles
|
||||
../bin/verilator_coverage_bin_dbg: obj_dbg prefiles
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
|
||||
else
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_SRC)
|
||||
endif
|
||||
|
||||
CPPFLAGSWALL = $(CPPFLAGS)
|
||||
CPPFLAGSPARSER = $(CPPFLAGS) $(CFG_CXXFLAGS_PARSER)
|
||||
|
||||
|
||||
+7
-1
@@ -67,7 +67,7 @@ private:
|
||||
timesp->unlinkFrBackWithNext();
|
||||
timenewp->addNext(timesp);
|
||||
}
|
||||
nodep->fmtp()->exprsp(timenewp);
|
||||
nodep->fmtp()->addExprsp(timenewp);
|
||||
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
|
||||
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
@@ -202,6 +202,9 @@ private:
|
||||
AstNode *newifp = nodep->cloneTree(false);
|
||||
bool allow_none = nodep->unique0Pragma();
|
||||
|
||||
// Empty case means no property
|
||||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
|
||||
|
||||
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
||||
// predicates evaluates to true.
|
||||
AstNode* ohot = ((allow_none || hasDefaultElse)
|
||||
@@ -259,6 +262,9 @@ private:
|
||||
else propp = onep;
|
||||
}
|
||||
}
|
||||
// Empty case means no property
|
||||
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
|
||||
|
||||
bool allow_none = has_default || nodep->unique0Pragma();
|
||||
AstNode* ohot = (allow_none
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
|
||||
+2
-2
@@ -979,7 +979,7 @@ void AstNode::dumpTreeGdb() { // For GDB only
|
||||
dumpTree(cout);
|
||||
}
|
||||
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only
|
||||
string filename = filenamep ? filenamep : v3Global.debugFilename("debug",98);
|
||||
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree",98);
|
||||
v3Global.rootp()->dumpTreeFile(filename);
|
||||
}
|
||||
|
||||
@@ -1037,7 +1037,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
if (doDump) {
|
||||
{ // Write log & close
|
||||
UINFO(2,"Dumping "<<filename<<endl);
|
||||
const VL_UNIQUE_PTR<ofstream> logsp (V3File::new_ofstream(filename, append));
|
||||
const vl_unique_ptr<ofstream> logsp (V3File::new_ofstream(filename, append));
|
||||
if (logsp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
*logsp<<"Verilator Tree Dump (format 0x3900) from <e"<<dec<<editCountLast()<<">";
|
||||
*logsp<<" to <e"<<dec<<editCountGbl()<<">"<<endl;
|
||||
|
||||
+79
-39
@@ -82,7 +82,7 @@ public:
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"UNSIGNED","SIGNED","NOSIGN"
|
||||
};
|
||||
return names[m_e];
|
||||
@@ -203,19 +203,42 @@ public:
|
||||
return AstEdgeType::ET_ILLEGAL;
|
||||
}
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"%E-edge", "ANY", "BOTH", "POS", "NEG", "HIGH", "LOW",
|
||||
"COMBO","INITIAL","SETTLE","NEVER"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
const char* verilogKwd() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"%E-edge", "[any]", "edge", "posedge", "negedge", "[high]","[low]",
|
||||
"*","[initial]","[settle]","[never]"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
}
|
||||
// Return true iff this and the other have mutually exclusive transitions
|
||||
bool exclusiveEdge(const AstEdgeType& other) const {
|
||||
switch (m_e) {
|
||||
case AstEdgeType::ET_POSEDGE:
|
||||
switch (other.m_e) {
|
||||
case AstEdgeType::ET_NEGEDGE: // FALLTHRU
|
||||
case AstEdgeType::ET_LOWEDGE:
|
||||
return true;
|
||||
default: {}
|
||||
}
|
||||
break;
|
||||
case AstEdgeType::ET_NEGEDGE:
|
||||
switch (other.m_e) {
|
||||
case AstEdgeType::ET_POSEDGE: // FALLTHRU
|
||||
case AstEdgeType::ET_HIGHEDGE:
|
||||
return true;
|
||||
default: {}
|
||||
}
|
||||
break;
|
||||
default: {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline AstEdgeType () : m_e(ET_ILLEGAL) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline AstEdgeType (en _e) : m_e(_e) {}
|
||||
@@ -270,7 +293,7 @@ public:
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"%E-AT",
|
||||
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
|
||||
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
|
||||
@@ -315,7 +338,7 @@ public:
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"%E-unk",
|
||||
"bit", "byte", "chandle", "int", "integer", "logic", "longint",
|
||||
"real", "shortint", "shortreal", "time",
|
||||
@@ -328,7 +351,7 @@ public:
|
||||
return names[m_e];
|
||||
};
|
||||
const char* dpiType() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"%E-unk",
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "short int", "float", "long long",
|
||||
@@ -340,7 +363,7 @@ public:
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
static void test() {
|
||||
static void selfTest() {
|
||||
UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).ascii()," MAX"),"Enum array mismatch");
|
||||
UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).dpiType()," MAX"),"Enum array mismatch");
|
||||
}
|
||||
@@ -446,7 +469,7 @@ public:
|
||||
explicit inline AstVarType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"?","GPARAM","LPARAM","GENVAR",
|
||||
"VAR","INPUT","OUTPUT","INOUT",
|
||||
"SUPPLY0","SUPPLY1","WIRE","WREAL","IMPLICITWIRE",
|
||||
@@ -489,7 +512,7 @@ public:
|
||||
else return m_e;
|
||||
}
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"","VL_LIKELY","VL_UNLIKELY"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
@@ -522,7 +545,7 @@ public:
|
||||
else return m_e;
|
||||
}
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"","clker","non_clker"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
@@ -548,7 +571,7 @@ public:
|
||||
explicit inline VAlwaysKwd (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"always","always_ff","always_latch","always_comb"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
@@ -598,7 +621,7 @@ public:
|
||||
bool addNewline() const { return m_e!=DT_WRITE; }
|
||||
bool needScopeTracking() const { return m_e!=DT_DISPLAY && m_e!=DT_WRITE; }
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"display","write","info","error","warning","fatal"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
@@ -621,7 +644,7 @@ public:
|
||||
explicit inline AstParseRefExp (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
static const char* const names[] = {
|
||||
"","TEXT","PREDOT"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
@@ -658,10 +681,14 @@ struct VNumRange {
|
||||
return false;
|
||||
}
|
||||
//
|
||||
class LeftRight {};
|
||||
VNumRange() : m_hi(0), m_lo(0), mu_flags(0) {}
|
||||
VNumRange(int hi, int lo, bool littleEndian)
|
||||
: m_hi(0), m_lo(0), mu_flags(0)
|
||||
{ init(hi,lo,littleEndian); }
|
||||
VNumRange(LeftRight, int left, int right)
|
||||
: m_hi(0), m_lo(0), mu_flags(0)
|
||||
{ init((right>left)?right:left, (right>left)?left:right, (right>left)); }
|
||||
~VNumRange() {}
|
||||
// MEMBERS
|
||||
void init(int hi, int lo, bool littleEndian) {
|
||||
@@ -734,6 +761,7 @@ class VNUser {
|
||||
public:
|
||||
VNUser() {}
|
||||
// non-explicit:
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VNUser(int i) { m_u.up = 0; m_u.ui = i; }
|
||||
explicit VNUser(void* p) { m_u.up = p; }
|
||||
~VNUser() {}
|
||||
@@ -918,7 +946,7 @@ public:
|
||||
inline bool operator== (const V3Hash& rh) const { return m_both==rh.m_both; }
|
||||
inline bool operator!= (const V3Hash& rh) const { return m_both!=rh.m_both; }
|
||||
inline bool operator< (const V3Hash& rh) const { return m_both<rh.m_both; }
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
class Illegal {}; // for creator type-overload selection
|
||||
class FullValue {}; // for creator type-overload selection
|
||||
explicit V3Hash(Illegal) { m_both=0; }
|
||||
@@ -1087,6 +1115,8 @@ public:
|
||||
// ACCESSORS
|
||||
virtual string name() const { return ""; }
|
||||
virtual void name(const string& name) { this->v3fatalSrc("name() called on object without name() method"); }
|
||||
virtual void tag(const string& text) {}
|
||||
virtual string tag() const { return ""; }
|
||||
virtual string verilogKwd() const { return ""; }
|
||||
string shortName() const; // Name with __PVT__ removed for concatenating scopes
|
||||
static string dedotName(const string& namein); // Name with dots removed
|
||||
@@ -1258,7 +1288,7 @@ public:
|
||||
|
||||
// METHODS - Iterate on a tree
|
||||
AstNode* cloneTree(bool cloneNextLink);
|
||||
bool gateTree() { return gateTreeIter(); } // Is tree gateOptimizable?
|
||||
bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable?
|
||||
bool sameTree(AstNode* node2p); // Does tree of this == node2p?
|
||||
bool sameGateTree(AstNode* node2p); // Does tree of this == node2p?, not allowing non-isGateOptimizable
|
||||
void deleteTree(); // Always deletes the next link
|
||||
@@ -1284,7 +1314,7 @@ public:
|
||||
virtual bool isUnlikely() const { return false; } // Else $stop or similar statement which means an above IF statement is unlikely to be taken
|
||||
virtual int instrCount() const { return 0; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash::Illegal()); } // Not a node that supports it
|
||||
virtual bool same(AstNode* otherp) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
virtual bool hasDType() const { return false; } // Iff has a data type; dtype() must be non null
|
||||
virtual AstNodeDType* getChildDTypep() const { return NULL; } // Iff has a non-null childDTypep(), as generic node function
|
||||
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
|
||||
@@ -1366,7 +1396,7 @@ public:
|
||||
virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors?
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeBiop : public AstNodeMath {
|
||||
@@ -1393,7 +1423,7 @@ public:
|
||||
virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors?
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeTriop : public AstNodeMath {
|
||||
@@ -1419,7 +1449,7 @@ public:
|
||||
virtual bool sizeMattersThs() = 0; // True if output result depends on ths size
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeBiCom : public AstNodeBiop {
|
||||
@@ -1458,6 +1488,7 @@ public:
|
||||
virtual bool sizeMattersLhs() { return false; } virtual bool sizeMattersRhs() { return false; }
|
||||
virtual bool sizeMattersThs() { return false; }
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0;
|
||||
};
|
||||
|
||||
class AstNodePreSel : public AstNode {
|
||||
@@ -1478,7 +1509,7 @@ public:
|
||||
void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); }
|
||||
// METHODS
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeStmt : public AstNode {
|
||||
@@ -1510,7 +1541,7 @@ public:
|
||||
virtual bool cleanRhs() { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
virtual string verilogKwd() const { return "="; }
|
||||
virtual bool brokeLhsMustBeLvalue() const = 0;
|
||||
};
|
||||
@@ -1530,7 +1561,7 @@ public:
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeIf : public AstNodeStmt {
|
||||
@@ -1552,7 +1583,7 @@ public:
|
||||
virtual bool isGateDedupable() const { return true; }
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
void branchPred(AstBranchPred flag) { m_branchPred = flag; }
|
||||
AstBranchPred branchPred() const { return m_branchPred; }
|
||||
};
|
||||
@@ -1644,8 +1675,9 @@ public:
|
||||
ASTNODE_BASE_FUNCS(NodeText)
|
||||
virtual void dump(ostream& str=cout);
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castNodeText()->text(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstNodeText* asamep = static_cast<const AstNodeText*>(samep);
|
||||
return text() == asamep->text(); }
|
||||
const string& text() const { return m_text; }
|
||||
};
|
||||
|
||||
@@ -1680,6 +1712,7 @@ public:
|
||||
virtual AstNodeDType* virtRefDTypep() const { return NULL; } // Iff has a non-null refDTypep(), as generic node function
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { } // Iff has refDTypep(), set as generic node function
|
||||
virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
virtual AstNodeDType* subDTypep() const { return NULL; } // Iff has a non-null subDTypep(), as generic node function
|
||||
//
|
||||
// Changing the width may confuse the data type resolution, so must clear TypeTable cache after use.
|
||||
void widthForce(int width, int sized) { m_width=width; m_widthMin=sized; }
|
||||
@@ -1766,24 +1799,24 @@ public:
|
||||
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
|
||||
m_refDTypep = m_refDTypep->clonep();
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const {
|
||||
AstNodeArrayDType* sp = samep->castNodeArrayDType();
|
||||
return (msb()==sp->msb()
|
||||
&& subDTypep()==sp->subDTypep()
|
||||
&& rangenp()->sameTree(sp->rangenp())); } // HashedDT doesn't recurse, so need to check children
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return (msb()==asamep->msb()
|
||||
&& subDTypep()==asamep->subDTypep()
|
||||
&& rangenp()->sameTree(asamep->rangenp())); } // HashedDT doesn't recurse, so need to check children
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
AstNodeArrayDType* sp = samep->castNodeArrayDType();
|
||||
return (sp
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return (asamep
|
||||
&& type() == samep->type()
|
||||
&& msb() == sp->msb()
|
||||
&& rangenp()->sameTree(sp->rangenp())
|
||||
&& subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()));
|
||||
&& msb() == asamep->msb()
|
||||
&& rangenp()->sameTree(asamep->rangenp())
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
@@ -1948,6 +1981,8 @@ private:
|
||||
bool m_inLibrary:1; // From a library, no error if not used, never top level
|
||||
bool m_dead:1; // LinkDot believes is dead; will remove in Dead visitors
|
||||
bool m_internal:1; // Internally created
|
||||
bool m_recursive:1; // Recursive module
|
||||
bool m_recursiveClone:1; // If recursive, what module it clones, otherwise NULL
|
||||
int m_level; // 1=top module, 2=cell off top module, ...
|
||||
int m_varNum; // Incrementing variable number
|
||||
int m_typeNum; // Incrementing implicit type number
|
||||
@@ -1955,7 +1990,8 @@ public:
|
||||
AstNodeModule(FileLine* fl, const string& name)
|
||||
: AstNode (fl)
|
||||
,m_name(name), m_origName(name)
|
||||
,m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false), m_internal(false)
|
||||
,m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false)
|
||||
,m_internal(false), m_recursive(false), m_recursiveClone(false)
|
||||
,m_level(0), m_varNum(0), m_typeNum(0) { }
|
||||
ASTNODE_BASE_FUNCS(NodeModule)
|
||||
virtual void dump(ostream& str);
|
||||
@@ -1985,6 +2021,10 @@ public:
|
||||
bool dead() const { return m_dead; }
|
||||
void internal(bool flag) { m_internal = flag; }
|
||||
bool internal() const { return m_internal; }
|
||||
void recursive(bool flag) { m_recursive = flag; }
|
||||
bool recursive() const { return m_recursive; }
|
||||
void recursiveClone(bool flag) { m_recursiveClone = flag; }
|
||||
bool recursiveClone() const { return m_recursiveClone; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+15
-9
@@ -26,6 +26,7 @@
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3File.h"
|
||||
@@ -69,7 +70,7 @@ void AstNodeClassDType::repairMemberCache() {
|
||||
}
|
||||
|
||||
const char* AstNodeClassDType::broken() const {
|
||||
set<AstMemberDType*> exists;
|
||||
vl_unordered_set<AstMemberDType*> exists;
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
|
||||
exists.insert(itemp);
|
||||
}
|
||||
@@ -548,28 +549,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
||||
return out;
|
||||
}
|
||||
|
||||
bool AstSenTree::hasClocked() {
|
||||
bool AstSenTree::hasClocked() const {
|
||||
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp=senp->nextp()->castNodeSenItem()) {
|
||||
if (senp->isClocked()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasSettle() {
|
||||
bool AstSenTree::hasSettle() const {
|
||||
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp=senp->nextp()->castNodeSenItem()) {
|
||||
if (senp->isSettle()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasInitial() {
|
||||
bool AstSenTree::hasInitial() const {
|
||||
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp=senp->nextp()->castNodeSenItem()) {
|
||||
if (senp->isInitial()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AstSenTree::hasCombo() {
|
||||
bool AstSenTree::hasCombo() const {
|
||||
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
|
||||
for (AstNodeSenItem* senp = sensesp(); senp; senp=senp->nextp()->castNodeSenItem()) {
|
||||
if (senp->isCombo()) return true;
|
||||
@@ -763,10 +764,6 @@ void AstAlways::dump(ostream& str) {
|
||||
if (keyword() != VAlwaysKwd::ALWAYS) str<<" ["<<keyword().ascii()<<"]";
|
||||
}
|
||||
|
||||
void AstArraySel::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
|
||||
}
|
||||
void AstAttrOf::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" ["<<attrType().ascii()<<"]";
|
||||
@@ -782,6 +779,7 @@ void AstCCast::dump(ostream& str) {
|
||||
}
|
||||
void AstCell::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (recursive()) str<<" [RECURSIVE]";
|
||||
if (modp()) { str<<" -> "; modp()->dump(str); }
|
||||
else { str<<" ->UNLINKED:"<<modName(); }
|
||||
}
|
||||
@@ -890,6 +888,8 @@ void AstNodeModule::dump(ostream& str) {
|
||||
if (modPublic()) str<<" [P]";
|
||||
if (inLibrary()) str<<" [LIB]";
|
||||
if (dead()) str<<" [DEAD]";
|
||||
if (recursiveClone()) str<<" [RECURSIVE-CLONE]";
|
||||
else if (recursive()) str<<" [RECURSIVE]";
|
||||
}
|
||||
void AstPackageExport::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
@@ -906,6 +906,12 @@ void AstSel::dump(ostream& str) {
|
||||
if (declElWidth()!=1) str<<"/"<<declElWidth();
|
||||
}
|
||||
}
|
||||
void AstSliceSel::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (declRange().ranged()) {
|
||||
str<<" decl"<<declRange();
|
||||
}
|
||||
}
|
||||
void AstTypeTable::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
for (int i=0; i<(int)(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
|
||||
|
||||
+198
-129
@@ -100,8 +100,9 @@ public:
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(num().toHash()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return num().isCaseEq(samep->castConst()->num()); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstConst* sp = static_cast<const AstConst*>(samep);
|
||||
return num().isCaseEq(sp->num()); }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
bool isEqAllOnes() const { return num().isEqAllOnes(width()); }
|
||||
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); }
|
||||
@@ -142,7 +143,7 @@ public:
|
||||
virtual void dump(ostream& str);
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstGatePin : public AstNodeMath {
|
||||
@@ -178,7 +179,7 @@ public:
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
|
||||
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
|
||||
@@ -203,6 +204,7 @@ class AstTypedef : public AstNode {
|
||||
private:
|
||||
string m_name;
|
||||
bool m_attrPublic;
|
||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||
public:
|
||||
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, AstNodeDType* dtp)
|
||||
: AstNode(fl), m_name(name) {
|
||||
@@ -216,7 +218,7 @@ public:
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse
|
||||
// METHODS
|
||||
@@ -226,6 +228,8 @@ public:
|
||||
void name(const string& flag) { m_name = flag; }
|
||||
bool attrPublic() const { return m_attrPublic; }
|
||||
void attrPublic(bool flag) { m_attrPublic = flag; }
|
||||
virtual void tag(const string& text) { m_tag = text;}
|
||||
virtual string tag() const { return m_tag; }
|
||||
};
|
||||
|
||||
class AstTypedefFwd : public AstNode {
|
||||
@@ -257,14 +261,16 @@ public:
|
||||
m_uniqueNum = uniqueNumInc();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(DefImplicitDType)
|
||||
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castDefImplicitDType()->m_uniqueNum; }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstDefImplicitDType* sp = static_cast<const AstDefImplicitDType*>(samep);
|
||||
return m_uniqueNum == sp->m_uniqueNum; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return type()==samep->type() && same(samep); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
void* containerp() const { return m_containerp; }
|
||||
// METHODS
|
||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
|
||||
@@ -399,8 +405,9 @@ public:
|
||||
ASTNODE_NODE_FUNCS(BasicDType)
|
||||
virtual void dump(ostream& str);
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); }
|
||||
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
|
||||
return samep->castBasicDType()->m == m; }
|
||||
virtual bool same(const AstNode* samep) const { // width/widthMin/numeric compared elsewhere
|
||||
const AstBasicDType* sp = static_cast<const AstBasicDType*>(samep);
|
||||
return m == sp->m; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return type()==samep->type() && same(samep); }
|
||||
virtual string name() const { return m.m_keyword.ascii(); }
|
||||
@@ -465,15 +472,16 @@ public:
|
||||
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
|
||||
m_refDTypep = m_refDTypep->clonep();
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (m_refDTypep==samep->castConstDType()->m_refDTypep); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstConstDType* sp = static_cast<const AstConstDType*>(samep);
|
||||
return (m_refDTypep == sp->m_refDTypep); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return skipRefp()->similarDType(samep->skipRefp()); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } // node's type() included elsewhere
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable
|
||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
@@ -550,10 +558,11 @@ public:
|
||||
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
|
||||
m_refDTypep = m_refDTypep->clonep();
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (m_refDTypep==samep->castRefDType()->m_refDTypep
|
||||
&& m_name==samep->castRefDType()->m_name
|
||||
&& m_packagep==samep->castRefDType()->m_packagep); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstRefDType* asamep = static_cast<const AstRefDType*>(samep);
|
||||
return (m_refDTypep == asamep->m_refDTypep
|
||||
&& m_name == asamep->m_name
|
||||
&& m_packagep == asamep->m_packagep); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return skipRefp()->similarDType(samep->skipRefp()); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(m_packagep)); }
|
||||
@@ -582,7 +591,7 @@ public:
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep=nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
AstNodeDType* subDTypep() const { return m_refDTypep; }
|
||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
||||
};
|
||||
@@ -610,6 +619,7 @@ class AstMemberDType : public AstNodeDType {
|
||||
private:
|
||||
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
|
||||
string m_name; // Name of variable
|
||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||
int m_lsb; // Within this level's packed struct, the LSB of the first bit of the member
|
||||
//UNSUP: int m_randType; // Randomization type (IEEE)
|
||||
public:
|
||||
@@ -635,7 +645,7 @@ public:
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
@@ -650,6 +660,8 @@ public:
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
// METHODS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual void tag(const string& text) { m_tag = text;}
|
||||
virtual string tag() const { return m_tag; }
|
||||
int lsb() const { return m_lsb; }
|
||||
void lsb(int lsb) { m_lsb=lsb; }
|
||||
};
|
||||
@@ -688,8 +700,9 @@ public:
|
||||
virtual const char* broken() const { BROKEN_RTN(!itemp()); return NULL; }
|
||||
virtual int instrCount() const { return 0; }
|
||||
virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return itemp()==samep->castEnumItemRef()->itemp(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstEnumItemRef* sp = static_cast<const AstEnumItemRef*>(samep);
|
||||
return itemp() == sp->itemp(); }
|
||||
AstEnumItem* itemp() const { return m_itemp; }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
@@ -720,13 +733,15 @@ public:
|
||||
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
|
||||
m_refDTypep = m_refDTypep->clonep();
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castEnumDType()->m_uniqueNum; }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstEnumDType* sp = static_cast<const AstEnumDType*>(samep);
|
||||
return m_uniqueNum == sp->m_uniqueNum; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Data type
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable
|
||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
@@ -766,8 +781,6 @@ class AstArraySel : public AstNodeSel {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
private:
|
||||
unsigned m_start;
|
||||
unsigned m_length;
|
||||
void init(AstNode* fromp) {
|
||||
if (fromp && fromp->dtypep()->skipRefp()->castNodeArrayDType()) {
|
||||
// Strip off array to find what array references
|
||||
@@ -776,11 +789,11 @@ private:
|
||||
}
|
||||
public:
|
||||
AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
:AstNodeSel(fl, fromp, bitp), m_start(0), m_length(1) {
|
||||
:AstNodeSel(fl, fromp, bitp) {
|
||||
init(fromp);
|
||||
}
|
||||
AstArraySel(FileLine* fl, AstNode* fromp, int bit)
|
||||
:AstNodeSel(fl, fromp, new AstConst(fl,bit)), m_start(0), m_length(1) {
|
||||
:AstNodeSel(fl, fromp, new AstConst(fl,bit)) {
|
||||
init(fromp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ArraySel)
|
||||
@@ -792,18 +805,13 @@ public:
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isGateOptimizable() const { return true; } // esp for V3Const::ifSameAssign
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
unsigned length() const { return m_length; }
|
||||
void length(unsigned length) { m_length = length; }
|
||||
void start(unsigned start) { m_start = start; }
|
||||
unsigned start() const { return m_start; }
|
||||
// Special operators
|
||||
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
|
||||
virtual void dump(ostream& str);
|
||||
};
|
||||
|
||||
class AstWordSel : public AstNodeSel {
|
||||
@@ -822,7 +830,7 @@ public:
|
||||
virtual bool cleanLhs() { return true; } virtual bool cleanRhs() { return true; }
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstSelExtract : public AstNodePreSel {
|
||||
@@ -909,7 +917,7 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual bool sizeMattersThs() {return false;}
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs()*(lsbp()->castConst()?3:10); }
|
||||
AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
AstNode* lsbp() const { return op2p(); } // op2 = Msb selection expression
|
||||
@@ -923,6 +931,40 @@ public:
|
||||
void declElWidth(int flag) { m_declElWidth = flag; }
|
||||
};
|
||||
|
||||
class AstSliceSel : public AstNodeTriop {
|
||||
// Multiple array element extraction
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math, constant math
|
||||
private:
|
||||
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
|
||||
public:
|
||||
AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange)
|
||||
: AstNodeTriop(fl, fromp,
|
||||
new AstConst(fl, declRange.lo()),
|
||||
new AstConst(fl, declRange.elements()))
|
||||
, m_declRange(declRange) { }
|
||||
ASTNODE_NODE_FUNCS(SliceSel)
|
||||
virtual void dump(ostream& str);
|
||||
virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, const V3Number& width) {
|
||||
V3ERROR_NA; }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; } // Removed before EmitC
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual bool cleanLhs() { return false; }
|
||||
virtual bool cleanRhs() { return true; }
|
||||
virtual bool cleanThs() { return true; }
|
||||
virtual bool sizeMattersLhs() { return false; }
|
||||
virtual bool sizeMattersRhs() { return false; }
|
||||
virtual bool sizeMattersThs() { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
virtual int instrCount() const { return 10; } // Removed before matters
|
||||
AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
// For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods
|
||||
VNumRange& declRange() { return m_declRange; }
|
||||
void declRange(const VNumRange& flag) { m_declRange = flag; }
|
||||
};
|
||||
|
||||
class AstMemberSel : public AstNodeMath {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
@@ -948,7 +990,7 @@ public:
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual bool same(AstNode* samep) const { return true; } // dtype comparison does it all for us
|
||||
virtual bool same(const AstNode* samep) const { return true; } // dtype comparison does it all for us
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
@@ -985,6 +1027,7 @@ class AstVar : public AstNode {
|
||||
private:
|
||||
string m_name; // Name of variable
|
||||
string m_origName; // Original name before dot addition
|
||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||
AstVarType m_varType; // Type of variable
|
||||
bool m_input:1; // Input or inout
|
||||
bool m_output:1; // Output or inout
|
||||
@@ -1097,7 +1140,7 @@ public:
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
void attrClockEn(bool flag) { m_attrClockEn = flag; }
|
||||
void attrClocker(AstVarAttrClocker flag) { m_attrClocker = flag; }
|
||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||
@@ -1125,6 +1168,8 @@ public:
|
||||
void trace(bool flag) { m_trace=flag; }
|
||||
// METHODS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual void tag(const string& text) { m_tag = text;}
|
||||
virtual string tag() const { return m_tag; }
|
||||
virtual string directionName() const { return (isInout() ? "inout" : isInput() ? "input"
|
||||
: isOutput() ? "output" : varType().ascii()); }
|
||||
bool isInput() const { return m_input; }
|
||||
@@ -1228,7 +1273,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(DefParam)
|
||||
virtual bool cleanRhs() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
AstNode* rhsp() const { return op1p(); } // op1 = Assign from
|
||||
string path() const { return m_path; }
|
||||
};
|
||||
@@ -1349,8 +1394,9 @@ public:
|
||||
ASTNODE_NODE_FUNCS(VarRef)
|
||||
virtual void dump(ostream& str);
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()->name()),V3Hash(hiername())); }
|
||||
virtual bool same(AstNode* samep) const { return same(samep->castVarRef()); }
|
||||
inline bool same(AstVarRef* samep) const {
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return same(static_cast<const AstVarRef*>(samep)); }
|
||||
inline bool same(const AstVarRef* samep) const {
|
||||
if (varScopep()) return (varScopep()==samep->varScopep()
|
||||
&& lvalue()==samep->lvalue());
|
||||
else return (hiername()==samep->hiername()
|
||||
@@ -1393,11 +1439,12 @@ public:
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()),V3Hash(dotted())); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (hiername()==samep->castVarXRef()->hiername()
|
||||
&& varp()==samep->castVarXRef()->varp()
|
||||
&& name()==samep->castVarXRef()->name()
|
||||
&& dotted()==samep->castVarXRef()->dotted()); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstVarXRef* asamep = static_cast<const AstVarXRef*>(samep);
|
||||
return (hiername() == asamep->hiername()
|
||||
&& varp() == asamep->varp()
|
||||
&& name() == asamep->name()
|
||||
&& dotted() == asamep->dotted()); }
|
||||
};
|
||||
|
||||
class AstPin : public AstNode {
|
||||
@@ -1511,6 +1558,7 @@ public:
|
||||
class AstPackageExportStarStar : public AstNode {
|
||||
// A package export *::* declaration
|
||||
public:
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
AstPackageExportStarStar(FileLine* fl)
|
||||
: AstNode (fl) {}
|
||||
ASTNODE_NODE_FUNCS(PackageExportStarStar)
|
||||
@@ -1625,13 +1673,14 @@ private:
|
||||
string m_modName; // Module the cell instances
|
||||
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
|
||||
bool m_hasIfaceVar:1; // True if a Var has been created for this cell
|
||||
bool m_recursive:1; // Self-recursive module
|
||||
bool m_trace:1; // Trace this cell
|
||||
public:
|
||||
AstCell(FileLine* fl, const string& instName, const string& modName,
|
||||
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
|
||||
: AstNode(fl)
|
||||
, m_name(instName), m_origName(instName), m_modName(modName)
|
||||
, m_modp(NULL), m_hasIfaceVar(false), m_trace(true) {
|
||||
, m_modp(NULL), m_hasIfaceVar(false), m_recursive(false), m_trace(true) {
|
||||
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
|
||||
ASTNODE_NODE_FUNCS(Cell)
|
||||
// No cloneRelink, we presume cloneee's want the same module linkages
|
||||
@@ -1656,6 +1705,8 @@ public:
|
||||
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
|
||||
void trace(bool flag) { m_trace=flag; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
void recursive(bool flag) { m_recursive = flag; }
|
||||
bool recursive() const { return m_recursive; }
|
||||
};
|
||||
|
||||
class AstCellInline : public AstNode {
|
||||
@@ -1794,9 +1845,10 @@ public:
|
||||
virtual void dump(ostream& str);
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_expect),V3Hash(m_name)); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (expect() == samep->castParseRef()->expect()
|
||||
&& m_name==samep->castParseRef()->m_name); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstParseRef* asamep = static_cast<const AstParseRef*>(samep);
|
||||
return (expect() == asamep->expect()
|
||||
&& m_name == asamep->m_name); }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
@@ -1820,8 +1872,8 @@ public:
|
||||
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) {
|
||||
m_packagep = m_packagep->clonep();
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (m_packagep==samep->castPackageRef()->m_packagep); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return (m_packagep==static_cast<const AstPackageRef*>(samep)->m_packagep); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_packagep); }
|
||||
virtual void dump(ostream& str=cout);
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
@@ -1945,8 +1997,8 @@ public:
|
||||
ASTNODE_NODE_FUNCS(SenItem)
|
||||
virtual void dump(ostream& str);
|
||||
virtual V3Hash sameHash() const { return V3Hash(edgeType()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return edgeType()==samep->castSenItem()->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
|
||||
AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized
|
||||
@@ -2003,10 +2055,10 @@ public:
|
||||
void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); }
|
||||
void multi(bool flag) { m_multi = true; }
|
||||
// METHODS
|
||||
bool hasClocked(); // Includes a clocked statement
|
||||
bool hasSettle(); // Includes a SETTLE SenItem
|
||||
bool hasInitial(); // Includes a INITIAL SenItem
|
||||
bool hasCombo(); // Includes a COMBO SenItem
|
||||
bool hasClocked() const; // Includes a clocked statement
|
||||
bool hasSettle() const; // Includes a SETTLE SenItem
|
||||
bool hasInitial() const; // Includes a INITIAL SenItem
|
||||
bool hasCombo() const; // Includes a COMBO SenItem
|
||||
};
|
||||
|
||||
class AstAlways : public AstNode {
|
||||
@@ -2037,7 +2089,7 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(AlwaysPublic)
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
//
|
||||
AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list
|
||||
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
|
||||
@@ -2132,8 +2184,8 @@ public:
|
||||
m_direction = direction;
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Pull)
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return direction()==samep->castPull()->direction(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return direction()==static_cast<const AstPull*>(samep)->direction(); }
|
||||
void lhsp(AstNode* np) { setOp1p(np); }
|
||||
AstNode* lhsp() const { return op1p(); } // op1 = Assign to
|
||||
uint32_t direction() const { return (uint32_t) m_direction; }
|
||||
@@ -2172,7 +2224,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(Comment)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual V3Hash sameHash() const { return V3Hash(); } // Ignore name in comments
|
||||
virtual bool same(AstNode* samep) const { return true; } // Ignore name in comments
|
||||
virtual bool same(const AstNode* samep) const { return true; } // Ignore name in comments
|
||||
};
|
||||
|
||||
class AstCond : public AstNodeCond {
|
||||
@@ -2183,6 +2235,8 @@ public:
|
||||
AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
|
||||
: AstNodeCond(fl, condp, expr1p, expr2p) {}
|
||||
ASTNODE_NODE_FUNCS(Cond)
|
||||
virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) {
|
||||
return new AstCond(this->fileline(), condp, expr1p, expr2p); }
|
||||
};
|
||||
|
||||
class AstCondBound : public AstNodeCond {
|
||||
@@ -2193,6 +2247,8 @@ public:
|
||||
AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
|
||||
: AstNodeCond(fl, condp, expr1p, expr2p) {}
|
||||
ASTNODE_NODE_FUNCS(CondBound)
|
||||
virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) {
|
||||
return new AstCondBound(this->fileline(), condp, expr1p, expr2p); }
|
||||
};
|
||||
|
||||
class AstCoverDecl : public AstNodeStmt {
|
||||
@@ -2231,11 +2287,12 @@ public:
|
||||
void hier(const string& flag) { m_hier=flag; }
|
||||
void comment(const string& flag) { m_text=flag; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (fileline() == samep->castCoverDecl()->fileline()
|
||||
&& hier()==samep->castCoverDecl()->hier()
|
||||
&& comment()==samep->castCoverDecl()->comment()
|
||||
&& column()==samep->castCoverDecl()->column()); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstCoverDecl* asamep = static_cast<const AstCoverDecl*>(samep);
|
||||
return (fileline() == asamep->fileline()
|
||||
&& hier() == asamep->hier()
|
||||
&& comment() == asamep->comment()
|
||||
&& column() == asamep->column()); }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp=nodep; }
|
||||
// dataDecl NULL means "use this one", but often you want "this" to indicate to get data from here
|
||||
@@ -2260,8 +2317,8 @@ public:
|
||||
virtual void dump(ostream& str);
|
||||
virtual int instrCount() const { return 1+2*instrCountLd(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(declp()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return declp()==samep->castCoverInc()->declp(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return declp() == static_cast<const AstCoverInc*>(samep)->declp(); }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isOutputter() const { return true; }
|
||||
@@ -2283,7 +2340,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(CoverToggle)
|
||||
virtual int instrCount() const { return 3+instrCountBranch()+instrCountLd(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return true; }
|
||||
virtual bool isOutputter() const { return false; } // Though the AstCoverInc under this is an outputter
|
||||
@@ -2327,8 +2384,8 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Case)
|
||||
virtual string verilogKwd() const { return casez()?"casez":casex()?"casex":"case"; }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return m_casex==samep->castCase()->m_casex; }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return m_casex==static_cast<const AstCase*>(samep)->m_casex; }
|
||||
bool casex() const { return m_casex==VCaseType::CT_CASEX; }
|
||||
bool casez() const { return m_casex==VCaseType::CT_CASEZ; }
|
||||
bool caseInside() const { return m_casex==VCaseType::CT_CASEINSIDE; }
|
||||
@@ -2391,9 +2448,10 @@ public:
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual bool same(AstNode* samep) const { return text()==samep->castSFormatF()->text(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return text()==static_cast<const AstSFormatF*>(samep)->text(); }
|
||||
virtual string verilogKwd() const { return "$sformatf"; }
|
||||
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||
void addExprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||
AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text=text; }
|
||||
@@ -2436,7 +2494,8 @@ public:
|
||||
virtual bool isOutputter() const { return true; } // SPECIAL: $display makes output
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(displayType()); }
|
||||
virtual bool same(AstNode* samep) const { return displayType()==samep->castDisplay()->displayType(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return displayType()==static_cast<const AstDisplay*>(samep)->displayType(); }
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
AstDisplayType displayType() const { return m_displayType; }
|
||||
void displayType(AstDisplayType type) { m_displayType = type; }
|
||||
@@ -2469,7 +2528,7 @@ public:
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter
|
||||
AstSFormatF* fmtp() const { return op1p()->castSFormatF(); }
|
||||
AstNode* lhsp() const { return op3p(); }
|
||||
@@ -2509,7 +2568,7 @@ public:
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* filep() const { return op2p(); }
|
||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||
};
|
||||
@@ -2531,7 +2590,7 @@ public:
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* filep() const { return op1p(); }
|
||||
AstNode* filenamep() const { return op2p(); }
|
||||
AstNode* modep() const { return op3p(); }
|
||||
@@ -2553,7 +2612,7 @@ public:
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* filep() const { return op2p(); }
|
||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||
};
|
||||
@@ -2581,8 +2640,8 @@ public:
|
||||
virtual bool isOutputter() const { return true; } // SPECIAL: makes output
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castFScanF()->text(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return text()==static_cast<const AstFScanF*>(samep)->text(); }
|
||||
AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output
|
||||
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
@@ -2614,8 +2673,8 @@ public:
|
||||
virtual bool isOutputter() const { return true; } // SPECIAL: makes output
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castSScanF()->text(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return text()==static_cast<const AstSScanF*>(samep)->text(); }
|
||||
AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output
|
||||
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
@@ -2641,7 +2700,8 @@ public:
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return isHex()==samep->castReadMem()->isHex(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return isHex()==static_cast<const AstReadMem*>(samep)->isHex(); }
|
||||
bool isHex() const { return m_isHex; }
|
||||
AstNode* filenamep() const { return op1p(); }
|
||||
AstNode* memp() const { return op2p(); }
|
||||
@@ -2664,7 +2724,7 @@ public:
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
};
|
||||
|
||||
@@ -2686,7 +2746,7 @@ public:
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
};
|
||||
|
||||
@@ -2706,7 +2766,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* searchp() const { return op1p(); } // op1 = Search expression
|
||||
void searchp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* outp() const { return op2p(); } // op2 = Expressions to output
|
||||
@@ -2730,8 +2790,8 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castTestPlusArgs()->text(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return text() == static_cast<const AstTestPlusArgs*>(samep)->text(); }
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text=text; }
|
||||
};
|
||||
@@ -2759,7 +2819,7 @@ public:
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstRepeat : public AstNodeStmt {
|
||||
@@ -2774,7 +2834,7 @@ public:
|
||||
virtual bool isGateOptimizable() const { return false; } // Not releavant - converted to FOR
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstWhile : public AstNodeStmt {
|
||||
@@ -2794,7 +2854,7 @@ public:
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||
};
|
||||
@@ -2858,7 +2918,7 @@ private:
|
||||
bool m_unique0Pragma; // unique0 case
|
||||
bool m_priorityPragma; // priority case
|
||||
public:
|
||||
AstIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
||||
AstIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp=NULL)
|
||||
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
||||
m_uniquePragma=false; m_unique0Pragma=false; m_priorityPragma=false;
|
||||
}
|
||||
@@ -2887,7 +2947,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(JumpLabel)
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
// op1 = Statements
|
||||
AstNode* stmtsp() const { return op1p(); } // op1 = List of statements
|
||||
void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
@@ -2911,8 +2971,8 @@ public:
|
||||
virtual void dump(ostream& str);
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(labelp()); }
|
||||
virtual bool same(AstNode* samep) const { // Also same if identical tree structure all the way down, but hard to detect
|
||||
return labelp()==samep->castJumpGo()->labelp(); }
|
||||
virtual bool same(const AstNode* samep) const { // Also same if identical tree structure all the way down, but hard to detect
|
||||
return labelp() == static_cast<const AstJumpGo*>(samep)->labelp(); }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks
|
||||
AstJumpLabel* labelp() const { return m_labelp; }
|
||||
@@ -2936,7 +2996,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; } // Not relevant
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstChangeXor : public AstNodeBiComAsv {
|
||||
@@ -2979,7 +3039,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstBegin : public AstNode {
|
||||
@@ -3099,7 +3159,8 @@ public:
|
||||
return m_indices[listPos]; }
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return m_indices==samep->castInitArray()->m_indices; }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return m_indices == static_cast<const AstInitArray*>(samep)->m_indices; }
|
||||
};
|
||||
|
||||
class AstPragma : public AstNode {
|
||||
@@ -3116,8 +3177,8 @@ public:
|
||||
AstPragmaType pragType() const { return m_pragType; } // *=type of the pragma
|
||||
virtual V3Hash sameHash() const { return V3Hash(pragType()); }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return pragType()==samep->castPragma()->pragType(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return pragType() == static_cast<const AstPragma*>(samep)->pragType(); }
|
||||
};
|
||||
|
||||
class AstStop : public AstNodeStmt {
|
||||
@@ -3132,7 +3193,7 @@ public:
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual int instrCount() const { return 0; } // Rarely executes
|
||||
virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return fileline() == samep->fileline(); }
|
||||
};
|
||||
|
||||
@@ -3148,7 +3209,7 @@ public:
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual int instrCount() const { return 0; } // Rarely executes
|
||||
virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return fileline() == samep->fileline(); }
|
||||
};
|
||||
|
||||
@@ -3178,7 +3239,7 @@ public:
|
||||
virtual string name() const { return m_showname; }
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual bool same(AstNode* samep) const { return false; }
|
||||
virtual bool same(const AstNode* samep) const { return false; }
|
||||
string showname() const { return m_showname; } // * = Var name
|
||||
// Details on what we're tracing
|
||||
uint32_t code() const { return m_code; }
|
||||
@@ -3208,8 +3269,8 @@ public:
|
||||
virtual int instrCount() const { return 10+2*instrCountLd(); }
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(declp()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return declp()==samep->castTraceInc()->declp(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return declp() == static_cast<const AstTraceInc*>(samep)->declp(); }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isOutputter() const { return true; }
|
||||
@@ -3291,7 +3352,8 @@ public:
|
||||
dtypeSetUInt64(); }
|
||||
ASTNODE_NODE_FUNCS(ScopeName)
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return m_dpiExport==samep->castScopeName()->m_dpiExport; }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return m_dpiExport == static_cast<const AstScopeName*>(samep)->m_dpiExport; }
|
||||
virtual string emitVerilog() { return ""; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
@@ -3349,7 +3411,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstTime : public AstNodeTermop {
|
||||
@@ -3364,7 +3426,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountTime(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstTimeD : public AstNodeTermop {
|
||||
@@ -3379,7 +3441,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountTime(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstUCFunc : public AstNodeMath {
|
||||
@@ -3402,7 +3464,7 @@ public:
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
@@ -3763,7 +3825,8 @@ public:
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} // Special cased in V3Cast
|
||||
virtual V3Hash sameHash() const { return V3Hash(size()); }
|
||||
virtual bool same(AstNode* samep) const { return size()==samep->castCCast()->size(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return size() == static_cast<const AstCCast*>(samep)->size(); }
|
||||
virtual void dump(ostream& str=cout);
|
||||
//
|
||||
int size() const { return m_size; }
|
||||
@@ -3781,7 +3844,7 @@ public:
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstFEof : public AstNodeUniop {
|
||||
@@ -4888,7 +4951,7 @@ public:
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc
|
||||
};
|
||||
class AstPatMember : public AstNodeMath {
|
||||
@@ -4930,7 +4993,7 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(VAssert)
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstNode* passsp() const { return op2p(); } // op2 = if passes
|
||||
AstNode* failsp() const { return op3p(); } // op3 = if fails
|
||||
@@ -4991,7 +5054,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(PslCover)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual V3Hash sameHash() const { return V3Hash(name()); }
|
||||
virtual bool same(AstNode* samep) const { return samep->name() == name(); }
|
||||
virtual bool same(const AstNode* samep) const { return samep->name() == name(); }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
|
||||
@@ -5083,7 +5146,7 @@ public:
|
||||
virtual bool isPure() const { return false; }
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
@@ -5109,7 +5172,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(CFile)
|
||||
virtual string name() const { return m_name; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
virtual void dump(ostream& str=cout);
|
||||
bool slow() const { return m_slow; }
|
||||
void slow(bool flag) { m_slow = flag; }
|
||||
@@ -5130,6 +5193,7 @@ private:
|
||||
string m_cname; // C name, for dpiExports
|
||||
string m_rtnType; // void, bool, or other return type
|
||||
string m_argTypes;
|
||||
string m_ifdef; // #ifdef symbol around this function
|
||||
bool m_dontCombine:1; // V3Combine shouldn't compare this func tree, it's special
|
||||
bool m_skipDecl:1; // Don't declare it
|
||||
bool m_declPrivate:1; // Declare it private
|
||||
@@ -5172,11 +5236,13 @@ public:
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
virtual void dump(ostream& str=cout);
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return ((funcType()==samep->castCFunc()->funcType())
|
||||
&& (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid())
|
||||
&& (argTypes()==samep->castCFunc()->argTypes())
|
||||
&& (!(dpiImport() || dpiExport())
|
||||
|| name()==samep->castCFunc()->name())); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstCFunc* asamep = static_cast<const AstCFunc*>(samep);
|
||||
return ((funcType() == asamep->funcType())
|
||||
&& (rtnTypeVoid() == asamep->rtnTypeVoid())
|
||||
&& (argTypes() == asamep->argTypes())
|
||||
&& (!(dpiImport() || dpiExport())
|
||||
|| name() == asamep->name())); }
|
||||
//
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual int instrCount() const { return dpiImport() ? instrCountDpi() : 0; }
|
||||
@@ -5200,6 +5266,8 @@ public:
|
||||
void funcPublic(bool flag) { m_funcPublic = flag; }
|
||||
void argTypes(const string& str) { m_argTypes = str; }
|
||||
string argTypes() const { return m_argTypes; }
|
||||
void ifdef(const string& str) { m_ifdef = str; }
|
||||
string ifdef() const { return m_ifdef; }
|
||||
void funcType(AstCFuncType flag) { m_funcType = flag; }
|
||||
AstCFuncType funcType() const { return m_funcType; }
|
||||
bool isInline() const { return m_isInline; }
|
||||
@@ -5262,9 +5330,10 @@ public:
|
||||
virtual const char* broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return NULL; }
|
||||
virtual int instrCount() const { return instrCountCall(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(funcp()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (funcp()==samep->castCCall()->funcp()
|
||||
&& argTypes()==samep->castCCall()->argTypes()); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstCCall* asamep = static_cast<const AstCCall*>(samep);
|
||||
return (funcp() == asamep->funcp()
|
||||
&& argTypes() == asamep->argTypes()); }
|
||||
AstNode* exprsp() const { return op1p(); } // op1= expressions to print
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
@@ -5292,7 +5361,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(CReturn)
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
//
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
};
|
||||
@@ -5319,7 +5388,7 @@ public:
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
void addBodysp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
AstNode* bodysp() const { return op1p(); } // op1= expressions to print
|
||||
};
|
||||
@@ -5336,7 +5405,7 @@ public:
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstVarRef* varrefp() const { return op1p()->castVarRef(); } // op1= varref to reset
|
||||
};
|
||||
|
||||
@@ -5355,7 +5424,7 @@ public:
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
void addBodysp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
AstNode* bodysp() const { return op1p(); } // op1= expressions to print
|
||||
};
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
class V3Branch {
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
static void branchAll(AstNetlist* rootp);
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Broken.h"
|
||||
@@ -47,7 +47,7 @@ class BrokenTable : public AstNVisitor {
|
||||
private:
|
||||
// MEMBERS
|
||||
// For each node, we keep if it exists or not.
|
||||
typedef map<const AstNode*,int> NodeMap;
|
||||
typedef vl_unordered_map<const AstNode*,int> NodeMap; // Performance matters (when --debug)
|
||||
static NodeMap s_nodes; // Set of all nodes that exist
|
||||
// BITMASK
|
||||
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
|
||||
|
||||
+65
-18
@@ -23,6 +23,8 @@
|
||||
// for all AstCoverDecl, move the declaration into a _configure_coverage AstCFunc.
|
||||
// For each variable that needs reset, add a AstCReset node.
|
||||
//
|
||||
// For primary inputs, add _eval_debug_assertions.
|
||||
//
|
||||
// This transformation honors outputSplitCFuncs.
|
||||
//*************************************************************************
|
||||
#include "config_build.h"
|
||||
@@ -95,29 +97,74 @@ public:
|
||||
m_modp->addStmtp(m_tlFuncp);
|
||||
}
|
||||
~V3CCtorsVisitor() {}
|
||||
private:
|
||||
VL_UNCOPYABLE(V3CCtorsVisitor);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
void V3CCtors::cctorsAll() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
|
||||
// Process each module in turn
|
||||
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
|
||||
V3CCtorsVisitor configure_coverage (modp, "_configure_coverage",
|
||||
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
|
||||
"if (0 && vlSymsp && first) {} // Prevent unused\n");
|
||||
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
AstVar* varp = np->castVar();
|
||||
if (varp) var_reset.add(new AstCReset(varp->fileline(), new AstVarRef(varp->fileline(), varp, true)));
|
||||
AstCoverDecl* coverp = np->castCoverDecl();
|
||||
if (coverp) {
|
||||
AstNode* backp = coverp->backp();
|
||||
coverp->unlinkFrBack();
|
||||
configure_coverage.add(coverp);
|
||||
np = backp;
|
||||
void V3CCtors::evalAsserts() {
|
||||
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", NULL, "void");
|
||||
funcp->declPrivate(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->slow(false);
|
||||
funcp->ifdef("VL_DEBUG");
|
||||
modp->addStmtp(funcp);
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* varp = np->castVar()) {
|
||||
if (varp->isPrimaryIn() && !varp->isSc()) {
|
||||
if (AstBasicDType* basicp = varp->dtypeSkipRefp()->castBasicDType()) {
|
||||
int storedWidth = basicp->widthAlignBytes() * 8;
|
||||
int lastWordWidth = varp->width() % storedWidth;
|
||||
if (lastWordWidth != 0) {
|
||||
// if (signal & CONST(upper_non_clean_mask)) { fail; }
|
||||
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
|
||||
if (varp->isWide()) {
|
||||
newp = new AstWordSel(varp->fileline(), newp,
|
||||
new AstConst(varp->fileline(), varp->widthWords()-1));
|
||||
}
|
||||
uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
|
||||
V3Number num (varp->fileline(), storedWidth, value);
|
||||
newp = new AstAnd(varp->fileline(), newp,
|
||||
new AstConst(varp->fileline(), num));
|
||||
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
|
||||
new AstCStmt(varp->fileline(), "Verilated::overWidthError(\""+varp->prettyName()+"\");"));
|
||||
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
newp = ifp;
|
||||
funcp->addStmtsp(newp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3CCtors::cctorsAll() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
evalAsserts();
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
|
||||
// Process each module in turn
|
||||
{
|
||||
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* varp = np->castVar()) {
|
||||
var_reset.add(new AstCReset(varp->fileline(), new AstVarRef(varp->fileline(), varp, true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.coverage()) {
|
||||
V3CCtorsVisitor configure_coverage
|
||||
(modp, "_configure_coverage", EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
|
||||
"if (0 && vlSymsp && first) {} // Prevent unused\n");
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstCoverDecl* coverp = np->castCoverDecl()) {
|
||||
AstNode* backp = coverp->backp();
|
||||
coverp->unlinkFrBack();
|
||||
configure_coverage.add(coverp);
|
||||
np = backp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
class V3CCtors {
|
||||
public:
|
||||
static void cctorsAll();
|
||||
private:
|
||||
static void evalAsserts();
|
||||
};
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -496,7 +496,7 @@ private:
|
||||
}
|
||||
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc_edges.txt";
|
||||
const VL_UNIQUE_PTR<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
const vl_unique_ptr<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
*ofp<<"Edge Report for "<<v3Global.opt.prefix()<<endl;
|
||||
|
||||
|
||||
+1
-1
@@ -621,7 +621,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
}
|
||||
// Top level we could choose to make multiple gaters, or ORs under the gater
|
||||
// Right now we'll put OR lower down and let other optimizations deal
|
||||
if (nodep) nodep = new AstOr(eqnp->fileline(),nodep,eqnp);
|
||||
if (nodep) nodep = new AstOr(nodep->fileline(), nodep, eqnp);
|
||||
else nodep = eqnp;
|
||||
//if (debug()>=9) nodep->dumpTree(cout," followExpr: ");
|
||||
}
|
||||
|
||||
+88
-25
@@ -369,11 +369,11 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operandBiExtendConst(AstNodeBiop* nodep) {
|
||||
bool operandBiExtendConstShrink(AstNodeBiop* nodep) {
|
||||
// Loop unrolling favors standalone compares
|
||||
// EQ(const{width32}, EXTEND(xx{width3})) -> EQ(const{3}, xx{3})
|
||||
// Beware that the constant must have zero bits (+ 1 if signed) or compare
|
||||
// would be incorrect
|
||||
// The constant must have zero bits (+ 1 if signed) or compare
|
||||
// would be incorrect. See also operandBiExtendConst
|
||||
AstExtend* extendp = nodep->rhsp()->castExtend();
|
||||
if (!extendp) return false;
|
||||
AstNode* smallerp = extendp->lhsp();
|
||||
@@ -395,6 +395,19 @@ private:
|
||||
if (debug()>=9) nodep->dumpTree(cout,"BI(EXTEND)-ou:");
|
||||
return true;
|
||||
}
|
||||
bool operandBiExtendConstOver(AstNodeBiop* nodep) {
|
||||
// EQ(const{width32}, EXTEND(xx{width3})) -> constant
|
||||
// When the constant has non-zero bits above the extend it's a constant.
|
||||
// Avoids compiler warning
|
||||
AstExtend* extendp = nodep->rhsp()->castExtend();
|
||||
if (!extendp) return false;
|
||||
AstNode* smallerp = extendp->lhsp();
|
||||
int subsize = smallerp->width();
|
||||
AstConst* constp = nodep->lhsp()->castConst();
|
||||
if (!constp) return false;
|
||||
if (constp->num().isBitsZero(constp->width()-1, subsize)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
AstNode* afterComment(AstNode* nodep) {
|
||||
// Ignore comments, such as to determine if a AstIf is empty.
|
||||
@@ -472,11 +485,7 @@ private:
|
||||
if (!ifp || ifp->nextp()) return false; // Must be SINGLE statement
|
||||
if (!elsep || elsep->nextp()) return false;
|
||||
if (ifp->type() != elsep->type()) return false; // Can't mix an assigndly and an assign
|
||||
AstVarRef* ifvarp = ifp->lhsp()->castVarRef();
|
||||
AstVarRef* elsevarp = elsep->lhsp()->castVarRef();
|
||||
if (!ifvarp || !elsevarp) return false;
|
||||
if (ifvarp->isWide()) return false; // Would need temporaries, so not worth it
|
||||
if (!ifvarp->sameGateTree(elsevarp)) return false;
|
||||
if (!ifp->lhsp()->sameGateTree(elsep->lhsp())) return false;
|
||||
if (!ifp->rhsp()->gateTree()) return false;
|
||||
if (!elsep->rhsp()->gateTree()) return false;
|
||||
return true;
|
||||
@@ -1680,9 +1689,12 @@ private:
|
||||
// But might be same name with different scopes
|
||||
if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) return true;
|
||||
if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) return false;
|
||||
// Or rarely, different data types
|
||||
if (litemp->varrefp()->dtypep() < ritemp->varrefp()->dtypep()) return true;
|
||||
if (litemp->varrefp()->dtypep() > ritemp->varrefp()->dtypep()) return false;
|
||||
}
|
||||
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent
|
||||
// note the SenTree optimizer requires this order (more general firsst, less general last)
|
||||
// note the SenTree optimizer requires this order (more general first, less general last)
|
||||
if (litemp->edgeType() < ritemp->edgeType()) return true;
|
||||
if (litemp->edgeType() > ritemp->edgeType()) return false;
|
||||
}
|
||||
@@ -1893,7 +1905,7 @@ private:
|
||||
}
|
||||
else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
|
||||
&& operandIfIf(nodep)) {
|
||||
UINFO(0,"IF({a}) IF({b}) => IF({a} && {b})"<<endl);
|
||||
UINFO(9,"IF({a}) IF({b}) => IF({a} && {b})"<<endl);
|
||||
AstNodeIf* lowerIfp = nodep->ifsp()->castNodeIf();
|
||||
AstNode* condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* lowerIfsp = lowerIfp->ifsp()->unlinkFrBackWithNext();
|
||||
@@ -1909,6 +1921,51 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
|
||||
nodep->iterateChildren(*this);
|
||||
if (stmtDisplayDisplay(nodep)) return;
|
||||
}
|
||||
bool stmtDisplayDisplay(AstDisplay* nodep) {
|
||||
// DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2))
|
||||
if (!m_modp) return false; // Don't optimize under single statement
|
||||
if (!nodep->backp()) return false;
|
||||
AstDisplay* prevp = nodep->backp()->castDisplay();
|
||||
if (!prevp) return false;
|
||||
if (!((prevp->displayType() == nodep->displayType())
|
||||
|| (prevp->displayType() == AstDisplayType::DT_WRITE
|
||||
&& nodep->displayType() == AstDisplayType::DT_DISPLAY)
|
||||
|| (prevp->displayType() == AstDisplayType::DT_DISPLAY
|
||||
&& nodep->displayType() == AstDisplayType::DT_WRITE)))
|
||||
return false;
|
||||
if ((prevp->filep() && !nodep->filep())
|
||||
|| (!prevp->filep() && nodep->filep())
|
||||
|| !prevp->filep()->sameTree(nodep->filep())) return false;
|
||||
if (!prevp->fmtp() || prevp->fmtp()->nextp()
|
||||
|| !nodep->fmtp() || nodep->fmtp()->nextp()) return false;
|
||||
// We don't merge scopeNames as might be different scopes (late in process)
|
||||
// We don't merge arguments as might need to later print warnings with right line numbers
|
||||
AstSFormatF* pformatp = prevp->fmtp();
|
||||
if (!pformatp || pformatp->exprsp() || pformatp->scopeNamep()) return false;
|
||||
AstSFormatF* nformatp = nodep->fmtp();
|
||||
if (!nformatp || nformatp->exprsp() || nformatp->scopeNamep()) return false;
|
||||
//
|
||||
UINFO(9,"DISPLAY(SF({a})) DISPLAY(SF({b})) -> DISPLAY(SF({a}+{b}))"<<endl);
|
||||
// Convert DT_DISPLAY to DT_WRITE as may allow later optimizations
|
||||
if (prevp->displayType() == AstDisplayType::DT_DISPLAY) {
|
||||
prevp->displayType(AstDisplayType::DT_WRITE);
|
||||
pformatp->text(pformatp->text()+"\n");
|
||||
}
|
||||
// We can't replace prev() as the edit tracking iterators will get confused.
|
||||
// So instead we edit the prev note itself.
|
||||
if (prevp->addNewline()) pformatp->text(pformatp->text()+"\n");
|
||||
pformatp->text(pformatp->text()+nformatp->text());
|
||||
if (!prevp->addNewline() && nodep->addNewline()) {
|
||||
pformatp->text(pformatp->text()+"\n");
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
return true;
|
||||
}
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
// Substitute constants into displays. The main point of this is to
|
||||
// simplify assertion methodologies which call functions with display's.
|
||||
@@ -1947,7 +2004,7 @@ private:
|
||||
UINFO(9," DispConst: "<<fmt<<" -> "<<out<<" for "<<argp<<endl);
|
||||
// fmt = out w/ replace % with %% as it must be literal.
|
||||
fmt = VString::quotePercent(out);
|
||||
argp->unlinkFrBack()->deleteTree();
|
||||
argp->unlinkFrBack()->deleteTree(); VL_DANGLING(argp);
|
||||
}
|
||||
argp=nextp;
|
||||
}
|
||||
@@ -2147,7 +2204,7 @@ private:
|
||||
// This visit function here must allow for short-circuiting.
|
||||
TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)");
|
||||
TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)");
|
||||
TREEOP ("AstCond{$condp->castNot(), $expr1p, $expr2p}", "AstCond{$condp->op1p(), $expr2p, $expr1p}");
|
||||
TREEOP ("AstCond{$condp.castNot, $expr1p, $expr2p}", "AstCond{$condp->op1p(), $expr2p, $expr1p}");
|
||||
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isAllOnes, $expr2p}", "AstLogOr {$condp, $expr2p}"); // a?1:b == a||b
|
||||
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isZero}", "AstLogAnd{$condp, $expr1p}"); // a?b:0 == a&&b
|
||||
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isAllOnes}", "AstLogOr {AstNot{$condp}, $expr1p}"); // a?b:1 == ~a||b
|
||||
@@ -2216,12 +2273,18 @@ private:
|
||||
TREEOP ("AstShiftR{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
|
||||
TREEOP ("AstWordSel{operandWordOOB(nodep)}", "replaceZero(nodep)");
|
||||
// Compress out EXTENDs to appease loop unroller
|
||||
TREEOPV("AstEq {$rhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstNeq {$rhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstGt {$rhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstGte {$rhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstLt {$rhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstLte {$rhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstEq {$rhsp.castExtend,operandBiExtendConstShrink(nodep)}", "DONE");
|
||||
TREEOPV("AstNeq {$rhsp.castExtend,operandBiExtendConstShrink(nodep)}", "DONE");
|
||||
TREEOPV("AstGt {$rhsp.castExtend,operandBiExtendConstShrink(nodep)}", "DONE");
|
||||
TREEOPV("AstGte {$rhsp.castExtend,operandBiExtendConstShrink(nodep)}", "DONE");
|
||||
TREEOPV("AstLt {$rhsp.castExtend,operandBiExtendConstShrink(nodep)}", "DONE");
|
||||
TREEOPV("AstLte {$rhsp.castExtend,operandBiExtendConstShrink(nodep)}", "DONE");
|
||||
TREEOPV("AstEq {$rhsp.castExtend,operandBiExtendConstOver(nodep)}", "replaceZero(nodep)");
|
||||
TREEOPV("AstNeq {$rhsp.castExtend,operandBiExtendConstOver(nodep)}", "replaceNum(nodep,1)");
|
||||
TREEOPV("AstGt {$rhsp.castExtend,operandBiExtendConstOver(nodep)}", "replaceNum(nodep,1)");
|
||||
TREEOPV("AstGte {$rhsp.castExtend,operandBiExtendConstOver(nodep)}", "replaceNum(nodep,1)");
|
||||
TREEOPV("AstLt {$rhsp.castExtend,operandBiExtendConstOver(nodep)}", "replaceZero(nodep)");
|
||||
TREEOPV("AstLte {$rhsp.castExtend,operandBiExtendConstOver(nodep)}", "replaceZero(nodep)");
|
||||
// Identical operands on both sides
|
||||
// AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules
|
||||
// AstAdd->ShiftL(#,1) but uncommon
|
||||
@@ -2281,12 +2344,12 @@ private:
|
||||
TREEOPV("AstRedAnd{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOPV("AstRedOr {$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOPV("AstRedXor{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOPV("AstRedAnd{$lhsp->castConcat()}", "AstAnd{AstRedAnd{$lhsp->castConcat()->lhsp()}, AstRedAnd{$lhsp->castConcat()->rhsp()}}"); // &{a,b} => {&a}&{&b}
|
||||
TREEOPV("AstRedOr {$lhsp->castConcat()}", "AstOr {AstRedOr {$lhsp->castConcat()->lhsp()}, AstRedOr {$lhsp->castConcat()->rhsp()}}"); // |{a,b} => {|a}|{|b}
|
||||
TREEOPV("AstRedXor{$lhsp->castConcat()}", "AstXor{AstRedXor{$lhsp->castConcat()->lhsp()}, AstRedXor{$lhsp->castConcat()->rhsp()}}"); // ^{a,b} => {^a}^{^b}
|
||||
TREEOPV("AstRedAnd{$lhsp->castExtend(), $lhsp->width()>$lhsp->castExtend()->lhsp()->width()}", "replaceZero(nodep)"); // &{0,...} => 0 Prevents compiler limited range error
|
||||
TREEOPV("AstRedOr {$lhsp->castExtend()}", "AstRedOr {$lhsp->castExtend()->lhsp()}");
|
||||
TREEOPV("AstRedXor{$lhsp->castExtend()}", "AstRedXor{$lhsp->castExtend()->lhsp()}");
|
||||
TREEOPV("AstRedAnd{$lhsp.castConcat}", "AstAnd{AstRedAnd{$lhsp->castConcat()->lhsp()}, AstRedAnd{$lhsp->castConcat()->rhsp()}}"); // &{a,b} => {&a}&{&b}
|
||||
TREEOPV("AstRedOr {$lhsp.castConcat}", "AstOr {AstRedOr {$lhsp->castConcat()->lhsp()}, AstRedOr {$lhsp->castConcat()->rhsp()}}"); // |{a,b} => {|a}|{|b}
|
||||
TREEOPV("AstRedXor{$lhsp.castConcat}", "AstXor{AstRedXor{$lhsp->castConcat()->lhsp()}, AstRedXor{$lhsp->castConcat()->rhsp()}}"); // ^{a,b} => {^a}^{^b}
|
||||
TREEOPV("AstRedAnd{$lhsp.castExtend, $lhsp->width() > $lhsp->castExtend()->lhsp()->width()}", "replaceZero(nodep)"); // &{0,...} => 0 Prevents compiler limited range error
|
||||
TREEOPV("AstRedOr {$lhsp.castExtend}", "AstRedOr {$lhsp->castExtend()->lhsp()}");
|
||||
TREEOPV("AstRedXor{$lhsp.castExtend}", "AstRedXor{$lhsp->castExtend()->lhsp()}");
|
||||
TREEOPV("AstOneHot{$lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOPV("AstOneHot0{$lhsp.width1}", "replaceNum(nodep,1)");
|
||||
// Binary AND/OR is faster than logical and/or (usually)
|
||||
@@ -2298,7 +2361,7 @@ private:
|
||||
TREEOPV("AstConcat{operandConcatMove(nodep)}", "moveConcat(nodep)");
|
||||
TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())");
|
||||
// CONCAT(a[1],a[0]) -> a[1:0]
|
||||
TREEOPV("AstConcat{$lhsp->castSel(), $rhsp->castSel(), ifAdjacentSel($lhsp->castSel(),,$rhsp->castSel())}", "replaceConcatSel(nodep)");
|
||||
TREEOPV("AstConcat{$lhsp.castSel, $rhsp.castSel, ifAdjacentSel($lhsp->castSel(),,$rhsp->castSel())}", "replaceConcatSel(nodep)");
|
||||
TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)");
|
||||
// Common two-level operations that can be simplified
|
||||
TREEOP ("AstAnd {$lhsp.castOr, $rhsp.castOr, operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
|
||||
@@ -168,6 +168,7 @@ private:
|
||||
// Add signal to hold the old value
|
||||
string newvarname = (string)"__Vtogcov__"+nodep->shortName();
|
||||
AstVar* chgVarp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
|
||||
chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
|
||||
m_modp->addStmtp(chgVarp);
|
||||
|
||||
// Create bucket for each dimension * bit.
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
class V3Coverage {
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
static void coverage(AstNetlist* rootp);
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
class V3CoverageJoin {
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
static void coverageJoin(AstNetlist* rootp);
|
||||
};
|
||||
|
||||
|
||||
+8
-4
@@ -137,8 +137,10 @@ private:
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
checkAll(nodep);
|
||||
if (!nodep->dead()) {
|
||||
nodep->iterateChildren(*this);
|
||||
checkAll(nodep);
|
||||
}
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
@@ -280,12 +282,14 @@ private:
|
||||
AstNodeModule* nextmodp;
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
|
||||
nextmodp = modp->nextp()->castNodeModule();
|
||||
if (modp->level()>2 && modp->user1()==0 && !modp->internal()) {
|
||||
if (modp->dead() || (modp->level()>2 && modp->user1()==0 && !modp->internal())) {
|
||||
// > 2 because L1 is the wrapper, L2 is the top user module
|
||||
UINFO(4," Dead module "<<modp<<endl);
|
||||
// And its children may now be killable too; correct counts
|
||||
// Recurse, as cells may not be directly under the module but in a generate
|
||||
DeadModVisitor visitor(modp);
|
||||
if (!modp->dead()) { // If was dead didn't increment user1's
|
||||
DeadModVisitor visitor(modp);
|
||||
}
|
||||
modp->unlinkFrBack()->deleteTree(); VL_DANGLING(modp);
|
||||
retry = true;
|
||||
}
|
||||
|
||||
+5
-5
@@ -77,7 +77,6 @@ private:
|
||||
// AstVarScope::user4p() -> AstAlwaysPost*. Post block for this variable
|
||||
// AstVarScope::user5() -> VarUsage. Tracks delayed vs non-delayed usage
|
||||
// AstVar::user2() -> bool. Set true if already made warning
|
||||
// AstVar::user4() -> int. Vector number, for assignment creation
|
||||
// AstVarRef::user2() -> bool. Set true if already processed
|
||||
// AstAlwaysPost::user2() -> ActActive*. Points to activity block of signal (valid when AstAlwaysPost::user4p is valid)
|
||||
// AstAlwaysPost::user4() -> AstIf*. Last IF (__Vdlyvset__) created under this AlwaysPost
|
||||
@@ -102,7 +101,8 @@ private:
|
||||
typedef std::map<pair<AstNodeModule*,string>,AstVar*> VarMap;
|
||||
VarMap m_modVarMap; // Table of new var names created under module
|
||||
V3Double0 m_statSharedSet;// Statistic tracking
|
||||
|
||||
typedef std::map<AstVarScope*,int> ScopeVecMap;
|
||||
ScopeVecMap m_scopeVecMap; // Next var number for each scope
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -195,7 +195,7 @@ private:
|
||||
arrayselp = lhsp->castArraySel();
|
||||
}
|
||||
if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
|
||||
if (arrayselp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");
|
||||
if (arrayselp->dtypep()->skipRefp()->castUnpackArrayDType()) nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
|
||||
UINFO(4,"AssignDlyArray: "<<nodep<<endl);
|
||||
//
|
||||
@@ -211,7 +211,7 @@ private:
|
||||
if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
varrefp->unlinkFrBack();
|
||||
AstVar* oldvarp = varrefp->varp();
|
||||
int modVecNum = oldvarp->user4(); oldvarp->user4(modVecNum+1);
|
||||
int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
|
||||
//
|
||||
deque<AstNode*> dimreadps; // Read value for each dimension of assignment
|
||||
for (unsigned dimension=0; dimension<dimvalp.size(); dimension++) {
|
||||
@@ -370,7 +370,7 @@ private:
|
||||
&& nodep->lhsp()->castSel()->fromp()->castArraySel())) {
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newlhsp = createDlyArray(nodep, lhsp);
|
||||
if (m_inLoop) nodep->v3warn(E_BLKLOOPINIT,"Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
|
||||
if (m_inLoop) nodep->v3warn(BLKLOOPINIT,"Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
|
||||
if (newlhsp) {
|
||||
nodep->lhsp(newlhsp);
|
||||
} else {
|
||||
|
||||
+93
-44
@@ -53,7 +53,8 @@ private:
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope
|
||||
bool m_needThis; // Add thisp to function
|
||||
bool m_modSingleton; // m_modp is only instanced once
|
||||
bool m_needThis; // Make function non-static
|
||||
FuncMmap m_modFuncs; // Name of public functions added
|
||||
|
||||
// METHODS
|
||||
@@ -63,41 +64,91 @@ private:
|
||||
return level;
|
||||
}
|
||||
|
||||
string descopedName(AstScope* scopep, bool& hierThisr, AstVar* varp=NULL) {
|
||||
static bool modIsSingleton(AstNodeModule* modp) {
|
||||
// True iff there's exactly one instance of this module in the design.
|
||||
int instances = 0;
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (stmtp->castScope()) {
|
||||
if (++instances > 1) { return false; }
|
||||
}
|
||||
}
|
||||
return (instances == 1);
|
||||
}
|
||||
|
||||
// Construct the best prefix to reference an object in 'scopep'
|
||||
// from a CFunc in 'm_scopep'. Result may be relative
|
||||
// ("this->[...]") or absolute ("vlTOPp->[...]").
|
||||
//
|
||||
// Using relative references allows V3Combine'ing
|
||||
// code across multiple instances of the same module.
|
||||
//
|
||||
// Sets 'hierThisr' true if the object is local to this scope
|
||||
// (and could be made into a function-local later in V3Localize),
|
||||
// false if the object is in another scope.
|
||||
string descopedName(const AstScope* scopep, bool& hierThisr,
|
||||
const AstVar* varp=NULL) {
|
||||
UASSERT(scopep, "Var/Func not scoped\n");
|
||||
hierThisr = true;
|
||||
hierThisr = (scopep == m_scopep);
|
||||
|
||||
// It's possible to disable relative references. This is a concession
|
||||
// to older compilers (gcc < 4.5.x) that don't understand __restrict__
|
||||
// well and emit extra ld/st to guard against pointer aliasing
|
||||
// when this-> and vlTOPp-> are mixed in the same function.
|
||||
//
|
||||
// "vlTOPp" is declared "restrict" so better compilers understand
|
||||
// that it won't alias with "this".
|
||||
bool relativeRefOk = v3Global.opt.relativeCFuncs();
|
||||
|
||||
// Use absolute refs in top-scoped routines, keep them static.
|
||||
// The DPI callback registration depends on representing top-level
|
||||
// static routines as plain function pointers. That breaks if those
|
||||
// become true OO routines.
|
||||
//
|
||||
// V3Combine wouldn't likely be able to combine top-level
|
||||
// routines anyway, so there's no harm in keeping these static.
|
||||
if (m_modp->isTop()) {
|
||||
relativeRefOk = false;
|
||||
}
|
||||
|
||||
// Use absolute refs if this scope is the only instance of the module.
|
||||
// Saves a bit of overhead on passing the 'this' pointer, and there's no
|
||||
// need to be nice to V3Combine when we have only a single instance.
|
||||
// The risk that this prevents combining identical logic from differently-
|
||||
// named but identical modules seems low.
|
||||
if (m_modSingleton) {
|
||||
relativeRefOk = false;
|
||||
}
|
||||
|
||||
if (varp && varp->isFuncLocal()) {
|
||||
hierThisr = true;
|
||||
return ""; // Relative to function, not in this
|
||||
} else if (scopep == m_scopep && m_modp->isTop()) {
|
||||
//return ""; // Reference to scope we're in, no need to HIER-> it
|
||||
return "vlTOPp->";
|
||||
} else if (scopep == m_scopep && !m_modp->isTop()
|
||||
&& 0) { // We no longer thisp-> as still get ambiguation problems
|
||||
m_needThis = true;
|
||||
return "thisp->"; // this-> but with restricted aliasing
|
||||
} else if (scopep->aboveScopep() && scopep->aboveScopep()==m_scopep
|
||||
&& 0 // DISABLED: GCC considers the pointers ambiguous, so goes ld/store crazy
|
||||
) {
|
||||
// Reference to scope of cell directly under this module, can just "cell->"
|
||||
string name = scopep->name();
|
||||
string::size_type pos;
|
||||
if ((pos = name.rfind(".")) != string::npos) {
|
||||
name.erase(0,pos+1);
|
||||
}
|
||||
hierThisr = false;
|
||||
return name+"->";
|
||||
} else {
|
||||
// Reference to something else, use global variable
|
||||
UINFO(8," Descope "<<scopep<<endl);
|
||||
UINFO(8," to "<<scopep->name()<<endl);
|
||||
UINFO(8," under "<<m_scopep->name()<<endl);
|
||||
hierThisr = false;
|
||||
if (!scopep->aboveScopep()) { // Top
|
||||
return "vlTOPp->"; // == "vlSymsp->TOPp->", but GCC would suspect aliases
|
||||
} else {
|
||||
return scopep->nameVlSym()+".";
|
||||
}
|
||||
}
|
||||
} else if (relativeRefOk && scopep == m_scopep) {
|
||||
m_needThis = true;
|
||||
return "this->";
|
||||
} else if (relativeRefOk && scopep->aboveScopep()
|
||||
&& scopep->aboveScopep()==m_scopep) {
|
||||
// Reference to scope of cell directly under this module, can just "cell->"
|
||||
string name = scopep->name();
|
||||
string::size_type pos;
|
||||
if ((pos = name.rfind(".")) != string::npos) {
|
||||
name.erase(0,pos+1);
|
||||
}
|
||||
m_needThis = true;
|
||||
return name+"->";
|
||||
} else {
|
||||
// Reference to something elsewhere, or relative refences
|
||||
// are disabled. Use global variable
|
||||
UINFO(8," Descope "<<scopep<<endl);
|
||||
UINFO(8," to "<<scopep->name()<<endl);
|
||||
UINFO(8," under "<<m_scopep->name()<<endl);
|
||||
if (!scopep->aboveScopep()) { // Top
|
||||
// We could also return "vlSymsp->TOPp->" here, but GCC would
|
||||
// suspect aliases.
|
||||
return "vlTOPp->";
|
||||
} else {
|
||||
return scopep->nameVlSym()+".";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void makePublicFuncWrappers() {
|
||||
@@ -166,7 +217,7 @@ private:
|
||||
}
|
||||
}
|
||||
// Not really any way the user could do this, and we'd need to come up with some return value
|
||||
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_DISPLAY,
|
||||
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_WARNING,
|
||||
// string("%%Error: ")+name+"() called with bad scope", NULL));
|
||||
//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
|
||||
if (debug()>=9) newfuncp->dumpTree(cout," newfunc: ");
|
||||
@@ -182,6 +233,7 @@ private:
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_modFuncs.clear();
|
||||
m_modSingleton = modIsSingleton(m_modp);
|
||||
nodep->iterateChildren(*this);
|
||||
makePublicFuncWrappers();
|
||||
m_modp = NULL;
|
||||
@@ -222,11 +274,7 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(true);
|
||||
if (m_needThis) {
|
||||
nodep->v3fatalSrc("old code");
|
||||
// Really we should have more node types for backend optimization of this stuff
|
||||
string text = v3Global.opt.modPrefix() + "_" + m_modp->name()
|
||||
+"* thisp = &("+m_scopep->nameVlSym()+");\n";
|
||||
nodep->addInitsp(new AstCStmt(nodep->fileline(), text));
|
||||
nodep->isStatic(false);
|
||||
}
|
||||
// If it's under a scope, move it up to the top
|
||||
if (m_scopep) {
|
||||
@@ -248,11 +296,12 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DescopeVisitor(AstNetlist* nodep) {
|
||||
m_modp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_needThis = false;
|
||||
nodep->accept(*this);
|
||||
explicit DescopeVisitor(AstNetlist* nodep)
|
||||
: m_modp(NULL),
|
||||
m_scopep(NULL),
|
||||
m_modSingleton(false),
|
||||
m_needThis(false) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~DescopeVisitor() {}
|
||||
};
|
||||
|
||||
+49
-16
@@ -27,6 +27,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3String.h"
|
||||
@@ -433,14 +434,14 @@ public:
|
||||
puts("}\n");
|
||||
}
|
||||
virtual void visit(AstStop* nodep) {
|
||||
puts("vl_stop(");
|
||||
puts("VL_STOP_MT(");
|
||||
putsQuoted(nodep->fileline()->filename());
|
||||
puts(",");
|
||||
puts(cvtToStr(nodep->fileline()->lineno()));
|
||||
puts(",\"\");\n");
|
||||
}
|
||||
virtual void visit(AstFinish* nodep) {
|
||||
puts("vl_finish(");
|
||||
puts("VL_FINISH_MT(");
|
||||
putsQuoted(nodep->fileline()->filename());
|
||||
puts(",");
|
||||
puts(cvtToStr(nodep->fileline()->lineno()));
|
||||
@@ -871,12 +872,14 @@ class EmitCImp : EmitCStmts {
|
||||
splitSizeInc(nodep);
|
||||
|
||||
puts("\n");
|
||||
if (nodep->ifdef()!="") puts("#ifdef "+nodep->ifdef()+"\n");
|
||||
if (nodep->isInline()) puts("VL_INLINE_OPT ");
|
||||
puts(nodep->rtnTypeVoid()); puts(" ");
|
||||
puts(modClassName(m_modp)+"::"+nodep->name()
|
||||
+"("+cFuncArgs(nodep)+") {\n");
|
||||
|
||||
puts("VL_DEBUG_IF(VL_PRINTF(\" ");
|
||||
// "+" in the debug indicates a print from the model
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ ");
|
||||
for (int i=0;i<m_modp->level();i++) { puts(" "); }
|
||||
puts(modClassName(m_modp)+"::"+nodep->name()
|
||||
+"\\n\"); );\n");
|
||||
@@ -906,6 +909,7 @@ class EmitCImp : EmitCStmts {
|
||||
|
||||
//puts("__Vm_activity = true;\n");
|
||||
puts("}\n");
|
||||
if (nodep->ifdef()!="") puts("#endif // "+nodep->ifdef()+"\n");
|
||||
}
|
||||
|
||||
void emitChangeDet() {
|
||||
@@ -937,7 +941,7 @@ class EmitCImp : EmitCStmts {
|
||||
if (nodep->lhsp()->castVarRef()) {
|
||||
varname = ": "+nodep->lhsp()->castVarRef()->varp()->prettyName();
|
||||
}
|
||||
puts(")) VL_PRINTF(\"\tCHANGE: "+nodep->fileline()->ascii()
|
||||
puts(")) VL_DBG_MSGF(\" CHANGE: "+nodep->fileline()->ascii()
|
||||
+varname+"\\n\"); );\n");
|
||||
}
|
||||
}
|
||||
@@ -999,7 +1003,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
||||
if (nodep->isSc()) {
|
||||
m_ctorVarsVec.push_back(nodep);
|
||||
if (nodep->attrScClocked() && nodep->isInput()) {
|
||||
puts("sc_in_clk\t");
|
||||
puts("sc_in_clk ");
|
||||
} else {
|
||||
if (nodep->isInout()) puts("sc_inout<");
|
||||
else if (nodep->isInput()) puts("sc_in<");
|
||||
@@ -1007,7 +1011,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
||||
else nodep->v3fatalSrc("Unknown type");
|
||||
|
||||
puts(nodep->scType());
|
||||
puts(">\t");
|
||||
puts("> ");
|
||||
}
|
||||
puts(nodep->name());
|
||||
emitDeclArrayBrackets(nodep);
|
||||
@@ -1464,7 +1468,8 @@ void EmitCImp::emitVarReset(AstVar* varp) {
|
||||
}
|
||||
bool zeroit = (varp->attrFileDescr() // Zero it out, so we don't core dump if never call $fopen
|
||||
|| (varp->basicp() && varp->basicp()->isZeroInit())
|
||||
|| (varp->name().size()>=1 && varp->name()[0]=='_' && v3Global.opt.underlineZero()));
|
||||
|| (varp->name().size()>=1 && varp->name()[0]=='_' && v3Global.opt.underlineZero())
|
||||
|| (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0"));
|
||||
if (varp->isWide()) {
|
||||
// DOCUMENT: We randomize everything. If the user wants a _var to be zero,
|
||||
// there should be a initial statement. (Different from verilator2.)
|
||||
@@ -1728,27 +1733,45 @@ void EmitCImp::emitSensitives() {
|
||||
|
||||
void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
||||
puts("\nvoid "+modClassName(modp)+"::eval() {\n");
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate "+modClassName(modp)+"::eval\\n\"); );\n");
|
||||
puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n");
|
||||
puts(EmitCBaseVisitor::symTopAssign()+"\n");
|
||||
puts("#ifdef VL_DEBUG\n");
|
||||
putsDecoration("// Debug assertions\n");
|
||||
puts("_eval_debug_assertions();\n");
|
||||
puts("#endif // VL_DEBUG\n");
|
||||
putsDecoration("// Initialize\n");
|
||||
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);\n");
|
||||
if (v3Global.opt.inhibitSim()) {
|
||||
puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n");
|
||||
}
|
||||
|
||||
if (v3Global.opt.threads()) { // THREADED-TODO move to per-train
|
||||
uint32_t trainId = 0;
|
||||
putsDecoration("// Train "+cvtToStr(trainId)+" start\n");
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"Train starting, trainId="+cvtToStr(trainId)+"\\n\"););\n");
|
||||
puts("Verilated::trainId("+cvtToStr(trainId)+");\n");
|
||||
}
|
||||
|
||||
putsDecoration("// Evaluate till stable\n");
|
||||
puts("VL_DEBUG_IF(VL_PRINTF(\"\\n----TOP Evaluate "+modClassName(modp)+"::eval\\n\"); );\n");
|
||||
puts("int __VclockLoop = 0;\n");
|
||||
puts("QData __Vchange = 1;\n");
|
||||
puts("while (VL_LIKELY(__Vchange)) {\n");
|
||||
puts( "VL_DEBUG_IF(VL_PRINTF(\" Clock loop\\n\"););\n");
|
||||
puts( "VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n");
|
||||
if (v3Global.opt.trace()) {
|
||||
puts("vlSymsp->__Vm_activity = true;\n");
|
||||
}
|
||||
puts( "_eval(vlSymsp);\n");
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "if (VL_UNLIKELY(++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
|
||||
+")) vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n");
|
||||
+")) VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n");
|
||||
puts("}\n");
|
||||
if (v3Global.opt.threads()) { // THREADED-TODO move to end of all trains on thread
|
||||
puts("Verilated::endOfThreadTrain(vlSymsp->__Vm_evalMsgQp);\n");
|
||||
}
|
||||
if (v3Global.opt.threads()) {
|
||||
puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
|
||||
}
|
||||
puts("}\n");
|
||||
splitSizeInc(10);
|
||||
|
||||
@@ -1766,7 +1789,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
||||
puts( "_eval(vlSymsp);\n");
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "if (VL_UNLIKELY(++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
|
||||
+")) vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't DC converge\");\n");
|
||||
+")) VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Verilated model didn't DC converge\");\n");
|
||||
puts( "}\n");
|
||||
puts("}\n");
|
||||
splitSizeInc(10);
|
||||
@@ -1842,9 +1865,11 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
|
||||
AstCFunc* funcp = *it;
|
||||
if (!funcp->dpiImport()) { // DPI is prototyped in __Dpi.h
|
||||
ofp()->putsPrivate(funcp->declPrivate());
|
||||
if (funcp->ifdef()!="") puts("#ifdef "+funcp->ifdef()+"\n");
|
||||
if (funcp->isStatic()) puts("static ");
|
||||
puts(funcp->rtnTypeVoid()); puts(" ");
|
||||
puts(funcp->name()); puts("("+cFuncArgs(funcp)+");\n");
|
||||
if (funcp->ifdef()!="") puts("#endif // "+funcp->ifdef()+"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1880,9 +1905,14 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
|
||||
// Declare foreign instances up front to make C++ happy
|
||||
puts("class "+symClassName()+";\n");
|
||||
vl_unordered_set<string> didClassName;
|
||||
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstCell* cellp=nodep->castCell()) {
|
||||
puts("class "+modClassName(cellp->modp())+";\n");
|
||||
string className = modClassName(cellp->modp());
|
||||
if (didClassName.find(className)==didClassName.end()) {
|
||||
puts("class "+className+";\n");
|
||||
didClassName.insert(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.trace()) {
|
||||
@@ -1904,7 +1934,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
bool did = false;
|
||||
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstCell* cellp=nodep->castCell()) {
|
||||
if (!did++) {
|
||||
if (!did) {
|
||||
did = true;
|
||||
putsDecoration("// CELLS\n");
|
||||
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");
|
||||
@@ -2044,8 +2075,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
|
||||
// Save/restore
|
||||
if (v3Global.opt.savable() && modp->isTop()) {
|
||||
puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, "+modClassName(modp)+"& rhs) { rhs.__Vserialize(os); return os; }\n");
|
||||
puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, "+modClassName(modp)+"& rhs) { rhs.__Vdeserialize(os); return os; }\n");
|
||||
puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, "+modClassName(modp)+"& rhs) {\n"
|
||||
"Verilated::quiesce(); rhs.__Vserialize(os); return os; }\n");
|
||||
puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, "+modClassName(modp)+"& rhs) {\n"
|
||||
"Verilated::quiesce(); rhs.__Vdeserialize(os); return os; }\n");
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
@@ -2203,7 +2236,7 @@ class EmitCTrace : EmitCStmts {
|
||||
putsDecoration("// Callback from vcd->open()\n");
|
||||
puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n");
|
||||
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
|
||||
puts("if (!Verilated::calcUnusedSigs()) vl_fatal(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
|
||||
puts("if (!Verilated::calcUnusedSigs()) VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
|
||||
|
||||
puts("vcdp->scopeEscape(' ');\n");
|
||||
puts("t->traceInitThis (vlSymsp, vcdp, code);\n");
|
||||
|
||||
+9
-3
@@ -329,14 +329,17 @@ void EmitCSyms::emitSymHdr() {
|
||||
{ // Scope names
|
||||
bool did = false;
|
||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||
if (!did++) puts("\n// SCOPE NAMES\n");
|
||||
if (!did) {
|
||||
did = true;
|
||||
puts("\n// SCOPE NAMES\n");
|
||||
}
|
||||
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
|
||||
}
|
||||
}
|
||||
|
||||
puts("\n// CREATORS\n");
|
||||
puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n");
|
||||
puts((string)"~"+symClassName()+"() {};\n");
|
||||
puts((string)"~"+symClassName()+"() {}\n");
|
||||
|
||||
puts("\n// METHODS\n");
|
||||
puts("inline const char* name() { return __Vm_namep; }\n");
|
||||
@@ -432,7 +435,10 @@ void EmitCSyms::emitSymImp() {
|
||||
{ // Setup scope names
|
||||
bool did = false;
|
||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||
if (!did++) puts("// Setup scope names\n");
|
||||
if (!did) {
|
||||
did = true;
|
||||
puts("// Setup scope names\n");
|
||||
}
|
||||
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
|
||||
putsQuoted(it->second.m_prettyName);
|
||||
puts(");\n");
|
||||
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
of.puts("\n### Switches...\n");
|
||||
of.puts("# Coverage output mode? 0/1 (from --coverage)\n");
|
||||
of.puts("VM_COVERAGE = "); of.puts(v3Global.opt.coverage()?"1":"0"); of.puts("\n");
|
||||
of.puts("# Threaded output mode? 0/1/N threads (from --threads)\n");
|
||||
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
|
||||
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
|
||||
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
|
||||
|
||||
|
||||
@@ -493,6 +493,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
puts("]");
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
nodep->fromp()->iterateAndNext(*this);
|
||||
puts(cvtToStr(nodep->declRange()));
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
putfs(nodep,"typedef ");
|
||||
nodep->dtypep()->iterateAndNext(*this); puts(" ");
|
||||
|
||||
+20
-42
@@ -37,8 +37,13 @@
|
||||
// Emit statements and math operators
|
||||
|
||||
class EmitXmlFileVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// AstNode::user1 -> uint64_t, number to connect crossrefs
|
||||
|
||||
// MEMBERS
|
||||
V3OutFile* m_ofp;
|
||||
uint64_t m_id;
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -64,10 +69,21 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
}
|
||||
|
||||
// XML methods
|
||||
void outputId(AstNode* nodep) {
|
||||
if (!nodep->user1()) { nodep->user1(++m_id); }
|
||||
puts("\""+cvtToStr(nodep->user1())+"\"");
|
||||
}
|
||||
void outputTag(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||
puts("<"+tag+" "+nodep->fileline()->xml());
|
||||
if (nodep->castNodeDType()) { puts(" id="); outputId(nodep); }
|
||||
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
|
||||
if (nodep->tag()!="") { puts(" tag="); putsQuoted(nodep->tag()); }
|
||||
if (AstNodeDType* dtp = nodep->castNodeDType()) {
|
||||
if (dtp->subDTypep()) { puts(" sub_dtype_id="); outputId(dtp->subDTypep()->skipRefp()); }
|
||||
} else {
|
||||
if (nodep->dtypep()) { puts(" dtype_id="); outputId(nodep->dtypep()->skipRefp()); }
|
||||
}
|
||||
}
|
||||
void outputChildrenEnd(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||
@@ -110,13 +126,13 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
outputChildrenEnd(nodep, "port");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
outputTag(nodep, "contAssign"); // IEEE: vpiContAssign
|
||||
outputChildrenEnd(nodep, "contAssign");
|
||||
outputTag(nodep, "contassign"); // IEEE: vpiContAssign
|
||||
outputChildrenEnd(nodep, "contassign");
|
||||
}
|
||||
|
||||
// Data types
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
outputTag(nodep, "basicDType ");
|
||||
outputTag(nodep, "basicdtype ");
|
||||
if (nodep->isRanged()) {
|
||||
puts(" left=\""+cvtToStr(nodep->left())+"\"");
|
||||
puts(" right=\""+cvtToStr(nodep->right())+"\"");
|
||||
@@ -132,50 +148,12 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
||||
public:
|
||||
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) {
|
||||
m_ofp = ofp;
|
||||
m_id = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~EmitXmlFileVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Emit to a stream (perhaps stringstream)
|
||||
|
||||
class EmitXmlPrefixedFormatter : public V3OutFormatter {
|
||||
ostream& m_os;
|
||||
string m_prefix; // What to print at beginning of each line
|
||||
int m_flWidth; // Padding of fileline
|
||||
int m_column; // Rough location; need just zero or non-zero
|
||||
FileLine* m_prefixFl;
|
||||
// METHODS
|
||||
virtual void putcOutput(char chr) {
|
||||
if (chr == '\n') {
|
||||
m_column = 0;
|
||||
m_os<<chr;
|
||||
} else {
|
||||
if (m_column == 0) {
|
||||
m_column = 10;
|
||||
m_os<<m_prefixFl->ascii()+":";
|
||||
m_os<<V3OutFile::indentSpaces(m_flWidth-(m_prefixFl->ascii().length()+1));
|
||||
m_os<<" ";
|
||||
m_os<<m_prefix;
|
||||
}
|
||||
m_column++;
|
||||
m_os<<chr;
|
||||
}
|
||||
}
|
||||
public:
|
||||
void prefixFl(FileLine* fl) { m_prefixFl = fl; }
|
||||
FileLine* prefixFl() const { return m_prefixFl; }
|
||||
int column() const { return m_column; }
|
||||
EmitXmlPrefixedFormatter(ostream& os, const string& prefix, int flWidth)
|
||||
: V3OutFormatter("__STREAM", V3OutFormatter::LA_VERILOG)
|
||||
, m_os(os), m_prefix(prefix), m_flWidth(flWidth) {
|
||||
m_column = 0;
|
||||
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
|
||||
}
|
||||
virtual ~EmitXmlPrefixedFormatter() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// EmitXml class functions
|
||||
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ string V3Error::lineStr (const char* filename, int lineno) {
|
||||
const char* fnslashp = strrchr (filename, '/');
|
||||
if (fnslashp) filename = fnslashp+1;
|
||||
out<<filename<<":"<<dec<<lineno<<":";
|
||||
const char* spaces = " ";
|
||||
const char* const spaces = " ";
|
||||
size_t numsp = out.str().length(); if (numsp>20) numsp = 20;
|
||||
out<<(spaces + numsp);
|
||||
return out.str();
|
||||
@@ -215,7 +215,7 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
|
||||
}
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
if (debug()) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final",990));
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",990));
|
||||
if (s_errorExitCb) s_errorExitCb();
|
||||
V3Stats::statsFinalAll(v3Global.rootp());
|
||||
V3Stats::statsReport();
|
||||
|
||||
+10
-5
@@ -48,7 +48,6 @@ public:
|
||||
I_LINT, // All lint messages
|
||||
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
||||
// Error codes:
|
||||
E_BLKLOOPINIT, // Error: Delayed assignment to array inside for loops
|
||||
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
|
||||
E_MULTITOP, // Error: Multiple top level modules
|
||||
E_TASKNSVAR, // Error: Task I/O not simple
|
||||
@@ -60,7 +59,9 @@ public:
|
||||
ASSIGNDLY, // Assignment delays
|
||||
ASSIGNIN, // Assigning to input
|
||||
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
|
||||
BLKLOOPINIT, // Delayed assignment to array inside for loops
|
||||
BLKSEQ, // Blocking assignments in sequential block
|
||||
BSSPACE, // Backslash space
|
||||
CASEINCOMPLETE, // Case statement has missing values
|
||||
CASEOVERLAP, // Case statements overlap
|
||||
CASEWITHX, // Case with X values
|
||||
@@ -68,6 +69,7 @@ public:
|
||||
CDCRSTLOGIC, // Logic in async reset path
|
||||
CLKDATA, // Clock used as data
|
||||
CMPCONST, // Comparison is constant due to limited range
|
||||
COLONPLUS, // :+ instead of +:
|
||||
COMBDLY, // Combinatorial delayed assignment
|
||||
DEFPARAM, // Style: Defparam
|
||||
DECLFILENAME, // Declaration doesn't match filename
|
||||
@@ -121,13 +123,13 @@ public:
|
||||
// Boolean
|
||||
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
||||
// Errors
|
||||
"BLKLOOPINIT", "DETECTARRAY", "MULTITOP", "TASKNSVAR",
|
||||
"DETECTARRAY", "MULTITOP", "TASKNSVAR",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN",
|
||||
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
|
||||
"BLKANDNBLK", "BLKSEQ",
|
||||
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CLKDATA",
|
||||
"CMPCONST", "COMBDLY", "DEFPARAM", "DECLFILENAME",
|
||||
"CMPCONST", "COLONPLUS", "COMBDLY", "DEFPARAM", "DECLFILENAME",
|
||||
"ENDLABEL", "GENCLK",
|
||||
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
|
||||
"INCABSPATH", "INITIALDLY",
|
||||
@@ -150,6 +152,7 @@ public:
|
||||
// Warnings we'll present to the user as errors
|
||||
// Later -Werror- options may make more of these.
|
||||
bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK
|
||||
|| m_e==BLKLOOPINIT
|
||||
|| m_e==IMPURE || m_e==MODDUP); }
|
||||
// Warnings to mention manual
|
||||
bool mentionManual() const { return ( m_e==EC_FATALSRC || m_e==SYMRSVDWORD
|
||||
@@ -157,9 +160,11 @@ public:
|
||||
|
||||
// Warnings that are lint only
|
||||
bool lintError() const { return ( m_e==ALWCOMBORDER
|
||||
|| m_e==BSSPACE
|
||||
|| m_e==CASEINCOMPLETE || m_e==CASEOVERLAP
|
||||
|| m_e==CASEWITHX || m_e==CASEX
|
||||
|| m_e==CMPCONST
|
||||
|| m_e==COLONPLUS
|
||||
|| m_e==ENDLABEL
|
||||
|| m_e==IMPLICIT
|
||||
|| m_e==LITENDIAN
|
||||
@@ -214,7 +219,7 @@ class V3Error {
|
||||
V3Error() { cerr<<("Static class"); abort(); }
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
// ACCESSORS
|
||||
static void debugDefault(int level) { s_debugDefault = level; }
|
||||
static int debugDefault() { return s_debugDefault; }
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ private:
|
||||
}
|
||||
bool expandWide (AstNodeAssign* nodep, AstArraySel* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl);
|
||||
if (rhsp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");
|
||||
if (nodep->dtypep()->skipRefp()->castUnpackArrayDType()) nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone (rhsp, w));
|
||||
}
|
||||
|
||||
+39
-13
@@ -34,6 +34,14 @@
|
||||
# define INFILTER_PIPE // Allow pipe filtering. Needs fork()
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STAT_NSEC // i.e. Linux 2.6, from configure
|
||||
# define VL_STAT_CTIME_NSEC(stat) ((stat).st_ctim.tv_nsec) // Nanoseconds
|
||||
# define VL_STAT_MTIME_NSEC(stat) ((stat).st_mtim.tv_nsec) // Nanoseconds
|
||||
#else
|
||||
# define VL_STAT_CTIME_NSEC(stat) (0)
|
||||
# define VL_STAT_MTIME_NSEC(stat) (0)
|
||||
#endif
|
||||
|
||||
#ifdef INFILTER_PIPE
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
@@ -62,6 +70,7 @@ class V3FileDependImp {
|
||||
public:
|
||||
DependFile(const string& filename, bool target)
|
||||
: m_target(target), m_filename(filename) {
|
||||
m_stat.st_ctime = 0;
|
||||
m_stat.st_mtime = 0;
|
||||
}
|
||||
~DependFile() {}
|
||||
@@ -69,7 +78,10 @@ class V3FileDependImp {
|
||||
bool target() const { return m_target; }
|
||||
off_t size() const { return m_stat.st_size; }
|
||||
ino_t ino() const { return m_stat.st_ino; }
|
||||
time_t mtime() const { return m_stat.st_mtime; }
|
||||
time_t cstime() const { return m_stat.st_ctime; } // Seconds
|
||||
time_t cnstime() const { return VL_STAT_CTIME_NSEC(m_stat); } // Nanoseconds
|
||||
time_t mstime() const { return m_stat.st_mtime; } // Seconds
|
||||
time_t mnstime() const { return VL_STAT_MTIME_NSEC(m_stat); } // Nanoseconds
|
||||
void loadStats() {
|
||||
if (!m_stat.st_mtime) {
|
||||
string fn = filename();
|
||||
@@ -122,7 +134,7 @@ V3FileDependImp dependImp; // Depend implementation class
|
||||
// V3FileDependImp
|
||||
|
||||
inline void V3FileDependImp::writeDepend(const string& filename) {
|
||||
const VL_UNIQUE_PTR<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
const vl_unique_ptr<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
|
||||
for (set<DependFile>::iterator iter=m_filenameList.begin();
|
||||
@@ -158,7 +170,7 @@ inline void V3FileDependImp::writeDepend(const string& filename) {
|
||||
}
|
||||
|
||||
inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) {
|
||||
const VL_UNIQUE_PTR<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
const vl_unique_ptr<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
|
||||
string cmdline = stripQuotes(cmdlineIn);
|
||||
@@ -178,14 +190,17 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
|
||||
*ofp<<(iter->target()?"T":"S")<<" ";
|
||||
*ofp<<" "<<setw(8)<<showSize;
|
||||
*ofp<<" "<<setw(8)<<showIno;
|
||||
*ofp<<" "<<setw(11)<<iter->mtime();
|
||||
*ofp<<" "<<setw(11)<<iter->cstime();
|
||||
*ofp<<" "<<setw(11)<<iter->cnstime();
|
||||
*ofp<<" "<<setw(11)<<iter->mstime();
|
||||
*ofp<<" "<<setw(11)<<iter->mnstime();
|
||||
*ofp<<" \""<<iter->filename()<<"\"";
|
||||
*ofp<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) {
|
||||
const VL_UNIQUE_PTR<ifstream> ifp (V3File::new_ifstream_nodepend(filename));
|
||||
const vl_unique_ptr<ifstream> ifp (V3File::new_ifstream_nodepend(filename));
|
||||
if (ifp->fail()) {
|
||||
UINFO(2," --check-times failed: no input "<<filename<<endl);
|
||||
return false;
|
||||
@@ -209,31 +224,42 @@ inline bool V3FileDependImp::checkTimes(const string& filename, const string& cm
|
||||
off_t chkSize; *ifp>>chkSize;
|
||||
ino_t chkIno; *ifp>>chkIno;
|
||||
if (ifp->eof()) break; // Needed to read final whitespace before found eof
|
||||
time_t chkMtime; *ifp>>chkMtime;
|
||||
time_t chkCstime; *ifp>>chkCstime;
|
||||
time_t chkCnstime; *ifp>>chkCnstime;
|
||||
time_t chkMstime; *ifp>>chkMstime;
|
||||
time_t chkMnstime; *ifp>>chkMnstime;
|
||||
char quote; *ifp>>quote;
|
||||
string chkFilename; getline(*ifp, chkFilename, '"');
|
||||
//UINFO(9," got d="<<chkDir<<" s="<<chkSize<<" mt="<<chkMtime<<" fn = "<<chkFilename<<endl);
|
||||
|
||||
V3Options::fileNfsFlush(chkFilename);
|
||||
struct stat chkStat;
|
||||
int err = stat(chkFilename.c_str(), &chkStat);
|
||||
if (err!=0) {
|
||||
UINFO(2," --check-times failed: missing "<<chkFilename<<endl);
|
||||
return false;
|
||||
}
|
||||
if (filename != chkFilename) { // See above; we were writing it at the time...
|
||||
//UINFO(9," got d="<<chkDir<<" s="<<chkSize<<" ct="<<chkCstime<<"."<<chkCnstime<<" mt="<<chkMstime<<"."<<chkMnstime<<" fn = "<<chkFilename<<endl);
|
||||
//UINFO(9," nowSt s="<<chkStat.st_size<<" mt="<<chkStat.st_mtime<<" ct="<<chkStat.st_ctime<<" fn = "<<chkFilename<<endl);
|
||||
if (filename != chkFilename) { // Other then the .dat file itself, as we were writing it at the time...
|
||||
// We'd like this rule:
|
||||
//if (!(chkStat.st_size == chkSize
|
||||
// && chkStat.st_mtime == chkMtime) {
|
||||
// && chkStat.st_mtime == chkMstime) {
|
||||
// However NFS messes us up, as there might be some data outstanding when
|
||||
// we determined the original size. For safety, we know the creation time
|
||||
// must be within a few second window... call it 20 sec.
|
||||
if (!(chkStat.st_size >= chkSize
|
||||
&& chkStat.st_ino == chkIno
|
||||
&& chkStat.st_mtime >= chkMtime
|
||||
&& chkStat.st_mtime <= (chkMtime + 20))) {
|
||||
&& chkStat.st_ctime == chkCstime
|
||||
&& VL_STAT_CTIME_NSEC(chkStat) == chkCnstime
|
||||
&& chkStat.st_mtime <= (chkMstime + 20)
|
||||
// Not comparing chkMnstime
|
||||
)) {
|
||||
UINFO(2," --check-times failed: out-of-date "<<chkFilename
|
||||
<<"; "<<chkStat.st_size<<"=?"<<chkSize
|
||||
<<" "<<chkStat.st_mtime<<"=?"<<chkMtime<<endl);
|
||||
<<" "<<chkStat.st_ctime<<"."<<VL_STAT_CTIME_NSEC(chkStat)
|
||||
<<"=?"<<chkCstime<<"."<<chkCnstime
|
||||
<<" "<<chkStat.st_mtime<<"."<<VL_STAT_MTIME_NSEC(chkStat)
|
||||
<<"=?"<<chkMstime<<"."<<chkMnstime<<endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -565,7 +591,7 @@ const char* V3OutFormatter::indentStr(int num) {
|
||||
static char str[MAXSPACE+20];
|
||||
char* cp = str;
|
||||
if (num>MAXSPACE) num=MAXSPACE;
|
||||
if (m_lang!=LA_VERILOG) { // verilogPrefixedTree doesn't want tabs
|
||||
if (m_lang!=LA_VERILOG && m_lang!=LA_XML) { // verilogPrefixedTree doesn't want tabs
|
||||
while (num>=8) {
|
||||
*cp++ = '\t';
|
||||
num -= 8;
|
||||
|
||||
+9
-6
@@ -76,19 +76,22 @@ public:
|
||||
class V3InFilterImp;
|
||||
|
||||
class V3InFilter {
|
||||
V3InFilterImp* m_impp;
|
||||
V3InFilter(const V3InFilter&); ///< N/A, no copy constructor
|
||||
public:
|
||||
// TYPES
|
||||
typedef list<string> StrList;
|
||||
|
||||
private:
|
||||
V3InFilterImp* m_impp;
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(V3InFilter);
|
||||
public:
|
||||
explicit V3InFilter(const string& command);
|
||||
~V3InFilter();
|
||||
|
||||
// METHODS
|
||||
// Read file contents and return it. Return true on success.
|
||||
bool readWholefile(const string& filename, StrList& outl);
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit V3InFilter(const string& command);
|
||||
~V3InFilter();
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
+5
-2
@@ -18,10 +18,13 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
@@ -254,7 +257,7 @@ string FileLine::warnMore() const {
|
||||
}
|
||||
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
typedef set<FileLine*> FileLineCheckSet;
|
||||
typedef vl_unordered_set<FileLine*> FileLineCheckSet;
|
||||
FileLineCheckSet fileLineLeakChecks;
|
||||
|
||||
void* FileLine::operator new(size_t size) {
|
||||
|
||||
+5
-1
@@ -35,6 +35,7 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Gate.h"
|
||||
@@ -668,7 +669,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
||||
bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp, const GateOkVisitor& okVisitor) {
|
||||
// Return true if can optimize
|
||||
// Return false if the consuming logic has an output signal that the replacement logic has as an input
|
||||
typedef set<AstVarScope*> VarScopeSet;
|
||||
typedef vl_unordered_set<AstVarScope*> VarScopeSet;
|
||||
// Use map to find duplicates between two lists
|
||||
VarScopeSet varscopes;
|
||||
// Replacement logic usually has shorter input list, so faster to build list based on it
|
||||
@@ -864,6 +865,9 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode*
|
||||
// optimizing away this assignment, etc.
|
||||
consumerp = V3Const::constifyEdit(consumerp);
|
||||
if (debug()>=5) consumerp->dumpTree(cout,"\telimUseDne: ");
|
||||
// Some previous input edges may have disappeared, perhaps all of them.
|
||||
// If we remove the edges we can further optimize
|
||||
// See e.g t_var_overzero.v.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-8
@@ -149,9 +149,10 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
AstNodeAssign* m_assignp; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
AstCFunc* m_tracingCallp; // Currently tracing a call to this cfunc
|
||||
AstNodeAssign* m_assignp; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
@@ -173,8 +174,20 @@ private:
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Enter the function and trace it
|
||||
|
||||
m_tracingCallp = nodep->funcp();
|
||||
nodep->funcp()->accept(*this);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
if (m_tracingCallp != nodep) {
|
||||
// Only consider logic within a CFunc when looking
|
||||
// at the call to it, and not when scanning whatever
|
||||
// scope it happens to live beneath.
|
||||
return;
|
||||
}
|
||||
m_tracingCallp = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
//----
|
||||
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
@@ -213,11 +226,12 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit GenClkReadVisitor(AstNetlist* nodep) {
|
||||
m_activep = NULL;
|
||||
m_assignp = NULL;
|
||||
m_topModp = NULL;
|
||||
nodep->accept(*this);
|
||||
explicit GenClkReadVisitor(AstNetlist* nodep)
|
||||
: m_activep(NULL)
|
||||
, m_tracingCallp(NULL)
|
||||
, m_assignp(NULL)
|
||||
, m_topModp(NULL) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~GenClkReadVisitor() {}
|
||||
};
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public:
|
||||
V3Options opt; // All options; let user see them directly
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
// CONSTRUCTORS
|
||||
V3Global() {
|
||||
m_debugFileNumber = 0;
|
||||
m_widthMinUsage = VWidthMinUsage::LINT_WIDTH;
|
||||
|
||||
+6
-6
@@ -121,7 +121,7 @@ uint32_t V3GraphVertex::outHash() const {
|
||||
ostream& operator<<(ostream& os, V3GraphVertex* vertexp) {
|
||||
os<<" VERTEX="<<vertexp->name();
|
||||
if (vertexp->rank()) os<<" r"<<vertexp->rank();
|
||||
if (vertexp->fanout()) os<<" f"<<vertexp->fanout();
|
||||
if (vertexp->fanout()!=0.0) os<<" f"<<vertexp->fanout();
|
||||
if (vertexp->color()) os<<" c"<<vertexp->color();
|
||||
return os;
|
||||
}
|
||||
@@ -274,21 +274,21 @@ void V3Graph::dumpEdge(ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep)
|
||||
}
|
||||
}
|
||||
|
||||
void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) {
|
||||
void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) const {
|
||||
if (v3Global.opt.dumpTree()) {
|
||||
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
|
||||
}
|
||||
}
|
||||
|
||||
//! Variant of dumpDotFilePrefixed without --dump option check
|
||||
void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) {
|
||||
void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) const {
|
||||
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
|
||||
}
|
||||
|
||||
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) {
|
||||
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
||||
// This generates a file used by graphviz, http://www.graphviz.org
|
||||
// "hardcoded" parameters:
|
||||
const VL_UNIQUE_PTR<ofstream> logp (V3File::new_ofstream(filename));
|
||||
const vl_unique_ptr<ofstream> logp (V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
|
||||
// Header
|
||||
@@ -327,7 +327,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) {
|
||||
<<"\t[fontsize=8 "
|
||||
<<"label=\""<<(vertexp->name()!="" ? vertexp->name() : "\\N");
|
||||
if (vertexp->rank()) *logp<<" r"<<vertexp->rank();
|
||||
if (vertexp->fanout()) *logp<<" f"<<vertexp->fanout();
|
||||
if (vertexp->fanout()!=0.0) *logp<<" f"<<vertexp->fanout();
|
||||
if (vertexp->color()) *logp<<"\\n c"<<vertexp->color();
|
||||
*logp<<"\"";
|
||||
*logp<<", color="<<vertexp->dotColor();
|
||||
|
||||
+6
-5
@@ -65,7 +65,7 @@ public:
|
||||
V3Graph();
|
||||
virtual ~V3Graph();
|
||||
static void debug(int level) { s_debug = level; }
|
||||
virtual string dotRankDir() { return "TB"; } // rankdir for dot plotting
|
||||
virtual string dotRankDir() const { return "TB"; } // rankdir for dot plotting
|
||||
|
||||
// METHODS
|
||||
void clear(); // Empty it of all vertices/edges, as if making a new object
|
||||
@@ -127,12 +127,12 @@ public:
|
||||
|
||||
/// Debugging
|
||||
void dump(ostream& os=cout);
|
||||
void dumpDotFile(const string& filename, bool colorAsSubgraph);
|
||||
void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph=false);
|
||||
void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph=false);
|
||||
void dumpDotFile(const string& filename, bool colorAsSubgraph) const;
|
||||
void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph=false) const;
|
||||
void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph=false) const;
|
||||
void userClearVertices();
|
||||
void userClearEdges();
|
||||
static void test();
|
||||
static void selfTest();
|
||||
|
||||
// CALLBACKS
|
||||
virtual void loopsMessageCb(V3GraphVertex* vertexp) { v3fatalSrc("Loops detected in graph: "<<vertexp); }
|
||||
@@ -181,6 +181,7 @@ public:
|
||||
virtual string dotShape() const { return ""; }
|
||||
virtual string dotStyle() const { return ""; }
|
||||
virtual string dotName() const { return ""; }
|
||||
virtual uint32_t rankAdder() const { return 1; }
|
||||
virtual int sortCmp(const V3GraphVertex* rhsp) const {
|
||||
// LHS goes first if of lower rank, or lower fanout
|
||||
if (m_rank < rhsp->m_rank) return -1;
|
||||
|
||||
+1
-1
@@ -300,7 +300,7 @@ private:
|
||||
vertexp->rank(currentRank);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
vertexIterate(edgep->top(),currentRank+1);
|
||||
vertexIterate(edgep->top(), currentRank + vertexp->rankAdder());
|
||||
}
|
||||
}
|
||||
vertexp->user(2);
|
||||
|
||||
+1
-1
@@ -351,7 +351,7 @@ void V3GraphTestImport::dotImport() {
|
||||
|
||||
//======================================================================
|
||||
|
||||
void V3Graph::test() {
|
||||
void V3Graph::selfTest() {
|
||||
// Execute all of the tests
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{ V3GraphTestStrong test; test.run(); }
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) {
|
||||
}
|
||||
|
||||
void V3Hashed::dumpFile(const string& filename, bool tree) {
|
||||
const VL_UNIQUE_PTR<ofstream> logp (V3File::new_ofstream(filename));
|
||||
const vl_unique_ptr<ofstream> logp (V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
|
||||
map<int,int> dist;
|
||||
|
||||
+88
-40
@@ -53,22 +53,34 @@ private:
|
||||
// NODE STATE
|
||||
// Output
|
||||
// AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
|
||||
// Entire netlist (can be cleared after this visit completes)
|
||||
// Internal state (can be cleared after this visit completes)
|
||||
// AstNodeModule::user2() // CIL_*. Allowed to automatically inline module
|
||||
// AstNodeModule::user3() // int. Number of cells referencing this module
|
||||
AstUser1InUse m_inuser1;
|
||||
// AstNodeModule::user4() // int. Statements in module
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
|
||||
enum {CIL_NOTHARD=0, // For user2, inline not supported
|
||||
CIL_NOTSOFT, // For user2, don't inline unless user overrides
|
||||
CIL_MAYBE}; // For user2, might inline
|
||||
// For the user2 field:
|
||||
enum {CIL_NOTHARD=0, // Inline not supported
|
||||
CIL_NOTSOFT, // Don't inline unless user overrides
|
||||
CIL_MAYBE, // Might inline
|
||||
CIL_USER}; // Pragma suggests inlining
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Flattened cell's containing module
|
||||
int m_stmtCnt; // Statements in module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
V3Double0 m_statUnsup; // Statistic tracking
|
||||
|
||||
typedef vector<AstNodeModule*> ModVec;
|
||||
ModVec m_allMods; // All modules, in top-down order.
|
||||
|
||||
// Within the context of a given module, LocalInstanceMap maps
|
||||
// from child modules to the count of each child's local instantiations.
|
||||
typedef map<AstNodeModule*, int> LocalInstanceMap;
|
||||
|
||||
// We keep a LocalInstanceMap for each module in the design
|
||||
map<AstNodeModule*, LocalInstanceMap> m_instances;
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
@@ -92,39 +104,23 @@ private:
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_stmtCnt = 0;
|
||||
m_modp = nodep;
|
||||
m_allMods.push_back(nodep);
|
||||
m_modp->user2(CIL_MAYBE);
|
||||
m_modp->user4(0); // statement count
|
||||
if (m_modp->castIface()) {
|
||||
// Inlining an interface means we no longer have a cell handle to resolve to.
|
||||
// If inlining moves post-scope this can perhaps be relaxed.
|
||||
cantInline("modIface",true);
|
||||
}
|
||||
if (m_modp->modPublic()) cantInline("modPublic",false);
|
||||
//
|
||||
|
||||
nodep->iterateChildren(*this);
|
||||
//
|
||||
bool userinline = nodep->user1();
|
||||
int allowed = nodep->user2();
|
||||
int refs = nodep->user3();
|
||||
// Should we automatically inline this module?
|
||||
// inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
|
||||
bool doit = ((allowed == CIL_NOTSOFT || allowed == CIL_MAYBE)
|
||||
&& (userinline
|
||||
|| ((allowed == CIL_MAYBE)
|
||||
&& (refs==1
|
||||
|| m_stmtCnt < INLINE_MODS_SMALLER
|
||||
|| v3Global.opt.inlineMult() < 1
|
||||
|| refs*m_stmtCnt < v3Global.opt.inlineMult()))));
|
||||
// Packages aren't really "under" anything so they confuse this algorithm
|
||||
if (nodep->castPackage()) doit = false;
|
||||
UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
|
||||
<<" "<<nodep<<endl);
|
||||
nodep->user1(doit);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
nodep->modp()->user3Inc();
|
||||
nodep->modp()->user3Inc(); // Inc refs
|
||||
m_instances[m_modp][nodep->modp()]++;
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstPragma* nodep) {
|
||||
@@ -132,8 +128,9 @@ private:
|
||||
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
|
||||
if (!m_modp) {
|
||||
nodep->v3error("Inline pragma not under a module");
|
||||
} else {
|
||||
m_modp->user1(1);
|
||||
} else if (m_modp->user2() == CIL_MAYBE
|
||||
|| m_modp->user2() == CIL_NOTSOFT) {
|
||||
m_modp->user2(CIL_USER);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); // Remove so don't propagate to upper cell...
|
||||
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
|
||||
@@ -156,30 +153,71 @@ private:
|
||||
if (!nodep->packagep()) nodep->taskp(NULL);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
// Nop's to speed up the loop
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
m_stmtCnt++;
|
||||
m_modp->user4Inc(); // statement count
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
// Don't count assignments, as they'll likely flatten out
|
||||
// Still need to iterate though to nullify VarXRefs
|
||||
int oldcnt = m_stmtCnt;
|
||||
int oldcnt = m_modp->user4();
|
||||
nodep->iterateChildren(*this);
|
||||
m_stmtCnt = oldcnt;
|
||||
m_modp->user4(oldcnt);
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
// Build user2, user3, and user4 for all modules.
|
||||
// Also build m_allMods and m_instances.
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
// Iterate through all modules in bottom-up order.
|
||||
// Make a final inlining decision for each.
|
||||
for (ModVec::reverse_iterator it=m_allMods.rbegin(); it!=m_allMods.rend(); ++it) {
|
||||
AstNodeModule* modp = *it;
|
||||
|
||||
// If we're going to inline some modules into this one,
|
||||
// update user4 (statement count) to reflect that:
|
||||
int statements = modp->user4();
|
||||
LocalInstanceMap& localsr = m_instances[modp];
|
||||
for (LocalInstanceMap::iterator it = localsr.begin(); it != localsr.end(); ++it) {
|
||||
AstNodeModule* childp = it->first;
|
||||
if (childp->user1()) { // inlining child
|
||||
statements += (childp->user4() * it->second);
|
||||
}
|
||||
}
|
||||
modp->user4(statements);
|
||||
|
||||
int allowed = modp->user2();
|
||||
int refs = modp->user3();
|
||||
|
||||
// Should we automatically inline this module?
|
||||
// inlineMult = 2000 by default.
|
||||
// If a mod*#refs is < this # nodes, can inline it
|
||||
bool doit = ((allowed == CIL_USER)
|
||||
|| ((allowed == CIL_MAYBE)
|
||||
&& (refs==1
|
||||
|| statements < INLINE_MODS_SMALLER
|
||||
|| v3Global.opt.inlineMult() < 1
|
||||
|| refs*statements < v3Global.opt.inlineMult())));
|
||||
// Packages aren't really "under" anything so they confuse this algorithm
|
||||
if (modp->castPackage()) doit = false;
|
||||
UINFO(4, " Inline="<<doit<<" Possible="<<allowed
|
||||
<<" Refs="<<refs<<" Stmts="<<statements<<" "<<modp<<endl);
|
||||
modp->user1(doit);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
m_stmtCnt++;
|
||||
if (m_modp) {
|
||||
m_modp->user4Inc(); // Inc statement count
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
explicit InlineMarkVisitor(AstNode* nodep) {
|
||||
m_modp = NULL;
|
||||
m_stmtCnt = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~InlineMarkVisitor() {
|
||||
@@ -187,6 +225,7 @@ public:
|
||||
// Done with these, are not outputs
|
||||
AstNode::user2ClearTree();
|
||||
AstNode::user3ClearTree();
|
||||
AstNode::user4ClearTree();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -443,11 +482,13 @@ private:
|
||||
// AstVar::user3() // bool Don't alias the user2, keep it as signal
|
||||
// AstCell::user4 // AstCell* of the created clone
|
||||
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
V3Double0 m_statCells; // Statistic tracking
|
||||
|
||||
static int debug() {
|
||||
@@ -575,8 +616,15 @@ public:
|
||||
|
||||
void V3Inline::inlineAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
InlineMarkVisitor mvisitor (nodep);
|
||||
InlineVisitor visitor (nodep);
|
||||
AstUser1InUse m_inuser1; // output of InlineMarkVisitor,
|
||||
// input to InlineVisitor.
|
||||
{
|
||||
// Scoped to clean up temp userN's
|
||||
InlineMarkVisitor mvisitor (nodep);
|
||||
}
|
||||
{
|
||||
InlineVisitor visitor (nodep);
|
||||
}
|
||||
// Remove all modules that were inlined
|
||||
// V3Dead will also clean them up, but if we have debug on, it's a good
|
||||
// idea to avoid dumping the hugely exploded tree.
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public:
|
||||
_ENUM_END
|
||||
};
|
||||
const char* ascii() const {
|
||||
const char* names[] = {
|
||||
const char* const names[] = {
|
||||
// These must match the `begin_keywords values.
|
||||
" ERROR",
|
||||
"1364-1995",
|
||||
|
||||
+62
-12
@@ -35,6 +35,7 @@
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3LinkCells.h"
|
||||
@@ -53,7 +54,6 @@ public:
|
||||
virtual void loopsMessageCb(V3GraphVertex* vertexp);
|
||||
};
|
||||
|
||||
|
||||
class LinkCellsVertex : public V3GraphVertex {
|
||||
AstNodeModule* m_modp;
|
||||
public:
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
virtual ~LinkCellsVertex() {}
|
||||
AstNodeModule* modp() const { return m_modp; }
|
||||
virtual string name() const { return modp()->name(); }
|
||||
// Recursive modules get space for maximum recursion
|
||||
virtual uint32_t rankAdder() const { return m_modp->recursiveClone() ? (1+v3Global.opt.moduleRecursionDepth()) : 1; }
|
||||
};
|
||||
|
||||
class LibraryVertex : public V3GraphVertex {
|
||||
@@ -74,8 +76,9 @@ public:
|
||||
|
||||
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
|
||||
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
|
||||
vvertexp->modp()->v3error("Recursive module (module instantiates itself): "
|
||||
vvertexp->modp()->v3error("Unsupported: Recursive multiple modules (module instantiates something leading back to itself): "
|
||||
<<vvertexp->modp()->prettyName());
|
||||
vvertexp->modp()->v3error("Note self-recursion (module instantiating itself directly) is supported.");
|
||||
V3Error::abortIfErrors();
|
||||
} else { // Everything should match above, but...
|
||||
v3fatalSrc("Recursive instantiations");
|
||||
@@ -90,10 +93,13 @@ private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNodeModule::user1p() // V3GraphVertex* Vertex describing this module
|
||||
// AstCell::user1() // bool Did it.
|
||||
// AstNodeModule::user2p() // AstNodeModule* clone used for de-recursing
|
||||
// AstCell::user1p() // ==V3NodeModule* if done, != if unprocessed
|
||||
// AstCell::user2() // bool clone renaming completed
|
||||
// Allocated across all readFiles in V3Global::readFiles:
|
||||
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
V3InFilter* m_filterp; // Parser filter
|
||||
@@ -105,7 +111,7 @@ private:
|
||||
LinkCellsGraph m_graph; // Linked graph of all cell interconnects
|
||||
LibraryVertex* m_libVertexp; // Vertex at root of all libraries
|
||||
V3GraphVertex* m_topVertexp; // Vertex of top module
|
||||
set<string> m_declfnWarned; // Files we issued DECLFILENAME on
|
||||
vl_unordered_set<string> m_declfnWarned; // Files we issued DECLFILENAME on
|
||||
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
@@ -188,6 +194,7 @@ private:
|
||||
UINFO(2,"Link Module: "<<nodep<<endl);
|
||||
if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName()
|
||||
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename())
|
||||
&& !nodep->recursiveClone()
|
||||
&& !nodep->internal()) {
|
||||
// We only complain once per file, otherwise library-like files have a huge mess of warnings
|
||||
if (m_declfnWarned.find(nodep->fileline()->filename()) == m_declfnWarned.end()) {
|
||||
@@ -266,16 +273,58 @@ private:
|
||||
|
||||
virtual void visit(AstCell* nodep) {
|
||||
// Cell: Resolve its filename. If necessary, parse it.
|
||||
if (nodep->user1SetOnce()) return; // AstBind and AstNodeModule may call a cell twice
|
||||
if (!nodep->modp()) {
|
||||
// Execute only once. Complication is that cloning may result in user1 being set (for pre-clone)
|
||||
// so check if user1() matches the m_mod, if 0 never did it, if !=, it is an unprocessed clone
|
||||
bool cloned = (nodep->user1p() && nodep->user1p()!=m_modp);
|
||||
if (nodep->user1p()==m_modp) return; // AstBind and AstNodeModule may call a cell twice
|
||||
nodep->user1p(m_modp);
|
||||
//
|
||||
if (!nodep->modp() || cloned) {
|
||||
UINFO(4,"Link Cell: "<<nodep<<endl);
|
||||
// Use findIdFallback instead of findIdFlat; it doesn't matter for now
|
||||
// but we might support modules-under-modules someday.
|
||||
AstNodeModule* modp = resolveModule(nodep,nodep->modName());
|
||||
if (modp) {
|
||||
nodep->modp(modp);
|
||||
// Track module depths, so can sort list from parent down to children
|
||||
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
|
||||
AstNodeModule* cellmodp = resolveModule(nodep, nodep->modName());
|
||||
if (cellmodp) {
|
||||
if (cellmodp == m_modp
|
||||
|| cellmodp->user2p() == m_modp) {
|
||||
UINFO(1,"Self-recursive module "<<cellmodp<<endl);
|
||||
cellmodp->recursive(true);
|
||||
nodep->recursive(true);
|
||||
if (!cellmodp->recursiveClone()) {
|
||||
// In the non-Vrcm, which needs to point to Vrcm flavor
|
||||
//
|
||||
// Make a clone which this cell points to
|
||||
// Later, the clone's cells will also point clone'd name
|
||||
// This lets us link the XREFs between the (uncloned) children so
|
||||
// they don't point to the same module which would
|
||||
// break parameter resolution.
|
||||
AstNodeModule* otherModp = cellmodp->user2p()->castNodeModule();
|
||||
if (!otherModp) {
|
||||
otherModp = cellmodp->cloneTree(false);
|
||||
otherModp->name(otherModp->name()+"__Vrcm");
|
||||
otherModp->user1p(NULL); // Need new vertex
|
||||
otherModp->user2p(cellmodp);
|
||||
otherModp->recursiveClone(true);
|
||||
// user1 etc will retain its pre-clone value
|
||||
cellmodp->user2p(otherModp);
|
||||
v3Global.rootp()->addModulep(otherModp);
|
||||
new V3GraphEdge(&m_graph, vertex(cellmodp), vertex(otherModp), 1, false);
|
||||
}
|
||||
cellmodp = otherModp;
|
||||
nodep->modp(cellmodp);
|
||||
}
|
||||
else {
|
||||
// In the Vrcm, which needs to point back to Vrcm flavor
|
||||
// The cell already has the correct resolution (to Vrcm)
|
||||
nodep->modp(cellmodp);
|
||||
// We don't create a V3GraphEdge (as it would be circular)
|
||||
}
|
||||
}
|
||||
else { // Non-recursive
|
||||
// Track module depths, so can sort list from parent down to children
|
||||
nodep->modp(cellmodp);
|
||||
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(cellmodp), 1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove AstCell(AstPin("",NULL)), it's a side effect of how we parse "()"
|
||||
@@ -310,8 +359,9 @@ private:
|
||||
if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum()));
|
||||
}
|
||||
if (nodep->modp()) {
|
||||
nodep->modName(nodep->modp()->name());
|
||||
// Note what pins exist
|
||||
set<string> ports; // Symbol table of all connected port names
|
||||
vl_unordered_set<string> ports; // Symbol table of all connected port names
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
||||
if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
|
||||
if (!pinp->exprp()) {
|
||||
|
||||
+46
-16
@@ -87,6 +87,7 @@ private:
|
||||
// NODE STATE
|
||||
// Cleared on Netlist
|
||||
// AstNodeModule::user1p() // VSymEnt*. Last symbol created for this node
|
||||
// AstNodeModule::user2() // bool. Currently processing for recursion check
|
||||
// ... Note maybe more than one, as can be multiple hierarchy places
|
||||
// AstVarScope::user2p() // AstVarScope*. Base alias for AstInline of this signal
|
||||
// AstVar::user2p() // AstFTask*. If a function variable, the task that links to the variable
|
||||
@@ -134,7 +135,7 @@ public:
|
||||
void dump(const string& nameComment="linkdot", bool force=false) {
|
||||
if (debug()>=6 || force) {
|
||||
string filename = v3Global.debugFilename(nameComment)+".txt";
|
||||
const VL_UNIQUE_PTR<ofstream> logp (V3File::new_ofstream(filename));
|
||||
const vl_unique_ptr<ofstream> logp (V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
ostream& os = *logp;
|
||||
m_syms.dump(os);
|
||||
@@ -161,7 +162,7 @@ public:
|
||||
if (!diddump && v3Global.opt.dumpTree()) {
|
||||
diddump = true;
|
||||
dump("linkdot-preerr",true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr"));
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,6 +596,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
AstBegin* m_beginp; // Current Begin/end block
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
bool m_inGenerate; // Inside a generate
|
||||
bool m_inRecursion; // Inside a recursive module
|
||||
int m_paramNum; // Parameter number, for position based connection
|
||||
int m_beginNum; // Begin block number, 0=none seen
|
||||
int m_modBeginNum; // Begin block number in module, 0=none seen
|
||||
@@ -682,8 +684,11 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
int oldParamNum = m_paramNum;
|
||||
int oldBeginNum = m_beginNum;
|
||||
int oldModBeginNum = m_modBeginNum;
|
||||
if (doit) {
|
||||
UINFO(2," Link Module: "<<nodep<<endl);
|
||||
if (doit && nodep->user2()) {
|
||||
nodep->v3error("Unsupported: Identically recursive module (module instantiates itself, without changing parameters): "
|
||||
<<AstNode::prettyName(nodep->origName()));
|
||||
} else if (doit) {
|
||||
UINFO(4," Link Module: "<<nodep<<endl);
|
||||
if (nodep->dead()) nodep->v3fatalSrc("Module in cell tree mislabeled as dead?");
|
||||
VSymEnt* upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp();
|
||||
m_packagep = nodep->castPackage();
|
||||
@@ -703,7 +708,9 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
m_modBeginNum = 0;
|
||||
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
|
||||
// Iterate
|
||||
nodep->user2(true);
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user2(false);
|
||||
nodep->user4(true);
|
||||
// Interfaces need another pass when signals are resolved
|
||||
if (AstIface* ifacep = nodep->castIface()) {
|
||||
@@ -730,6 +737,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
virtual void visit(AstCell* nodep) {
|
||||
UINFO(5," CELL under "<<m_scope<<" is "<<nodep<<endl);
|
||||
// Process XREFs/etc inside pins
|
||||
if (nodep->recursive() && m_inRecursion) return;
|
||||
nodep->iterateChildren(*this);
|
||||
// Recurse in, preserving state
|
||||
string oldscope = m_scope;
|
||||
@@ -737,6 +745,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
VSymEnt* oldModSymp = m_modSymp;
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
int oldParamNum = m_paramNum;
|
||||
bool oldRecursion = m_inRecursion;
|
||||
// Where do we add it?
|
||||
VSymEnt* aboveSymp = m_curSymp;
|
||||
string origname = AstNode::dedotName(nodep->name());
|
||||
@@ -755,6 +764,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
m_scope = m_scope+"."+nodep->name();
|
||||
m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope);
|
||||
m_beginp = NULL;
|
||||
m_inRecursion = nodep->recursive();
|
||||
// We don't report NotFoundModule, as may be a unused module in a generate
|
||||
if (nodep->modp()) nodep->modp()->accept(*this);
|
||||
}
|
||||
@@ -763,6 +773,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
m_modSymp = oldModSymp;
|
||||
m_curSymp = oldCurSymp;
|
||||
m_paramNum = oldParamNum;
|
||||
m_inRecursion = oldRecursion;
|
||||
}
|
||||
virtual void visit(AstCellInline* nodep) {
|
||||
UINFO(5," CELLINLINE under "<<m_scope<<" is "<<nodep<<endl);
|
||||
@@ -1005,7 +1016,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPackageImport* nodep) {
|
||||
UINFO(2," Link: "<<nodep<<endl);
|
||||
UINFO(4," Link: "<<nodep<<endl);
|
||||
VSymEnt* srcp = m_statep->getNodeSym(nodep->packagep());
|
||||
if (nodep->name()!="*") {
|
||||
VSymEnt* impp = srcp->findIdFlat(nodep->name());
|
||||
@@ -1031,7 +1042,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
||||
}
|
||||
virtual void visit(AstPackageExportStarStar* nodep) {
|
||||
UINFO(2," Link: "<<nodep<<endl);
|
||||
UINFO(4," Link: "<<nodep<<endl);
|
||||
m_curSymp->exportStarStar(m_statep->symsp());
|
||||
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
||||
}
|
||||
@@ -1051,6 +1062,7 @@ public:
|
||||
m_beginp = NULL;
|
||||
m_ftaskp = NULL;
|
||||
m_inGenerate = false;
|
||||
m_inRecursion = false;
|
||||
m_paramNum = 0;
|
||||
m_beginNum = 0;
|
||||
m_modBeginNum = 0;
|
||||
@@ -1394,9 +1406,10 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
||||
if (!symp) {
|
||||
nodep->v3error("Modport item not found: "<<nodep->prettyName());
|
||||
} else if (AstVar* varp = symp->nodep()->castVar()) {
|
||||
// Make symbol under modport that points at the _interface_'s var, not the modport.
|
||||
// Make symbol under modport that points at the _interface_'s var via the modport.
|
||||
// (Need modport still to test input/output markings)
|
||||
nodep->varp(varp);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), varp, NULL/*package*/);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), nodep, NULL/*package*/);
|
||||
} else if (AstVarScope* vscp = symp->nodep()->castVarScope()) {
|
||||
// Make symbol under modport that points at the _interface_'s var, not the modport.
|
||||
nodep->varp(vscp->varp());
|
||||
@@ -1482,7 +1495,7 @@ private:
|
||||
m_unresolved = false; m_unlinkedScope = NULL;
|
||||
}
|
||||
string ascii() const {
|
||||
static const char* names[] = { "NONE","PACKAGE","SCOPE","FINAL","MEMBER" };
|
||||
static const char* const names[] = { "NONE","PACKAGE","SCOPE","FINAL","MEMBER" };
|
||||
ostringstream sstr;
|
||||
sstr<<"ds="<<names[m_dotPos];
|
||||
sstr<<" dse"<<(void*)m_dotSymp;
|
||||
@@ -1514,6 +1527,23 @@ private:
|
||||
m_statep->insertSym(moduleSymp, newp->name(), newp, NULL/*packagep*/);
|
||||
}
|
||||
}
|
||||
AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, bool lvalue) {
|
||||
// Return a variable if possible, auto converting a modport to variable
|
||||
if (!symp) {
|
||||
return NULL;
|
||||
} else if (symp->nodep()->castVar()) {
|
||||
return symp->nodep()->castVar();
|
||||
} else if (symp->nodep()->castModportVarRef()) {
|
||||
AstModportVarRef* snodep = symp->nodep()->castModportVarRef();
|
||||
AstVar* varp = snodep->varp();
|
||||
if (lvalue && snodep->isInput()) {
|
||||
nodep->v3error("Attempt to drive input-only modport: "<<nodep->prettyName());
|
||||
} // else other simulators don't warn about reading, and IEEE doesn't say illegal
|
||||
return varp;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
void taskFuncSwapCheck(AstNodeFTaskRef* nodep) {
|
||||
if (nodep->taskp() && nodep->taskp()->castTask()
|
||||
&& nodep->castFuncRef()) nodep->v3error("Illegal call of a task as a function: "<<nodep->prettyName());
|
||||
@@ -1805,7 +1835,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (AstVar* varp = foundp->nodep()->castVar()) {
|
||||
else if (AstVar* varp = foundToVarp(foundp, nodep, false)) {
|
||||
AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(varp->subDTypep());
|
||||
if (ifacerefp) {
|
||||
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
|
||||
@@ -1926,7 +1956,7 @@ private:
|
||||
UINFO(9," linkVarRef se"<<(void*)m_curSymp<<" n="<<nodep<<endl);
|
||||
if (!m_curSymp) nodep->v3fatalSrc("NULL lookup symbol table");
|
||||
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
|
||||
if (AstVar* varp = foundp ? foundp->nodep()->castVar() : NULL) {
|
||||
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : NULL) {
|
||||
nodep->varp(varp);
|
||||
nodep->packagep(foundp->packagep()); // Generally set by parse, but might be an import
|
||||
}
|
||||
@@ -1960,7 +1990,7 @@ private:
|
||||
dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
AstVar* varp = foundp ? foundp->nodep()->castVar() : NULL;
|
||||
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : NULL;
|
||||
nodep->varp(varp);
|
||||
UINFO(7," Resolved "<<nodep<<endl); // Also prints varp
|
||||
if (!nodep->varp()) {
|
||||
@@ -2286,21 +2316,21 @@ public:
|
||||
int V3LinkDot::debug() { return LinkDotState::debug(); }
|
||||
|
||||
void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
||||
LinkDotState state (rootp, step);
|
||||
LinkDotFindVisitor visitor(rootp,&state);
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree"));
|
||||
if (step == LDS_PRIMARY || step == LDS_PARAMED) {
|
||||
// Initial link stage, resolve parameters
|
||||
LinkDotParamVisitor visitors(rootp,&state);
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
|
||||
}
|
||||
else if (step == LDS_ARRAYED) {}
|
||||
else if (step == LDS_SCOPED) {
|
||||
// Well after the initial link when we're ready to operate on the flat design,
|
||||
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
|
||||
LinkDotScopeVisitor visitors(rootp,&state);
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
|
||||
}
|
||||
else v3fatalSrc("Bad case");
|
||||
state.dump();
|
||||
|
||||
+1
-1
@@ -336,7 +336,7 @@ private:
|
||||
AstNode* lastVarsp = firstVarsp;
|
||||
while (lastVarsp->nextp()) { lastVarsp = lastVarsp->nextp(); dimension++; }
|
||||
for (AstNode* varsp = lastVarsp; varsp; varsp=varsp->backp()) {
|
||||
UINFO(0,"foreachVar "<<varsp<<endl);
|
||||
UINFO(9,"foreachVar "<<varsp<<endl);
|
||||
FileLine* fl = varsp->fileline();
|
||||
AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP,
|
||||
varsp->name(), nodep->findSigned32DType());
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@
|
||||
// VAR(BLOCKTEMP...
|
||||
// if only referenced in a CFUNC, make it local to that CFUNC
|
||||
// VAR(others
|
||||
// if non-public, set before used, and in signle CFUNC, make it local
|
||||
// if non-public, set before used, and in single CFUNC, make it local
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
VarFlags flags (nodep->varp());
|
||||
if (flags.m_done) {
|
||||
nodep->hiername(""); // Remove thisp->
|
||||
nodep->hiername(""); // Remove this->
|
||||
nodep->hierThis(true);
|
||||
}
|
||||
}
|
||||
|
||||
+46
-5
@@ -410,6 +410,18 @@ V3LangCode V3Options::fileLanguage(const string &filename) {
|
||||
//######################################################################
|
||||
// Environment
|
||||
|
||||
string V3Options::getenvBuiltins(const string& var) {
|
||||
if (var == "PERL") return getenvPERL();
|
||||
else if (var == "SYSTEMC") return getenvSYSTEMC();
|
||||
else if (var == "SYSTEMC_ARCH") return getenvSYSTEMC_ARCH();
|
||||
else if (var == "SYSTEMC_INCLUDE") return getenvSYSTEMC_INCLUDE();
|
||||
else if (var == "SYSTEMC_LIBDIR") return getenvSYSTEMC_LIBDIR();
|
||||
else if (var == "VERILATOR_ROOT") return getenvVERILATOR_ROOT();
|
||||
else {
|
||||
return V3Os::getenvStr(var,"");
|
||||
}
|
||||
}
|
||||
|
||||
string V3Options::getenvPERL() {
|
||||
return V3Os::getenvStr("PERL","perl");
|
||||
}
|
||||
@@ -665,8 +677,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
|
||||
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
|
||||
else if ( !strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); }
|
||||
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/) ) { m_reportUnoptflat = flag; }
|
||||
else if ( onoff (sw, "-relative-cfuncs", flag/*ref*/) ) { m_relativeCFuncs = flag; }
|
||||
else if ( onoff (sw, "-relative-includes", flag/*ref*/) ) { m_relativeIncludes = flag; }
|
||||
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/) ) { m_reportUnoptflat = flag; }
|
||||
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
|
||||
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; }
|
||||
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
|
||||
@@ -762,6 +775,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( !strncmp (sw, "-G", strlen("-G"))) {
|
||||
addParameter(string (sw+strlen("-G")), false);
|
||||
}
|
||||
else if ( !strcmp (sw, "-getenv") && (i+1)<argc ) {
|
||||
shift;
|
||||
cout<<V3Options::getenvBuiltins(argv[i])<<endl;
|
||||
exit(0);
|
||||
}
|
||||
else if ( !strncmp (sw, "-I", 2)) {
|
||||
addIncDirUser(parseFileArg(optdir, string (sw+strlen("-I"))));
|
||||
}
|
||||
@@ -910,8 +928,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
}
|
||||
else {
|
||||
string msg = sw+strlen("-Wwarn-");
|
||||
if (!(FileLine::globalWarnOff(msg, false))) {
|
||||
fl->v3fatal("Unknown warning specified: "<<sw);
|
||||
V3ErrorCode code (msg.c_str());
|
||||
if (code == V3ErrorCode::EC_ERROR) {
|
||||
if (!isFuture(msg)) {
|
||||
fl->v3fatal("Unknown warning specified: "<<sw);
|
||||
}
|
||||
} else {
|
||||
FileLine::globalWarnOff(code, false);
|
||||
V3Error::pretendError(code, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -960,6 +984,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
shift; m_prefix = argv[i];
|
||||
if (m_modPrefix=="") m_modPrefix = m_prefix;
|
||||
}
|
||||
else if ( !strcmp (sw, "-no-threads") ) { m_threads = 0; } // Undocumented until functional
|
||||
else if ( !strcmp (sw, "-threads") && (i+1)<argc ) { // Undocumented until functional
|
||||
shift; m_threads = atoi(argv[i]);
|
||||
if (m_threads < 0) fl->v3fatal("--threads must be >= 0: "<<argv[i]);
|
||||
}
|
||||
else if ( !strcmp (sw, "-top-module") && (i+1)<argc ) {
|
||||
shift; m_topModule = argv[i];
|
||||
}
|
||||
@@ -976,6 +1005,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
fl->v3fatal("Unknown setting for --x-assign: "<<argv[i]);
|
||||
}
|
||||
}
|
||||
else if ( !strcmp (sw, "-x-initial") && (i+1)<argc) {
|
||||
shift;
|
||||
if (!strcmp (argv[i], "0")) { m_xInitial="0"; }
|
||||
else if (!strcmp (argv[i], "fast")) { m_xInitial="fast"; }
|
||||
else if (!strcmp (argv[i], "unique")) { m_xInitial="unique"; }
|
||||
else {
|
||||
fl->v3fatal("Unknown setting for --x-initial: "<<argv[i]);
|
||||
}
|
||||
}
|
||||
else if ( !strcmp (sw, "-y") && (i+1)<argc ) {
|
||||
shift; addIncDirUser (parseFileArg(optdir,string (argv[i])));
|
||||
}
|
||||
@@ -1014,7 +1052,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
|
||||
// Read the specified -f filename and process as arguments
|
||||
UINFO(1,"Reading Options File "<<filename<<endl);
|
||||
|
||||
const VL_UNIQUE_PTR<ifstream> ifp (V3File::new_ifstream(filename));
|
||||
const vl_unique_ptr<ifstream> ifp (V3File::new_ifstream(filename));
|
||||
if (ifp->fail()) {
|
||||
fl->v3error("Cannot open -f command file: "+filename);
|
||||
return;
|
||||
@@ -1177,13 +1215,15 @@ V3Options::V3Options() {
|
||||
m_preprocOnly = false;
|
||||
m_preprocNoLine = false;
|
||||
m_public = false;
|
||||
m_reportUnoptflat = false;
|
||||
m_relativeCFuncs = true;
|
||||
m_relativeIncludes = false;
|
||||
m_reportUnoptflat = false;
|
||||
m_savable = false;
|
||||
m_skipIdentical = true;
|
||||
m_stats = false;
|
||||
m_statsVars = false;
|
||||
m_systemC = false;
|
||||
m_threads = 0;
|
||||
m_trace = false;
|
||||
m_traceDups = false;
|
||||
m_traceParams = true;
|
||||
@@ -1198,6 +1238,7 @@ V3Options::V3Options() {
|
||||
m_dumpTree = 0;
|
||||
m_ifDepth = 0;
|
||||
m_inlineMult = 2000;
|
||||
m_moduleRecursion = 100;
|
||||
m_outputSplit = 0;
|
||||
m_outputSplitCFuncs = 0;
|
||||
m_outputSplitCTrace = 0;
|
||||
|
||||
+12
-5
@@ -36,7 +36,6 @@
|
||||
|
||||
class V3OptionsImp;
|
||||
class FileLine;
|
||||
struct stat;
|
||||
|
||||
typedef vector<string> V3StringList;
|
||||
typedef set<string> V3StringSet;
|
||||
@@ -88,8 +87,9 @@ class V3Options {
|
||||
bool m_pinsUint8; // main switch: --pins-uint8
|
||||
bool m_profileCFuncs;// main switch: --profile-cfuncs
|
||||
bool m_public; // main switch: --public
|
||||
bool m_reportUnoptflat; // main switch: --report-unoptflat
|
||||
bool m_relativeCFuncs; // main switch: --relative-cfuncs
|
||||
bool m_relativeIncludes; // main switch: --relative-includes
|
||||
bool m_reportUnoptflat; // main switch: --report-unoptflat
|
||||
bool m_savable; // main switch: --savable
|
||||
bool m_systemC; // main switch: --sc: System C instead of simple C++
|
||||
bool m_skipIdentical;// main switch: --skip-identical
|
||||
@@ -109,10 +109,12 @@ class V3Options {
|
||||
int m_dumpTree; // main switch: --dump-tree
|
||||
int m_ifDepth; // main switch: --if-depth
|
||||
int m_inlineMult; // main switch: --inline-mult
|
||||
int m_moduleRecursion;// main switch: --module-recursion-depth
|
||||
int m_outputSplit; // main switch: --output-split
|
||||
int m_outputSplitCFuncs;// main switch: --output-split-cfuncs
|
||||
int m_outputSplitCTrace;// main switch: --output-split-ctrace
|
||||
int m_pinsBv; // main switch: --pins-bv
|
||||
int m_threads; // main switch: --threads (0 == --no-threads)
|
||||
int m_traceDepth; // main switch: --trace-depth
|
||||
int m_traceMaxArray;// main switch: --trace-max-array
|
||||
int m_traceMaxWidth;// main switch: --trace-max-width
|
||||
@@ -133,6 +135,7 @@ class V3Options {
|
||||
string m_topModule; // main switch: --top-module
|
||||
string m_unusedRegexp; // main switch: --unused-regexp
|
||||
string m_xAssign; // main switch: --x-assign
|
||||
string m_xInitial; // main switch: --x-initial
|
||||
|
||||
// Language is now held in FileLine, on a per-node basis. However we still
|
||||
// have a concept of the default language at a global level.
|
||||
@@ -178,10 +181,9 @@ class V3Options {
|
||||
bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc);
|
||||
string filePathCheckOneDir(const string& modname, const string& dirname);
|
||||
|
||||
V3Options(const V3Options&); ///< N/A, no copy constructor
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(V3Options);
|
||||
public:
|
||||
// CREATORS
|
||||
V3Options();
|
||||
~V3Options();
|
||||
void setDebugMode(int level);
|
||||
@@ -243,6 +245,7 @@ class V3Options {
|
||||
bool lintOnly() const { return m_lintOnly; }
|
||||
bool ignc() const { return m_ignc; }
|
||||
bool inhibitSim() const { return m_inhibitSim; }
|
||||
bool relativeCFuncs() const { return m_relativeCFuncs; }
|
||||
bool reportUnoptflat() const { return m_reportUnoptflat; }
|
||||
bool vpi() const { return m_vpi; }
|
||||
bool xInitialEdge() const { return m_xInitialEdge; }
|
||||
@@ -252,10 +255,12 @@ class V3Options {
|
||||
int dumpTree() const { return m_dumpTree; }
|
||||
int ifDepth() const { return m_ifDepth; }
|
||||
int inlineMult() const { return m_inlineMult; }
|
||||
int moduleRecursionDepth() const { return m_moduleRecursion; }
|
||||
int outputSplit() const { return m_outputSplit; }
|
||||
int outputSplitCFuncs() const { return m_outputSplitCFuncs; }
|
||||
int outputSplitCTrace() const { return m_outputSplitCTrace; }
|
||||
int pinsBv() const { return m_pinsBv; }
|
||||
int threads() const { return m_threads; }
|
||||
int traceDepth() const { return m_traceDepth; }
|
||||
int traceMaxArray() const { return m_traceMaxArray; }
|
||||
int traceMaxWidth() const { return m_traceMaxWidth; }
|
||||
@@ -274,6 +279,7 @@ class V3Options {
|
||||
string topModule() const { return m_topModule; }
|
||||
string unusedRegexp() const { return m_unusedRegexp; }
|
||||
string xAssign() const { return m_xAssign; }
|
||||
string xInitial() const { return m_xInitial; }
|
||||
|
||||
const V3StringSet& cppFiles() const { return m_cppFiles; }
|
||||
const V3StringList& cFlags() const { return m_cFlags; }
|
||||
@@ -329,6 +335,7 @@ class V3Options {
|
||||
// Most of these may be built into the executable with --enable-defenv,
|
||||
// see the README. If adding new variables, also see src/Makefile_obj.in
|
||||
// Also add to V3Options::showVersion()
|
||||
static string getenvBuiltins(const string& var);
|
||||
static string getenvPERL();
|
||||
static string getenvSYSTEMC();
|
||||
static string getenvSYSTEMC_ARCH();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user