Compare commits

...
119 Commits
Author SHA1 Message Date
Wilson Snyder 0478dbdd1f Version bump 2017-11-25 15:42:11 -05:00
Wilson Snyder 38b0e8a777 Fix some clang-analyzer warnings 2017-11-25 15:41:49 -05:00
Wilson Snyder fe9f1add6f examples: Fix wide signal overflow, and stop on errors. 2017-11-25 15:14:31 -05:00
Wilson Snyder ae9179f412 Fix partial slicing with pattern assignments, bug991. 2017-11-23 14:55:32 -05:00
Wilson Snyder 4c35a76cdb Tests: bug795 2017-11-23 11:38:09 -05:00
Wilson Snyder 8ca3428fb6 Tests: Add split tests, towards bug1244 2017-11-23 11:30:35 -05:00
Wilson Snyder 7369500bb7 Fix cppcheck warnings 2017-11-23 10:43:34 -05:00
Wilson Snyder 45702e319b Support $size/$bits/etc on type references. 2017-11-23 10:17:56 -05:00
Wilson Snyder 813468bfe6 Work around bison 3.0 bug printing wrong debug token names 2017-11-23 09:50:15 -05:00
Wilson Snyder 78192308e1 Tests: Favor make -C over cd+make. No functional change. 2017-11-23 08:56:13 -05:00
John Coiner cb72390b57 Internals: Remove dead loop-related code in V3Order.cpp and V3OrderGraph.h
Signed-off-by: Wilson Snyder <[email protected]>
2017-11-23 08:26:36 -05:00
John Coiner 71b2eeef67 Internals: V3GenClk should scan CFunc internals only at the CCall
Signed-off-by: Wilson Snyder <[email protected]>
2017-11-23 08:21:20 -05:00
Wilson Snyder 57c8590b21 When resolving module names, only use defines if no other choice. 2017-11-22 18:44:19 -05:00
Wilson Snyder f8ad0a0923 Fix false DECLFILENAME on recursive modules. 2017-11-21 22:01:28 -05:00
Wilson Snyder 7c443ab108 Fix error on "unique case" with no cases. 2017-11-21 21:52:37 -05:00
Wilson Snyder 0d645757e7 Less debug verbosity 2017-11-21 21:52:22 -05:00
Wilson Snyder dd37c2ea86 Support $error/$warning in elaboration time blocks. 2017-11-21 21:10:42 -05:00
Wilson Snyder d3032bfc21 Fix flex warning. 2017-11-21 21:10:14 -05:00
Wilson Snyder bd6ecdfa6f Fix mis-showing debug message. 2017-11-21 20:04:29 -05:00
Wilson Snyder 3558e70722 Commentary 2017-11-18 17:52:06 -05:00
Wilson Snyder a579e9273b Support self-recursive modules, bug659. 2017-11-18 17:42:35 -05:00
Wilson Snyder 21369bec95 Internals: Renames in prep for recursion. No functional change. 2017-11-18 17:40:10 -05:00
Wilson Snyder d119d10569 Add BSSPACE and COLONPLUS lint warnings. 2017-11-15 20:19:12 -05:00
Wilson Snyder 38988c005c Fix false unused warning on interfaces, bug1241. 2017-11-14 20:10:25 -05:00
Wilson Snyder 8cc4b588b2 Add error when driving input-only modport. 2017-11-14 19:50:31 -05:00
Wilson Snyder 12607abb33 Remove tabs from --xml output. 2017-11-13 18:24:18 -05:00
Wilson Snyder 562f17ea4b Fix xml tags on typedefs. 2017-11-13 18:04:13 -05:00
Wilson Snyder 0aea9b7709 Update references to coverage.dat, msg2412. 2017-11-13 07:20:36 -05:00
Wilson Snyder c0afe96b80 Fix addition of data types to --xml. 2017-11-09 18:04:16 -05:00
John Coiner 5c919cd0de Fix null dereference crash in width process.
Signed-off-by: Wilson Snyder <[email protected]>
2017-11-09 07:43:30 -05:00
Wilson Snyder f555c93c11 Add data types to --xml. 2017-11-08 21:27:15 -05:00
Wilson Snyder cbb7cd16d0 Detect MSB overflow when under VL_DEBUG, bug1238. 2017-11-05 21:47:55 -05:00
Wilson Snyder 4d074b5414 Commentary 2017-11-05 13:05:50 -05:00
Wilson Snyder dfd22b2b07 Examples: Add +trace flag at runtime 2017-11-05 06:51:29 -05:00
John Coiner 6edaef9598 Internals: Fix debugging with null logicp() graphs.
Signed-off-by: Wilson Snyder <[email protected]>
2017-11-04 18:12:29 -04:00
John Coiner f63e946f04 Internals: Add consts. No functional change.
Signed-off-by: Wilson Snyder <[email protected]>
2017-11-02 18:02:11 -04:00
Wilson Snyder add5cc8b56 Internals: Add VL_UNCOPYABLE to make classes uncopyable. No functional change intended. 2017-11-01 18:51:41 -04:00
John Coiner 2a4e830bee Tests: Fix over sensitive line number.
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-31 21:22:35 -04:00
Wilson Snyder eb87232472 Fix stats critical fast path calculation. 2017-10-30 22:38:47 -04:00
Wilson Snyder 52c3031a82 Internals: Rename selfTest, no functional change. 2017-10-30 19:01:58 -04:00
John Coiner df471e87eb Internals: Break unnecessary dependencies in V3Order.
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-28 13:31:04 -04:00
Wilson Snyder ec6fae5d1a Internals: Add const to same() methods. No functional change. 2017-10-28 10:26:34 -04:00
Wilson Snyder cb422a9a02 Internals: Number astgen from 1 as 0p looks like Op. No functional change. 2017-10-28 08:48:24 -04:00
Wilson Snyder f91bac7b31 Rewrite include libraries to support VL_THREADED towards future threading 2017-10-26 21:51:51 -04:00
Wilson Snyder d542921ff7 Tests: Detect old GCC and skip unsupported tests. 2017-10-26 21:48:45 -04:00
Wilson Snyder ad693d67b2 Mark Verilated functions with multithreaded status. No functional change. 2017-10-26 20:05:42 -04:00
Wilson Snyder 350932e9c0 Fix false failure on clang 3.8 2017-10-26 19:14:05 -04:00
John Coiner 4e98d96755 Internals: Add const's. No functional change intended.
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-26 18:42:50 -04:00
Wilson Snyder c17a9eb5f1 Tests: Fix driver when VERILATOR_ROOT not set. 2017-10-26 07:34:02 -04:00
Wilson Snyder 252ed4c1ae Fix clang warning 2017-10-26 07:27:47 -04:00
Wilson Snyder f9fd634fae Internals: Fix VL_DBG_MSGF va_list corruption in last commit. 2017-10-25 23:01:45 -04:00
Wilson Snyder c17c81254e Internals: Use = delete via a macro for a bit of C++11 forward compatibility 2017-10-25 20:00:38 -04:00
Wilson Snyder 5ead61dc7b Unify format of VL_DEBUG print messages 2017-10-24 22:56:58 -04:00
Wilson Snyder e403db5877 tests: Simplify includes; HARNESS_UPDATE_GOLDEN to whitespace fix 2017-10-24 19:58:52 -04:00
Wilson Snyder 32874fa848 Internals: Misc VCD code cleanups. No functional change. 2017-10-21 17:53:23 -04:00
Wilson Snyder b90f383cfe Add --threads option through to makefiles, unadvertised for now. 2017-10-21 16:41:43 -04:00
Wilson Snyder eb65984368 Tests: Additional display merge tests. No functional change. 2017-10-21 13:50:31 -04:00
Wilson Snyder 10e0d34140 Refactor verilated_vpi.h to move most code to .cpp. No functional change intended. 2017-10-19 21:33:22 -04:00
Wilson Snyder f4b00d3c64 Call VL_PRINTF/vl_stop/vl_finish/vl_fatal through wrappers as hook for future MT use. 2017-10-19 19:40:51 -04:00
Wilson Snyder cc0b780412 Internals: More use of unordered_map/set. No functional change intended. 2017-10-18 18:22:58 -04:00
Wilson Snyder fbbbe4ec87 Commentary 2017-10-18 17:54:39 -04:00
Wilson Snyder 1372d62186 Remove duplicate class forward declarations. 2017-10-18 17:38:10 -04:00
Ahmed El-Mahmoudy a69936de74 Spelling fixes
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-16 21:58:47 -04:00
Wilson Snyder f5dfa1e9c3 Fix MacOS portability, bug1232. 2017-10-15 10:36:50 -04:00
Wilson Snyder 5fb21c2159 devel release 2017-10-14 20:47:25 -04:00
Wilson Snyder 132f61e900 Fix version 2017-10-14 16:20:17 -04:00
Wilson Snyder 0e9be8eea0 Version bump 2017-10-14 16:15:07 -04:00
Wilson Snyder 96f5f66c26 Move generated objects into bin/ to match --prefix installations 2017-10-14 16:09:02 -04:00
Wilson Snyder bbed4d50ab Fix clang and cppcheck warnings. 2017-10-14 14:51:57 -04:00
Wilson Snyder 4b7ee8267b Slicing: Fix off-by-one error earlier this version. 2017-10-14 14:04:15 -04:00
Wilson Snyder f6a745a4c2 Fix clang warnings. 2017-10-14 14:03:12 -04:00
Wilson Snyder a23a5505c4 configure: Check compiler works. 2017-10-14 13:20:58 -04:00
Wilson Snyder 21030f0a4f Internals: C++ style casts. No functional change intended. 2017-10-14 13:00:42 -04:00
Wilson Snyder d21824cbae Internals: Refactor verilated_vcd to move singleton into only .cpp. No functional change intended. 2017-10-14 13:00:25 -04:00
Wilson Snyder 124786ad1b Tests: Require newest compiler with thread test. 2017-10-14 12:57:42 -04:00
Wilson Snyder f81daac9c0 Fix MacOS portability, bug1231. 2017-10-14 12:56:16 -04:00
Wilson Snyder db8e8392fa Fix MacOS portability, bug1230. 2017-10-14 09:00:39 -04:00
Wilson Snyder 5bc2f87d3e Fix --skip-identical to handle closer timestamps looking at ctime. 2017-10-13 20:34:36 -04:00
Wilson Snyder de35c90847 Fix float-conversion warning, bug1229. 2017-10-11 19:01:37 -04:00
Wilson Snyder bc813fddcc tests: Fix examples when VERILATOR_ROOT not set 2017-10-11 19:01:02 -04:00
Wilson Snyder 13c91f5fce Internals: Refactor VerilatorSerialize to remove intermediate class. No functional change intended. 2017-10-11 18:55:31 -04:00
Wilson Snyder ac4690d74b Internals: Add const's. No functional change 2017-10-10 22:22:17 -04:00
Wilson Snyder a1a8f17617 Internals: Add const's. No functional change 2017-10-10 20:24:10 -04:00
Wilson Snyder 12be852a43 Fix ` expansion of defines, bug1227, bug1228. 2017-10-10 18:44:10 -04:00
Wilson Snyder 440fbef79b Untabify examples. No functional change. 2017-10-10 07:18:01 -04:00
Wilson Snyder e1c221a4d5 Tests: Add t_dist_tabs.pl 2017-10-09 22:08:22 -04:00
Wilson Snyder e1f1c82d4e Fix -E duplicating output, bug1226. 2017-10-09 21:08:50 -04:00
Wilson Snyder 3c1b82255e Change VL_THREADED to use C++11, and compute and test related GCC flags automatically 2017-10-07 21:29:57 -04:00
Wilson Snyder 6bd47b54df Tests: Add t_include_all. Fix GCC warning when DPI with VPI. 2017-10-07 21:21:12 -04:00
Wilson Snyder 3261a45ec1 configure: Add new _MY_CXX_CHECK_SET. No functional change. 2017-10-07 15:25:23 -04:00
Wilson Snyder 0ac116bb4e Internals: Favor C++ cast style. No functional change intended. 2017-10-07 15:01:19 -04:00
Wilson Snyder 221e4ff6fe Fix ` expansion of empty defines, bug1225. 2017-10-07 14:09:33 -04:00
Wilson Snyder fe80499f9c Internals: Move preproc DEV expansion when in ifndef, cleanup prep for bug1225. 2017-10-07 14:09:31 -04:00
Wilson Snyder d3d1f3ab60 Internals: Cleanup preproc in prep for bug1225. No functional change. 2017-10-07 14:09:17 -04:00
Chris Randall 264b888ef2 Add /*verilator tag*/ for XML extraction applications.
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-06 07:33:52 -04:00
John Coiner ba270e09a4 Add --no-relative-cfuncs and related default optimization, bug1224.
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-05 18:18:11 -04:00
Wilson Snyder 8281ee1520 Optimize arrayed if assignments 2017-10-04 22:10:44 -04:00
Wilson Snyder 75aab4e9d2 Fix conditional slices and add related optimizations. 2017-10-04 21:27:34 -04:00
Wilson Snyder b532a47e4a Internals: Prep for V3Slice rewrite. No functional change intended. 2017-10-04 21:15:19 -04:00
Wilson Snyder 77a3d683e3 Fix unnecessary Vdly variables, bug1224 partial. 2017-10-03 21:26:42 -04:00
Wilson Snyder c132d0e1fe Fix extra duplicate multiclk blocks when dtypes differ 2017-10-02 22:58:34 -04:00
Wilson Snyder 1a6348f113 Optimize display+display statements. 2017-10-02 20:25:10 -04:00
Wilson Snyder 89ac6ab594 Fix memory leak in VerilatedVcd dumps, bug1222 partial. 2017-10-02 18:49:00 -04:00
Wilson Snyder 3d1012b73b Allow disabling BLKLOOPINIT (Intentionally undocumented), part of last commit 2017-10-01 23:36:19 -04:00
Wilson Snyder c98ad79e68 Allow disabling BLKLOOPINIT (Intentionally undocumented) 2017-10-01 23:23:02 -04:00
Wilson Snyder 82460b0da3 Commentary 2017-10-01 23:06:16 -04:00
Wilson Snyder 0bdc57a14a Fix lost .tree debug file extensions in recent commit. 2017-10-01 22:17:37 -04:00
Wilson Snyder 33780a09df Add --x-initial option 2017-10-01 21:31:40 -04:00
John Coiner a9c9d5ca4b Fix over-aggressive inlining, bug1223.
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-01 18:02:58 -04:00
Wilson Snyder ab07dbdb9d Fix over-aggressive inlining, bug1223. 2017-10-01 18:00:27 -04:00
Wilson Snyder 6dd6750985 Remove empty _configure_coverage in emitted code. 2017-10-01 16:44:53 -04:00
John Coiner 59aa0f43d5 Tests: In t_dist_whitespace, indicate what line has errant whitespace
Signed-off-by: Wilson Snyder <[email protected]>
2017-10-01 16:09:56 -04:00
Wilson Snyder 04ca6a4307 Fix compiler warning when WIDTH warning ignored on large compare. 2017-10-01 10:21:27 -04:00
John Coiner c7cbe11ba4 Fix Ubuntu 17.10 issues, bug1223 partial.
Signed-off-by: Wilson Snyder <[email protected]>
2017-09-30 13:33:14 -04:00
Wilson Snyder 4794093aba Replaced test_c/test_sc with new examples/ directory. 2017-09-23 21:18:07 -04:00
Wilson Snyder 46e300b2c5 Add --getenv option. 2017-09-23 18:03:39 -04:00
Wilson Snyder c693e52f6c Fix false unused warning on line coverage objects 2017-09-23 18:00:44 -04:00
Wilson Snyder 4e2ec09f9a Tests: The internal test_verilated test directory is moved to be part of test_regress. 2017-09-23 10:49:29 -04:00
Wilson Snyder cdbae456d5 devel release 2017-09-23 10:11:06 -04:00
259 changed files with 8152 additions and 3742 deletions
+63
View File
@@ -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;"
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+1 -1
View File
@@ -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.
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+52
View File
@@ -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
+41
View File
@@ -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);
}
+12
View File
@@ -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
+67
View File
@@ -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
+51
View File
@@ -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;
}
+12
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
*.dmp
*.log
*.csrc
*.vcd
obj_*
logs
+96
View File
@@ -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
+55
View File
@@ -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
+2
View File
@@ -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 .
+119
View File
@@ -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);
}
+58
View File
@@ -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
+42
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
*.dmp
*.log
*.csrc
*.vcd
obj_*
logs
+109
View File
@@ -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
+63
View File
@@ -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
+2
View File
@@ -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 .
+141
View File
@@ -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;
}
+58
View File
@@ -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
+42
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+444 -269
View File
File diff suppressed because it is too large Load Diff
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6 -7
View File
@@ -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;
+6 -4
View File
@@ -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();
}
+7 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
//=============================================================================
+6 -5
View File
@@ -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
};
+6 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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); }
+6 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+10 -456
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -29,7 +29,7 @@
class V3Branch {
public:
// CREATORS
// CONSTRUCTORS
static void branchAll(AstNetlist* rootp);
};
+2 -2
View File
@@ -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
View File
@@ -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;
}
}
}
}
}
+2
View File
@@ -30,6 +30,8 @@
class V3CCtors {
public:
static void cctorsAll();
private:
static void evalAsserts();
};
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)");
+1
View File
@@ -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
View File
@@ -29,7 +29,7 @@
class V3Coverage {
public:
// CREATORS
// CONSTRUCTORS
static void coverage(AstNetlist* rootp);
};
+1 -1
View File
@@ -29,7 +29,7 @@
class V3CoverageJoin {
public:
// CREATORS
// CONSTRUCTORS
static void coverageJoin(AstNetlist* rootp);
};
+8 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
+2
View File
@@ -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");
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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