Compare commits

..
97 Commits
Author SHA1 Message Date
Wilson Snyder 1a3378e0f5 Add --stats-vars, bug851. 2014-12-20 08:28:31 -05:00
Wilson Snyder 5c3eee34a1 Fix underscores in real literals, bug863. 2014-12-19 18:14:32 -05:00
Wilson Snyder 2b5017e610 Fix tracing SystemC signals with structures, bug858. Remove SC tracing of wrapper. 2014-12-10 22:33:28 -05:00
Wilson Snyder e755c7fdcc Internals: Rename to avoid off-by-one 2014-11-29 08:56:07 -05:00
Wilson Snyder 8d463b33cd Fix enum name off-by-one, bug854. 2014-11-29 08:47:03 -05:00
Wilson Snyder 7d9b21a874 Commentary 2014-11-28 21:37:47 -05:00
Wilson Snyder a118921b21 Fix bare generates in interfaces, bug789. 2014-11-28 21:32:57 -05:00
Wilson Snyder a1aefd2330 Tests: Check for bug509. 2014-11-28 20:54:55 -05:00
Wilson Snyder 8b511379ac Tests: Disabled test for static vars 2014-11-28 20:44:07 -05:00
Wilson Snyder c1593f856d Support enum.first/name and similar methods, bug848. 2014-11-28 20:34:23 -05:00
Wilson Snyder 93f1d7643d Fix duplicate Vdimtables and rename 2014-11-28 20:25:58 -05:00
Wilson Snyder ce4dfb4296 Fix misc string handling issues. 2014-11-28 20:24:42 -05:00
Wilson Snyder 2e5f5010f7 Internals: Make V3Width dimensionValue more generic. No functional change. 2014-11-28 15:51:35 -05:00
Wilson Snyder 7c588c2e30 Tests: Rename test. 2014-11-28 15:11:03 -05:00
Wilson Snyder 43be4cf2b5 Add 'string' printing and comparisons, bug746, bug747, etc. 2014-11-28 15:01:50 -05:00
Wilson Snyder 8b457b9b66 Internal: Rename string functions. No functional change. 2014-11-28 13:50:37 -05:00
Wilson Snyder 25efee2e62 Fix loss of data types in V3Premit. From strings branch. 2014-11-28 10:43:05 -05:00
Wilson Snyder 546c91a940 Fix runtime error with autoflush. 2014-11-28 07:56:21 -05:00
Wilson Snyder 85ebc5f7bd Fix called with narrow output strings 2014-11-27 12:32:41 -05:00
Wilson Snyder e002b0e25f Fix new inlining to be less aggressive 2014-11-27 12:04:16 -05:00
Wilson Snyder 4944383769 Fix to install verilator_coverage manpage. 2014-11-27 11:44:06 -05:00
Wilson Snyder 68c6f0ff07 Inline C functions that are used only once, msg1525. 2014-11-27 10:52:38 -05:00
Wilson Snyder 5078152292 Tests: Fix sigstop on parallel tests 2014-11-27 10:48:27 -05:00
Wilson Snyder 9837b40330 Remove SystemPerl tests 2014-11-27 08:30:54 -05:00
Jeremy Bennett cb645c9a74 Add missing header.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-26 16:46:16 -05:00
Wilson Snyder 87573a9fef Part of earlier commit - no SystemPerl now for coverage. 2014-11-24 18:37:55 -05:00
Wilson Snyder 7c486e27ba Tests: Remove unneeded SystemPerl dependencies. 2014-11-24 07:53:33 -05:00
Wilson Snyder 4a3bdc340d Tests: Remove unneeded SystemPerl dependencies. 2014-11-23 22:18:07 -05:00
Wilson Snyder 903ee0622d Remove test_vcs directory. 2014-11-23 22:04:09 -05:00
Wilson Snyder d33ad7600b Commentary. Cleanup stale SystemPerl references. 2014-11-23 22:00:00 -05:00
Wilson Snyder 9ec35a2348 New verilator_coverage and infrastructure to replace SystemPerl's vcoverage. 2014-11-23 21:06:10 -05:00
Wilson Snyder 6da13c6486 Internals: Split V3Error into V3FileLine. No functional change. 2014-11-22 11:48:39 -05:00
Wilson Snyder 87a47a5ca0 Remove PSL support 2014-11-22 10:14:14 -05:00
Wilson Snyder c682f1c16a Commentary and internal cleanups. 2014-11-22 09:04:14 -05:00
Wilson Snyder 591075a8ed Fix sc_main test to make trace data. 2014-11-18 19:43:44 -05:00
Wilson Snyder 41701673a0 devel release 2014-11-15 08:43:27 -05:00
Wilson Snyder 55f0d4ddd8 Version bump 2014-11-15 08:38:44 -05:00
Wilson Snyder 6d66fcaa57 Fix +define+A+B to define A and B to match other simulators, bug847. 2014-11-13 19:05:07 -05:00
Wilson Snyder 26e79ca889 Fix quoted comment slashes in defines, bug845. 2014-11-12 16:37:51 -05:00
Wilson Snyder 62eb247c1e Optimize SUB/ADD together. 2014-11-09 18:33:54 -05:00
Wilson Snyder c5fd583b2c Fix select when partially out-of-bound, bug823. 2014-11-09 18:29:52 -05:00
Wilson Snyder 117db3e11c Trace_off now operates on cells, bug826. 2014-11-08 14:15:10 -05:00
Wilson Snyder 3f82fd2f37 Add public enums, bug833. 2014-11-07 07:50:11 -05:00
Wilson Snyder e9c46afcf7 Fix public parameters in unused packages, bug804. 2014-11-06 17:53:01 -05:00
Wilson Snyder 3234fa15ef Fix trace overflow on huge arrays, bug834. 2014-11-05 22:22:27 -05:00
Jie Xu 7ef84df852 Add optimization of wires from arrayed cells, msg1447.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-05 21:09:35 -05:00
Jie Xu 4e2884b509 Optimize e.g. {(b<<4)[7:4], (b<<4)[3:0]}. From assignmerge tree.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-05 20:58:36 -05:00
Wilson Snyder 03100020ab Fix not tracing modules following primitives, bug837. 2014-11-04 07:49:03 -05:00
Wilson Snyder 8bfb5cc5e9 Internals: Add sameGateTree. 2014-11-02 19:52:49 -05:00
Wilson Snyder cf6d07aafa Add optimization of operators between concats, msg1447. 2014-10-22 21:44:41 -04:00
Wilson Snyder 85c3179dbd Commentary 2014-10-21 19:11:46 -04:00
Wilson Snyder bfbca34eb0 Fix cast-to-size context-determined sizing, bug828. 2014-10-17 19:01:04 -04:00
Wilson Snyder b73edc0564 Fix generate unrolling with function call, bug830. 2014-10-15 21:29:37 -04:00
Wilson Snyder 6ba90e3a50 devel release 2014-09-21 09:06:40 -04:00
Wilson Snyder e8edbad18c Version bump 2014-09-21 09:04:36 -04:00
Wilson Snyder c86fec5307 Fix string formats under deep expressions, bug820. 2014-09-21 08:52:09 -04:00
Wilson Snyder 6e476255ca Support power operator with real, bug809. 2014-09-21 08:24:44 -04:00
Wilson Snyder 27af9b6b06 Fix clang warnings, bug818. 2014-09-11 21:28:53 -04:00
Wilson Snyder f8208fa961 Print Aborting before aborting, bug819 2014-09-05 21:40:04 -04:00
Wilson Snyder 87b9cb49ad Fix / multi-argument ordering, bug816. 2014-09-04 22:25:19 -04:00
Wilson Snyder b2da0772e6 Commentary 2014-09-04 22:15:11 -04:00
Wilson Snyder 4f73e0850e Improve verilator_profcfunc time attributions. 2014-08-28 22:10:39 -04:00
Wilson Snyder b6a39db627 Fix optional parameter keyword in module #(), bug810. 2014-08-27 07:57:20 -04:00
Wilson Snyder 3a83b06572 Fix over-shift structure optimization error, bug803. 2014-07-28 07:31:01 -04:00
Wilson Snyder fe5bf01b25 Fix dpiGetContext in dotted scopes, bug740. 2014-07-21 20:55:52 -04:00
Wilson Snyder 5559ec903b Fix error when tracing public parameters, bug722. 2014-07-21 20:44:33 -04:00
Wilson Snyder 18750028b2 Fix mis-optimization of bit-swap in wide signal, bug800. 2014-07-04 09:13:59 -04:00
Wilson Snyder 6b88648c67 Commentary, bug799 2014-07-02 21:04:51 -04:00
Wilson Snyder 58ee803cb4 Fix test GCC warning, bug794. 2014-06-26 21:45:14 -04:00
Wilson Snyder 894ff73c7d Internals: Fix clang warning, bug791. 2014-06-19 18:02:42 -04:00
Wilson Snyder 8031f0ed7f Fix duplicate anonymous structures in , bug788. 2014-06-15 11:18:47 -04:00
Wilson Snyder 3a56b5da47 devel release 2014-06-10 20:43:10 -04:00
Wilson Snyder fedcb6d26a Version bump 2014-06-10 20:39:51 -04:00
Wilson Snyder eed3c5e543 Tests: Add t_tri_array and enable t_sv_cpu. 2014-06-10 20:02:18 -04:00
Wilson Snyder e26ab67e25 Report tristate errors closer to code which created them. 2014-06-10 19:58:51 -04:00
Wilson Snyder e77b7427b4 Fix shift corner-case, bug 774. 2014-06-10 19:13:55 -04:00
Wilson Snyder 475e4207cc Fix late constant division by zero giving X error, bug775. 2014-06-09 22:27:04 -04:00
Wilson Snyder 71b2eed32c Fix false name conflict on cells in generate blocks, bug749. 2014-06-09 22:00:45 -04:00
Wilson Snyder 6cf50e6579 Fix string corruption, bug780. 2014-06-08 21:36:18 -04:00
Wilson Snyder 69468708e2 Fix DETECTARRAY error on packed arrays, bug770. 2014-06-07 09:53:40 -04:00
Wilson Snyder 5da5678e64 Fix pattern assignment to conditionals, bug769. 2014-06-06 21:52:16 -04:00
Wilson Snyder a428e7f618 Fix pattern assignment to arrayed basic type, bug769. 2014-06-06 21:14:44 -04:00
Wilson Snyder 0eb5a0a539 Add -P to suppress `line and blanks with preprocessing, bug781. 2014-06-06 20:22:20 -04:00
Wilson Snyder a1c1ff9981 Fix seg-fault with variable of parameterized interface, bug692. 2014-05-28 07:33:40 -04:00
Wilson Snyder 2029ade18c Change SYMRSVDWORD to print as warning rather than error. 2014-05-28 07:24:02 -04:00
Wilson Snyder 5f8f474c0c Fix shift with XOR mis-optimization, bug776. 2014-05-26 18:16:52 -04:00
Wilson Snyder f705f9b275 Fix C compiler interpreting signing, bug773. 2014-05-24 08:00:01 -04:00
Wilson Snyder 91e706ec1f Fix X shift issue, bug772. 2014-05-24 07:05:23 -04:00
Wilson Snyder dcf351f847 Copyright 2014-05-20 06:12:08 -04:00
Wilson Snyder 06744b664a Fix huge shifts to zero with -Wno-WIDTH, bug768. 2014-05-16 07:09:43 -04:00
Wilson Snyder d3049d9c89 Fix huge shifts to zero with -Wno-WIDTH, bug766. 2014-05-15 21:49:43 -04:00
Wilson Snyder 1f2abb9c0f Fix gate primitives with arrays and non-arrayed pins. 2014-05-15 20:57:09 -04:00
Wilson Snyder 9f0d7e50a5 Using command line -Wno-{WARNING} now overrides file-local lint_on. 2014-05-15 20:54:45 -04:00
Wilson Snyder 5f262a8f11 Fix ENDLABEL warnings on escaped identifiers. 2014-05-15 20:52:22 -04:00
Wilson Snyder f62bc6a2e5 Support SV 2012 package import before port list. 2014-05-15 20:50:42 -04:00
Wilson Snyder d7e4bc1379 Fix huge shifts to zero with -Wno-WIDTH, bug765. 2014-05-13 08:10:59 -04:00
Wilson Snyder cd2d6575c6 devel release 2014-05-11 16:58:01 -04:00
248 changed files with 8544 additions and 3028 deletions
+1
View File
@@ -23,3 +23,4 @@ gdbrun*
internals.txt
verilator.txt
verilator_bin*
verilator_coverage_bin*
+110
View File
@@ -3,6 +3,116 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.867 devel
** New verilator_coverage program added to replace SystemPerl's vcoverage.
** PSL support was removed, please use System Verilog assertions.
** SystemPerl mode is deprecated and now untested.
*** Support enum.first/name and similar methods, bug460, bug848.
*** Add 'string' printing and comparisons, bug746, bug747, etc.
*** Inline C functions that are used only once, msg1525. [Jie Xu]
*** Fix tracing SystemC signals with structures, bug858. [Eivind Liland]
Note that SystemC traces will no longer show the signals
in the wrapper, they can be seen one level further down.
**** Add --stats-vars, bug851. [Jeremy Bennett]
**** Fix bare generates in interfaces, bug789. [Bob Newgard]
**** Fix underscores in real literals, bug863. [Jonathon Donaldson]
* Verilator 3.866 2014-11-15
*** Fix +define+A+B to define A and B to match other simulators, bug847. [Adam Krolnik]
*** Add optimization of wires from arrayed cells, msg1447. [Jie Xu]
*** Add optimization of operators between concats, msg1447. [Jie Xu]
*** Add public enums, bug833. [Jonathon Donaldson]
*** Trace_off now operates on cells, bug826. [Lane Brooks]
**** Fix public parameters in unused packages, bug804. [Jonathon Donaldson]
**** Fix select when partially out-of-bound, bug823. [Cliffort Wolf]
**** Fix generate unrolling with function call, bug830. [Steven Slatter]
**** Fix cast-to-size context-determined sizing, bug828. [Geoff Barrett]
**** Fix not tracing modules following primitives, bug837. [Jie Xu]
**** Fix trace overflow on huge arrays, bug834. [Geoff Barrett]
**** Fix quoted comment slashes in defines, bug845. [Adam Krolnik]
* Verilator 3.864 2014-09-21
*** Support power operator with real, bug809. [Jonathon Donaldson]
**** Improve verilator_profcfunc time attributions. [Jonathon Donaldson]
**** Fix duplicate anonymous structures in $root, bug788. [Bob Newgard]
**** Fix mis-optimization of bit-swap in wide signal, bug800. [Jie Xu]
**** Fix error when tracing public parameters, bug722. [Jonathon Donaldson]
**** Fix dpiGetContext in dotted scopes, bug740. [Geoff Barrett]
**** Fix over-shift structure optimization error, bug803. [Jeff Bush]
**** Fix optional parameter keyword in module #(), bug810. [Iztok Jeras]
**** Fix $warning/$error multi-argument ordering, bug816. [Jonathon Donaldson]
**** Fix clang warnings, bug818. [Iztok Jeras]
**** Fix string formats under deep expressions, bug820. [Iztok Jeras]
* Verilator 3.862 2014-06-10
*** Using command line -Wno-{WARNING} now overrides file-local lint_on.
*** Add -P to suppress `line and blanks with preprocessing, bug781. [Derek Lockhart]
*** Support SV 2012 package import before port list.
**** Change SYMRSVDWORD to print as warning rather than error.
**** Fix seg-fault with variable of parameterized interface, bug692. [Jie Xu]
**** Fix false name conflict on cells in generate blocks, bug749. [Igor Lesik]
**** Fix pattern assignment to basic types, bug767. [Jie Xu]
**** Fix pattern assignment to conditionals, bug769. [Jie Xu]
**** Fix shift corner-cases, bug765, bug766, bug768, bug772, bug774, bug776. [Clifford Wolf]
**** Fix C compiler interpreting signing, bug773. [Clifford Wolf]
**** Fix late constant division by zero giving X error, bug775. [Clifford Wolf]
**** Fix gate primitives with arrays and non-arrayed pins.
**** Fix DETECTARRAY error on packed arrays, bug770. [Jie Xu]
**** Fix ENDLABEL warnings on escaped identifiers.
**** Fix string corruption, bug780. [Derek Lockhart]
* Verilator 3.860 2014-05-11
** PSL is no longer supported, please use System Verilog assertions.
+1
View File
@@ -28,6 +28,7 @@ config.status$
verilator.log
verilator.tex
verilator_bin.*
verilator_coverage_bin.*
.vcsmx_rebuild$
autom4te\.cache/
nodist/
+22 -17
View File
@@ -100,10 +100,11 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
SHELL = /bin/sh
SUBDIRS = src test_verilated test_c test_sc test_sp test_regress test_vcs
SUBDIRS = src test_verilated test_c test_sc test_regress
INFOS = README README.html README.pdf internals.txt internals.html \
internals.pdf verilator.txt verilator.html verilator.1 verilator.pdf
internals.pdf verilator.txt verilator.html verilator.1 verilator.pdf \
verilator_coverage.1
# Files that can be generated, but should be up to date for a distribution.
DISTDEP = info Makefile
@@ -122,6 +123,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
.*attributes */.*attributes */*/.*attributes \
src/.*ignore src/*.in src/*.cpp src/*.[chly] \
src/astgen src/bisonpre src/*fix src/cppcheck_filtered \
src/vlcovgen \
src/.gdbinit \
src/*.pl src/*.pod \
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
@@ -140,6 +142,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
INST_PROJ_FILES = \
bin/verilator \
bin/verilator_coverage \
bin/verilator_includer \
bin/verilator_profcfunc \
include/verilated.mk \
@@ -149,6 +152,7 @@ INST_PROJ_FILES = \
INST_PROJ_BIN_FILES = \
verilator_bin \
verilator_bin_dbg \
verilator_coverage_bin_dbg \
DISTFILES := $(DISTFILES_INC)
@@ -165,7 +169,8 @@ all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
.PHONY:verilator_exe
.PHONY:verilator_bin
.PHONY:verilator_bin_dbg
verilator_exe verilator_bin verilator_bin_dbg:
.PHONY:verilator_coverage_bin_dbg
verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg:
@echo ------------------------------------------------------------
@echo "making verilator in src" ; \
(cd src && $(MAKE) $(OBJCACHE_JOBS) )
@@ -179,17 +184,15 @@ msg_test: all_nomsg
.PHONY:test
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
test: test_vcs test_c test_sc test_sp test_verilated test_regress
test: test_c test_sc test_verilated test_regress
else
test: test_c test_sc test_sp
test: test_c test_sc
endif
@echo "Tests passed!"
@echo
@echo "Type 'make install' to install documentation."
@echo
test_vcs: all_nomsg
@(cd test_vcs && $(MAKE))
test_c: all_nomsg
@(cd test_c && $(MAKE))
test_c_debug: all_nomsg
@@ -198,10 +201,6 @@ test_sc: all_nomsg
@(cd test_sc && $(MAKE))
test_sc_debug: all_nomsg
@(cd test_sc && $(MAKE) test_debug)
test_sp: all_nomsg
@(cd test_sp && $(MAKE))
test_sp_debug: all_nomsg
@(cd test_sp && $(MAKE) test_debug)
test_verilated: all_nomsg
@(cd test_verilated && $(MAKE))
test_regress: all_nomsg
@@ -213,6 +212,9 @@ info: $(INFOS)
verilator.1: ${srcdir}/bin/verilator
pod2man $< $@
verilator_coverage.1: ${srcdir}/bin/verilator_coverage
pod2man $< $@
verilator.txt: ${srcdir}/bin/verilator
$(POD2TEXT) $< $@
@@ -261,13 +263,13 @@ internals.pdf: internals.pod Makefile
-rm -f internals.toc internals.aux internals.idx internals.out
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
verilator_includer verilator_profcfunc
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \
verilator_coverage verilator_includer verilator_profcfunc
# Some scripts go into both the search path and pkgdatadir,
# so they can be found by the user, and under $VERILATOR_ROOT.
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1
VL_INST_INC_BLDDIR_FILES = \
include/verilated.mk \
@@ -281,14 +283,15 @@ 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 \
test_sp/Makefile test_sp/Makefile_obj \
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 )
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
@@ -311,7 +314,6 @@ installdata:
done
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sp
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
cd $(srcdir) \
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
@@ -351,6 +353,7 @@ INST_PROJ_CVS = cp_if_cvs_diff
install-project: dist
@echo "Install-project to $(DIRPROJECT)"
strip verilator_bin*
strip verilator_coverage_bin*
$(MAKE) install-project-quick
for p in $(VL_INST_MAN_FILES) ; do \
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
@@ -374,6 +377,7 @@ endif
install-cadtools: dist
@echo "Install-project to $(CAD_DIR)"
strip verilator_bin*
strip verilator_coverage_bin*
$(MAKE) install-cadtools-quick
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
for p in $(VL_INST_MAN_FILES) ; do \
@@ -459,7 +463,8 @@ clean mostlyclean distclean maintainer-clean::
rm -f *.tex
distclean maintainer-clean::
rm -f Makefile config.status config.cache config.log verilator_bin* TAGS
rm -f Makefile config.status config.cache config.log TAGS
rm -f verilator_bin* verilator_coverage_bin*
rm -f include/verilated.mk include/verilated_config.h
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
-17
View File
@@ -30,23 +30,6 @@ Configure/Make/Install
* Full MSVC++ compilation (does scons support this?) (4.000?)
* Distribute with flex/bison already expanded?
Flex library not needed. Probably too difficult to be worth it.
* Integrate SystemPerl coverage
see the SystemPerl git branch coverage_only
(Note in /usr/include there are no upper cased include files.)
Coverage.pm -- Need all functionality, but in C?
Coverage/Item.pm -- Need all functionality, but in C?
Coverage/ItemKey.pm -- Need all functionality, but in C?
sp_preproc -- Some steps in here need to be moved to generated C
-- -- note uses Verilog::Getopt
src/Sp.cpp -- n/a
src/SpCommon.h -- mostly overlaps verilatedos.h
src/SpCoverage.cpp/h -- All needed
src/SpFunctor.cpp/h -- No longer used
src/SpTraceVcd.cpp/h -- MOVED
src/SpTraceVcdC.cpp/h -- MOVED
src/sp_log.cpp/h -- Not needed
src/systemperl.h -- some stuff may be cut
vcoverage -- Need all functionality, but in C?
Testing:
* Move test_c/sp/v/verilated into test_regress format (4.000?)
+82 -91
View File
@@ -24,14 +24,10 @@ BEGIN {
}
}
use File::Path;
use File::Basename;
use Getopt::Long;
use FindBin qw($RealBin $RealScript);
use IO::File;
use Pod::Usage;
use Config;
use Cwd qw(abs_path getcwd);
use strict;
use vars qw ($Debug @Opt_Verilator_Sw);
@@ -209,17 +205,13 @@ Verilator - Convert Verilog code to C++/SystemC
=head1 DESCRIPTION
Verilator converts synthesizable (not behavioral) Verilog code, plus some
Synthesis, SystemVerilog and a small subset of Verilog AMS
assertions, into C++, SystemC or SystemPerl code. It is not a complete
simulator, just a compiler.
Synthesis, SystemVerilog and a small subset of Verilog AMS assertions, into
C++ or SystemC code. It is not a complete simulator, but a compiler.
Verilator is invoked with parameters similar to GCC, Cadence
Verilog-XL/NC-Verilog, or Synopsys's VCS. It reads the specified Verilog
code, lints it, and optionally adds coverage and waveform tracing code.
For C++ and SystemC formats, it outputs .cpp and .h files. For SystemPerl
format, it outputs .sp files for the SystemPerl preprocessor, which greatly
simplifies writing SystemC code and is available at
L<http://www.veripool.org>.
For C++ and SystemC formats, it outputs .cpp and .h files.
The files created by Verilator are then compiled with C++. The user writes
a little C++ wrapper file, which instantiates the top level module, and
@@ -267,7 +259,7 @@ descriptions in the next sections for more information.
--debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a level
--default-language <lang> Default language to parse
+define+<var>+<value> Set preprocessor define
+define+<var>=<value> Set preprocessor define
--dump-tree Enable dumping .tree files
--dump-treei <level> Enable dumping .tree files at a level
-E Preprocess, but do not compile
@@ -303,6 +295,7 @@ descriptions in the next sections for more information.
--output-split <bytes> Split .cpp files into pieces
--output-split-cfuncs <statements> Split .cpp functions
--output-split-ctrace <statements> Split tracing functions
-P Disable line numbers and blanks with -E
--pins-bv <bits> Specify types for top level ports
--pins-sc-uint Specify types for top level ports
--pins-sc-biguint Specify types for top level ports
@@ -315,8 +308,8 @@ descriptions in the next sections for more information.
--report-unoptflat Extra diagnostics for UNOPTFLAT
--savable Enable model save-restore
--sc Create SystemC output
--sp Create SystemPerl output
--stats Create statistics file
--stats-vars Provide statistics on variables
-sv Enable SystemVerilog parsing
+systemverilogext+<ext> Synonym for +1800-2012ext+<ext>
--top-module <topname> Name of top level input module
@@ -451,7 +444,7 @@ run on the generated makefile these will be passed to the C++ compiler
=item --cc
Specifies C++ without SystemC output mode; see also --sc and --sp.
Specifies C++ without SystemC output mode; see also --sc.
=item --cdc
@@ -571,13 +564,16 @@ the comment "DefaultClock":
=item -DI<var>=I<value>
Defines the given preprocessor symbol. Same as +define; +define is fairly
standard across Verilog tools while -D is an alias for GCC compatibility.
Defines the given preprocessor symbol, without allowing. Similar to
+define; +define is fairly standard across Verilog tools while -D is an
alias for GCC compatibility.
=item --debug
Select the debug built image of Verilator (if available), and enable more
internal assertions, debugging messages, and intermediate form dump files.
internal assertions (equivelent to C<--debug-check>), debugging messages
(equivelent to C<--debugi 4>), and intermediate form dump files (equivilent
to C<--dump-tree>).
=item --debug-check
@@ -589,9 +585,9 @@ changing debug verbosity. Enabled automatically when --debug specified.
=item --debugi-<srcfile> <level>
Rarely needed - for developer use. Set internal debugging level globally
to the specified debug level (1-10) or set the specified source file to the
specified level. Higher levels produce more detailed messages (plain
C<--debug> is equivalent to C<--debugi 4>).
to the specified debug level (1-10) or set the specified Verilator source
file to the specified level (e.g. C<--debugi-V3Width 9>). Higher levels
produce more detailed messages.
=item --default-language I<value>
@@ -612,10 +608,13 @@ used.
If no language is specified, either by this flag or +I<lang>ext+ options,
then the latest SystemVerilog language (IEEE 1800-2012) is used.
=item +define+I<var>+I<value>
=item +define+I<var>=I<value>
Defines the given preprocessor symbol. Same as -D; +define is fairly
standard across Verilog tools while -D is an alias for GCC compatibility.
=item +define+I<var>=I<value>+I<var2>=I<value2>...
Defines the given preprocessor symbol, or multiple symbols if separated by
plusses. Similar to -D; +define is fairly standard across Verilog tools
while -D is an alias for GCC compatibility.
=item --dump-tree
@@ -781,8 +780,10 @@ Disables optimization of the model.
=item -O3
Enables slow optimizations. This may reduce simulation runtimes at the
cost of compile time. This currently sets --inline-mult -1.
Enables slow optimizations for the code Verilator itself generates (as
opposed to "-CFLAGS -O3" which effects the C compiler's optimization. -O3
may reduce simulation runtimes at the cost of compile time. This currently
sets --inline-mult -1.
=item -OI<optimization-letter>
@@ -830,6 +831,11 @@ function.
Enables splitting trace functions in the output .cpp/.sp files into
multiple functions. Defaults to same setting as --output-split-cfuncs.
=item -P
With -E, disable generation of `line markers and blank lines, similar to
GCC -P flag.
=item --pins64
Backward compatible alias for "--pins-bv 65". Note that's a 65, not a 64.
@@ -955,16 +961,18 @@ other data the process needs saved/restored. For example:
=item --sc
Specifies SystemC output mode; see also --cc and -sp.
=item --sp
Specifies SystemPerl output mode; see also --cc and -sc.
Specifies SystemC output mode; see also --cc.
=item --stats
Creates a dump file with statistics on the design in {prefix}__stats.txt.
=item --stats-vars
Creates more detailed statistics including a list of all the variables by
size (plain --stats just gives a count). See --stats, which is implied by
this.
=item -sv
Specifies SystemVerilog language features should be enabled; equivalent to
@@ -1088,7 +1096,8 @@ supports which the older version does not support.
=item -Wno-I<message>
Disable the specified warning message.
Disable the specified warning message. This will override any lint_on
directives in the source, i.e. the warning will still not be printed.
=item -Wno-lint
@@ -1276,7 +1285,7 @@ the test_c directory in the distribution for an example.
=head1 EXAMPLE SYSTEMC EXECUTION
This is an example similar to the above, but using SystemPerl.
This is an example similar to the above, but using SystemC.
mkdir test_our_sc
cd test_our_sc
@@ -1311,17 +1320,7 @@ your operating system (as an RPM), first you need to point to the kit:
Now we run Verilator on our little example.
verilator -Wall --sp our.v
Then we convert the SystemPerl output to SystemC.
cd obj_dir
export SYSTEMPERL=/path/to/where/systemperl/kit/came/from
$SYSTEMPERL/sp_preproc --preproc *.sp
(You can also skip the above sp_preproc by getting pure SystemC from
Verilator by replacing the verilator --sp flag in the previous step with
-sc.)
verilator -Wall --sc our.v
We then can compile it
@@ -1350,7 +1349,7 @@ 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_sp directory in the distribution for an example.
the test_sc directory in the distribution for an example.
=head1 BENCHMARKING & OPTIMIZATION
@@ -1408,6 +1407,10 @@ especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
both compilation and link. Note LTO may cause excessive compile times on
large designs.
If you are using your own makefiles, you may want to compile the Verilated
code with -DVL_INLINE_OPT=inline. This will inline functions, however this
requires that all cpp files be compiled in a single compiler run.
You may uncover further tuning possibilities by profiling the Verilog code.
Use Verilator's --profile-cfuncs, then GCC's -g -pg. You can then run
either oprofile or gprof to see where in the C++ code the time is spent.
@@ -1435,11 +1438,6 @@ For -cc and -sc mode, it also creates:
{prefix}{each_verilog_module}.cpp // Lower level internal C++ files
{prefix}{each_verilog_module}.h // Lower level internal header files
For -sp mode, instead of .cpp and .h it creates:
{prefix}.sp // Top level SystemC file
{prefix}{each_verilog_module}.sp // Lower level internal SC files
In certain optimization modes, it also creates:
{prefix}__Dpi.h // DPI import and export declarations
@@ -1514,21 +1512,6 @@ specified, it will come from a default optionally specified at configure
time (before Verilator was compiled), or computed from
SYSTEMC/lib-SYSTEMC_ARCH.
=item SYSTEMPERL
Specifies the directory containing the SystemPerl distribution kit. This
is used to find the SystemPerl library and include files. If not
specified, it will come from a default optionally specified at configure
time (before Verilator was compiled). See also SYSTEMPERL_INCLUDE.
=item SYSTEMPERL_INCLUDE
Specifies the directory containing the Verilog-Perl include .cpp files,
from the src/ directory of the SystemPerl kit. If not specified, it will
be computed from the SYSTEMPERL environment variable if it is set, and if
SYSTEMPERL is not set SYSTEMPERL_INCLUDE will come from a default
optionally specified at configure time (before Verilator was compiled).
=item VCS_HOME
If set, specifies the directory containing the Synopsys VCS distribution.
@@ -1918,6 +1901,9 @@ Disables the specified lint warning, in the specified filename (or wildcard
with '*' or '?', or all files if omitted) and range of line numbers (or all
lines if omitted).
Using '*' will override any lint_on directives in the source, i.e. the
warning will still not be printed.
If the -msg is omitted, all lint warnings are disabled. This will override
all later lint warning enables for the specified region.
@@ -2162,8 +2148,8 @@ Specifies the module the comment appears in may be inlined into any modules
that use this module. This is useful to speed up simulation time with some
small loss of trace visibility and modularity. Note signals under inlined
submodules will be named I<submodule>__DOT__I<subsignal> as C++ does not
allow "." in signal names. SystemPerl when tracing such signals will
replace the __DOT__ with the period.
allow "." in signal names. When tracing such signals the tracing routines
will replace the __DOT__ with the period.
=item /*verilator isolate_assignments*/
@@ -2237,6 +2223,14 @@ reduce the size of the final executable when a task is used a very large
number of times. For this flag to work, the task and tasks below it must
be pure; they cannot reference any variables outside the task itself.
=item /*verilator public*/ (typedef enum)
Used after an enum typedef declaration to indicate the emitted C code
should have the enum values visible. Due to C++ language restrictions, this
may only be used on 64-bit or narrower integral enumerations.
typedef enum logic [2:0] { ZERO = 3'b0 } pub_t /*verilator public*/;
=item /*verilator public*/ (variable)
Used after an input, output, register, or wire declaration to indicate the
@@ -2324,12 +2318,14 @@ behavior. See the test_regress/t/t_dpi_display.v file for an example.
=item /*verilator tracing_off*/
Disable waveform tracing for all future signals that are declared in this
module. Often this is placed just after a primitive's module statement, so
that the entire module is not traced.
module, or cells below this module. Often this is placed just after a
primitive's module statement, so that the entire module and cells below it
are not traced.
=item /*verilator tracing_on*/
Re-enable waveform tracing for all future signals that are declared.
Re-enable waveform tracing for all future signals or cells that are
declared.
=back
@@ -2608,8 +2604,9 @@ All specify blocks and timing checks are ignored.
=item string
String is supported only to the point that they can be passed to DPI
imports.
String is supported only to the point that they can be assigned,
concatenated, compared, and passed to DPI imports. Standard method calls
on strings are not supported.
=item timeunit, timeprecision
@@ -2958,8 +2955,8 @@ simulators.
Warns that an `include filename specifies an absolute path. This means the
code will not work on any other system with a different file system layout.
Instead of using absolute paths, relative paths (preferably without any
directory specified whatever) should be used, and +include used on the
command line to specify the top include source directory.
directory specified whatever) should be used, and +incdir used on the
command line to specify the top include source directories.
Disabled by default as this is a code style warning; it will simulate
correctly.
@@ -3088,10 +3085,9 @@ simulators.
=item SYMRSVDWORD
Error that a symbol matches a C++ reserved word and using this as a symbol
name would result in odd C compiler errors. You may disable this error
message as you would disable warnings, but the symbol will be renamed by
Verilator to avoid the conflict.
Warning that a symbol matches a C++ reserved word and using this as a symbol
name would result in odd C compiler errors. You may disable this warning,
but the symbol will be renamed by Verilator to avoid the conflict.
=item SYNCASYNCNET
@@ -3380,7 +3376,7 @@ so your simulator shouldn't have to be -- and Verilator is closer to the
synthesis interpretation, so this is a good thing for getting working
silicon.
=item Will Verilator output remain under my own copyright?
=item Will Verilator output remain under my own license?
Yes, it's just like using GCC on your programs; this is why Verilator uses
the "GNU *Lesser* Public License Version 3" instead of the more typical
@@ -3432,10 +3428,6 @@ flag.
Note you can also call ->trace on multiple Verilated objects with the same
trace file if you want all data to land in the same output file.
Note also older versions of Verilator used the SystemPerl package and
SpTraceVcdC class. This still works, but is depreciated as it requires
strong coupling between the Verilator and SystemPerl versions.
#include "verilated_vcd_c.h"
...
int main(int argc, char **argv, char **env) {
@@ -3458,7 +3450,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_sp/sc_main.cpp file of the distribution, and below.
test_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
@@ -3510,22 +3502,21 @@ network disk. Network disks are generally far slower.
=item How do I do coverage analysis?
Verilator supports both block (line) coverage and user inserted functional
coverage. Both require the SystemPerl package to be installed but do not
require use of the SystemPerl output mode.
coverage.
First, run verilator with the --coverage option. If you're using your own
makefile, compile the model with the GCC flag -DSP_COVERAGE (if using
makefile, compile the model with the GCC flag -DVM_COVERAGE (if using
Verilator's, it will do this for you.)
Run your tests in different directories. Each test will create a
logs/coverage.pl file.
After running all of your tests, the vcoverage utility (from the SystemPerl
package) is executed. Vcoverage reads the logs/coverage.pl file(s), and
creates an annotated source code listing showing code coverage details.
After running all of your tests, verilator_coverage is executed.
Verilator_coverage reads the logs/coverage.pl 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_sp/logs/coverage_source directory. Grep for lines starting
see the test_sc/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?)
@@ -3817,7 +3808,7 @@ Major concepts by Paul Wasson and Duane Galbi.
=head1 SEE ALSO
L<verilator_profcfunc>, L<systemperl>, L<vcoverage>, L<make>,
L<verilator_coverage>, L<verilator_profcfunc>, L<make>,
L<verilator --help> which is the source for this document,
+291
View File
@@ -0,0 +1,291 @@
: # -*-Mode: perl;-*- use perl, wherever it is
eval 'exec perl -wS $0 ${1+"$@"}'
if 0;
######################################################################
#
# Copyright 2003-2014 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
######################################################################
require 5.006_001;
use warnings;
BEGIN {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
use Getopt::Long;
use FindBin qw($RealBin $RealScript);
use IO::File;
use Pod::Usage;
use Cwd qw(abs_path getcwd);
use strict;
use vars qw ($Debug @Opt_Verilator_Sw);
#######################################################################
#######################################################################
# main
autoflush STDOUT 1;
autoflush STDERR 1;
$Debug = 0;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
# We sneak a look at the flags so we can do some pre-environment checks
# All flags will hit verilator...
foreach my $sw (@ARGV) {
$sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!;
push @Opt_Verilator_Sw, $sw;
}
Getopt::Long::config ("no_auto_abbrev","pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
# Normal, non gdb
run (verilator_coverage_bin()
." ".join(' ',@Opt_Verilator_Sw));
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
}
sub debug {
shift;
my $level = shift;
$Debug = $level||3;
}
#######################################################################
#######################################################################
# Builds
sub verilator_coverage_bin {
my $bin = "";
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|| "verilator_coverage_bin_dbg");
if (defined($ENV{VERILATOR_ROOT})) {
my $dir = $ENV{VERILATOR_ROOT};
if (-x "$dir/bin/$basename") { # From a "make install" into VERILATOR_ROOT
$bin = "$dir/bin/$basename";
} else {
$bin = "$dir/$basename"; # From pointing to kit directory
}
} else {
if (-x "$RealBin/$basename") {
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
} else {
$bin = $basename; # Find in PATH
}
# Note we don't look under bin/$basename which would be right if running
# in the kit dir. Running that would likely break, since
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
}
return $bin;
}
#######################################################################
#######################################################################
# Utilities
sub run {
# Run command, check errors
my $command = shift;
$! = undef; # Cleanup -x
print "\t$command\n" if $Debug>=3;
system($command);
my $status = $?;
if ($status) {
if ($! =~ /no such file or directory/i) {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
} else {
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
}
}
#######################################################################
#######################################################################
package main;
__END__
=pod
=head1 NAME
verilator_coverage - Verilator coverage analyzer
=head1 SYNOPSIS
verilator_coverage --help
verilator_coverage --version
verilator_coverage --annotate <obj>
verilator_coverage -write merged.dat -read <datafiles>...
Verilator_coverage processes Verilator coverage reports.
With --anotate, it reads the specified data file and generates annotated
source code with coverage metrics annotated. If multiple coverage points
exist on the same line, additional lines will be inserted to report the
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
into Emacs and do a M-x keep-lines to include only those statistics of
interest.
For Verilog conditions that should never occur, you should add a $stop
statement. This will remove the coverage during the next build.
=head1 ARGUMENTS
=over 4
=item I<filename>
Specify input data file, may be repeated to read multiple inputs. If no
data file is specified, by default coverage.dat is read.
=item --annotate I<output_directory>
Sprcifies the directory name that source files with annotated coverage data
should be written to.
=item --annotate-all
Specifies all files should be shown. By default, only those source files
which have low coverage are written to the output directory.
=item --annotate-min I<count>
Specifies the minimum occurrence count that should be flagged if the
coverage point does not include a specified threshold. Defaults to 10.
=item --help
Displays this message and program version and exits.
=item --rank
Print an experimental report listing the relative importance of each test
in covering all of the coverage points. The report shows "Covered" which
indicates the number of points that test covers; a test is considered to
cover a point if it has a bucket count of at least 1. The "rank" column has
a higher number t indicate the test is more important, and rank 0 means the
test does not need to be run to cover the points. "RankPts" indicates the
number of coverage points this test will contribute to overall coverage if
all tests are run in the order of highest to lowest rank.
=item --unlink
When using --write to combine coverage data, unlink all input files after
the output has been created.
=item --version
Displays program version and exits.
=item --write I<filename>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename. This is useful in scripts to
combine many sequential runs into one master coverage file.
=back
=head1 VERILOG ARGUMENTS
The following arguments are compatible with GCC, VCS and most Verilog
programs.
=over 4
=item +libext+I<ext>+I<ext>...
Defines the extensions for Verilog files.
=item +define+I<var>+I<value>
=item -DI<var>=I<value>
Defines the given variable.
=item +incdir+I<dir>
=item -II<dir>
Specifies a directory for finding include files.
=item -f I<file>
Specifies a file containing additional command line arguments.
=item -y I<dir>
Specifies a module search directory.
=back
=head1 DISTRIBUTION
The latest version is available from L<http://www.veripool.org/>.
Copyright 2003-2014 by Wilson Snyder. Verilator is free software; you can
redistribute it and/or modify the Verilator internals under the terms of
either the GNU Lesser General Public License Version 3 or the Perl Artistic
License Version 2.0.
=head1 AUTHORS
Wilson Snyder <[email protected]>
=head1 SEE ALSO
C<verilator>
L<verilator_coverage --help> which is the source for this document.
=cut
######################################################################
+5 -1
View File
@@ -12,5 +12,9 @@ require 5.005;
use warnings;
print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
foreach my $param (@ARGV) {
print "#include \"$param\"\n"
if ($param =~ /^-D([^=]+)=(.*)/) {
print "#define $1 $2\n"
} else {
print "#include \"$param\"\n"
}
}
+15 -1
View File
@@ -118,6 +118,18 @@ sub profcfunc {
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
@@ -129,7 +141,7 @@ sub profcfunc {
}
foreach my $type qw(type design module) {
foreach my $type (qw(type design module)) {
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
@@ -150,8 +162,10 @@ sub profcfunc {
print("Verilog code profile:\n");
print(" These are split into three categories:\n");
print(" C++: Time in non-Verilated C++ code\n");
print(" Prof: Time in profile overhead\n");
print(" VBlock: Time attributable to a block in a Verilog file and line\n");
print(" VCommon: Time in a Verilated module, due to all parts of the design\n");
print(" VLib: Time in Verilated common libraries, called by the Verilated code\n");
print("\n");
print(" % cumulative self \n");
+4 -2
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.860 2014-05-11])
AC_INIT([Verilator],[3.867 devel])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
@@ -122,15 +122,17 @@ AC_DEFUN([_MY_CXX_CHECK_OPT],
# For example, -Wno-div-by-zero isn't in 4.1.2
_MY_CXX_CHECK_OPT(-Wno-char-subscripts)
_MY_CXX_CHECK_OPT(-Wno-parentheses-equality)
# Random code often does / 0. Unfortunately VL_DIV_I(0,0) will warn
# without this flag, even though there's a conditional to prevent the divide.
# We still don't add no-div-by-zero as it throws message to stdout, though doesn't die.
#_MY_CXX_CHECK_OPT(-Wno-div-by-zero)
_MY_CXX_CHECK_OPT(-Wno-sign-compare)
_MY_CXX_CHECK_OPT(-Wno-uninitialized)
_MY_CXX_CHECK_OPT(-Wno-unused-but-set-variable)
_MY_CXX_CHECK_OPT(-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(-Wno-unused-variable)
_MY_CXX_CHECK_OPT(-Wno-unused-but-set-variable)
_MY_CXX_CHECK_OPT(-fbracket-depth=4096)
AC_SUBST(CFG_CXXFLAGS_NO_UNUSED)
# Checks for library functions.
-2
View File
@@ -635,9 +635,7 @@ INPUT = doxygen-mainpage \
test_c \
test_regress \
test_sc \
test_sp \
test_v \
test_vcs \
test_verilated
# This tag can be used to specify the character encoding of the source files
+56 -3
View File
@@ -74,6 +74,9 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
Verilated::gotFinish(true);
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
Verilated::flushCall();
VL_PRINTF("Aborting...\n");
Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush
abort();
}
#endif
@@ -340,6 +343,12 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
output += cstrp;
break;
}
case '@': { // Verilog/C++ string
va_arg(ap, int); // # bits is ignored
const string* cstrp = va_arg(ap, const string*);
output += *cstrp;
break;
}
case 'e':
case 'f':
case 'g': {
@@ -759,6 +768,50 @@ void VL_FCLOSE_I(IData fdi) {
VerilatedImp::fdDelete(fdi);
}
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) {
VL_STATIC_OR_THREAD string output; // static only for speed
output = "";
va_list ap;
va_start(ap,formatp);
_vl_vsformat(output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) {
VL_STATIC_OR_THREAD string output; // static only for speed
output = "";
va_list ap;
va_start(ap,formatp);
_vl_vsformat(output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) {
VL_STATIC_OR_THREAD string output; // static only for speed
output = "";
va_list ap;
va_start(ap,formatp);
_vl_vsformat(output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) {
VL_STATIC_OR_THREAD string output; // static only for speed
output = "";
va_list ap;
va_start(ap,formatp);
_vl_vsformat(output, formatp, ap);
va_end(ap);
_VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
VL_STATIC_OR_THREAD string output; // static only for speed
output = "";
@@ -1250,9 +1303,9 @@ void VerilatedScope::scopeDump() const {
m_callbacksp[i], VerilatedImp::exportName(i));
}
}
if (varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp()->begin();
it != varsp()->end(); ++it) {
if (VerilatedVarNameMap* varsp = this->varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
it != varsp->end(); ++it) {
VL_PRINTF(" VAR %p: %s\n", &(it->second), it->first);
}
}
+9 -5
View File
@@ -375,6 +375,10 @@ extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
extern IData VL_SYSTEM_IW(int lhsnwords, WDataInP lhs);
@@ -1458,7 +1462,7 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) {
static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP lwp, IData rd) {
VL_ZERO_RESET_W(lbits, owp);
// Slice size should never exceed the lhs width
int ssize = ((int)rd < lbits) ? ((int)rd) : lbits;
int ssize = (rd < (IData)lbits) ? rd : ((IData)lbits);
for (int istart=0; istart<lbits; istart+=rd) {
int ostart=lbits-rd-istart;
ostart = ostart > 0 ? ostart : 0;
@@ -1558,7 +1562,7 @@ static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or
static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) {
int word_shift = VL_BITWORD_I(rd);
int bit_shift = VL_BITBIT_I(rd);
if ((int)rd >= obits) {
if (rd >= (IData)obits) { // rd may be huge with MSB set
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
} else if (bit_shift==0) { // Aligned word shift (<<0,<<32,<<64 etc)
for (int i=0; i < word_shift; i++) owp[i] = 0;
@@ -1576,7 +1580,7 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP l
static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) {
int word_shift = VL_BITWORD_I(rd); // Maybe 0
int bit_shift = VL_BITBIT_I(rd);
if ((int)rd >= obits) {
if (rd >= (IData)obits) { // rd may be huge with MSB set
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
} else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc)
int copy_words = (VL_WORDS_I(obits)-word_shift);
@@ -1622,7 +1626,7 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
int bit_shift = VL_BITBIT_I(rd);
int lmsw = VL_WORDS_I(obits)-1;
IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]);
if ((int)rd >= obits) { // Shifting past end, sign in all of lbits
if (rd >= (IData)obits) { // Shifting past end, sign in all of lbits
for (int i=0; i <= lmsw; i++) owp[i] = sign;
owp[lmsw] &= VL_MASK_I(lbits);
} else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc)
@@ -1661,7 +1665,7 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData rd) {
int word = VL_BITWORD_I(rd);
if (VL_UNLIKELY((int)rd>lbits)) {
if (VL_UNLIKELY(rd>(IData)lbits)) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
// We return all 1's as that's more likely to find bugs (?) than 0's.
} else {
+9 -6
View File
@@ -23,7 +23,9 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
# Programs
SP_PREPROC = sp_preproc
SP_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
SP_INCLUDER = $(VERILATOR_INCLUDER)
VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
######################################################################
# Make checks
@@ -43,14 +45,14 @@ VK_CPPFLAGS_ALWAYS += \
-DVL_PRINTF=printf \
-DVM_TRACE=$(VM_TRACE) \
-DVM_COVERAGE=$(VM_COVERAGE) \
$(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
VK_CPPFLAGS_WALL += -Wall \
$(CFG_CXXFLAGS_NO_UNUSED) \
-Werror
endif
CPPFLAGS += -I. $(VK_CPPFLAGS_ALWAYS) $(VK_CPPFLAGS_WALL)
CPPFLAGS += -I. $(VK_CPPFLAGS_WALL) $(VK_CPPFLAGS_ALWAYS)
VPATH += ..
VPATH += $(VERILATOR_ROOT)/include
@@ -151,15 +153,15 @@ VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
ifneq ($(VM_PARALLEL_BUILDS),1)
ifneq ($(VM_PARALLEL_BUILDS),0)
# Fast building, all .cpp's in one fell swoop
# This saves about 5 sec per module, but can be slower if only a little changes
VK_OBJS += $(VM_PREFIX)__ALLcls.o $(VM_PREFIX)__ALLsup.o
all_cpp: $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp
$(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP)
$(SP_INCLUDER) $^ > $@
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
$(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP)
$(SP_INCLUDER) $^ > $@
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
else
#Slow way of building... Each .cpp file by itself
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
@@ -195,6 +197,7 @@ debug-make::
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
@echo CPPFLAGS: $(CPPFLAGS)
@echo
######################################################################
+451
View File
@@ -0,0 +1,451 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2014 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.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Verilator coverage analysis
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_cov.h"
#include "verilated_cov_key.h"
#include <map>
#include <deque>
#include <fstream>
//=============================================================================
// VerilatedCovImpBase
/// Implementation base class for constants
struct VerilatedCovImpBase {
// TYPES
enum { MAX_KEYS = 33 }; /// Maximum user arguments + filename+lineno
enum { KEY_UNDEF = 0 }; /// Magic key # for unspecified values
};
//=============================================================================
// VerilatedCovImpItem
/// Implementation class for a VerilatedCov item
class VerilatedCovImpItem : VerilatedCovImpBase {
public: // But only local to this file
// MEMBERS
int m_keys[MAX_KEYS]; ///< Key
int m_vals[MAX_KEYS]; ///< Value for specified key
// CONSTRUCTORS
// Derived classes should call zero() in their constructor
VerilatedCovImpItem() {
for (int i=0; i<MAX_KEYS; i++) m_keys[i]=KEY_UNDEF;
}
virtual ~VerilatedCovImpItem() {}
virtual vluint64_t count() const = 0;
virtual void zero() const = 0;
};
//=============================================================================
/// VerilatedCoverItem templated for a specific class
/// Creates a new coverage item for the specified type.
/// This isn't in the header file for auto-magic conversion because it
/// inlines to too much code and makes compilation too slow.
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
private:
// MEMBERS
T* m_countp; ///< Count value
public:
// METHODS
virtual vluint64_t count() const { return *m_countp; }
virtual void zero() const { *m_countp = 0; }
// CONSTRUCTORS
VerilatedCoverItemSpec(T* countp) : m_countp(countp) { zero(); }
virtual ~VerilatedCoverItemSpec() {}
};
//=============================================================================
// VerilatedCovImp
/// Implementation class for VerilatedCov. See that class for public method information.
/// All value and keys are indexed into a unique number. Thus we can greatly reduce
/// the storage requirements for otherwise identical keys.
class VerilatedCovImp : VerilatedCovImpBase {
private:
// TYPES
typedef map<string,int> ValueIndexMap;
typedef map<int,string> IndexValueMap;
typedef deque<VerilatedCovImpItem*> ItemList;
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
VerilatedCovImpItem* m_insertp; ///< Item about to insert
const char* m_insertFilenamep; ///< Filename about to insert
int m_insertLineno; ///< Line number about to insert
// CONSTRUCTORS
VerilatedCovImp() {
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
}
public:
~VerilatedCovImp() { clear(); }
static VerilatedCovImp& imp() {
static VerilatedCovImp s_singleton;
return s_singleton;
}
private:
// PRIVATE METHODS
int valueIndex(const string& value) {
static int nextIndex = KEY_UNDEF+1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++; assert(nextIndex>0);
m_valueIndexes.insert(make_pair(value, nextIndex));
m_indexValues.insert(make_pair(nextIndex, value));
return nextIndex;
}
string dequote(const string& text) {
// Quote any special characters
string rtn;
for (const char* pos = text.c_str(); *pos; pos++) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
rtn += hex;
} else {
rtn += *pos;
}
}
return rtn;
}
bool legalKey(const string& key) {
// 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...
// (Considered using numeric keys, but will remain back compatible.)
if (key.length()<2) return false;
if (key.length()==2 && isdigit(key[1])) return false;
return true;
}
string keyValueFormatter (const string& key, const string& value) {
string name;
if (key.length()==1 && isalpha(key[0])) {
name += string("\001")+key;
} else {
name += string("\001")+dequote(key);
}
name += string("\002")+dequote(value);
return name;
}
string combineHier (const string& old, const string& add) {
// (foo.a.x, foo.b.x) => foo.*.x
// (foo.a.x, foo.b.y) => foo.*
// (foo.a.x, foo.b) => foo.*
if (old == add) return add;
if (old == "") return add;
if (add == "") return old;
const char* a = old.c_str();
const char* b = add.c_str();
// Scan forward to first mismatch
const char* apre = a;
const char* bpre = b;
while (*apre == *bpre) { apre++; bpre++; }
// We used to backup and split on only .'s but it seems better to be verbose
// and not assume . is the separator
string prefix = string(a,apre-a);
// Scan backward to last mismatch
const char* apost = a+strlen(a)-1;
const char* bpost = b+strlen(b)-1;
while (*apost == *bpost
&& apost>apre && bpost>bpre) { apost--; bpost--; }
// Forward to . so we have a whole word
string suffix = *bpost ? string(bpost+1) : "";
string out = prefix+"*"+suffix;
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
return out;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const string& match) {
for (int i=0; i<MAX_KEYS; i++) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
string val = m_indexValues[itemp->m_vals[i]];
if (string::npos != val.find(match)) { // Found
return true;
}
}
}
return false;
}
void selftest() {
// 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");
}
public:
// PUBLIC METHODS
void clear() {
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
}
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
}
void clearNonMatch (const char* matchp) {
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
} else {
newlist.push_back(itemp);
}
}
m_items = newlist;
}
}
void zero() {
for (ItemList::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) {
assert(!m_insertp);
m_insertp = itemp;
}
void insertf (const char* filenamep, int lineno) {
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp (const char* ckeyps[MAX_KEYS],
const char* valps[MAX_KEYS]) {
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
VlCovCvtToCStr linestrp (m_insertLineno);
ckeyps[1]="lineno"; valps[1]=linestrp;
// Default page if not specified
const char* fnstartp = m_insertFilenamep;
while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
const char* fnendp = fnstartp;
while (*fnendp && *fnendp!='.') fnendp++;
string page_default = "sp_user/"+string(fnstartp,fnendp-fnstartp);
ckeyps[2]="page"; valps[2]=page_default.c_str();
// Keys -> strings
string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; i++) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; i++) {
if (keys[i]!="") {
for (int j=i+1; j<MAX_KEYS; j++) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
}
}
}
}
// Insert the values
int addKeynum=0;
for (int i=0; i<MAX_KEYS; i++) {
const string key = keys[i];
if (keys[i]!="") {
const string val = valps[i];
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
vl_fatal("",0,"",msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
}
void write (const char* filename) {
#ifndef VM_COVERAGE
vl_fatal("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif
selftest();
ofstream os (filename);
if (os.fail()) {
string msg = (string)"%Error: Can't write '"+filename+"'";
vl_fatal("",0,"",msg.c_str());
return;
}
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef map<string,pair<string,vluint64_t> > EventMap;
EventMap eventCounts;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
string name;
string hier;
bool per_instance = false;
for (int i=0; i<MAX_KEYS; i++) {
if (itemp->m_keys[i] != KEY_UNDEF) {
string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
if (key == VL_CIK_HIER) {
hier = val;
} else {
// Print it
name += keyValueFormatter(key,val);
}
}
}
if (per_instance) { // Not collapsing hierarchies
name += keyValueFormatter(VL_CIK_HIER,hier);
hier = "";
}
// Group versus point labels don't matter here, downstream
// deals with it. Seems bad for sizing though and doesn't
// allow easy addition of new group codes (would be
// inefficient)
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const string& oldhier = cit->second.first;
cit->second.second += itemp->count();
cit->second.first = combineHier(oldhier, hier);
} else {
eventCounts.insert(make_pair(name, make_pair(hier,itemp->count())));
}
}
// Output body
for (EventMap::iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
os<<"C '"<<dec;
os<<it->first;
if (it->second.first != "") os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
os<<"' "<<it->second.second;
os<<endl;
}
}
};
//=============================================================================
// VerilatedCov
void VerilatedCov::clear() {
VerilatedCovImp::imp().clear();
}
void VerilatedCov::clearNonMatch (const char* matchp) {
VerilatedCovImp::imp().clearNonMatch(matchp);
}
void VerilatedCov::zero() {
VerilatedCovImp::imp().zero();
}
void VerilatedCov::write (const char* filenamep) {
VerilatedCovImp::imp().write(filenamep);
}
void VerilatedCov::_inserti (vluint32_t* itemp) {
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint32_t>(itemp));
}
void VerilatedCov::_inserti (vluint64_t* itemp) {
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
}
void VerilatedCov::_insertf (const char* filename, int lineno) {
VerilatedCovImp::imp().insertf(filename,lineno);
}
#define K(n) const char* key ## n
#define A(n) const char* key ## n, const char* val ## n // Argument list
#define C(n) key ## n, val ## n // Calling argument list
#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)) {
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
= {NULL,NULL,NULL, // filename,lineno,page
key0,key1,key2,key3,key4,key5,key6,key7,key8,key9,
key10,key11,key12,key13,key14,key15,key16,key17,key18,key19,
key20,key21,key22,key23,key24,key25,key26,key27,key28,key29};
const char* valps[VerilatedCovImpBase::MAX_KEYS]
= {NULL,NULL,NULL, // filename,lineno,page
val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,
val10,val11,val12,val13,val14,val15,val16,val17,val18,val19,
val20,val21,val22,val23,val24,val25,val26,val27,val28,val29};
VerilatedCovImp::imp().insertp(keyps, valps);
}
// 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)) {
_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)) {
_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 string& val4, A(5),A(6)) {
_insertp(C(0),C(1),
key2,VlCovCvtToCStr(val2), key3,VlCovCvtToCStr(val3), key4, val4.c_str(),
C(5),C(6),N(7),N(8),N(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));
}
#undef A
#undef C
#undef N
#undef K
+146
View File
@@ -0,0 +1,146 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2014 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.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Coverage analysis support
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#ifndef _VERILATED_COV_H_
#define _VERILATED_COV_H_ 1
#include "verilatedos.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
//=============================================================================
/// Conditionally compile coverage code
#ifdef VM_COVERAGE
# define VL_IF_COVER(stmts) do { stmts ; } while(0)
#else
# define VL_IF_COVER(stmts) do { if(0) { stmts ; } } while(0)
#endif
//=============================================================================
/// Insert a item for coverage analysis.
/// The first argument is a pointer to the count to be dumped.
/// The remaining arguments occur in pairs: A string key, and a value.
/// The value may be a string, or another type which will be auto-converted to a string.
///
/// Some typical keys:
/// filename File the recording occurs in. Defaults to __FILE__
/// lineno Line number the recording occurs in. Defaults to __LINE__
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
/// hier Hierarchical name. Defaults to name()
/// type Type of coverage. Defaults to "user"
/// Other types are 'block', 'fsm', 'toggle'.
/// comment Description of the coverage event. Should be set by the user.
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
/// thresh Threshold to consider fully covered.
/// If unspecified, downstream tools will determine it.
///
/// Examples:
///
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; i++) { m_cases[i]=0; }
/// }
/// for (int i=0; i<10; i++) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
#define VL_COVER_INSERT(countp,args...) \
VL_IF_COVER(VerilatedCov::_inserti(countp); \
VerilatedCov::_insertf(__FILE__,__LINE__); \
VerilatedCov::_insertp("hier", name(), args))
//=============================================================================
/// Convert VL_COVER_INSERT value arguments to strings
template< class T> std::string vlCovCvtToStr (const T& t) {
ostringstream os; os<<t; return os.str();
}
/// Usage: something(VlCovCvtToCStr(i))
/// Note the pointer will only be valid for as long as the object remains
/// in scope!
struct VlCovCvtToCStr {
string m_str;
// Casters
template< class T> VlCovCvtToCStr (const T& t) {
ostringstream os; os<<t; m_str=os.str();
}
~VlCovCvtToCStr() {}
operator const char* () const { return m_str.c_str(); };
};
//=============================================================================
// VerilatedCov
/// Verilator coverage global class
////
/// Global class with methods affecting all coverage data.
class VerilatedCov {
public:
// GLOBAL METHODS
/// Return default filename
static const char* defaultFilename() { return "coverage.dat"; }
/// Write all coverage data to a file
static void write (const char* filenamep = defaultFilename());
/// 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);
// _insert2: Set default filename and line number
static void _insertf (const char* filename, int lineno);
// _insert3: Set parameters
// We could have just the maximum argument version, but this compiles
// much slower (nearly 2x) than having smaller versions also. However
// there's not much more gain in having a version for each number of args.
#define K(n) const char* key ## n
#define A(n) const char* key ## n, const char* valp ## n // Argument list
#define D(n) const char* key ## n = NULL, const char* valp ## n = NULL // Argument list
static void _insertp (D(0),D(1),D(2),D(3),D(4),D(5),D(6),D(7),D(8),D(9));
static void _insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
,A(10),D(11),D(12),D(13),D(14),D(15),D(16),D(17),D(18),D(19));
static void _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),D(21),D(22),D(23),D(24),D(25),D(26),D(27),D(28),D(29));
// Backward compatibility for Verilator
static void _insertp (A(0), A(1), K(2),int val2, K(3),int val3,
K(4),const string& val4, A(5),A(6));
#undef K
#undef A
#undef D
/// Clear coverage points (and call delete on all items)
static void clear();
/// Clear items not matching the provided string
static void clearNonMatch (const char* matchp);
/// Zero coverage points
static void zero();
};
#endif // guard
+147
View File
@@ -0,0 +1,147 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2014 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.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Coverage item keys
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#ifndef _VERILATED_COV_KEY_H_
#define _VERILATED_COV_KEY_H_ 1
#include "verilatedos.h"
#include <string>
using namespace std;
//=============================================================================
// Data used to edit below file, using vlcovgen
#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
VLCOVGEN_ITEM("name=>'col0_name', short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'")
VLCOVGEN_ITEM("name=>'col1_name', short=>'C1', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'col2_name', short=>'C2', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'col3_name', short=>'C3', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'column', short=>'n', group=>1, default=>0, descr=>'Column number for the item. Used to disambiguate multiple coverage points on the same line number'")
VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr=>'Filename of the item'")
VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ")
VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'row2_name', short=>'R2', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'row3_name', short=>'R3', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'table', short=>'T', group=>1, default=>undef, descr=>'The name of the table for automatically generated tables'")
VLCOVGEN_ITEM("name=>'thresh', short=>'s', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'type', short=>'t', group=>1, default=>'', descr=>'Type of coverage (block, line, fsm, etc)'")
// Bin attributes
VLCOVGEN_ITEM("name=>'col0', short=>'c0', group=>0, default=>undef, descr=>'The (enumeration) value name for this column in a table cross' ")
VLCOVGEN_ITEM("name=>'col1', short=>'c1', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'col2', short=>'c2', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'col3', short=>'c3', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'comment', short=>'o', group=>0, default=>'', descr=>'Textual description for the item'")
VLCOVGEN_ITEM("name=>'hier', short=>'h', group=>0, default=>'', descr=>'Hierarchy path name for the item'")
VLCOVGEN_ITEM("name=>'limit', short=>'L', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'lineno', short=>'l', group=>0, default=>0, descr=>'Line number for the item'")
VLCOVGEN_ITEM("name=>'row0', short=>'r0', group=>0, default=>undef, descr=>'The (enumeration) value name for this row in a table cross'")
VLCOVGEN_ITEM("name=>'row1', short=>'r1', group=>0, default=>undef, ")
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"
#define VL_CIK_COL1 "c1"
#define VL_CIK_COL1_NAME "C1"
#define VL_CIK_COL2 "c2"
#define VL_CIK_COL2_NAME "C2"
#define VL_CIK_COL3 "c3"
#define VL_CIK_COL3_NAME "C3"
#define VL_CIK_COLUMN "n"
#define VL_CIK_COMMENT "o"
#define VL_CIK_FILENAME "f"
#define VL_CIK_GROUPCMT "O"
#define VL_CIK_GROUPDESC "d"
#define VL_CIK_GROUPNAME "g"
#define VL_CIK_HIER "h"
#define VL_CIK_LIMIT "L"
#define VL_CIK_LINENO "l"
#define VL_CIK_PER_INSTANCE "P"
#define VL_CIK_ROW0 "r0"
#define VL_CIK_ROW0_NAME "R0"
#define VL_CIK_ROW1 "r1"
#define VL_CIK_ROW1_NAME "R1"
#define VL_CIK_ROW2 "r2"
#define VL_CIK_ROW2_NAME "R2"
#define VL_CIK_ROW3 "r3"
#define VL_CIK_ROW3_NAME "R3"
#define VL_CIK_TABLE "T"
#define VL_CIK_THRESH "s"
#define VL_CIK_TYPE "t"
#define VL_CIK_WEIGHT "w"
// VLCOVGEN_CIK_AUTO_EDIT_END
class VerilatedCovKey {
public:
static string shortKey(const string& key) {
// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
if (key == "col0") return VL_CIK_COL0;
if (key == "col0_name") return VL_CIK_COL0_NAME;
if (key == "col1") return VL_CIK_COL1;
if (key == "col1_name") return VL_CIK_COL1_NAME;
if (key == "col2") return VL_CIK_COL2;
if (key == "col2_name") return VL_CIK_COL2_NAME;
if (key == "col3") return VL_CIK_COL3;
if (key == "col3_name") return VL_CIK_COL3_NAME;
if (key == "column") return VL_CIK_COLUMN;
if (key == "comment") return VL_CIK_COMMENT;
if (key == "filename") return VL_CIK_FILENAME;
if (key == "groupcmt") return VL_CIK_GROUPCMT;
if (key == "groupdesc") return VL_CIK_GROUPDESC;
if (key == "groupname") return VL_CIK_GROUPNAME;
if (key == "hier") return VL_CIK_HIER;
if (key == "limit") return VL_CIK_LIMIT;
if (key == "lineno") return VL_CIK_LINENO;
if (key == "per_instance") return VL_CIK_PER_INSTANCE;
if (key == "row0") return VL_CIK_ROW0;
if (key == "row0_name") return VL_CIK_ROW0_NAME;
if (key == "row1") return VL_CIK_ROW1;
if (key == "row1_name") return VL_CIK_ROW1_NAME;
if (key == "row2") return VL_CIK_ROW2;
if (key == "row2_name") return VL_CIK_ROW2_NAME;
if (key == "row3") return VL_CIK_ROW3;
if (key == "row3_name") return VL_CIK_ROW3_NAME;
if (key == "table") return VL_CIK_TABLE;
if (key == "thresh") return VL_CIK_THRESH;
if (key == "type") return VL_CIK_TYPE;
if (key == "weight") return VL_CIK_WEIGHT;
// VLCOVGEN_SHORT_AUTO_EDIT_END
return key;
}
};
#endif // guard
+12 -1
View File
@@ -41,13 +41,24 @@ inline string VL_CVT_PACK_STR_NQ(QData lhs) {
IData lw[2]; VL_SET_WQ(lw, lhs);
return VL_CVT_PACK_STR_NW(2, lw);
}
inline string VL_CVT_PACK_STR_NQ(string lhs) {
inline string VL_CVT_PACK_STR_NQ(const string& lhs) {
return lhs;
}
inline string VL_CVT_PACK_STR_NI(IData lhs) {
IData lw[1]; lw[0] = lhs;
return VL_CVT_PACK_STR_NW(1, lw);
}
inline string VL_CONCATN_NNN(const string& lhs, const string& rhs) {
return lhs+rhs;
}
inline string VL_REPLICATEN_NNQ(int,int,int rbits, const string& lhs, IData rep) {
string out; out.reserve(lhs.length() * rep);
for (unsigned times=0; times<rep; times++) out += lhs;
return out;
}
inline string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const string& lhs, IData rep) {
return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
}
extern void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
extern string VL_SFORMATF_NX(const char* formatp, ...);
+6 -3
View File
@@ -62,8 +62,9 @@ bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t siz
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) {
if (VL_UNLIKELY(readDiffers(datap,size))) {
string fn = filename();
string msg = (string)"Can't deserialize save-restore file as was made from different model";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
vl_fatal(fn.c_str(), 0, "", msg.c_str());
close();
}
return *this; // For function chaining
@@ -82,8 +83,9 @@ void VerilatedSerialize::header() {
void VerilatedDeserialize::header() {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
string fn = filename();
string msg = (string)"Can't deserialize; file has wrong header signature";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
vl_fatal(fn.c_str(), 0, "", msg.c_str());
close();
}
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
@@ -98,8 +100,9 @@ void VerilatedSerialize::trailer() {
void VerilatedDeserialize::trailer() {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
string fn = filename();
string msg = (string)"Can't deserialize; file has wrong end-of-file signature";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
vl_fatal(fn.c_str(), 0, "", msg.c_str());
close();
}
}
+29 -10
View File
@@ -57,7 +57,7 @@ vector<VerilatedVcd*> VerilatedVcd::s_vcdVecp; ///< List of all created traces
// VerilatedVcdCallInfo
/// Internal callback routines for each module being traced.
////
/// Each SystemPerl module that wishes to be traced registers a set of
/// Each module that wishes to be traced registers a set of
/// callbacks stored in this class. When the trace file is being
/// constructed, this class provides the callback routines to be executed.
@@ -172,8 +172,8 @@ void VerilatedVcd::makeNameMap() {
// 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) {
const char* hiername = (*it).first.c_str();
if (hiername[0] == '\t') nullScope=true;
const string& hiername = it->first;
if (hiername.size() >= 1 && hiername[0] == '\t') nullScope=true;
}
if (nullScope) {
NameMap* newmapp = new NameMap;
@@ -261,6 +261,20 @@ void VerilatedVcd::printTime (vluint64_t timeui) {
printQuad(timeui);
}
void VerilatedVcd::bufferResize(vluint64_t minsize) {
// minsize is size of largest write. We buffer at least 8 times as much data,
// writing when we are 3/4 full (with thus 2*minsize remaining free)
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
char* oldbufp = m_wrBufp;
m_wrChunkSize = minsize*2;
m_wrBufp = new char [m_wrChunkSize * 8];
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
m_writep = m_wrBufp + (m_writep - oldbufp);
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
delete oldbufp; oldbufp=NULL;
}
}
void VerilatedVcd::bufferFlush () {
// We add output data to m_writep.
// When it gets nearly full we dump it using this routine which calls write()
@@ -352,7 +366,8 @@ void VerilatedVcd::dumpHeader () {
printStr("$date "); printStr(ctime(&time_str)); printStr(" $end\n");
printStr("$timescale ");
printStr(doubleToTimescale(m_timeRes).c_str());
const string& timeResStr = doubleToTimescale(m_timeRes);
printStr(timeResStr.c_str());
printStr(" $end\n");
makeNameMap();
@@ -370,10 +385,11 @@ void VerilatedVcd::dumpHeader () {
// Print the signal names
const char* lastName = "";
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
const char* hiername = (*it).first.c_str();
const char* decl = (*it).second.c_str();
const string& hiernamestr = it->first;
const string& decl = it->second;
// Determine difference between the old and new names
const char* hiername = hiernamestr.c_str();
const char* lp = lastName;
const char* np = hiername;
lastName = hiername;
@@ -408,7 +424,7 @@ void VerilatedVcd::dumpHeader () {
}
printIndent(0);
printStr(decl);
printStr(decl.c_str());
}
while (m_modDepth>1) {
@@ -442,6 +458,9 @@ void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
}
// Make sure write buffer is large enough (one character per bit), plus header
bufferResize(bits+1024);
// Save declaration info
VerilatedVcdSig sig = VerilatedVcdSig(code, bits);
m_sigs.push_back(sig);
@@ -520,7 +539,7 @@ void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
(*((double*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", newval);
m_writep += strlen(m_writep);
*m_writep++=' '; printCode(code); *m_writep++='\n';
@@ -528,7 +547,7 @@ void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
}
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
(*((float*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", (double)newval);
m_writep += strlen(m_writep);
*m_writep++=' '; printCode(code); *m_writep++='\n';
@@ -701,5 +720,5 @@ main() {
//********************************************************************
// Local Variables:
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && g++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// End:
+11 -8
View File
@@ -77,7 +77,9 @@ private:
vluint64_t m_timeLastDump; ///< Last time we did a dump
char* m_wrBufp; ///< Output buffer
char* m_wrFlushp; ///< Output buffer flush trigger location
char* m_writep; ///< Write pointer into output buffer
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
@@ -87,13 +89,12 @@ private:
NameMap* m_namemapp; ///< List of names for the header
static vector<VerilatedVcd*> s_vcdVecp; ///< List of all created traces
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16*1024; }
void bufferResize(vluint64_t minsize);
void bufferFlush();
void bufferCheck() {
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
if (VL_UNLIKELY(m_writep > (m_wrBufp+(bufferSize()-bufferInsertSize())))) {
if (VL_UNLIKELY(m_writep > m_wrFlushp)) {
bufferFlush();
}
}
@@ -135,17 +136,19 @@ protected:
public:
// CREATORS
VerilatedVcd () : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
m_wrBufp = new char [bufferSize()];
m_writep = m_wrBufp;
m_namemapp = NULL;
m_timeRes = m_timeUnit = 1e-9;
m_timeLastDump = 0;
m_sigs_oldvalp = NULL;
m_evcd = false;
m_scopeEscape = '.'; // Backward compatibility
m_wroteBytes = 0;
m_fd = 0;
m_fullDump = true;
m_wrChunkSize = 8*1024;
m_wrBufp = new char [m_wrChunkSize*8];
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
m_writep = m_wrBufp;
m_wroteBytes = 0;
}
~VerilatedVcd();
@@ -392,7 +395,7 @@ public:
/// Create a VCD dump file in C standalone (no SystemC) simulations.
class VerilatedVcdC {
VerilatedVcd m_sptrace; ///< SystemPerl trace file being created
VerilatedVcd m_sptrace; ///< Trace file being created
public:
// CONSTRUCTORS
VerilatedVcdC() {}
+1 -1
View File
@@ -15,7 +15,7 @@
//=============================================================================
///
/// \file
/// \brief SystemPerl Tracing in VCD Format
/// \brief Verilator tracing in VCD Format
///
/// AUTHOR: Wilson Snyder
///
+1 -1
View File
@@ -15,7 +15,7 @@
//=============================================================================
///
/// \file
/// \brief SystemPerl tracing in VCD format
/// \brief Verilator tracing in VCD format
///
/// AUTHOR: Wilson Snyder
///
+19 -26
View File
@@ -97,8 +97,8 @@ public:
virtual const char* fullname() { return "<null>"; }
virtual const char* defname() { return "<null>"; }
virtual const vluint32_t type() { return 0; }
virtual const vluint32_t size() { return 0; }
virtual const VerilatedRange* rangep() { return 0; }
virtual const vluint32_t size() const { return 0; }
virtual const VerilatedRange* rangep() const { return NULL; }
virtual vpiHandle dovpi_scan() { return 0; }
};
@@ -136,7 +136,7 @@ public:
class VerilatedVpioRange : public VerilatedVpio {
const VerilatedRange* m_range;
bool m_iteration;
vlsint32_t m_iteration;
public:
VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
virtual ~VerilatedVpioRange() {}
@@ -182,7 +182,7 @@ class VerilatedVpioVar : public VerilatedVpio {
protected:
void* m_varDatap; // varp()->datap() adjusted for array entries
vlsint32_t m_index;
const VerilatedRange& get_range() {
const VerilatedRange& get_range() const {
// Determine number of dimensions and return outermost
return (m_varp->dims()>1) ? m_varp->array() : m_varp->range();
}
@@ -208,8 +208,8 @@ public:
if (varp()->vldir() != vpiNoDirection) return vpiPort;
return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */
}
virtual const vluint32_t size() { return get_range().elements(); }
virtual const VerilatedRange* rangep() { return &get_range(); }
virtual const 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 string out;
@@ -237,8 +237,8 @@ public:
virtual ~VerilatedVpioMemoryWord() {}
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiMemoryWord; }
virtual const vluint32_t size() { return varp()->range().elements(); }
virtual const VerilatedRange* rangep() { return &(varp()->range()); }
virtual const vluint32_t size() const { return varp()->range().elements(); }
virtual const VerilatedRange* rangep() const { return &(varp()->range()); }
virtual const char* fullname() {
VL_STATIC_OR_THREAD string out;
char num[20]; sprintf(num,"%d",m_index);
@@ -259,10 +259,11 @@ public:
virtual const vluint32_t type() { return vpiIterator; }
virtual vpiHandle dovpi_scan() {
if (VL_LIKELY(m_scopep->varsp())) {
if (VL_UNLIKELY(!m_started)) { m_it = m_scopep->varsp()->begin(); m_started=true; }
else if (VL_UNLIKELY(m_it == m_scopep->varsp()->end())) return 0;
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 == m_scopep->varsp()->end()) return 0;
if (m_it == varsp->end()) return 0;
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))
->castVpiHandle());
} else {
@@ -430,15 +431,10 @@ class VerilatedVpiError {
t_vpi_error_info m_errorInfo;
bool m_flag;
char m_buff[VL_VPI_LINE_SIZE];
void setError(PLI_BYTE8 *message, PLI_BYTE8 *file, PLI_INT32 line) {
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 = NULL;
do_callbacks();
}
void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) {
setError( message, file, line);
m_errorInfo.code = code;
do_callbacks();
}
@@ -464,14 +460,11 @@ public:
return this;
}
void setMessage(string file, PLI_INT32 line, string message, ...) {
static VL_THREAD string filehold;
_VL_VPI_ERROR_SET;
m_errorInfo.state = vpiPLI;
setError((PLI_BYTE8*)m_buff, (PLI_BYTE8*)file.c_str(), line);
}
void setMessage(PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line, string message, ...) {
_VL_VPI_ERROR_SET;
m_errorInfo.state = vpiPLI;
setError((PLI_BYTE8*)message.c_str(), code, file, line);
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;
@@ -926,9 +919,9 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
value_p->value.str = outStr;
switch (vop->varp()->vltype()) {
// outStrSz does not include NULL termination so add one
case VLVT_UINT8 : snprintf(outStr, outStrSz+1, "%hhu", (unsigned int)*((CData*)(vop->varDatap()))); return;
case VLVT_UINT16: snprintf(outStr, outStrSz+1, "%hu", (unsigned int)*((SData*)(vop->varDatap()))); return;
case VLVT_UINT32: snprintf(outStr, outStrSz+1, "%u", (unsigned int)*((IData*)(vop->varDatap()))); return;
case VLVT_UINT8 : snprintf(outStr, outStrSz+1, "%hhu", (unsigned char )*((CData*)(vop->varDatap()))); return;
case VLVT_UINT16: snprintf(outStr, outStrSz+1, "%hu", (unsigned short)*((SData*)(vop->varDatap()))); return;
case VLVT_UINT32: snprintf(outStr, outStrSz+1, "%u", (unsigned int )*((IData*)(vop->varDatap()))); return;
case VLVT_UINT64: snprintf(outStr, outStrSz+1, "%llu", (unsigned long long)*((QData*)(vop->varDatap()))); return;
default:
strcpy(outStr, "-1");
+7
View File
@@ -105,6 +105,13 @@
# define VL_UNIQUE_PTR auto_ptr
#endif
//=========================================================================
// Optimization
#ifndef VL_INLINE_OPT
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
#endif
//=========================================================================
// Warning disabled
+4 -10
View File
@@ -473,10 +473,10 @@ be warning free.
=item --enable-longtests
In addition to the standard C, SystemC and SystemPerl tests also run the
tests in the C<test_vcs>, C<test_verilated> and C<test_regress> directories
when using I<make test>. This is disabled by default as SystemC/SystemPerl
installation problems would otherwise falsely indicate a Verilator problem.
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.
=back
@@ -491,12 +491,6 @@ There are some traps to avoid when running regression tests
=item *
The regression tests will assume that you have a version of SystemPerl to
match. Typically if working on Verilator from git, also use SystemPerl from
git.
=item *
When checking the MANIFEST, the test will barf on unexpected code in the
Verilator tree. So make sure to keep any such code outside the tree.
-141
View File
@@ -1,141 +0,0 @@
#!/usr/bin/perl -w
######################################################################
#
# Copyright 2010-2014 by Wilson Snyder. This package 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
######################################################################
# DESCRIPTION: Diff Verilator includes against SystemPerl include files
use Getopt::Long;
use IO::File;
use strict;
our $Debug;
our $Bad;
if (! GetOptions (
#"help" => \&usage,
"debug" => sub { $Debug = 1; },
)) {
die "usage();"
}
diff("$ARGV[0]/include/verilated_vcd_c.h", "$ARGV[1]/src/SpTraceVcdC.h");
diff("$ARGV[0]/include/verilated_vcd_sc.h", "$ARGV[1]/src/SpTraceVcd.h");
diff("$ARGV[0]/include/verilated_vcd_c.cpp", "$ARGV[1]/src/SpTraceVcdC.cpp");
diff("$ARGV[0]/include/verilated_vcd_sc.cpp", "$ARGV[1]/src/SpTraceVcd.cpp");
exit(10) if $Bad;
sub diff {
my $a=shift;
my $b=shift;
my $ta = "/tmp/spdiff.$$.a";
my $tb = "/tmp/spdiff.$$.b";
prep($a,$ta);
prep($b,$tb);
system("diff -u -w $ta $tb");
}
sub prep {
my $filename = shift;
my $wfilename = shift;
my $sp;
if ($filename =~ m!src/Sp!) {
$sp = "Sp";
} elsif ($filename =~ m!include/verilated!) {
} else {
die "%Error: Not sure if Sp/Verilated: $filename,\n";
}
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename";
my $fho = IO::File->new(">$wfilename") or die "%Error: $! writing $wfilename";
my @wf;
my $off;
while (defined(my $line = $fh->getline)) {
if ($line =~ m!// *SPDIFF_OFF!) {
$off = 1;
next;
} elsif ($line =~ m!// *SPDIFF_ON!) {
$off = 0;
next;
}
next if $off;
next if $line =~ /compile-command:/;
$line =~ s/SP_ABORT.*// if $sp;
$line =~ s/SP_NOTICE.*// if $sp;
$line =~ s/vl_fatal.*// if !$sp;
$line =~ s/VL_PRINT.*// if !$sp;
$line =~ s/Copyright \d+-\d+/Copyright #-#/g;
push @wf, $line;
my $check = $line;
$check =~ s/\bspace//i;
$check =~ s/\bsplit//i;
$check =~ s/"SP_TRACE"//;
if ($sp && $check =~ /Verilat/i
&& $check !~ /and newer/) {
warn "%Warning: $filename:$.: Verilator text in Sp version: $line";
$Bad = 1;
} elsif (!$sp && $check =~ /\b(Sp|SP)/
) {
warn "%Warning: $filename:$.: Sp text in Verilator version: $line";
$Bad = 1;
} elsif (!$sp && $check =~ /\<uint[0-9]+_t/) {
warn "%Warning: $filename:$.: uint in Verilator version: $line";
$Bad = 1;
}
}
!$off or die "%Error: $filename: SPDIFF_OFF block never terminated\n";
my $wholefile = join('',@wf);
if ($sp) {
$wholefile =~ s/SPTRACEVCDC_VERSION/VERILATED_VCD_VERSION/g;
$wholefile =~ s/SPTRACEVCDC_/VERILATED_VCD_C_/g;
$wholefile =~ s/SPTRACEVCD_TEST/VERILATED_VCD_TEST/g;
$wholefile =~ s/SPTRACEVCD_/VERILATED_VCD_SC_/g;
#
$wholefile =~ s/\bSpTraceFile\b/VerilatedVcdSc/g;
$wholefile =~ s/\bSpTraceFileC\b/VerilatedVcdC/g;
$wholefile =~ s/\bSpTraceVcd\b/VerilatedVcd/g;
$wholefile =~ s/\bSpTraceVcdCFile\b/VerilatedVcdC/g;
#
$wholefile =~ s/\bSpTraceCallInfo\b/VerilatedVcdCallInfo/g;
$wholefile =~ s/\bSpTraceCallback_t/VerilatedVcdCallback_t/g;
$wholefile =~ s/\bSpTraceVcd_/VerilatedVcd_/g;
$wholefile =~ s/\bSpTraceVcdSig\b/VerilatedVcdSig/g;
$wholefile =~ s/\bSpScBvExposer/VlScBvExposer/g;
#
$wholefile =~ s/\b(uint[0-9]+_t)/vl$1/g;
$wholefile =~ s/%ll/%" VL_PRI64 "/g;
$wholefile =~ s/\(long long unsigned\)n/ n/g; # printQuad
#
$wholefile =~ s/\bSP_SC_BV/VL_SC_BV/g;
$wholefile =~ s/\bSP_UNLIKELY/VL_UNLIKELY/g;
}
$fho->print($wholefile);
}
# Local Variables:
# compile-command: "./spdiff $SYP $V4"
# End:
+2 -12
View File
@@ -76,14 +76,6 @@ instead.)
=item
If you will be using SystemPerl or coverage, download and install
System-Perl, L<http://www.veripool.org/systemperl>. Note you'll need to
set a C<SYSTEMPERL> environment variable to point to the downloaded kit.
Optionally also set C<SYSTEMPERL_INCLUDE> to point to the installed
headers.
=item
You will need the C<flex> and C<bison> packages installed.
=item
@@ -95,8 +87,8 @@ C<cd> to the Verilator directory containing this README.
You now have to decide how you're going to eventually install the kit.
Note Verilator builds the current value of VERILATOR_ROOT, SYSTEMC_INCLUDE,
SYSTEMC_LIBDIR, SYSTEMPERL, and SYSTEMPERL_INCLUDE as defaults into the
executable, so try to have them correct before configuring.
and SYSTEMC_LIBDIR as defaults into the executable, so try to have them
correct before configuring.
=over 4
@@ -198,8 +190,6 @@ The directories in the kit after de-taring are as follows:
test_v => Example Verilog code for other test dirs
test_c => Example Verilog->C++ conversion
test_sc => Example Verilog->SystemC conversion
test_sp => Example Verilog->SystemPerl conversion
test_vcs => Example Verilog->VCS conversion (test the test)
test_verilated => Internal tests
test_regress => Internal tests
+6 -2
View File
@@ -46,7 +46,7 @@ obj_opt:
obj_dbg:
mkdir $@
.PHONY: ../verilator_bin ../verilator_bin_dbg
.PHONY: ../verilator_bin ../verilator_bin_dbg ../verilator_coverage_bin_dbg
opt: ../verilator_bin
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
@@ -59,11 +59,15 @@ else
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj
endif
dbg: ../verilator_bin_dbg
dbg: ../verilator_bin_dbg ../verilator_coverage_bin_dbg
../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
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
prefiles::
prefiles:: config_rev.h
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
+19 -7
View File
@@ -127,6 +127,7 @@ HEADERS = $(wildcard V*.h v*.h)
ASTGEN = $(srcdir)/astgen
BISONPRE = $(srcdir)/bisonpre
FLEXFIX = $(srcdir)/flexfix
VLCOVGEN = $(srcdir)/vlcovgen
######################################################################
#### Top level
@@ -186,6 +187,7 @@ RAW_OBJS = \
V3Error.o \
V3Expand.o \
V3File.o \
V3FileLine.o \
V3Gate.o \
V3GenClk.o \
V3Graph.o \
@@ -233,26 +235,30 @@ RAW_OBJS = \
V3WidthSel.o \
# Non-concatable
OBJS += \
NC_OBJS += \
V3ParseImp.o \
V3ParseGrammar.o \
V3ParseLex.o \
V3PreProc.o \
# verilator_coverage
VLCOV_OBJS = \
VlcMain.o \
#### Linking
ifeq ($(VL_DEBUG),)
# Building with fewer objects to better optimize
#OBJS += V3__CONCAT.o
OBJS += $(RAW_OBJS)
ifeq ($(VL_VLCOV),)
PREDEP_H = V3Ast__gen_classes.h
OBJS += $(RAW_OBJS) $(NC_OBJS)
else
OBJS += $(RAW_OBJS)
PREDEP_H =
OBJS += $(VLCOV_OBJS)
endif
V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
$(PERL) $(srcdir)/../bin/verilator_includer $^ > $@
$(TGT): V3Ast__gen_classes.h $(OBJS)
$(TGT): $(PREDEP_H) $(OBJS)
@echo " Linking $@..."
-rm -rf $@ [email protected]
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
@@ -287,6 +293,12 @@ V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
# Target rule called before parallel build to make generated files
serial:: V3Ast__gen_classes.h V3ParseBison.c
serial_vlcov:: vlcovgen.d
vlcovgen.d: $(VLCOVGEN) $(srcdir)/include/verilated_cov_key.h
$(PERL) $(VLCOVGEN) --srcdir $(srcdir)
touch $@
V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h
$(PERL) $(ASTGEN) -I$(srcdir) --classes
+7 -24
View File
@@ -61,10 +61,13 @@ private:
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
AstNode* timesp = nodep->fmtp()->exprsp(); if (timesp) timesp->unlinkFrBack();
// cppcheck-suppress nullPointer
timesp = timesp->addNext(new AstTime(nodep->fileline()));
nodep->fmtp()->exprsp(timesp);
AstNode* timenewp = new AstTime(nodep->fileline());
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
nodep->fmtp()->exprsp(timenewp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
}
@@ -128,19 +131,13 @@ private:
if (message!="") covincp->declp()->comment(message);
bodysp = covincp;
}
} else if (nodep->castPslAssert()) {
bodysp = newFireAssert(nodep,message);
// We assert the property is always true... so report when it fails
// (Note this is opposite the behavior of coverage statements.)
// Need: 'never' operator: not hold in current or any future cycle
propp = new AstLogNot (nodep->fileline(), propp);
} else {
nodep->v3fatalSrc("Unknown node type");
}
if (stmtsp) bodysp = bodysp->addNext(stmtsp);
AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
bodysp = ifp;
if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
//
AstNode* newp = new AstAlways (nodep->fileline(),
VAlwaysKwd::ALWAYS,
@@ -306,12 +303,6 @@ private:
nodep->stmtsp(), nodep->name()); nodep=NULL;
++m_statAsCover;
}
virtual void visit(AstPslAssert* nodep, AstNUser*) {
nodep->iterateChildren(*this);
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
NULL, nodep->name()); nodep=NULL;
++m_statAsPsl;
}
virtual void visit(AstVAssert* nodep, AstNUser*) {
nodep->iterateChildren(*this);
newVAssertion(nodep, nodep->propp()); nodep=NULL;
@@ -336,14 +327,6 @@ private:
m_beginp = lastp;
}
// VISITORS //========== Temporal Layer
// VISITORS //========== Boolean Layer
virtual void visit(AstPslBool* nodep, AstNUser*) {
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
-15
View File
@@ -73,14 +73,6 @@ private:
}
// VISITORS //========== Statements
virtual void visit(AstPslDefClock* nodep, AstNUser*) {
nodep->iterateChildren(*this);
// Store the new default clock, reset on new module
m_seniDefaultp = nodep->sensesp();
// Trash it
nodep->unlinkFrBack();
pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstClocking* nodep, AstNUser*) {
UINFO(8," CLOCKING"<<nodep<<endl);
// Store the new default clock, reset on new module
@@ -101,13 +93,6 @@ private:
nodep->sentreep(newSenTree(nodep));
clearAssertInfo();
}
virtual void visit(AstPslAssert* nodep, AstNUser*) {
if (nodep->sentreep()) return; // Already processed
clearAssertInfo();
nodep->iterateChildren(*this);
nodep->sentreep(newSenTree(nodep));
clearAssertInfo();
}
virtual void visit(AstPslClocked* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_senip) {
+10 -38
View File
@@ -203,31 +203,6 @@ string AstNode::prettyTypeName() const {
return string(typeName())+" '"+prettyName()+"'";
}
string AstNode::quoteName(const string& namein) {
// Encode control chars into C style escapes
// Reverse is V3Parse::deQuote
const char* start = namein.c_str();
string out;
for (const char* pos = start; *pos; pos++) {
if (pos[0]=='\\' || pos[0]=='"') {
out += string("\\")+pos[0];
} else if (pos[0]=='\n') {
out += "\\n";
} else if (pos[0]=='\r') {
out += "\\r";
} else if (pos[0]=='\t') {
out += "\\t";
} else if (isprint(pos[0])) {
out += pos[0];
} else {
// This will also cover \a etc
char octal[10]; sprintf(octal,"\\%03o",pos[0]);
out += octal;
}
}
return out;
}
//######################################################################
// Insertion
@@ -884,24 +859,21 @@ void AstNode::cloneRelinkTree() {
//======================================================================
// Comparison
bool AstNode::sameTree(AstNode* node2p) {
return sameTreeIter(node2p, true);
}
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext) {
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext, bool gateOnly) {
// Return true if the two trees are identical
if (this==NULL && node2p==NULL) return true;
if (this==NULL || node2p==NULL) return false;
if (this->type() != node2p->type()
|| this->dtypep() != node2p->dtypep()
|| !this->same(node2p)) {
|| !this->same(node2p)
|| (gateOnly && !this->isGateOptimizable())) {
return false;
}
return (this->op1p()->sameTreeIter(node2p->op1p(),false)
&& this->op2p()->sameTreeIter(node2p->op2p(),false)
&& this->op3p()->sameTreeIter(node2p->op3p(),false)
&& this->op4p()->sameTreeIter(node2p->op4p(),false)
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false))
return (this->op1p()->sameTreeIter(node2p->op1p(),false,gateOnly)
&& this->op2p()->sameTreeIter(node2p->op2p(),false,gateOnly)
&& this->op3p()->sameTreeIter(node2p->op3p(),false,gateOnly)
&& this->op4p()->sameTreeIter(node2p->op4p(),false,gateOnly)
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false,gateOnly))
);
}
@@ -915,8 +887,8 @@ ostream& operator<<(ostream& os, V3Hash rhs) {
V3Hash::V3Hash(const string& name) {
uint32_t val = 0;
for (const char* c=name.c_str(); *c; c++) {
val = val*31 + *c;
for (string::const_iterator it = name.begin(); it!=name.end(); ++it) {
val = val*31 + *it;
}
setBoth(1,val);
}
+75 -34
View File
@@ -23,6 +23,7 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Number.h"
#include "V3Global.h"
#include <vector>
@@ -236,6 +237,15 @@ public:
DIM_SIZE, // V3Width processes
DIM_UNPK_DIMENSIONS, // V3Width converts to constant
//
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
//
ENUM_FIRST, // V3Width processes
ENUM_LAST, // V3Width processes
ENUM_NUM, // V3Width processes
ENUM_NEXT, // V3Width processes
ENUM_PREV, // V3Width processes
ENUM_NAME, // V3Width processes
//
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
//
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
@@ -255,6 +265,8 @@ public:
"%E-AT",
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
"DT_PUBLIC",
"ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME",
"MEMBER_BASE",
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
@@ -380,9 +392,8 @@ public:
bool isOpaque() const { // IE not a simple number we can bit optimize
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT);
}
bool isDouble() const {
return (m_e==DOUBLE);
}
bool isDouble() const { return m_e==DOUBLE; }
bool isString() const { return m_e==STRING; }
};
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
@@ -932,7 +943,7 @@ class AstNode {
AstNode* cloneTreeIterList();
void checkTreeIter(AstNode* backp);
void checkTreeIterList(AstNode* backp);
bool sameTreeIter(AstNode* node2p, bool ignNext);
bool sameTreeIter(AstNode* node2p, bool ignNext, bool gateOnly);
void deleteTreeIter();
void deleteNode();
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
@@ -1004,6 +1015,7 @@ public:
static int instrCountDouble() { return 8; } ///< Instruction cycles to convert or do floats
static int instrCountDoubleDiv() { return 40; } ///< Instruction cycles to divide floats
static int instrCountDoubleTrig() { return 200; } ///< Instruction cycles to do triganomics
static int instrCountString() { return 100; } ///< Instruction cycles to do string ops
static int instrCountCall() { return instrCountBranch()+10; } ///< Instruction cycles to call subroutine
static int instrCountTime() { return instrCountCall()+5; } ///< Instruction cycles to determine simulation time
@@ -1013,7 +1025,6 @@ public:
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
static string quoteName(const string& namein); // Name with control chars quoted
static string prettyName(const string& namein); // Name for printing out to the user
static string encodeName(const string& namein); // Encode user name into internal C representation
static string encodeNumber(vlsint64_t numin); // Encode number into internal C representation
@@ -1039,6 +1050,7 @@ public:
bool isWide() const { return (width()>VL_QUADSIZE); }
bool isDouble() const;
bool isSigned() const;
bool isString() const;
AstNUser* user1p() const {
// Slows things down measurably, so disabled by default
@@ -1116,6 +1128,7 @@ public:
void dtypeSetLogicSized(int width, int widthMin, AstNumeric numeric) { dtypep(findLogicDType(width,widthMin,numeric)); }
void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); }
void dtypeSetDouble() { dtypep(findDoubleDType()); }
void dtypeSetString() { dtypep(findStringDType()); }
void dtypeSetSigned32() { dtypep(findSigned32DType()); }
void dtypeSetUInt32() { dtypep(findUInt32DType()); } // Twostate
void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate
@@ -1123,6 +1136,7 @@ public:
// Data type locators
AstNodeDType* findLogicBoolDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); }
AstNodeDType* findDoubleDType() { return findBasicDType(AstBasicDTypeKwd::DOUBLE); }
AstNodeDType* findStringDType() { return findBasicDType(AstBasicDTypeKwd::STRING); }
AstNodeDType* findSigned32DType() { return findBasicDType(AstBasicDTypeKwd::INTEGER); }
AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); } // Twostate
AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); } // Twostate
@@ -1158,6 +1172,7 @@ public:
// METHODS - Iterate on a tree
AstNode* cloneTree(bool cloneNextLink);
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
void checkTree(); // User Interface version
void checkIter() const;
@@ -1216,8 +1231,9 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
virtual ~Ast ##name() {} \
Ast ##name * cloneTree(bool cloneNext) { return AstNode::cloneTree(cloneNext)->cast ##name(); }
struct AstNodeMath : public AstNode {
class AstNodeMath : public AstNode {
// Math -- anything that's part of an expression tree
public:
AstNodeMath(FileLine* fl)
: AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeMath)
@@ -1232,8 +1248,9 @@ struct AstNodeMath : public AstNode {
bool isOpaque() { return castCvtPackString()!=NULL; }
};
struct AstNodeTermop : public AstNodeMath {
class AstNodeTermop : public AstNodeMath {
// Terminal operator -- a operator with no "inputs"
public:
AstNodeTermop(FileLine* fl)
: AstNodeMath(fl) {}
ASTNODE_BASE_FUNCS(NodeTermop)
@@ -1243,8 +1260,9 @@ struct AstNodeTermop : public AstNodeMath {
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
};
struct AstNodeUniop : public AstNodeMath {
class AstNodeUniop : public AstNodeMath {
// Unary math
public:
AstNodeUniop(FileLine* fl, AstNode* lhsp)
: AstNodeMath(fl) {
dtypeFrom(lhsp);
@@ -1256,15 +1274,17 @@ struct AstNodeUniop : public AstNodeMath {
virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; // Set out to evaluation of a AstConst'ed lhs
virtual bool cleanLhs() = 0;
virtual bool sizeMattersLhs() = 0; // True if output result depends on lhs size
virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors?
virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors?
virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors?
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; }
};
struct AstNodeBiop : public AstNodeMath {
class AstNodeBiop : public AstNodeMath {
// Binary math
public:
AstNodeBiop(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeMath(fl) {
setOp1p(lhs); setOp2p(rhs); }
@@ -1279,15 +1299,17 @@ struct AstNodeBiop : public AstNodeMath {
virtual bool cleanRhs() = 0; // True if RHS must have extra upper bits zero
virtual bool sizeMattersLhs() = 0; // True if output result depends on lhs size
virtual bool sizeMattersRhs() = 0; // True if output result depends on rhs size
virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors?
virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors?
virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors?
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; }
};
struct AstNodeTriop : public AstNodeMath {
class AstNodeTriop : public AstNodeMath {
// Trinary math
public:
AstNodeTriop(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNodeMath(fl) {
setOp1p(lhs); setOp2p(rhs); setOp3p(ths); }
@@ -1311,20 +1333,23 @@ struct AstNodeTriop : public AstNodeMath {
virtual bool same(AstNode*) const { return true; }
};
struct AstNodeBiCom : public AstNodeBiop {
class AstNodeBiCom : public AstNodeBiop {
// Binary math with commutative properties
public:
AstNodeBiCom(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiop(fl, lhs, rhs) {}
ASTNODE_BASE_FUNCS(NodeBiCom)
};
struct AstNodeBiComAsv : public AstNodeBiCom {
class AstNodeBiComAsv : public AstNodeBiCom {
// Binary math with commutative & associative properties
public:
AstNodeBiComAsv(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiCom(fl, lhs, rhs) {}
ASTNODE_BASE_FUNCS(NodeBiComAsv)
};
struct AstNodeCond : public AstNodeTriop {
class AstNodeCond : public AstNodeTriop {
public:
AstNodeCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
: AstNodeTriop(fl, condp, expr1p, expr2p) {
if (expr1p) dtypeFrom(expr1p);
@@ -1346,8 +1371,9 @@ struct AstNodeCond : public AstNodeTriop {
virtual int instrCount() const { return instrCountBranch(); }
};
struct AstNodePreSel : public AstNode {
class AstNodePreSel : public AstNode {
// Something that becomes an AstSel
public:
AstNodePreSel(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNode(fl) {
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
@@ -1366,8 +1392,9 @@ struct AstNodePreSel : public AstNode {
virtual bool same(AstNode*) const { return true; }
};
struct AstNodeStmt : public AstNode {
class AstNodeStmt : public AstNode {
// Statement -- anything that's directly under a function
public:
AstNodeStmt(FileLine* fl)
: AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeStmt)
@@ -1376,7 +1403,8 @@ struct AstNodeStmt : public AstNode {
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
};
struct AstNodeAssign : public AstNodeStmt {
class AstNodeAssign : public AstNodeStmt {
public:
AstNodeAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeStmt(fl) {
setOp1p(rhsp); setOp2p(lhsp);
@@ -1397,7 +1425,8 @@ struct AstNodeAssign : public AstNodeStmt {
virtual string verilogKwd() const { return "="; }
};
struct AstNodeFor : public AstNodeStmt {
class AstNodeFor : public AstNodeStmt {
public:
AstNodeFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
AstNode* incsp, AstNode* bodysp)
: AstNodeStmt(fileline) {
@@ -1414,7 +1443,7 @@ struct AstNodeFor : public AstNodeStmt {
virtual bool same(AstNode* samep) const { return true; }
};
struct AstNodeIf : public AstNodeStmt {
class AstNodeIf : public AstNodeStmt {
private:
AstBranchPred m_branchPred; // Branch prediction as taken/untaken?
public:
@@ -1438,7 +1467,8 @@ public:
AstBranchPred branchPred() const { return m_branchPred; }
};
struct AstNodeCase : public AstNodeStmt {
class AstNodeCase : public AstNodeStmt {
public:
AstNodeCase(FileLine* fl, AstNode* exprp, AstNode* casesp)
: AstNodeStmt(fl) {
setOp1p(exprp); addNOp2p(casesp);
@@ -1452,8 +1482,9 @@ struct AstNodeCase : public AstNodeStmt {
void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
};
struct AstNodeSenItem : public AstNode {
class AstNodeSenItem : public AstNode {
// An AstSenItem or AstSenGate
public:
AstNodeSenItem(FileLine* fl) : AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeSenItem)
virtual bool isClocked() const = 0;
@@ -1511,7 +1542,7 @@ public:
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
};
struct AstNodeText : public AstNode {
class AstNodeText : public AstNode {
private:
string m_text;
public:
@@ -1528,11 +1559,11 @@ public:
const string& text() const { return m_text; }
};
struct AstNodeDType : public AstNode {
private:
class AstNodeDType : public AstNode {
// Ideally width() would migrate to BasicDType as that's where it makes sense,
// but it's currently so prevalent in the code we leave it here.
// Note the below members are included in AstTypeTable::Key lookups
private:
int m_width; // (also in AstTypeTable::Key) Bit width of operation
int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation
AstNumeric m_numeric; // (also in AstTypeTable::Key) Node is signed
@@ -1550,8 +1581,9 @@ public:
virtual void dumpSmall(ostream& str);
virtual bool hasDType() const { return true; }
virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs to next non-typeref type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs/const/enum to next non-typeref type
virtual AstNodeDType* skipRefToConstp() const = 0; // recurses over typedefs to next non-typeref-or-const type
virtual AstNodeDType* skipRefToEnump() const = 0; // recurses over typedefs/const to next non-typeref-or-enum/struct type
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
virtual bool maybePointedTo() const { return true; }
@@ -1581,7 +1613,7 @@ public:
static int uniqueNumInc() { return ++s_uniqueNum; }
};
struct AstNodeClassDType : public AstNodeDType {
class AstNodeClassDType : public AstNodeDType {
private:
// TYPES
typedef map<string,AstMemberDType*> MemberNameMap;
@@ -1602,6 +1634,7 @@ public:
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// op1 = members
@@ -1620,7 +1653,7 @@ public:
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
};
struct AstNodeArrayDType : public AstNodeDType {
class AstNodeArrayDType : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
@@ -1658,6 +1691,7 @@ public:
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); }
int msb() const;
@@ -1666,8 +1700,9 @@ public:
VNumRange declRange() const;
};
struct AstNodeSel : public AstNodeBiop {
class AstNodeSel : public AstNodeBiop {
// Single bit range extraction, perhaps with non-constant selection or array selection
public:
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
:AstNodeBiop(fl, fromp, bitp) {}
ASTNODE_BASE_FUNCS(NodeSel)
@@ -1679,8 +1714,9 @@ struct AstNodeSel : public AstNodeBiop {
virtual bool hasDType() const { return true; }
};
struct AstNodeStream : public AstNodeBiop {
class AstNodeStream : public AstNodeBiop {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
public:
AstNodeStream(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (lhsp->dtypep()) {
dtypeSetLogicSized(lhsp->dtypep()->width(), lhsp->dtypep()->width(), AstNumeric::UNSIGNED);
@@ -1692,7 +1728,7 @@ struct AstNodeStream : public AstNodeBiop {
//######################################################################
// Tasks/functions common handling
struct AstNodeFTask : public AstNode {
class AstNodeFTask : public AstNode {
private:
string m_name; // Name of task
string m_cname; // Name of task if DPI import
@@ -1750,7 +1786,7 @@ public:
bool pure() const { return m_pure; }
};
struct AstNodeFTaskRef : public AstNode {
class AstNodeFTaskRef : public AstNode {
// A reference to a task (or function)
private:
AstNodeFTask* m_taskp; // [AfterLink] Pointer to task referenced
@@ -1796,7 +1832,7 @@ public:
void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
};
struct AstNodeModule : public AstNode {
class AstNodeModule : public AstNode {
// A module, package, program or interface declaration;
// something that can live directly under the TOP,
// excluding $unit package stuff
@@ -1810,12 +1846,13 @@ private:
bool m_internal:1; // Internally created
int m_level; // 1=top module, 2=cell off top module, ...
int m_varNum; // Incrementing variable number
int m_typeNum; // Incrementing implicit type number
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_level(0), m_varNum(0) { }
,m_level(0), m_varNum(0), m_typeNum(0) { }
ASTNODE_BASE_FUNCS(NodeModule)
virtual void dump(ostream& str);
virtual bool maybePointedTo() const { return true; }
@@ -1835,6 +1872,7 @@ public:
int level() const { return m_level; }
bool isTop() const { return level()==1; }
int varNumGetInc() { return ++m_varNum; }
int typeNumGetInc() { return ++m_typeNum; }
void modPublic(bool flag) { m_modPublic = flag; }
bool modPublic() const { return m_modPublic; }
void modTrace(bool flag) { m_modTrace = flag; }
@@ -1861,6 +1899,7 @@ inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() :
inline bool AstNode::width1() const { return dtypep() && dtypep()->width()==1; } // V3Const uses to know it can optimize
inline int AstNode::widthInstrs() const { return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); }
inline bool AstNode::isDouble() const { return dtypep() && dtypep()->castBasicDType() && dtypep()->castBasicDType()->isDouble(); }
inline bool AstNode::isString() const { return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); }
inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
inline bool AstNode::isZero() { return (this->castConst() && this->castConst()->num().isEqZero()); }
@@ -1868,6 +1907,8 @@ inline bool AstNode::isNeqZero() { return (this->castConst() && this->castConst
inline bool AstNode::isOne() { return (this->castConst() && this->castConst()->num().isEqOne()); }
inline bool AstNode::isAllOnes() { return (this->castConst() && this->castConst()->isEqAllOnes()); }
inline bool AstNode::isAllOnesV() { return (this->castConst() && this->castConst()->isEqAllOnesV()); }
inline bool AstNode::sameTree(AstNode* node2p) { return sameTreeIter(node2p, true, false); }
inline bool AstNode::sameGateTree(AstNode* node2p) { return sameTreeIter(node2p, true, true); }
inline void AstNodeVarRef::init() { if (m_varp) dtypep(m_varp->dtypep()); }
+30 -2
View File
@@ -515,6 +515,24 @@ string AstScopeName::scopeSymName() const {
return out;
}
string AstScopeName::scopeDpiName() const {
string out;
for (AstText* textp=scopeEntrp(); textp; textp=textp->nextp()->castText()) {
out += textp->text();
}
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
if (out.substr(0,1) == ".") out.replace(0,1,"");
string::size_type pos;
while ((pos=out.find(".")) != string::npos) {
out.replace(pos, 1, "__");
}
while ((pos=out.find("__DOT__")) != string::npos) {
out.replace(pos, 7, "__");
}
return out;
}
bool AstSenTree::hasClocked() {
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp=senp->nextp()->castNodeSenItem()) {
@@ -719,7 +737,10 @@ void AstNode::dump(ostream& str) {
} else { // V3Broken will throw an error
if (dtypep()) str<<" %Error-dtype-exp=null,got="<<(void*)dtypep();
}
if (name()!="") str<<" "<<AstNode::quoteName(name());
if (name()!="") {
if (castConst()) str<<" "<<name(); // Already quoted
else str<<" "<<V3Number::quoteNameControls(name());
}
}
void AstAlways::dump(ostream& str) {
@@ -801,6 +822,10 @@ void AstPin::dump(ostream& str) {
else { str<<" ->UNLINKED"; }
if (svImplicit()) str<<" [.SV]";
}
void AstTypedef::dump(ostream& str) {
this->AstNode::dump(str);
if (attrPublic()) str<<" [PUBLIC]";
}
void AstRange::dump(ostream& str) {
this->AstNode::dump(str);
if (littleEndian()) str<<" [LITTLE]";
@@ -828,7 +853,10 @@ void AstNodeDType::dumpSmall(ostream& str) {
<<((isSigned()&&!isDouble())?"s":"")
<<(isNosign()?"n":"")
<<(isDouble()?"d":"")
<<"w"<<(widthSized()?"":"u")<<width();
<<(isString()?"str":"");
if (!isDouble() && !isString()) {
str<<"w"<<(widthSized()?"":"u")<<width();
}
if (!widthSized()) str<<"/"<<widthMin();
str<<")";
}
+621 -331
View File
File diff suppressed because it is too large Load Diff
+41 -6
View File
@@ -21,6 +21,9 @@
// At each IF/(IF else).
// Count underneath $display/$stop statements.
// If more on if than else, this branch is unlikely, or vice-versa.
// At each FTASKREF,
// Count calls into the function
// Then, if FTASK is called only once, add inline attribute
//
//*************************************************************************
@@ -40,9 +43,18 @@
class BranchVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstFTask::user1() -> int. Number of references
AstUser1InUse m_inuser1;
// TYPES
typedef vector<AstCFunc*> CFuncVec;
// STATE
int m_likely; // Excuses for branch likely taken
int m_unlikely; // Excuses for branch likely not taken
CFuncVec m_cfuncsp; // List of all tasks
// METHODS
static int debug() {
@@ -55,6 +67,12 @@ private:
m_likely = false;
m_unlikely = false;
}
void checkUnlikely(AstNode* nodep) {
if (nodep->isUnlikely()) {
UINFO(4," UNLIKELY: "<<nodep<<endl);
m_unlikely++;
}
}
// VISITORS
virtual void visit(AstNodeIf* nodep, AstNUser*) {
@@ -83,20 +101,37 @@ private:
m_likely = lastLikely;
m_unlikely = lastUnlikely;
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
if (nodep->isUnlikely()) {
UINFO(4," UNLIKELY: "<<nodep<<endl);
m_unlikely++;
}
virtual void visit(AstCCall* nodep, AstNUser*) {
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
nodep->iterateChildren(*this);
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
checkUnlikely(nodep);
nodep->iterateChildren(*this);
}
// METHODS
void calc_tasks() {
for (CFuncVec::iterator it=m_cfuncsp.begin(); it!=m_cfuncsp.end(); ++it) {
AstCFunc* nodep = *it;
if (!nodep->dontInline()) {
nodep->isInline(true);
}
}
}
public:
// CONSTUCTORS
BranchVisitor(AstNetlist* nodep) {
reset();
nodep->iterateChildren(*this);
calc_tasks();
}
virtual ~BranchVisitor() {}
};
+11 -9
View File
@@ -83,17 +83,19 @@ private:
void genChangeDet(AstVarScope* vscp) {
AstVar* varp = vscp->varp();
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstUnpackArrayDType* uarrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstPackArrayDType* parrayp = varp->dtypeSkipRefp()->castPackArrayDType();
AstNodeClassDType *classp = varp->dtypeSkipRefp()->castNodeClassDType();
bool isArray = arrayp;
bool isUnpackArray = uarrayp;
bool isPackArray = parrayp;
bool isClass = classp && classp->packedUnsup();
int elements = isArray ? arrayp->elementsConst() : 1;
if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
int elements = isUnpackArray ? uarrayp->elementsConst() : 1;
if (isUnpackArray && (elements > DETECTARRAY_MAX_INDEXES)) {
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
<<vscp->warnMore()
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
} else if (!isArray && !isClass
} else if (!isUnpackArray && !isClass && !isPackArray
&& !varp->dtypeSkipRefp()->castBasicDType()) {
if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
@@ -110,17 +112,17 @@ private:
for (int index=0; index<elements; ++index) {
AstChangeDet* changep
= new AstChangeDet (vscp->fileline(),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), vscp, false)),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), newvscp, false)),
false);
m_chgFuncp->addStmtsp(changep);
AstAssign* initp
= new AstAssign (vscp->fileline(),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), newvscp, true)),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), vscp, false)));
m_chgFuncp->addFinalsp(initp);
}
+4
View File
@@ -238,6 +238,10 @@ private:
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->valuep());
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
// No cleaning, or would loose pointer to enum
nodep->iterateChildren(*this);
}
// Control flow operators
virtual void visit(AstNodeCond* nodep, AstNUser*) {
+1
View File
@@ -24,6 +24,7 @@
#include "verilatedos.h"
#include <string>
#include "V3Error.h"
#include "V3FileLine.h"
//######################################################################
+157 -10
View File
@@ -173,6 +173,16 @@ private:
if (rnodep->width() != bnodep->width()) return false;
return rnodep->lhsp()->castConst();
}
static bool operandSubAdd(AstNode* nodep) {
// SUB( ADD(CONSTx,y), CONSTz) -> ADD(SUB(CONSTx,CONSTz), y)
AstNodeBiop* np = nodep->castNodeBiop();
AstNodeBiop* lp = np->lhsp()->castNodeBiop();
return (lp
&& lp->lhsp()->castConst()
&& np->rhsp()->castConst()
&& lp->width()==np->width());
}
static bool operandAndOrSame(AstNode* nodep) {
// OR( AND(VAL,x), AND(VAL,y)) -> AND(VAL,OR(x,y))
// OR( AND(x,VAL), AND(y,VAL)) -> AND(OR(x,y),VAL)
@@ -274,6 +284,8 @@ private:
// We can only get rid of a<<b>>c or a<<b<<c, with constant b & c
// because bits may be masked in that process, or (b+c) may exceed the word width.
if (!(nodep->rhsp()->castConst() && lhsp->rhsp()->castConst())) return false;
if (nodep->rhsp()->castConst()->num().isFourState()
|| lhsp->rhsp()->castConst()->num().isFourState()) return false;
if (nodep->width()!=lhsp->width()) return false;
if (nodep->width()!=lhsp->lhsp()->width()) return false;
return true;
@@ -416,12 +428,12 @@ private:
static bool operandsSame(AstNode* node1p, AstNode* node2p) {
// For now we just detect constants & simple vars, though it could be more generic
if (node1p->castConst() && node2p->castConst()) {
return node1p->sameTree(node2p);
return node1p->sameGateTree(node2p);
}
else if (node1p->castVarRef() && node2p->castVarRef()) {
// Avoid comparing widthMin's, which results in lost optimization attempts
// If cleanup sameTree to be smarter, this can be restored.
//return node1p->sameTree(node2p);
// If cleanup sameGateTree to be smarter, this can be restored.
//return node1p->sameGateTree(node2p);
return node1p->same(node2p);
} else {
return false;
@@ -437,7 +449,7 @@ private:
AstVarRef* elsevarp = elsep->lhsp()->castVarRef();
if (!ifvarp || !elsevarp) return false;
if (ifvarp->isWide()) return false; // Would need temporaries, so not worth it
if (!ifvarp->sameTree(elsevarp)) return false;
if (!ifvarp->sameGateTree(elsevarp)) return false;
return true;
}
bool operandIfIf(AstNodeIf* nodep) {
@@ -448,6 +460,89 @@ private:
if (afterComment(lowerIfp->elsesp())) return false;
return true;
}
bool ifConcatMergeableBiop(AstNode* nodep) {
return (nodep->castAnd()
|| nodep->castOr()
|| nodep->castXor()
|| nodep->castXnor());
}
bool ifAdjacentSel(AstSel* lhsp, AstSel* rhsp) {
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (!lhsp || !rhsp) return false;
AstNode* lfromp = lhsp->fromp();
AstNode* rfromp = rhsp->fromp();
if (!lfromp || !rfromp || !lfromp->sameGateTree(rfromp)) return false;
AstConst* lstart = lhsp->lsbp()->castConst();
AstConst* rstart = rhsp->lsbp()->castConst();
AstConst* lwidth = lhsp->widthp()->castConst();
AstConst* rwidth = rhsp->widthp()->castConst();
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
int rend = (rstart->toSInt() + rwidth->toSInt());
if (rend == lstart->toSInt()) return true;
return false;
}
bool ifMergeAdjacent(AstNode* lhsp, AstNode* rhsp) {
// called by concatmergeable to determine if {lhsp, rhsp} make sense
if (!v3Global.opt.oAssemble()) return false; // opt disabled
// two same varref
if (operandsSame(lhsp, rhsp)) return true;
AstSel* lselp = lhsp->castSel();
AstSel* rselp = rhsp->castSel();
// a[i:0] a
if (lselp && !rselp && rhsp->sameGateTree(lselp->fromp()))
rselp = new AstSel(rhsp->fileline(), rhsp->cloneTree(false), 0, rhsp->width());
// a[i:j] {a[j-1:k], b}
if (lselp && !rselp && rhsp->castConcat())
return ifMergeAdjacent(lhsp, rhsp->castConcat()->lhsp());
// a a[msb:j]
if (rselp && !lselp && lhsp->sameGateTree(rselp->fromp()))
lselp = new AstSel(lhsp->fileline(), lhsp->cloneTree(false), 0, lhsp->width());
// {b, a[j:k]} a[k-1:i]
if (rselp && !lselp && lhsp->castConcat())
return ifMergeAdjacent(lhsp->castConcat()->rhsp(), rhsp);
if (!lselp || !rselp) return false;
// a[a:b] a[b-1:c] are adjacent
AstNode* lfromp = lselp->fromp();
AstNode* rfromp = rselp->fromp();
if (!lfromp || !rfromp || !lfromp->sameGateTree(rfromp)) return false;
AstConst* lstart = lselp->lsbp()->castConst();
AstConst* rstart = rselp->lsbp()->castConst();
AstConst* lwidth = lselp->widthp()->castConst();
AstConst* rwidth = rselp->widthp()->castConst();
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
int rend = (rstart->toSInt() + rwidth->toSInt());
// a[i:j] a[j-1:k]
if (rend == lstart->toSInt()) return true;
// a[i:0] a[msb:j]
if (rend == rfromp->width() && lstart->toSInt() == 0) return true;
return false;
}
bool concatMergeable(AstNode* lhsp, AstNode* rhsp) {
// determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantagous
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (lhsp->type() != rhsp->type()) return false;
if (!ifConcatMergeableBiop(lhsp)) return false;
AstNodeBiop* lp = lhsp->castNodeBiop();
AstNodeBiop* rp = rhsp->castNodeBiop();
if (!lp || !rp) return false;
// {a[]&b[], a[]&b[]}
bool lad = ifMergeAdjacent(lp->lhsp(), rp->lhsp());
bool rad = ifMergeAdjacent(lp->rhsp(), rp->rhsp());
if (lad && rad) return true;
// {a[] & b[]&c[], a[] & b[]&c[]}
else if (lad && concatMergeable(lp->rhsp(), rp->rhsp())) return true;
// {a[]&b[] & c[], a[]&b[] & c[]}
else if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true;
else {
// {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])}
if (concatMergeable(lp->lhsp(), rp->lhsp())
&& concatMergeable(lp->rhsp(), rp->rhsp()))
return true;
}
return false;
}
//----------------------------------------
// Constant Replacement functions.
@@ -529,7 +624,7 @@ private:
void replaceConstString (AstNode* oldp, const string& num) {
// Replace oldp node with a constant set to specified value
UASSERT (oldp, "Null old\n");
AstNode* newp = new AstConstString(oldp->fileline(), num);
AstNode* newp = new AstConst(oldp->fileline(), AstConst::String(), num);
if (debug()>5) oldp->dumpTree(cout," const_old: ");
if (debug()>5) newp->dumpTree(cout," _new: ");
oldp->replaceWith(newp);
@@ -666,6 +761,45 @@ private:
rrp->deleteTree();
//nodep->dumpTree(cout, " repShiftSame_new: ");
}
void replaceConcatSel(AstConcat* nodep) {
// {a[1], a[0]} -> a[1:0]
AstSel* lselp = nodep->lhsp()->unlinkFrBack()->castSel();
AstSel* rselp = nodep->rhsp()->unlinkFrBack()->castSel();
int lstart = lselp->lsbConst();
int lwidth = lselp->widthConst();
int rstart = rselp->lsbConst();
int rwidth = rselp->widthConst();
if ((rstart + rwidth) != lstart) nodep->v3fatalSrc("tried to merge two selects which are not adjacent");
AstSel* newselp = new AstSel(lselp->fromp()->fileline(), rselp->fromp()->cloneTree(false), rstart, lwidth+rwidth);
UINFO(5, "merged two adjacent sel "<<lselp <<" and "<<rselp<< " to one "<<newselp<<endl);
nodep->replaceWith(newselp);
lselp->deleteTree(); lselp = NULL;
rselp->deleteTree(); rselp = NULL;
nodep->deleteTree(); nodep = NULL;
}
void replaceConcatMerge(AstConcat* nodep) {
AstNodeBiop* lp = nodep->lhsp()->castNodeBiop();
AstNodeBiop* rp = nodep->rhsp()->castNodeBiop();
AstNode* llp = lp->lhsp()->cloneTree(false);
AstNode* lrp = lp->rhsp()->cloneTree(false);
AstNode* rlp = rp->lhsp()->cloneTree(false);
AstNode* rrp = rp->rhsp()->cloneTree(false);
if (concatMergeable(lp, rp)) {
AstConcat* newlp = new AstConcat(rlp->fileline(), llp, rlp);
AstConcat* newrp = new AstConcat(rrp->fileline(), lrp, rrp);
// use the lhs to replace the parent concat
lp->lhsp()->replaceWith(newlp);
lp->rhsp()->replaceWith(newrp);
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::fromBool(true));
UINFO(5, "merged "<< nodep <<endl);
rp->unlinkFrBack()->deleteTree(); rp = NULL;
nodep->replaceWith(lp->unlinkFrBack()); nodep->deleteTree(); nodep = NULL;
lp->lhsp()->accept(*this);
lp->rhsp()->accept(*this);
} else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
}
void replaceExtend (AstNode* nodep, AstNode* arg0p) {
// -> EXTEND(nodep)
// like a AstExtend{$rhsp}, but we need to set the width correctly from base node
@@ -790,7 +924,7 @@ private:
AstSel* sel2p = nextp->lhsp()->castSel(); if (!sel2p) return false;
AstVarRef* varref1p = sel1p->fromp()->castVarRef(); if (!varref1p) return false;
AstVarRef* varref2p = sel2p->fromp()->castVarRef(); if (!varref2p) return false;
if (!varref1p->sameTree(varref2p)) return false;
if (!varref1p->sameGateTree(varref2p)) return false;
AstConst* con1p = sel1p->lsbp()->castConst(); if (!con1p) return false;
AstConst* con2p = sel2p->lsbp()->castConst(); if (!con2p) return false;
// We need to make sure there's no self-references involved in either
@@ -1323,6 +1457,7 @@ private:
&& v3Global.opt.oConst()
&& !(nodep->varp()->isFuncLocal() // Default value, not a "known" constant for this usage
&& nodep->varp()->isInput())
&& !nodep->varp()->noSubst()
&& !nodep->varp()->isSigPublic())
|| nodep->varp()->isParam())) {
if (operandConst(valuep)) {
@@ -1537,7 +1672,7 @@ private:
AstSenItem* litemp = senp->castSenItem();
AstSenItem* ritemp = cmpp->castSenItem();
if (litemp && ritemp) {
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameTree(ritemp->varrefp()))
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameGateTree(ritemp->varrefp()))
|| (!litemp->varrefp() && !ritemp->varrefp())) {
// We've sorted in the order ANY, BOTH, POS, NEG, so we don't need to try opposite orders
if (( litemp->edgeType()==AstEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
@@ -1694,8 +1829,9 @@ private:
string fmt = "";
bool inPct = false;
AstNode* argp = nodep->exprsp();
for (const char* inp = nodep->text().c_str(); *inp; inp++) {
char ch = *inp; // Breaks with iterators...
string text = nodep->text();
for (string::const_iterator it = text.begin(); it!=text.end(); ++it) {
char ch = *it;
if (!inPct && ch=='%') {
inPct = true;
fmt = ch;
@@ -1907,6 +2043,7 @@ private:
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
// Trinary ops
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
@@ -2005,22 +2142,28 @@ private:
TREEOP ("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP ("AstEqD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP ("AstEqN {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP ("AstEqCase {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstEqWild {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGtD {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGtN {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGteD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGteN {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLtD {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLtN {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLteD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLteN {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqD {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqN {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqWild{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
@@ -2061,6 +2204,9 @@ private:
// CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c}))
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{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)");
TREEOP ("AstOr {$lhsp.castAnd,$rhsp.castAnd,operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
@@ -2068,11 +2214,12 @@ private:
TREEOP ("AstAnd {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
TREEOP ("AstOr {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
TREEOP ("AstXor {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
TREEOP ("AstXnor{operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
// "AstXnor{operandShiftSame(nodep)}", // Cannot ShiftSame as the shifted-in zeros might create a one
// Note can't simplify a extend{extends}, extends{extend}, as the sign bits end up in the wrong places
TREEOPV("AstExtend {$lhsp.castExtend}", "replaceExtend(nodep, nodep->lhsp()->castExtend()->lhsp())");
TREEOPV("AstExtendS{$lhsp.castExtendS}", "replaceExtend(nodep, nodep->lhsp()->castExtendS()->lhsp())");
TREEOPV("AstReplicate{$lhsp, $rhsp.isOne, $lhsp->width()==nodep->width()}", "replaceWLhs(nodep)"); // {1{lhs}}->lhs
TREEOPV("AstReplicateN{$lhsp, $rhsp.isOne, $lhsp->width()==nodep->width()}", "replaceWLhs(nodep)"); // {1{lhs}}->lhs
// Next rule because AUTOINST puts the width of bits in
// to pins, even when the widths are exactly the same across the hierarchy.
TREEOPV("AstSel{operandSelExtend(nodep)}", "DONE");
+16
View File
@@ -81,6 +81,7 @@ private:
typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap;
// STATE
AstNodeModule* m_modp; // Current module
vector<AstNode*> m_varEtcsp; // List of all encountered to avoid another loop through tree
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
@@ -112,6 +113,12 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_modp = nodep;
nodep->iterateChildren(*this);
checkAll(nodep);
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
@@ -158,6 +165,13 @@ private:
nodep->packagep()->user1Inc();
}
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
// Don't let packages with only public variables disappear
// Normal modules may disappear, e.g. if they are parameterized then removed
if (nodep->attrPublic() && m_modp && m_modp->castPackage()) m_modp->user1Inc();
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
@@ -168,6 +182,7 @@ private:
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
if (nodep->isSigPublic() && m_modp && m_modp->castPackage()) m_modp->user1Inc();
if (mightElim(nodep)) {
m_varEtcsp.push_back(nodep);
}
@@ -253,6 +268,7 @@ private:
public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes) {
m_modp = NULL;
m_elimUserVars = elimUserVars;
m_elimDTypes = elimDTypes;
m_sideEffect = false;
+79 -29
View File
@@ -96,6 +96,38 @@ public:
}
}
void emitTypedefs(AstNode* firstp) {
bool first = true;
for (AstNode* loopp=firstp; loopp; loopp = loopp->nextp()) {
if (AstTypedef* nodep = loopp->castTypedef()) {
if (nodep->attrPublic()) {
if (first) {
first = false;
puts("\n// TYPEDEFS\n");
puts("// That were declared public\n");
} else {
puts("\n");
}
if (AstEnumDType* adtypep = nodep->dtypep()->skipRefToEnump()->castEnumDType()) {
if (adtypep->width()>64) {
puts("// enum "+nodep->name()+" // Ignored: Too wide for C++\n");
} else {
puts("enum "+nodep->name()+" {\n");
for (AstEnumItem* itemp = adtypep->itemsp(); itemp; itemp=itemp->nextp()->castEnumItem()) {
puts(itemp->name());
puts(" = ");
itemp->valuep()->iterateAndNext(*this);
if (nodep->nextp()) puts(",");
puts("\n");
}
puts("};\n");
}
}
}
}
}
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
bool paren = true; bool decind = false;
@@ -195,9 +227,9 @@ public:
puts("&(vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts("])");
// If this isn't the first instantiation of this module under this
// design, don't really count the bucket, and rely on SystemPerl to
// design, don't really count the bucket, and rely on verilator_cov to
// aggregate counts. This is because Verilator combines all
// hiearchies itself, and if SystemPerl also did it, you'd end up
// hiearchies itself, and if verilator_cov also did it, you'd end up
// with (number-of-instant) times too many counts in this bin.
puts(", first"); // Enable, passed from __Vconfigure parameter
puts(", "); putsQuoted(nodep->fileline()->filename());
@@ -226,7 +258,9 @@ public:
virtual void visit(AstScopeName* nodep, AstNUser*) {
// For use under AstCCalls for dpiImports. ScopeNames under displays are handled in AstDisplay
if (!nodep->dpiExport()) {
putbs("(&(vlSymsp->__Vscope_"+nodep->scopeSymName()+"))");
// this is where the DPI import context scope is set
string scope = nodep->scopeDpiName();
putbs("(&(vlSymsp->__Vscope_"+scope+"))");
}
}
virtual void visit(AstSFormat* nodep, AstNUser*) {
@@ -246,12 +280,14 @@ public:
char format = '?';
bool pct=false;
int got=0;
for (const char* cp = nodep->text().c_str(); *cp; cp++) {
string txt = nodep->text();
for (string::const_iterator it=txt.begin(); it!=txt.end(); ++it) {
char ch = *it;
if (pct) {
pct = false;
switch (tolower(*cp)) {
switch (tolower(ch)) {
case '%':
prefix += *cp;
prefix += ch;
break;
case 'd': // FALLTHRU
case 'o': // FALLTHRU
@@ -259,22 +295,22 @@ public:
case 'x': // FALLTHRU
case 'b': // FALLTHRU
case 's':
got++; format = tolower(*cp);
got++; format = tolower(ch);
break;
case 'e': // FALLTHRU
case 'f': // FALLTHRU
case 'g':
got++; format = tolower(*cp);
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<*cp<<"'"<<endl);
got++; format = tolower(ch);
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
default:
got++;
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<*cp<<"'"<<endl);
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
}
}
else if (*cp == '%') pct = true;
else prefix += *cp;
else if (ch == '%') pct = true;
else prefix += ch;
}
if (got!=1) nodep->v3error("Missing or extra $value$plusargs format qualifier: '"<<nodep->text()<<"'"<<endl);
puts("VL_VALUEPLUSARGS_I");
@@ -584,6 +620,10 @@ public:
// Put out constant set to the specified variable, or given variable in a string
if (nodep->num().isFourState()) {
nodep->v3error("Unsupported: 4-state numbers in this context");
} else if (nodep->num().isString()) {
putbs("string(");
putsQuoted(nodep->num().toString());
puts(")");
} else if (nodep->isWide()) {
putbs("VL_CONST_W_");
puts(cvtToStr(VL_WORDS_I(nodep->num().widthMin())));
@@ -622,8 +662,9 @@ public:
// Only 32 bits - llx + long long here just to appease CPP format warning
if (num<10) puts(cvtToStr(num));
else ofp()->printf("0x%" VL_PRI64 "x", (vluint64_t)num);
//Unneeded-Causes %lx format warnings:
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
// If signed, we'll do our own functions
// But must be here, or <= comparisons etc may end up signed
puts("U");
}
}
void emitSetVarConstant(const string& assignString, AstConst* constp) {
@@ -643,9 +684,6 @@ public:
emitConstant(nodep, NULL, "");
}
}
virtual void visit(AstConstString* nodep, AstNUser*) {
putsQuoted(nodep->name());
}
// Just iterate
virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -658,6 +696,7 @@ public:
nodep->iterateChildren(*this);
}
// NOPs
virtual void visit(AstTypedef*, AstNUser*) {}
virtual void visit(AstPragma*, AstNUser*) {}
virtual void visit(AstCell*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstVar*, AstNUser*) {} // Handled outside the Visit class
@@ -665,7 +704,6 @@ public:
virtual void visit(AstTraceDecl*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstTraceInc*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstCFile*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstTypedef*, AstNUser*) {} // Nothing needed presently
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
puts((string)"\n???? // "+nodep->prettyTypeName()+"\n");
@@ -780,6 +818,7 @@ class EmitCImp : EmitCStmts {
//---------------------------------------
// VISITORS
using EmitCStmts::visit; // Suppress hidden overloaded virtual function warnng
virtual void visit(AstCFunc* nodep, AstNUser*) {
// TRACE_* and DPI handled elsewhere
if (nodep->funcType().isTrace()) return;
@@ -791,6 +830,7 @@ class EmitCImp : EmitCStmts {
splitSizeInc(nodep);
puts("\n");
if (nodep->isInline()) puts("VL_INLINE_OPT ");
puts(nodep->rtnTypeVoid()); puts(" ");
puts(modClassName(m_modp)+"::"+nodep->name()
+"("+cFuncArgs(nodep)+") {\n");
@@ -1129,17 +1169,20 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format,
struct EmitDispState {
string m_format; // "%s" and text from user
vector<char> m_argsChar; // Format of each argument to be printed
vector<AstNode*> m_argsp; // Each argument to be printed
vector<string> m_argsFunc; // Function before each argument to be printed
EmitDispState() { clear(); }
void clear() {
m_format = "";
m_argsChar.clear();
m_argsp.clear();
m_argsFunc.clear();
}
void pushFormat(const string& fmt) { m_format += fmt; }
void pushFormat(char fmt) { m_format += fmt; }
void pushArg(AstNode* nodep, const string& func) {
void pushArg(char fmtChar, AstNode* nodep, const string& func) {
m_argsChar.push_back(fmtChar);
m_argsp.push_back(nodep); m_argsFunc.push_back(func);
}
} emitDispState;
@@ -1192,6 +1235,7 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
// Arguments
for (unsigned i=0; i < emitDispState.m_argsp.size(); i++) {
puts(",");
char fmt = emitDispState.m_argsChar[i];
AstNode* argp = emitDispState.m_argsp[i];
string func = emitDispState.m_argsFunc[i];
ofp()->indentInc();
@@ -1199,8 +1243,10 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
if (func!="") puts(func);
if (argp) {
if (isScan) puts("&(");
else if (fmt == '@') puts("&(");
argp->iterate(*this);
if (isScan) puts(")");
else if (fmt == '@') puts(")");
}
ofp()->indentDec();
}
@@ -1249,8 +1295,8 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
pfmt = string("%") + vfmt + fmtLetter;
}
emitDispState.pushFormat(pfmt);
emitDispState.pushArg(NULL,cvtToStr(argp->widthMin()));
emitDispState.pushArg(argp,"");
emitDispState.pushArg(' ',NULL,cvtToStr(argp->widthMin()));
emitDispState.pushArg(fmtLetter,argp,"");
// Next parameter
*elistp = (*elistp)->nextp();
@@ -1289,6 +1335,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
break;
// Special codes
case '~': displayArg(nodep,&elistp,isScan, vfmt,'d'); break; // Signed decimal
case '@': displayArg(nodep,&elistp,isScan, vfmt,'@'); break; // Packed string
// Spec: h d o b c l
case 'b': displayArg(nodep,&elistp,isScan, vfmt,'b'); break;
case 'c': displayArg(nodep,&elistp,isScan, vfmt,'c'); break;
@@ -1306,7 +1353,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
string suffix = scopenamep->scopePrettyName();
if (suffix=="") emitDispState.pushFormat("%S");
else emitDispState.pushFormat("%N"); // Add a . when needed
emitDispState.pushArg(NULL, "vlSymsp->name()");
emitDispState.pushArg(' ',NULL, "vlSymsp->name()");
emitDispState.pushFormat(suffix);
break;
}
@@ -1345,9 +1392,6 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
if (varp->isIO() && modp->isTop() && optSystemC()) {
// System C top I/O doesn't need loading, as the lower level subinst code does it.
}
else if (varp->basicp() && varp->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
// Constructor deals with it
}
else if (varp->isParam()) {
if (!varp->valuep()) nodep->v3fatalSrc("No init for a param?");
// If a simple CONST value we initialize it using an enum
@@ -1366,6 +1410,9 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
varp->v3fatalSrc("InitArray under non-arrayed var");
}
}
else if (varp->basicp() && varp->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
// Constructor deals with it
}
else {
int vects = 0;
// This isn't very robust and may need cleanup for other data types
@@ -1381,7 +1428,7 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
}
bool zeroit = (varp->attrFileDescr() // Zero it out, so we don't core dump if never call $fopen
|| (varp->basicp() && varp->basicp()->isZeroInit())
|| (varp->name().c_str()[0]=='_' && v3Global.opt.underlineZero()));
|| (varp->name().size()>=1 && varp->name()[0]=='_' && v3Global.opt.underlineZero()));
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.)
@@ -1470,7 +1517,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
if (v3Global.opt.coverage() ) {
puts("\n// Coverage\n");
// Rather than putting out SP_COVER_INSERT calls directly, we do it via this function
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
// This gets around gcc slowness constructing all of the template arguments
// SystemPerl 1.301 is much faster, but it's nice to remain back
// compatible, and have a common wrapper.
@@ -1479,7 +1526,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
puts( "*countp = 0;\n");
puts( "SP_COVER_INSERT(countp,");
puts( "VL_COVER_INSERT(countp,");
puts( " \"filename\",filenamep,");
puts( " \"lineno\",lineno,");
puts( " \"column\",column,\n");
@@ -1789,7 +1836,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("#include \"verilated_save.h\"\n");
}
if (v3Global.opt.coverage()) {
puts("#include \"SpCoverage.h\"\n");
puts("#include \"verilated_cov.h\"\n");
if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together");
}
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
@@ -1839,6 +1886,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
}
}
emitTypedefs(modp->stmtsp());
puts("\n// PORTS\n");
if (modp->isTop()) puts("// The application code writes and reads these signals to\n");
if (modp->isTop()) puts("// propagate new values into/out from the Verilated model.\n");
@@ -2300,6 +2349,7 @@ class EmitCTrace : EmitCStmts {
}
// VISITORS
using EmitCStmts::visit; // Suppress hidden overloaded virtual function warnng
virtual void visit(AstNetlist* nodep, AstNUser*) {
// Top module only
nodep->topModulep()->accept(*this);
+2 -1
View File
@@ -383,7 +383,8 @@ void EmitCSyms::emitSymImp() {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (modp->isTop()) {
} else {
ofp()->printf("\t%c %-30s ", comma, scopep->nameDotless().c_str());
string nameDl = scopep->nameDotless();
ofp()->printf("\t%c %-30s ", comma, nameDl.c_str());
puts("(Verilated::catName(topp->name(),");
// The "." is added by catName
putsQuoted(scopep->prettyName());
+10 -11
View File
@@ -83,13 +83,13 @@ public:
if (v3Global.opt.savable()) {
putMakeClassEntry(of, "verilated_save.cpp");
}
if (v3Global.opt.coverage()) {
putMakeClassEntry(of, "verilated_cov.cpp");
}
if (v3Global.opt.systemPerl()) {
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
}
else {
if (v3Global.opt.coverage()) {
putMakeClassEntry(of, "SpCoverage.cpp");
}
if (v3Global.opt.trace()) {
putMakeClassEntry(of, "verilated_vcd_c.cpp");
if (v3Global.opt.systemC()) {
@@ -164,16 +164,16 @@ public:
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
of.puts("VM_USER_CFLAGS = \\\n");
for (V3StringSet::const_iterator it = v3Global.opt.cFlags().begin();
it != v3Global.opt.cFlags().end(); ++it) {
const V3StringSet& cFlags = v3Global.opt.cFlags();
for (V3StringSet::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
of.puts("\t"+*it+" \\\n");
}
of.puts("\n");
of.puts("# User LDLIBS (from -LDFLAGS on Verilator command line)\n");
of.puts("VM_USER_LDLIBS = \\\n");
for (V3StringSet::const_iterator it = v3Global.opt.ldLibs().begin();
it != v3Global.opt.ldLibs().end(); ++it) {
const V3StringSet& ldLibs = v3Global.opt.ldLibs();
for (V3StringSet::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) {
of.puts("\t"+*it+" \\\n");
}
of.puts("\n");
@@ -181,8 +181,8 @@ public:
V3StringSet dirs;
of.puts("# User .cpp files (from .cpp's on Verilator command line)\n");
of.puts("VM_USER_CLASSES = \\\n");
for (V3StringSet::const_iterator it = v3Global.opt.cppFiles().begin();
it != v3Global.opt.cppFiles().end(); ++it) {
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
of.puts("\t"+V3Options::filenameNonExt(cppfile)+" \\\n");
string dir = V3Options::filenameDir(cppfile);
@@ -207,8 +207,7 @@ public:
of.puts("\n### Executable rules... (from --exe)\n");
of.puts("VPATH += $(VM_USER_DIR)\n");
of.puts("\n");
for (V3StringSet::const_iterator it = v3Global.opt.cppFiles().begin();
it != v3Global.opt.cppFiles().end(); ++it) {
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
string basename = V3Options::filenameNonExt(cppfile);
of.puts(basename+".o: "+cppfile+"\n");
+2 -7
View File
@@ -57,7 +57,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
// Don't use to quote a filename for #include - #include doesn't \ escape.
// Duplicate in V3File - here so we can print to string
putsNoTracking("\"");
putsNoTracking(AstNode::quoteName(str));
putsNoTracking(V3Number::quoteNameControls(str));
putsNoTracking("\"");
}
@@ -553,10 +553,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstConst* nodep, AstNUser*) {
putfs(nodep,nodep->num().ascii(true,true));
}
virtual void visit(AstConstString* nodep, AstNUser*) {
putfs(nodep,"");
putsQuoted(nodep->name());
}
// Just iterate
virtual void visit(AstTopScope* nodep, AstNUser*) {
@@ -685,7 +681,6 @@ public:
class EmitVPrefixedVisitor : public EmitVBaseVisitor {
// MEMBERS
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the inheritance is another unused V3OutFormatter)
bool m_user3mark; // nodep->user3() if set means mark with %%
// METHODS
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) { m_formatter.puts(str); }
@@ -706,7 +701,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth), m_user3mark(user3mark) {
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth) {
if (user3mark) { AstUser3InUse::check(); }
nodep->accept(*this);
}
+1 -1
View File
@@ -59,7 +59,7 @@ class EmitXmlFileVisitor : public EmitCBaseVisitor {
// Don't use to quote a filename for #include - #include doesn't \ escape.
// Duplicate in V3File - here so we can print to string
putsNoTracking("\"");
putsNoTracking(AstNode::quoteName(str));
putsNoTracking(V3Number::quoteNameControls(str));
putsNoTracking("\"");
}
+6 -277
View File
@@ -27,7 +27,6 @@
# include "V3Ast.h"
# include "V3Global.h"
# include "V3Stats.h"
# include "V3Config.h"
#endif
//======================================================================
@@ -36,6 +35,8 @@
int V3Error::s_errCount = 0;
int V3Error::s_warnCount = 0;
int V3Error::s_debugDefault = 0;
int V3Error::s_errorLimit = V3Error::MAX_ERRORS;
bool V3Error::s_warnFatal = true;
int V3Error::s_tellManual = 0;
ostringstream V3Error::s_errorStr; // Error string being formed
V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL;
@@ -65,269 +66,6 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
m_e = V3ErrorCode::EC_ERROR;
}
//######################################################################
// FileLineSingleton class functions
const string FileLineSingleton::filenameLetters(int no) {
const int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number
char out[size];
char* op = out+size-1;
*--op = '\0'; // We build backwards
int num = no;
do {
*--op = 'a'+num%26;
num /= 26;
} while (num);
return op;
}
//! Convert filenames to a filenameno
//! This lets us assign a nice small identifier for debug messages, but more
//! importantly lets us use a 4 byte int instead of 8 byte pointer in every
//! FileLine.
//! We associate a language with each source file, so we also set the default
//! for this.
int FileLineSingleton::nameToNumber(const string& filename) {
FileNameNumMap::const_iterator it = m_namemap.find(filename);
if (VL_LIKELY(it != m_namemap.end())) return it->second;
int num = m_names.size();
m_names.push_back(filename);
m_languages.push_back(V3LangCode::mostRecent());
m_namemap.insert(make_pair(filename,num));
return num;
}
//! Support XML output
//! Experimental. Updated to also put out the language.
void FileLineSingleton::fileNameNumMapDumpXml(ostream& os) {
os<<"<files>\n";
for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) {
os<<"<file id=\""<<filenameLetters(it->second)
<<"\" filename=\""<<it->first
<<"\" language=\""<<numberToLang(it->second).ascii()<<"\"/>\n";
}
os<<"</files>\n";
}
//######################################################################
// FileLine class functions
FileLine::FileLine(FileLine::EmptySecret) {
// Sort of a singleton
m_lineno=0;
m_filenameno=singleton().nameToNumber("AstRoot");
m_warnOn=0;
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
warnOff(code, code.defaultsOff());
}
}
string FileLine::lineDirectiveStrg(int enterExit) const {
char numbuf[20]; sprintf(numbuf, "%d", lineno());
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
return ((string)"`line "+numbuf+" \""+filename()+"\" "+levelbuf+"\n");
}
void FileLine::lineDirective(const char* textp, int& enterExitRef) {
// Handle `line directive
// Skip `line
while (*textp && isspace(*textp)) textp++;
while (*textp && !isspace(*textp)) textp++;
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
// Grab linenumber
const char *ln = textp;
while (*textp && !isspace(*textp)) textp++;
if (isdigit(*ln)) {
this->lineno(atoi(ln));
}
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
// Grab filename
const char *fn = textp;
while (*textp && !(isspace(*textp) || *textp=='"')) textp++;
if (textp != fn) {
string strfn = fn;
strfn = strfn.substr(0, textp-fn);
this->filename(strfn);
}
// Grab level
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
if (isdigit(*textp)) enterExitRef = atoi(textp);
else enterExitRef = 0;
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
}
FileLine* FileLine::copyOrSameFileLine() {
// When a fileline is "used" to produce a node, calls this function.
// Return this, or a copy of this
// There are often more than one token per line, thus we use the
// same pointer as long as we're on the same line, file & warn state.
#ifndef _V3ERROR_NO_GLOBAL_
V3Config::applyIgnores(this); // Toggle warnings based on global config file
#endif
static FileLine* lastNewp = NULL;
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
return lastNewp;
}
FileLine* newp = new FileLine(this);
lastNewp = newp;
return newp;
}
void FileLine::updateLanguage () {
language(v3Global.opt.fileLanguage(filename()));
}
const string FileLine::filebasename() const {
string name = filename();
string::size_type pos;
if ((pos = name.rfind("/")) != string::npos) {
name.erase(0,pos+1);
}
return name;
}
const string FileLine::filebasenameNoExt() const {
string name = filebasename();
string::size_type pos;
if ((pos = name.find(".")) != string::npos) {
name = name.substr(0,pos);
}
return name;
}
const string FileLine::profileFuncname() const {
// Return string that is OK as a function name - for profiling
string name = filebasenameNoExt();
string::size_type pos;
while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
!= string::npos) {
name.replace(pos, 1, "_");
}
name += "__l"+cvtToStr(lineno());
return name;
}
string FileLine::ascii() const {
return filename()+":"+cvtToStr(lineno());
}
ostream& operator<<(ostream& os, FileLine* fileline) {
os <<fileline->ascii()<<": "<<hex;
return(os);
}
bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code (msg.c_str());
if (code < V3ErrorCode::EC_FIRST_WARN) {
return false;
} else if (v3Global.opt.lintOnly() // Lint mode is allowed to suppress some errors
&& code < V3ErrorCode::EC_MIN) {
return false;
} else {
warnOff(code, flag);
return true;
}
}
void FileLine::warnLintOff(bool flag) {
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
if (code.lintError()) warnOff(code, flag);
}
}
void FileLine::warnStyleOff(bool flag) {
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
if (code.styleError()) warnOff(code, flag);
}
}
bool FileLine::warnIsOff(V3ErrorCode code) const {
if (!m_warnOn.test(code)) return true;
// UNOPTFLAT implies UNOPT
if (code==V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) return true;
return false;
}
void FileLine::modifyStateInherit(const FileLine* fromp) {
// Any warnings that are off in "from", become off in "this".
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
if (fromp->warnIsOff(code)) {
this->warnOff(code, true);
}
}
}
void FileLine::v3errorEnd(ostringstream& str) {
if (this && m_lineno) {
ostringstream nsstr;
nsstr<<this<<str.str();
if (warnIsOff(V3Error::errorCode())) V3Error::suppressThisWarning();
V3Error::v3errorEnd(nsstr);
} else {
V3Error::v3errorEnd(str);
}
}
string FileLine::warnMore() const {
if (this && m_lineno) {
return V3Error::warnMore()+ascii()+": ";
} else {
return V3Error::warnMore();
}
}
#ifdef VL_LEAK_CHECKS
typedef set<FileLine*> FileLineCheckSet;
FileLineCheckSet fileLineLeakChecks;
void* FileLine::operator new(size_t size) {
FileLine* objp = static_cast<FileLine*>(::operator new(size));
fileLineLeakChecks.insert(objp);
return objp;
}
void FileLine::operator delete(void* objp, size_t size) {
if (!objp) return;
FileLine* flp = static_cast<FileLine*>(objp);
FileLineCheckSet::iterator it = fileLineLeakChecks.find(flp);
if (it != fileLineLeakChecks.end()) {
fileLineLeakChecks.erase(it);
} else {
flp->v3fatalSrc("Deleting FileLine object that was never tracked\n");
}
::operator delete(objp);
}
#endif
void FileLine::deleteAllRemaining() {
#ifdef VL_LEAK_CHECKS
// FileLines are allocated, but never nicely freed, as it's much faster
// that way. Unfortunately this makes our leak checking a big mess, so
// only when leak checking we'll track them all and cleanup.
while (1) {
FileLineCheckSet::iterator it=fileLineLeakChecks.begin();
if (it==fileLineLeakChecks.end()) break;
delete *it;
// Operator delete will remove the iterated object from the list.
// Eventually the list will be empty and terminate the loop.
}
fileLineLeakChecks.clear();
singleton().clear();
#endif
}
//######################################################################
// V3Error class functions
@@ -353,26 +91,15 @@ string V3Error::lineStr (const char* filename, int lineno) {
return out.str();
}
void V3Error::incWarnings() {
s_warnCount++;
// We don't exit on a lot of warnings.
}
void V3Error::incErrors() {
s_errCount++;
if (errorCount() == v3Global.opt.errorLimit()) { // Not >= as would otherwise recurse
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
v3fatal ("Exiting due to too many errors encountered; --error-limit="<<errorCount()<<endl);
}
}
void V3Error::abortIfErrors() {
if (errorCount()) {
abortIfWarnings();
}
}
void V3Error::abortIfWarnings() {
bool exwarn = v3Global.opt.warnFatal() && warnCount();
bool exwarn = warnFatal() && warnCount();
if (errorCount() && exwarn) {
v3fatal ("Exiting due to "<<dec<<errorCount()<<" error(s), "<<warnCount()<<" warning(s)\n");
} else if (errorCount()) {
@@ -422,7 +149,9 @@ void V3Error::vlAbort () {
void V3Error::suppressThisWarning() {
if (s_errorCode>=V3ErrorCode::EC_MIN) {
#ifndef _V3ERROR_NO_GLOBAL_
V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1);
#endif
s_errorSuppressed = true;
}
}
+14 -145
View File
@@ -30,8 +30,6 @@
#include <set>
#include <deque>
#include "V3LangCode.h"
//######################################################################
class V3ErrorCode {
@@ -144,9 +142,10 @@ 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==IMPURE || m_e==MODDUP || m_e==SYMRSVDWORD); }
|| m_e==IMPURE || m_e==MODDUP); }
// Warnings to mention manual
bool mentionManual() const { return ( m_e==EC_FATALSRC || pretendError() ); }
bool mentionManual() const { return ( m_e==EC_FATALSRC || m_e==SYMRSVDWORD
|| pretendError() ); }
// Warnings that are lint only
bool lintError() const { return ( m_e==ALWCOMBORDER
@@ -190,9 +189,11 @@ class V3Error {
static bool s_describedWarnings; // Told user how to disable warns
static bool s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning
static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error
static int s_debugDefault; // Default debugging level
static int s_debugDefault; // Option: --debugi Default debugging level
static int s_errorLimit; // Option: --error-limit Number of errors before exit
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
static int s_errCount; // Error count
static int s_warnCount; // Error count
static int s_warnCount; // Warning count
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
static ostringstream s_errorStr; // Error string being formed
static V3ErrorCode s_errorCode; // Error string being formed will abort
@@ -209,15 +210,19 @@ class V3Error {
// ACCESSORS
static void debugDefault(int level) { s_debugDefault = level; }
static int debugDefault() { return s_debugDefault; }
static void errorLimit(int level) { s_errorLimit = level; }
static int errorLimit() { return s_errorLimit; }
static void warnFatal(bool flag) { s_warnFatal = flag; }
static bool warnFatal() { return s_warnFatal; }
static string msgPrefix(); // returns %Error/%Warn
static int errorCount() { return s_errCount; }
static int warnCount() { return s_warnCount; }
static int errorOrWarnCount() { return errorCount()+warnCount(); }
// METHODS
static void incErrors();
static void incWarnings();
static void incWarnings() { s_warnCount++; }
static void init();
static void abortIfErrors();
static void abortIfErrors() { if (errorCount()) abortIfWarnings(); }
static void abortIfWarnings();
static void suppressThisWarning(); // Suppress next %Warn if user has it off
static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code]=flag; }
@@ -242,7 +247,7 @@ class V3Error {
inline int debug() { return V3Error::debugDefault(); }
inline void v3errorEnd(ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
// These allow errors using << operators: v3error("foo"<<"bar");
// Theses allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
// Note the commas are the comma operator, not separating arguments. These are needed to insure
// evaluation order as otherwise we couldn't insure v3errorPrep is called first.
@@ -284,140 +289,4 @@ inline string ucfirst(const string& text) {
return out;
}
//######################################################################
class FileLine;
//! Singleton class with tables of per-file data.
//! This singleton class contains tables of data that are unchanging in each
//! source file (each with its own unique filename number).
class FileLineSingleton {
// TYPES
typedef map<string,int> FileNameNumMap;
typedef map<string,V3LangCode> FileLangNumMap;
// MEMBERS
FileNameNumMap m_namemap; // filenameno for each filename
deque<string> m_names; // filename text for each filenameno
deque<V3LangCode> m_languages; // language for each filenameno
// COSNTRUCTORS
FileLineSingleton() { }
~FileLineSingleton() { }
protected:
friend class FileLine;
// METHODS
int nameToNumber(const string& filename);
const string numberToName(int filenameno) const { return m_names[filenameno]; }
const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
void fileNameNumMapDumpXml(ostream& os);
static const string filenameLetters(int fileno);
};
//! File and line number of an object, mostly for error reporting
//! This class is instantiated for every source code line (potentially
//! millions). To save space, per-file information (e.g. filename, source
//! language is held in tables in the FileLineSingleton class.
class FileLine {
int m_lineno;
int m_filenameno;
bitset<V3ErrorCode::_ENUM_MAX> m_warnOn;
private:
struct EmptySecret {};
inline static FileLineSingleton& singleton() {
static FileLineSingleton s;
return s;
}
inline static FileLine& defaultFileLine() {
static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
return *defFilelinep;
}
protected:
// User routines should never need to change line numbers
// We are storing pointers, so we CAN'T change them after initial reading.
friend class FileLineSingleton;
friend class V3ParseImp;
friend class V3PreLex;
friend class V3PreProcImp;
void lineno(int num) { m_lineno = num; }
void language (V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
void lineDirective(const char* textp, int& enterExitRef);
void linenoInc() { m_lineno++; }
void linenoIncInPlace() { m_lineno++; }
FileLine* copyOrSameFileLine();
public:
FileLine (const string& filename, int lineno) {
m_lineno=lineno; m_filenameno = singleton().nameToNumber(filename);
m_warnOn=defaultFileLine().m_warnOn; }
FileLine (FileLine* fromp) {
m_lineno=fromp->m_lineno; m_filenameno = fromp->m_filenameno; m_warnOn=fromp->m_warnOn; }
FileLine (EmptySecret);
~FileLine() { }
FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); }
FileLine* create(int lineno) { return create(filename(), lineno); }
static void deleteAllRemaining();
#ifdef VL_LEAK_CHECKS
static void* operator new(size_t size);
static void operator delete(void* obj, size_t size);
#endif
int lineno () const { return m_lineno; }
V3LangCode language () const { return singleton().numberToLang(m_filenameno); }
void updateLanguage ();
string ascii() const;
const string filename () const { return singleton().numberToName(m_filenameno); }
const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); }
const string filebasename () const;
const string filebasenameNoExt () const;
const string profileFuncname() const;
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; }
string lineDirectiveStrg(int enter_exit_level) const;
void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); } // Turn on/off warning messages on this line.
void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
bool warnOff(const string& code, bool flag); // Returns 1 if ok
bool warnIsOff(V3ErrorCode code) const;
void warnLintOff(bool flag);
void warnStyleOff(bool flag);
void warnStateFrom(const FileLine& from) { m_warnOn=from.m_warnOn; }
void warnResetDefault() { warnStateFrom(defaultFileLine()); }
// Specific flag ACCESSORS/METHODS
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE,flag); }
bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING,flag); }
// METHODS - Global
static void globalWarnLintOff(bool flag) {
defaultFileLine().warnLintOff(flag); }
static void globalWarnStyleOff(bool flag) {
defaultFileLine().warnStyleOff(flag); }
static void globalWarnOff(V3ErrorCode code, bool flag) {
defaultFileLine().warnOff(code, flag); }
static bool globalWarnOff(const string& code, bool flag) {
return defaultFileLine().warnOff(code, flag); }
static void fileNameNumMapDumpXml(ostream& os) {
singleton().fileNameNumMapDumpXml(os); }
// METHODS - Called from netlist
// Merge warning disables from another fileline
void modifyStateInherit(const FileLine* fromp);
// Change the current fileline due to actions discovered after parsing
// and may have side effects on other nodes sharing this FileLine.
// Use only when this is intended
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code,flag); }
// OPERATORS
void v3errorEnd(ostringstream& str);
string warnMore() const;
inline bool operator==(FileLine rhs) const {
return (m_lineno==rhs.m_lineno && m_filenameno==rhs.m_filenameno && m_warnOn==rhs.m_warnOn);
}
};
ostream& operator<<(ostream& os, FileLine* fileline);
#endif // Guard
+7 -3
View File
@@ -448,8 +448,8 @@ private:
AstNode* newp = new AstShiftR (nodep->fileline(),
fromp,
dropCondBound(lsbp),
nodep->width());
newp->dtypeFrom(nodep);
fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast
newp->dtypeFrom(fromp);
if (!nodep->isQuad() && fromp->isQuad()) {
newp = new AstCCast (newp->fileline(), newp, nodep);
}
@@ -583,11 +583,15 @@ private:
newSelBitBit(lhsp->lsbp()),
VL_WORDSIZE)),
oldvalp);
// Restrict the shift amount to 0-31, see bug804.
AstNode* shiftp = new AstAnd(nodep->fileline(), lhsp->lsbp()->cloneTree(true),
new AstConst(nodep->fileline(), VL_WORDSIZE-1));
AstNode* newp = new AstOr (lhsp->fileline(),
oldvalp,
new AstShiftL (lhsp->fileline(),
rhsp,
lhsp->lsbp()->cloneTree(true),
shiftp,
VL_WORDSIZE));
newp = new AstAssign (nodep->fileline(),
new AstWordSel (nodep->fileline(),
+13 -8
View File
@@ -71,7 +71,8 @@ class V3FileDependImp {
time_t mtime() const { return m_stat.st_mtime; }
void loadStats() {
if (!m_stat.st_mtime) {
int err = stat(filename().c_str(), &m_stat);
string fn = filename();
int err = stat(fn.c_str(), &m_stat);
if (err!=0) {
m_stat.st_mtime = 1;
// Not a error... This can occur due to `line directives in the .vpp files
@@ -258,15 +259,19 @@ bool V3File::checkTimes(const string& filename, const string& cmdline) {
return dependImp.checkTimes(filename, cmdline);
}
void V3File::createDir(const string& dirname) {
#ifndef _WIN32
mkdir(dirname.c_str(), 0777);
#else
mkdir(dirname.c_str());
#endif
}
void V3File::createMakeDir() {
static bool created = false;
if (!created) {
created = true;
#ifndef _WIN32
mkdir(v3Global.opt.makeDir().c_str(), 0777);
#else
mkdir(v3Global.opt.makeDir().c_str());
#endif
createDir(v3Global.opt.makeDir());
}
}
@@ -562,7 +567,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) { // verilogPrefixedTree doesn't want tabs
while (num>=8) {
*cp++ = '\t';
num -= 8;
@@ -752,7 +757,7 @@ void V3OutFormatter::putsQuoted(const char* strg) {
// Quote \ and " for use inside C programs
// Don't use to quote a filename for #include - #include doesn't \ escape.
putcNoTracking('"');
string quoted = AstNode::quoteName(strg);
string quoted = V3Number::quoteNameControls(strg);
for (const char* cp=quoted.c_str(); *cp; cp++) {
putcNoTracking (*cp);
}
+3 -2
View File
@@ -67,6 +67,7 @@ public:
static bool checkTimes(const string& filename, const string& cmdline);
// Directory utilities
static void createDir(const string& dirname);
static void createMakeDir();
};
@@ -188,8 +189,8 @@ public:
}
virtual ~V3OutCFile() {}
virtual void putsCellDecl(const string& classname, const string& cellname) {
this->printf("%-19s\t%s;\n",
(classname + "*").c_str(),cellname.c_str());
string classStar = classname + "*";
this->printf("%-19s\t%s;\n", classStar.c_str(), cellname.c_str());
}
virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); }
virtual void putsIntTopInclude() { }
+294
View File
@@ -0,0 +1,294 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Error handling
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <set>
#include "V3Error.h"
#include "V3FileLine.h"
#ifndef _V3ERROR_NO_GLOBAL_
# include "V3Ast.h"
# include "V3Global.h"
# include "V3Stats.h"
# include "V3Config.h"
#endif
//######################################################################
// FileLineSingleton class functions
const string FileLineSingleton::filenameLetters(int no) {
const int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number
char out[size];
char* op = out+size-1;
*--op = '\0'; // We build backwards
int num = no;
do {
*--op = 'a'+num%26;
num /= 26;
} while (num);
return op;
}
//! Convert filenames to a filenameno
//! This lets us assign a nice small identifier for debug messages, but more
//! importantly lets us use a 4 byte int instead of 8 byte pointer in every
//! FileLine.
//! We associate a language with each source file, so we also set the default
//! for this.
int FileLineSingleton::nameToNumber(const string& filename) {
FileNameNumMap::const_iterator it = m_namemap.find(filename);
if (VL_LIKELY(it != m_namemap.end())) return it->second;
int num = m_names.size();
m_names.push_back(filename);
m_languages.push_back(V3LangCode::mostRecent());
m_namemap.insert(make_pair(filename,num));
return num;
}
//! Support XML output
//! Experimental. Updated to also put out the language.
void FileLineSingleton::fileNameNumMapDumpXml(ostream& os) {
os<<"<files>\n";
for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) {
os<<"<file id=\""<<filenameLetters(it->second)
<<"\" filename=\""<<it->first
<<"\" language=\""<<numberToLang(it->second).ascii()<<"\"/>\n";
}
os<<"</files>\n";
}
//######################################################################
// FileLine class functions
FileLine::FileLine(FileLine::EmptySecret) {
// Sort of a singleton
m_lineno=0;
m_filenameno=singleton().nameToNumber("AstRoot");
m_warnOn=0;
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
warnOff(code, code.defaultsOff());
}
}
string FileLine::lineDirectiveStrg(int enterExit) const {
char numbuf[20]; sprintf(numbuf, "%d", lineno());
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
return ((string)"`line "+numbuf+" \""+filename()+"\" "+levelbuf+"\n");
}
void FileLine::lineDirective(const char* textp, int& enterExitRef) {
// Handle `line directive
// Skip `line
while (*textp && isspace(*textp)) textp++;
while (*textp && !isspace(*textp)) textp++;
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
// Grab linenumber
const char *ln = textp;
while (*textp && !isspace(*textp)) textp++;
if (isdigit(*ln)) {
this->lineno(atoi(ln));
}
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
// Grab filename
const char *fn = textp;
while (*textp && !(isspace(*textp) || *textp=='"')) textp++;
if (textp != fn) {
string strfn = fn;
strfn = strfn.substr(0, textp-fn);
this->filename(strfn);
}
// Grab level
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
if (isdigit(*textp)) enterExitRef = atoi(textp);
else enterExitRef = 0;
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
}
FileLine* FileLine::copyOrSameFileLine() {
// When a fileline is "used" to produce a node, calls this function.
// Return this, or a copy of this
// There are often more than one token per line, thus we use the
// same pointer as long as we're on the same line, file & warn state.
#ifndef _V3ERROR_NO_GLOBAL_
V3Config::applyIgnores(this); // Toggle warnings based on global config file
#endif
static FileLine* lastNewp = NULL;
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
return lastNewp;
}
FileLine* newp = new FileLine(this);
lastNewp = newp;
return newp;
}
const string FileLine::filebasename() const {
string name = filename();
string::size_type pos;
if ((pos = name.rfind("/")) != string::npos) {
name.erase(0,pos+1);
}
return name;
}
const string FileLine::filebasenameNoExt() const {
string name = filebasename();
string::size_type pos;
if ((pos = name.find(".")) != string::npos) {
name = name.substr(0,pos);
}
return name;
}
const string FileLine::profileFuncname() const {
// Return string that is OK as a function name - for profiling
string name = filebasenameNoExt();
string::size_type pos;
while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
!= string::npos) {
name.replace(pos, 1, "_");
}
name += "__l"+cvtToStr(lineno());
return name;
}
string FileLine::ascii() const {
return filename()+":"+cvtToStr(lineno());
}
ostream& operator<<(ostream& os, FileLine* fileline) {
os <<fileline->ascii()<<": "<<hex;
return(os);
}
bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code (msg.c_str());
if (code < V3ErrorCode::EC_FIRST_WARN) {
return false;
#ifndef _V3ERROR_NO_GLOBAL_
} else if (v3Global.opt.lintOnly() // Lint mode is allowed to suppress some errors
&& code < V3ErrorCode::EC_MIN) {
return false;
#endif
} else {
warnOff(code, flag);
return true;
}
}
void FileLine::warnLintOff(bool flag) {
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
if (code.lintError()) warnOff(code, flag);
}
}
void FileLine::warnStyleOff(bool flag) {
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
if (code.styleError()) warnOff(code, flag);
}
}
bool FileLine::warnIsOff(V3ErrorCode code) const {
if (!m_warnOn.test(code)) return true;
if (!defaultFileLine().m_warnOn.test(code)) return true; // Global overrides local
// UNOPTFLAT implies UNOPT
if (code==V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) return true;
return false;
}
void FileLine::modifyStateInherit(const FileLine* fromp) {
// Any warnings that are off in "from", become off in "this".
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = (V3ErrorCode)codei;
if (fromp->warnIsOff(code)) {
this->warnOff(code, true);
}
}
}
void FileLine::v3errorEnd(ostringstream& str) {
if (this && m_lineno) {
ostringstream nsstr;
nsstr<<this<<str.str();
if (warnIsOff(V3Error::errorCode())) V3Error::suppressThisWarning();
V3Error::v3errorEnd(nsstr);
} else {
V3Error::v3errorEnd(str);
}
}
string FileLine::warnMore() const {
if (this && m_lineno) {
return V3Error::warnMore()+ascii()+": ";
} else {
return V3Error::warnMore();
}
}
#ifdef VL_LEAK_CHECKS
typedef set<FileLine*> FileLineCheckSet;
FileLineCheckSet fileLineLeakChecks;
void* FileLine::operator new(size_t size) {
FileLine* objp = static_cast<FileLine*>(::operator new(size));
fileLineLeakChecks.insert(objp);
return objp;
}
void FileLine::operator delete(void* objp, size_t size) {
if (!objp) return;
FileLine* flp = static_cast<FileLine*>(objp);
FileLineCheckSet::iterator it = fileLineLeakChecks.find(flp);
if (it != fileLineLeakChecks.end()) {
fileLineLeakChecks.erase(it);
} else {
flp->v3fatalSrc("Deleting FileLine object that was never tracked\n");
}
::operator delete(objp);
}
#endif
void FileLine::deleteAllRemaining() {
#ifdef VL_LEAK_CHECKS
// FileLines are allocated, but never nicely freed, as it's much faster
// that way. Unfortunately this makes our leak checking a big mess, so
// only when leak checking we'll track them all and cleanup.
while (1) {
FileLineCheckSet::iterator it=fileLineLeakChecks.begin();
if (it==fileLineLeakChecks.end()) break;
delete *it;
// Operator delete will remove the iterated object from the list.
// Eventually the list will be empty and terminate the loop.
}
fileLineLeakChecks.clear();
singleton().clear();
#endif
}
+171
View File
@@ -0,0 +1,171 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Error handling
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3FileLine_H_
#define _V3FileLine_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include <string>
#include <iostream>
#include <sstream>
#include <bitset>
#include <map>
#include <set>
#include <deque>
#include "V3Error.h"
#include "V3LangCode.h"
//######################################################################
class FileLine;
//! Singleton class with tables of per-file data.
//! This singleton class contains tables of data that are unchanging in each
//! source file (each with its own unique filename number).
class FileLineSingleton {
// TYPES
typedef map<string,int> FileNameNumMap;
typedef map<string,V3LangCode> FileLangNumMap;
// MEMBERS
FileNameNumMap m_namemap; // filenameno for each filename
deque<string> m_names; // filename text for each filenameno
deque<V3LangCode> m_languages; // language for each filenameno
// COSNTRUCTORS
FileLineSingleton() { }
~FileLineSingleton() { }
protected:
friend class FileLine;
// METHODS
int nameToNumber(const string& filename);
const string numberToName(int filenameno) const { return m_names[filenameno]; }
const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
void fileNameNumMapDumpXml(ostream& os);
static const string filenameLetters(int fileno);
};
//! File and line number of an object, mostly for error reporting
//! This class is instantiated for every source code line (potentially
//! millions). To save space, per-file information (e.g. filename, source
//! language is held in tables in the FileLineSingleton class.
class FileLine {
int m_lineno;
int m_filenameno;
bitset<V3ErrorCode::_ENUM_MAX> m_warnOn;
private:
struct EmptySecret {};
inline static FileLineSingleton& singleton() {
static FileLineSingleton s;
return s;
}
inline static FileLine& defaultFileLine() {
static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
return *defFilelinep;
}
protected:
// User routines should never need to change line numbers
// We are storing pointers, so we CAN'T change them after initial reading.
friend class FileLineSingleton;
friend class V3ParseImp;
friend class V3PreLex;
friend class V3PreProcImp;
void lineno(int num) { m_lineno = num; }
void language (V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
void lineDirective(const char* textp, int& enterExitRef);
void linenoInc() { m_lineno++; }
void linenoIncInPlace() { m_lineno++; }
FileLine* copyOrSameFileLine();
public:
FileLine (const string& filename, int lineno) {
m_lineno=lineno; m_filenameno = singleton().nameToNumber(filename);
m_warnOn=defaultFileLine().m_warnOn; }
FileLine (FileLine* fromp) {
m_lineno=fromp->m_lineno; m_filenameno = fromp->m_filenameno; m_warnOn=fromp->m_warnOn; }
FileLine (EmptySecret);
~FileLine() { }
FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); }
FileLine* create(int lineno) { return create(filename(), lineno); }
static void deleteAllRemaining();
#ifdef VL_LEAK_CHECKS
static void* operator new(size_t size);
static void operator delete(void* obj, size_t size);
#endif
int lineno () const { return m_lineno; }
V3LangCode language () const { return singleton().numberToLang(m_filenameno); }
string ascii() const;
const string filename () const { return singleton().numberToName(m_filenameno); }
const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); }
const string filebasename () const;
const string filebasenameNoExt () const;
const string profileFuncname() const;
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; }
string lineDirectiveStrg(int enter_exit_level) const;
void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); } // Turn on/off warning messages on this line.
void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
bool warnOff(const string& code, bool flag); // Returns 1 if ok
bool warnIsOff(V3ErrorCode code) const;
void warnLintOff(bool flag);
void warnStyleOff(bool flag);
void warnStateFrom(const FileLine& from) { m_warnOn=from.m_warnOn; }
void warnResetDefault() { warnStateFrom(defaultFileLine()); }
// Specific flag ACCESSORS/METHODS
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE,flag); }
bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING,flag); }
// METHODS - Global
static void globalWarnLintOff(bool flag) {
defaultFileLine().warnLintOff(flag); }
static void globalWarnStyleOff(bool flag) {
defaultFileLine().warnStyleOff(flag); }
static void globalWarnOff(V3ErrorCode code, bool flag) {
defaultFileLine().warnOff(code, flag); }
static bool globalWarnOff(const string& code, bool flag) {
return defaultFileLine().warnOff(code, flag); }
static void fileNameNumMapDumpXml(ostream& os) {
singleton().fileNameNumMapDumpXml(os); }
// METHODS - Called from netlist
// Merge warning disables from another fileline
void modifyStateInherit(const FileLine* fromp);
// Change the current fileline due to actions discovered after parsing
// and may have side effects on other nodes sharing this FileLine.
// Use only when this is intended
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code,flag); }
// OPERATORS
void v3errorEnd(ostringstream& str);
string warnMore() const;
inline bool operator==(FileLine rhs) const {
return (m_lineno==rhs.m_lineno && m_filenameno==rhs.m_filenameno && m_warnOn==rhs.m_warnOn);
}
};
ostream& operator<<(ostream& os, FileLine* fileline);
#endif // Guard
+135 -5
View File
@@ -258,8 +258,8 @@ public:
if (!m_substTreep) {
clearSimple("No assignment found\n");
}
for (GateVarRefList::const_iterator it = rhsVarRefs().begin();
it != rhsVarRefs().end(); ++it) {
for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin();
it != m_rhsVarRefs.end(); ++it) {
if (m_lhsVarRef && m_lhsVarRef->varScopep() == (*it)->varScopep()) {
clearSimple("Circular logic\n"); // Oh my, we'll get a UNOPTFLAT much later.
}
@@ -303,6 +303,7 @@ private:
V3Double0 m_statSigs; // Statistic tracking
V3Double0 m_statRefs; // Statistic tracking
V3Double0 m_statDedupLogic; // Statistic tracking
V3Double0 m_statAssignMerged; // Statistic tracking
// METHODS
void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) {
@@ -352,6 +353,7 @@ private:
void consumedMove();
void replaceAssigns();
void dedupe();
void mergeAssigns();
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -368,6 +370,7 @@ private:
optimizeSignals(true);
// Remove redundant logic
if (v3Global.opt.oDedupe()) dedupe();
if (v3Global.opt.oAssemble()) mergeAssigns();
// Warn
warnSignals();
consumedMark();
@@ -506,6 +509,7 @@ public:
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
V3Stats::addStat("Optimizations, Gate assign merged", m_statAssignMerged);
}
};
@@ -593,8 +597,9 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
optimizeElimVar(vvertexp->varScp(), substp, consumerp);
// If the new replacement referred to a signal,
// Correct the graph to point to this new generating variable
for (GateVarRefList::const_iterator it = okVisitor.rhsVarRefs().begin();
it != okVisitor.rhsVarRefs().end(); ++it) {
const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
it != rhsVarRefs.end(); ++it) {
AstVarScope* newvarscp = (*it)->varScopep();
UINFO(9," Point-to-new vertex "<<newvarscp<<endl);
GateVarVertex* varvertexp = makeVarVertex(newvarscp);
@@ -1008,7 +1013,6 @@ private:
lvertexp->user(true);
}
}
return NULL;
}
@@ -1062,6 +1066,132 @@ void GateVisitor::dedupe() {
m_statDedupLogic += deduper.numDeduped();
}
//######################################################################
// Recurse through the graph, try to merge assigns
class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
AstNodeAssign* m_assignp;
AstActive* m_activep;
GateLogicVertex* m_logicvp;
V3Graph* m_graphp;
V3Double0 m_numMergedAssigns; // Statistic tracking
// assemble two Sel into one if possible
AstSel* merge(AstSel* pre, AstSel* cur) {
AstVarRef* preVarRefp = pre->fromp()->castVarRef();
AstVarRef* curVarRefp = cur->fromp()->castVarRef();
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) return NULL; // not the same var
AstConst* pstart = pre->lsbp()->castConst();
AstConst* pwidth = pre->widthp()->castConst();
AstConst* cstart = cur->lsbp()->castConst();
AstConst* cwidth = cur->widthp()->castConst();
if (!pstart || !pwidth || !cstart || !cwidth) return NULL; // too complicated
if (cur->lsbConst()+cur->widthConst() == pre->lsbConst())
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false), cur->lsbConst(), pre->widthConst()+cur->widthConst());
else return NULL;
}
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; ) {
V3GraphEdge* oldedgep = edgep;
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
if (AstNodeAssign* assignp = lvertexp->nodep()->castNodeAssign()) {
//if (lvertexp->outSize1() && assignp->lhsp()->castSel()) {
if (assignp->lhsp()->castSel() && lvertexp->outSize1()) {
UINFO(9, "assing to the nodep["<<assignp->lhsp()->castSel()->lsbConst()<<"]"<<endl);
// first assign with Sel-lhs
if (!m_activep) m_activep = lvertexp->activep();
if (!m_logicvp) m_logicvp = lvertexp;
if (!m_assignp) m_assignp = assignp;
// not under the same active
if (m_activep != lvertexp->activep()) {
m_activep = lvertexp->activep();
m_logicvp = lvertexp;
m_assignp = assignp;
continue;
}
AstSel* preselp = m_assignp->lhsp()->castSel();
AstSel* curselp = assignp->lhsp()->castSel();
if (!preselp || !curselp) continue;
if (AstSel* newselp = merge(preselp, curselp)) {
UINFO(5, "assemble to new sel: "<<newselp<<endl);
// replace preSel with newSel
preselp->replaceWith(newselp); preselp->deleteTree(); preselp = NULL;
// create new rhs for pre assignment
AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), assignp->rhsp()->cloneTree(false));
AstNode* oldrhsp = m_assignp->rhsp();
oldrhsp->replaceWith(newrhsp); oldrhsp->deleteTree(); oldrhsp = NULL;
m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(), m_assignp->width()+assignp->width(), AstNumeric::fromBool(true));
// don't need to delete, will be handled
//assignp->unlinkFrBack(); assignp->deleteTree(); assignp = NULL;
// update the graph
{
// delete all inedges to lvertexp
if (!lvertexp->inEmpty()) {
for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep; ) {
V3GraphEdge* oedgep = ledgep;
ledgep = ledgep->inNextp();
GateEitherVertex* fromvp = dynamic_cast<GateEitherVertex*>(oedgep->fromp());
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
oedgep->unlinkDelete(); oedgep = NULL;
}
}
// delete all outedges to lvertexp, only one
oldedgep->unlinkDelete(); oldedgep = NULL;
}
++m_numMergedAssigns;
} else {
m_assignp = assignp;
m_logicvp = lvertexp;
}
}
}
}
}
return NULL;
}
virtual AstNUser* visit(GateLogicVertex* lvertexp, AstNUser* vup) {
return NULL;
}
public:
GateMergeAssignsGraphVisitor(V3Graph* graphp) {
m_assignp = NULL;
m_activep = NULL;
m_logicvp = NULL;
m_numMergedAssigns = 0;
m_graphp = graphp;
}
void mergeAssignsTree(GateVarVertex* vvertexp) {
vvertexp->accept(*this);
}
V3Double0 numMergedAssigns() { return m_numMergedAssigns; }
};
//----------------------------------------------------------------------
void GateVisitor::mergeAssigns() {
GateMergeAssignsGraphVisitor merger(&m_graph);
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
merger.mergeAssignsTree(vvertexp);
}
}
m_statAssignMerged += merger.numMergedAssigns();
}
//######################################################################
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+5
View File
@@ -26,6 +26,7 @@
#include <string>
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Options.h"
class AstNetlist;
@@ -44,6 +45,7 @@ class V3Global {
int m_debugFileNumber; // Number to append to debug files created
bool m_assertDTypesResolved; // Tree should have dtypep()'s
bool m_assertWidthsMatch; // Tree should have width()==widthMin()
bool m_constRemoveXs; // Const needs to strip any Xs
bool m_needHInlines; // Need __Inlines file
bool m_needHeavy; // Need verilated_heavy.h include
bool m_dpi; // Need __Dpi include files
@@ -58,6 +60,7 @@ public:
m_debugFileNumber = 0;
m_assertDTypesResolved = false;
m_assertWidthsMatch = false;
m_constRemoveXs = false;
m_needHInlines = false;
m_needHeavy = false;
m_dpi = false;
@@ -77,6 +80,8 @@ public:
static void dumpCheckGlobalTree(const string& filename, int newNumber=0, bool doDump=true);
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
void assertWidthsMatch(bool flag) { m_assertWidthsMatch = flag; }
bool constRemoveXs() const { return m_constRemoveXs; }
void constRemoveXs(bool flag) { m_constRemoveXs = flag; }
string debugFilename(const string& nameComment, int newNumber=0) {
++m_debugFileNumber;
if (newNumber) m_debugFileNumber = newNumber;
+1
View File
@@ -96,6 +96,7 @@ public:
DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false)
: V3GraphVertex(graphp)
, m_start(start), m_accepting(accepting) {}
using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*)
virtual DfaVertex* clone(DfaGraph* graphp) {
return new DfaVertex(graphp, start(), accepting()); }
virtual ~DfaVertex() {}
+5
View File
@@ -314,6 +314,7 @@ private:
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (!m_cellp->isTrace()) nodep->trace(false);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
// Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
@@ -387,6 +388,10 @@ private:
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeAttrp(afterp);
afterp = nodep->scopeEntrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeEntrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeEntrp(afterp);
nodep->iterateChildren(*this);
}
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
+20 -3
View File
@@ -266,8 +266,8 @@ public:
if (nodep->modp()) nodep->modp()->user1p(symp);
checkDuplicate(abovep, nodep, nodep->origName());
abovep->reinsert(nodep->origName(), symp);
if (abovep != modSymp && !modSymp->findIdFlat(nodep->name())) {
// If it's foo_DOT_bar, we need to be able to find it under that too.
if (forScopeCreation() && abovep != modSymp && !modSymp->findIdFlat(nodep->name())) {
// If it's foo_DOT_bar, we need to be able to find it under "foo_DOT_bar" too.
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
modSymp->reinsert(nodep->name(), symp);
}
@@ -1451,6 +1451,7 @@ private:
virtual void visit(AstPin* nodep, AstNUser*) {
// Pin: Link to submodule's port
checkNoDot(nodep);
nodep->iterateChildren(*this);
if (!nodep->modVarp()) {
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n");
VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
@@ -1475,7 +1476,6 @@ private:
refp->user5p(nodep);
}
}
nodep->iterateChildren(*this);
}
// Early return() above when deleted
}
@@ -1805,6 +1805,15 @@ private:
// EnumItemRef may be under a dot. Should already be resolved.
nodep->iterateChildren(*this);
}
virtual void visit(AstMethodSel* nodep, AstNUser*) {
// Created here so should already be resolved.
DotStates lastStates = m_ds;
{
m_ds.init(m_curSymp);
nodep->iterateChildren(*this);
}
m_ds = lastStates;
}
virtual void visit(AstVar* nodep, AstNUser*) {
checkNoDot(nodep);
nodep->iterateChildren(*this);
@@ -1823,6 +1832,14 @@ private:
m_ds.m_dotp = NULL;
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
nodep->dotted(m_ds.m_dotText); // Maybe ""
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
// Found a Var, everything following is method call. {scope}.{var}.HERE {method} ( ARGS )
AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
AstNode* argsp = NULL; if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
AstNode* newp = new AstMethodSel(nodep->fileline(), varEtcp, VFlagChildDType(), nodep->name(), argsp);
nodep->replaceWith(newp);
pushDeletep(nodep); nodep=NULL;
return;
} else {
checkNoDot(nodep);
}
+6 -1
View File
@@ -130,7 +130,12 @@ void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
oldvarp->primaryIO(true);
varp->primaryIO(true);
}
if (varp->isIO() && v3Global.opt.systemC()) varp->sc(true);
if (varp->isIO() && v3Global.opt.systemC()) {
varp->sc(true);
// User can see trace one level down from the wrapper
// Avoids packing & unpacking SC signals a second time
varp->trace(false);
}
AstPin* pinp = new AstPin(oldvarp->fileline(),0,oldvarp->name(),
new AstVarRef(varp->fileline(),
+19 -2
View File
@@ -62,6 +62,7 @@ private:
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current task
AstNodeDType* m_dtypep; // Current data type
// METHODS
static int debug() {
@@ -104,6 +105,15 @@ private:
m_valueModp = upperValueModp;
}
}
virtual void visit(AstNodeDType* nodep, AstNUser*) {
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
AstNodeDType* upperDtypep = m_dtypep;
m_dtypep = nodep;
nodep->iterateChildren(*this);
m_dtypep = upperDtypep;
}
}
virtual void visit(AstEnumItem* nodep, AstNUser*) {
// Expand ranges
cleanFileline(nodep);
@@ -176,7 +186,13 @@ private:
virtual void visit(AstAttrOf* nodep, AstNUser*) {
cleanFileline(nodep);
nodep->iterateChildren(*this);
if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
if (nodep->attrType() == AstAttrType::DT_PUBLIC) {
AstTypedef* typep = nodep->backp()->castTypedef();
if (!typep) nodep->v3fatalSrc("Attribute not attached to typedef");
typep->attrPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->attrScClocked(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
@@ -265,7 +281,7 @@ private:
nodep->deleteTree(); nodep=NULL;
return;
} else {
defp = new AstTypedef(nodep->fileline(), nodep->name(), VFlagChildDType(), dtypep);
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, VFlagChildDType(), dtypep);
m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp));
backp->addNextHere(defp);
}
@@ -327,6 +343,7 @@ public:
m_varp = NULL;
m_modp = NULL;
m_ftaskp = NULL;
m_dtypep = NULL;
m_inAlways = false;
m_inGenerate = false;
m_needStart = false;
+2 -2
View File
@@ -250,8 +250,8 @@ private:
void expectFormat(AstNode* nodep, const string& format, AstNode* argp, bool isScan) {
// Check display arguments
bool inPct = false;
for (const char* inp = format.c_str(); *inp; inp++) {
char ch = tolower(*inp); // Breaks with iterators...
for (string::const_iterator it = format.begin(); it != format.end(); ++it) {
char ch = tolower(*it);
if (!inPct && ch=='%') {
inPct = true;
} else if (inPct) {
+105 -14
View File
@@ -25,6 +25,7 @@
#include <cstdarg>
#include <algorithm>
#include <iomanip>
#include "V3Global.h"
#include "V3Number.h"
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
@@ -33,7 +34,7 @@
// Read class functions
// CREATION
V3Number::V3Number(VerilogString, FileLine* fileline, const string& str) {
V3Number::V3Number(VerilogStringLiteral, FileLine* fileline, const string& str) {
// Create a number using a verilog string as the value, thus 8 bits per character.
// cppcheck bug - doesn't see init() resets these
// cppcheck: Member variable 'm_sized/m_width' is not initialized in the constructor
@@ -103,7 +104,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
}
// Otherwise...
else if (!m_sized) {
width(32, false); // Says the spec.
width(32, false); // Says IEEE 1800-2012 5.7.1
if (unbased) isSigned(true); // Also says the spec.
}
@@ -323,6 +324,7 @@ V3Number& V3Number::setAllBits1() {
return *this;
}
V3Number& V3Number::setAllBitsX() {
// Use setAllBitsXRemoved if calling this based on a non-X/Z input value such as divide by zero
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
opCleanThis();
return *this;
@@ -332,6 +334,20 @@ V3Number& V3Number::setAllBitsZ() {
opCleanThis();
return *this;
}
V3Number& V3Number::setAllBitsXRemoved() {
if (!v3Global.constRemoveXs()) {
return setAllBitsX();
} else {
// If we get a divide by zero we get Xs.
// But after V3Unknown we have removed Xs, so use --x-assign to direct-insert 0/1
if (v3Global.opt.xAssign() == "1") {
return setAllBits1();
} else {
return setAllBits0();
}
}
}
V3Number& V3Number::setMask(int nbits) {
setZero();
for (int bit=0; bit<nbits; bit++) { setBit(bit,1); }
@@ -349,6 +365,8 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
if (width()!=64) out<<"%E-bad-width-double";
else out<<toDouble();
return out.str();
} else if (isString()) {
return '"'+toString()+'"';
} else {
if ((m_value[words()-1] | m_valueX[words()-1]) & ~hiWordMask()) out<<"%E-hidden-bits";
}
@@ -388,6 +406,31 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
return out.str();
}
string V3Number::quoteNameControls(const string& namein) {
// Encode control chars into C style escapes
// Reverse is V3Parse::deQuote
const char* start = namein.c_str();
string out;
for (const char* pos = start; *pos; pos++) {
if (pos[0]=='\\' || pos[0]=='"') {
out += string("\\")+pos[0];
} else if (pos[0]=='\n') {
out += "\\n";
} else if (pos[0]=='\r') {
out += "\\r";
} else if (pos[0]=='\t') {
out += "\\t";
} else if (isprint(pos[0])) {
out += pos[0];
} else {
// This will also cover \a etc
char octal[10]; sprintf(octal,"\\%03o",pos[0]);
out += octal;
}
}
return out;
}
bool V3Number::displayedFmtLegal(char format) {
// Is this a valid format letter?
switch (tolower(format)) {
@@ -402,6 +445,7 @@ bool V3Number::displayedFmtLegal(char format) {
case 's': return true;
case 't': return true;
case 'x': return true;
case '@': return true; // Packed string
case '~': return true; // Signed decimal
default: return false;
}
@@ -457,6 +501,9 @@ string V3Number::displayed(const string& vformat) const {
str += (char)(v);
return str;
}
case '@': { // Packed string
return toString();
}
case 's': {
// Spec says always drop leading zeros, this isn't quite right, we space pad.
int bit=this->width()-1;
@@ -565,6 +612,7 @@ vlsint64_t V3Number::toSQuad() const {
string V3Number::toString() const {
UASSERT(!isFourState(),"toString with 4-state "<<*this);
// Spec says always drop leading zeros, this isn't quite right, we space pad.
if (isString()) return m_stringVal;
int bit=this->width()-1;
bool start=true;
while ((bit%8)!=7) bit++;
@@ -1125,21 +1173,29 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) {
if (rhs.isFourState()) return setAllBitsX();
setZero();
uint32_t rhsval = rhs.toUInt();
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(bit + rhsval));
if (rhsval < (uint32_t)lhs.width()) {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(bit + rhsval));
}
}
return *this;
}
V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits) {
// L(lhs) bit return
// The spec says a unsigned >>> still acts as a normal >>.
// We presume it is signed; as that's V3Width's job to convert to opShiftR
if (rhs.isFourState()) return setAllBitsX();
setZero();
uint32_t rhsval = rhs.toUInt();
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit + rhsval));
if (rhsval < (uint32_t)lhs.width()) {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit + rhsval, lbits));
}
} else {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(lbits-1));
}
}
return *this;
}
@@ -1240,7 +1296,7 @@ V3Number& V3Number::opDiv (const V3Number& lhs, const V3Number& rhs) {
UINFO(9, "opdiv "<<lhs<<" "<<rhs<<endl);
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
if (lhs.width()<=64) {
setQuad(lhs.toUQuad() / rhs.toUQuad());
return *this;
@@ -1253,7 +1309,7 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
// Signed divide
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
@@ -1270,7 +1326,7 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
if (lhs.width()<=64) {
setQuad(lhs.toUQuad() % rhs.toUQuad());
return *this;
@@ -1282,7 +1338,7 @@ V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
// Signed moddiv
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
@@ -1420,7 +1476,7 @@ V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs, bool lsign,
if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
if (rsign && rhs.isNegative()) {
if (lhs.isEqZero()) return setAllBitsX();
if (lhs.isEqZero()) return setAllBitsXRemoved();
else if (lhs.isEqOne()) return setQuad(1);
else if (lsign && lhs.isEqAllOnes()) {
if (rhs.bitIs1(0)) return setAllBits1(); // -1^odd=-1
@@ -1473,11 +1529,11 @@ V3Number& V3Number::opAssign (const V3Number& lhs) {
return *this;
}
V3Number& V3Number::opExtendS (const V3Number& lhs) {
V3Number& V3Number::opExtendS (const V3Number& lhs, uint32_t lbits) {
// Note may be a width change during the sign extension
setZero();
for(int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit));
setBit(bit,lhs.bitIsExtend(bit, lbits));
}
return *this;
}
@@ -1602,3 +1658,38 @@ V3Number& V3Number::opLtD (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opLteD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() <= rhs.toDouble());
}
//======================================================================
// Ops - String
V3Number& V3Number::opConcatN (const V3Number& lhs, const V3Number& rhs) {
return setString(lhs.toString() + rhs.toString());
}
V3Number& V3Number::opReplN (const V3Number& lhs, const V3Number& rhs) {
return opReplN(lhs, rhs.toUInt());
}
V3Number& V3Number::opReplN (const V3Number& lhs, uint32_t rhsval) {
string out; out.reserve(lhs.toString().length() * rhsval);
for (unsigned times=0; times<rhsval; times++) {
out += lhs.toString();
}
return setString(out);
}
V3Number& V3Number::opEqN (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toString() == rhs.toString());
}
V3Number& V3Number::opNeqN (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toString() != rhs.toString());
}
V3Number& V3Number::opGtN (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toString() > rhs.toString());
}
V3Number& V3Number::opGteN (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toString() >= rhs.toString());
}
V3Number& V3Number::opLtN (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toString() < rhs.toString());
}
V3Number& V3Number::opLteN (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toString() <= rhs.toString());
}
+41 -10
View File
@@ -25,6 +25,7 @@
#include <vector>
#include "V3Error.h"
#include "V3FileLine.h"
//============================================================================
@@ -34,13 +35,16 @@ class V3Number {
bool m_sized:1; // True if the user specified the width, else we track it.
bool m_signed:1; // True if signed value
bool m_double:1; // True if double real value
bool m_fromString:1; // True if from string
bool m_isString:1; // True if string
bool m_fromString:1; // True if from string literal
bool m_autoExtend:1; // True if SystemVerilog extend-to-any-width
FileLine* m_fileline;
vector<uint32_t> m_value; // The Value, with bit 0 being in bit 0 of this vector (unless X/Z)
vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
string m_stringVal; // If isString, the value of the string
// METHODS
V3Number& setSingleBits(char value);
V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; }
void opCleanThis();
public:
FileLine* fileline() const { return m_fileline; }
@@ -60,15 +64,18 @@ public:
}
private:
char bitIs (int bit) const {
if (bit>=m_width) {
if (bit>=m_width || bit<0) {
// We never sign extend
return '0';
}
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
char bitIsExtend (int bit) const {
if (bit>=m_width) {
bit = m_width-1;
char bitIsExtend (int bit, int lbits) const {
// lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less
if (bit<0) return '0';
UASSERT(lbits<=m_width, "Extend of wrong size");
if (bit>=lbits) {
bit = lbits ? lbits-1 : 0;
// We do sign extend
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] );
@@ -76,22 +83,28 @@ private:
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
bool bitIs0 (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return !bitIsXZ(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31)))==0 && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIs1 (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return false;
return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIs1Extend (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIs1Extend(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIsX (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsZ(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIsXZ(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsXZ(m_width-1);
return ( (m_valueX[bit/32] & (1UL<<(bit&31))) && 1);
return ( (m_valueX[bit/32] & (1UL<<(bit&31))));
}
bool bitIsZ (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsZ(m_width-1);
return ( (~m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
uint32_t bitsValue(int lsb, int nbits) const {
@@ -106,19 +119,22 @@ private:
V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
public:
class VerilogString {}; // for creator type-overload selection
// CONSTRUCTORS
V3Number(FileLine* fileline) { init(fileline, 1); }
V3Number(FileLine* fileline, int width) { init(fileline, width); } // 0=unsized
V3Number(FileLine* fileline, int width, uint32_t value) { init(fileline, width); m_value[0]=value; opCleanThis(); }
V3Number(FileLine* fileline, const char* source); // Create from a verilog 32'hxxxx number.
V3Number(VerilogString, FileLine* fileline, const string& vvalue);
class VerilogStringLiteral {}; // for creator type-overload selection
V3Number(VerilogStringLiteral, FileLine* fileline, const string& vvalue);
class String {};
V3Number(String, FileLine* fileline, const string& value) { init(fileline, 0); setString(value); }
private:
void init(FileLine* fileline, int swidth) {
m_fileline = fileline;
m_signed = false;
m_double = false;
m_isString = false;
m_autoExtend = false;
m_fromString = false;
width(swidth);
@@ -136,6 +152,7 @@ public:
}
// SETTERS
V3Number& setAllBitsXRemoved();
V3Number& setAllBitsX();
V3Number& setAllBitsZ();
V3Number& setAllBits0();
@@ -144,6 +161,7 @@ public:
// ACCESSORS
string ascii(bool prefixed=true, bool cleanVerilog=false) const;
static string quoteNameControls(const string& namein); // Add backslash quotes to strings
string displayed(const string& format) const;
static bool displayedFmtLegal(char format); // Is this a valid format letter?
int width() const { return m_width; }
@@ -154,6 +172,8 @@ public:
bool isSigned() const { return m_signed; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
bool isDouble() const { return m_double; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
void isDouble(bool flag) { m_double=flag; } // Only if have 64 bit value loaded, and want to indicate it's real
bool isString() const { return m_isString; }
void isString(bool flag) { m_isString=flag; }
bool isNegative() const { return bitIs1(width()-1); }
bool isFourState() const { for (int i=0;i<words();i++) {if (m_valueX[i]) return true;} return false; }
bool hasZ() const { for(int i=0;i<words();i++) {if((~m_value[i]) & m_valueX[i]) return true;} return false;}
@@ -198,7 +218,7 @@ public:
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
//
V3Number& opAssign (const V3Number& lhs);
V3Number& opExtendS (const V3Number& lhs); // Sign extension
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
V3Number& opRedOr (const V3Number& lhs);
V3Number& opRedAnd (const V3Number& lhs);
V3Number& opRedXor (const V3Number& lhs);
@@ -250,7 +270,7 @@ public:
V3Number& opRotR (const V3Number& lhs, const V3Number& rhs);
V3Number& opRotL (const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs); // Arithmetic w/carry
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry
V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs);
// Comparisons
V3Number& opEq (const V3Number& lhs, const V3Number& rhs);
@@ -283,6 +303,17 @@ public:
V3Number& opGteD (const V3Number& lhs, const V3Number& rhs);
V3Number& opLtD (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteD (const V3Number& lhs, const V3Number& rhs);
// "N" - string operations
V3Number& opConcatN (const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN (const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN (const V3Number& lhs, uint32_t rhs);
V3Number& opEqN (const V3Number& lhs, const V3Number& rhs);
V3Number& opNeqN (const V3Number& lhs, const V3Number& rhs);
V3Number& opGtN (const V3Number& lhs, const V3Number& rhs);
V3Number& opGteN (const V3Number& lhs, const V3Number& rhs);
V3Number& opLtN (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteN (const V3Number& lhs, const V3Number& rhs);
};
inline ostream& operator<<(ostream& os, V3Number rhs) { return os<<rhs.ascii(); }
+1
View File
@@ -22,6 +22,7 @@
#define V3NUMBER_ASCII_BINARY
#define _V3ERROR_NO_GLOBAL_ 1
#include "V3Error.cpp"
#include "V3FileLine.cpp"
#include "V3Number.cpp"
#include <config_build.h>
+39 -26
View File
@@ -107,17 +107,27 @@ void V3Options::addLangExt(const string& langext, const V3LangCode& lc) {
void V3Options::addLibExtV(const string& libext) {
m_impp->addLibExtV(libext);
}
void V3Options::addDefine(const string& defline) {
void V3Options::addDefine(const string& defline, bool allowPlus) {
// Split +define+foo=value into the appropriate parts and parse
string def = defline;
string value;
string::size_type pos;
if ( ((pos=defline.find("+")) != string::npos)
|| ((pos=defline.find("=")) != string::npos)) {
value = def.substr(pos+1);
def.erase(pos);
// Optional + says to allow multiple defines on the line
// + is not quotable, as other simulators do not allow that
string left = defline;
while (left != "") {
string def = left;
string::size_type pos;
if (allowPlus && ((pos=left.find("+")) != string::npos)) {
left = left.substr(pos+1);
def.erase(pos);
} else {
left = "";
}
string value;
if ((pos=def.find("=")) != string::npos) {
value = def.substr(pos+1);
def.erase(pos);
}
V3PreShell::defineCmdLine(def,value);
}
V3PreShell::defineCmdLine(def,value);
}
void V3Options::addCppFile(const string& filename) {
@@ -265,18 +275,18 @@ bool V3Options::filenameIsRel(const string& filename) {
}
bool V3Options::fileStatDir(const string& filename) {
struct stat m_stat; // Stat information
int err = stat(filename.c_str(), &m_stat);
struct stat sstat; // Stat information
int err = stat(filename.c_str(), &sstat);
if (err!=0) return false;
if (!S_ISDIR(m_stat.st_mode)) return false;
if (!S_ISDIR(sstat.st_mode)) return false;
return true;
}
bool V3Options::fileStatNormal(const string& filename) {
struct stat m_stat; // Stat information
int err = stat(filename.c_str(), &m_stat);
struct stat sstat; // Stat information
int err = stat(filename.c_str(), &sstat);
if (err!=0) return false;
if (S_ISDIR(m_stat.st_mode)) return false;
if (S_ISDIR(sstat.st_mode)) return false;
return true;
}
@@ -622,13 +632,14 @@ void V3Options::parseOpts (FileLine* fl, int argc, char** argv) {
// Default certain options and error check
// Detailed error, since this is what we often get when run with minimal arguments
if (vFiles().empty()) {
const V3StringList& vFilesList = vFiles();
if (vFilesList.empty()) {
v3fatal("verilator: No Input Verilog file specified on command line, see verilator --help for more information\n");
}
// Default prefix to the filename
if (prefix()=="" && topModule()!="") m_prefix = string("V")+topModule();
if (prefix()=="") m_prefix = string("V")+filenameNonExt(*(vFiles().begin()));
if (prefix()=="" && vFilesList.size()>=1) m_prefix = string("V")+filenameNonExt(*(vFilesList.begin()));
if (modPrefix()=="") m_modPrefix = prefix();
// Find files in makedir
@@ -667,7 +678,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
if (argv[i][0]=='+') {
char *sw = argv[i];
if ( !strncmp (sw, "+define+", 8)) {
addDefine (string (sw+strlen("+define+")));
addDefine (string (sw+strlen("+define+")), true);
}
else if ( !strncmp (sw, "+incdir+", 8)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
@@ -712,6 +723,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( !strcmp (sw, "-E") ) { m_preprocOnly = true; }
else if ( onoff (sw, "-MMD", flag/*ref*/) ) { m_makeDepend = flag; }
else if ( onoff (sw, "-MP", flag/*ref*/) ) { m_makePhony = flag; }
else if ( !strcmp (sw, "-P") ) { m_preprocNoLine = true; }
else if ( onoff (sw, "-assert", flag/*ref*/) ) { m_assert = flag; }
else if ( onoff (sw, "-autoflush", flag/*ref*/) ) { m_autoflush = flag; }
else if ( onoff (sw, "-bbox-sys", flag/*ref*/) ) { m_bboxSys = flag; }
@@ -742,14 +754,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-pins-uint8", flag/*ref*/) ){ m_pinsUint8 = flag; }
else if ( !strcmp (sw, "-private") ) { m_public = false; }
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
else if ( onoff (sw, "-psl-deprecated", flag/*ref*/) ) { m_psl = flag; } // Undocumented
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = 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; m_systemPerl = false; }
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
else if ( !strcmp (sw, "-sp") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = true; }
else if ( !strcmp (sw, "-sp-deprecated") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = true; } // Undocumented, old
else if ( onoff (sw, "-stats", flag/*ref*/) ) { m_stats = flag; }
else if ( onoff (sw, "-stats-vars", flag/*ref*/) ) { m_statsVars = flag; m_stats |= flag; }
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
@@ -772,6 +784,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
case 'b': m_oCombine = flag; break;
case 'c': m_oConst = flag; break;
case 'd': m_oDedupe = flag; break;
case 'm': m_oAssemble = flag; break;
case 'e': m_oCase = flag; break;
case 'f': m_oFlopGater = flag; break;
case 'g': m_oGate = flag; break;
@@ -800,7 +813,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
m_convergeLimit = atoi(argv[i]);
}
else if ( !strncmp (sw, "-D", 2)) {
addDefine (string (sw+strlen("-D")));
addDefine (string (sw+strlen("-D")), false);
}
else if ( !strcmp (sw, "-debug") ) {
setDebugMode(3);
@@ -820,7 +833,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
}
else if ( !strcmp (sw, "-error-limit") && (i+1)<argc ) {
shift;
m_errorLimit = atoi(argv[i]);
V3Error::errorLimit(atoi(argv[i]));
}
else if ( !strncmp (sw, "-I", 2)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("-I"))));
@@ -934,7 +947,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
FileLine::globalWarnStyleOff(true);
}
else if (!strcmp (sw, "-Wno-fatal")) {
m_warnFatal = false;
V3Error::warnFatal(false);
}
else {
string msg = sw+strlen("-Wno-");
@@ -1208,15 +1221,15 @@ V3Options::V3Options() {
m_makePhony = false;
m_orderClockDly = true;
m_outFormatOk = false;
m_warnFatal = true;
m_pinsBv = 65;
m_profileCFuncs = false;
m_preprocOnly = false;
m_psl = false;
m_preprocNoLine = false;
m_public = false;
m_savable = false;
m_skipIdentical = true;
m_stats = false;
m_statsVars = false;
m_systemC = false;
m_systemPerl = false;
m_trace = false;
@@ -1231,7 +1244,6 @@ V3Options::V3Options() {
m_convergeLimit = 100;
m_dumpTree = 0;
m_errorLimit = 50;
m_ifDepth = 0;
m_inlineMult = 2000;
m_outputSplit = 0;
@@ -1316,6 +1328,7 @@ void V3Options::optimize(int level) {
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = flag;
m_oAssemble = flag;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+8 -8
View File
@@ -59,6 +59,7 @@ class V3Options {
bool m_preprocOnly; // main switch: -E
bool m_makeDepend; // main switch: -MMD
bool m_makePhony; // main switch: -MP
bool m_preprocNoLine;// main switch: -P
bool m_assert; // main switch: --assert
bool m_autoflush; // main switch: --autoflush
bool m_bboxSys; // main switch: --bbox-sys
@@ -76,18 +77,17 @@ class V3Options {
bool m_lintOnly; // main switch: --lint-only
bool m_orderClockDly;// main switch: --order-clock-delay
bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified
bool m_warnFatal; // main switch: --warnFatal
bool m_pinsScUint; // main switch: --pins-sc-uint
bool m_pinsScBigUint;// main switch: --pins-sc-biguint
bool m_pinsUint8; // main switch: --pins-uint8
bool m_profileCFuncs;// main switch: --profile-cfuncs
bool m_psl; // main switch: --psl
bool m_public; // main switch: --public
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
bool m_systemPerl; // main switch: --sp: System Perl instead of SystemC (m_systemC also set)
bool m_stats; // main switch: --stats
bool m_statsVars; // main switch: --stats-vars
bool m_trace; // main switch: --trace
bool m_traceDups; // main switch: --trace-dups
bool m_traceParams; // main switch: --trace-params
@@ -100,7 +100,6 @@ class V3Options {
int m_convergeLimit;// main switch: --converge-limit
int m_dumpTree; // main switch: --dump-tree
int m_errorLimit; // main switch: --error-limit
int m_ifDepth; // main switch: --if-depth
int m_inlineMult; // main switch: --inline-mult
int m_outputSplit; // main switch: --output-split
@@ -138,6 +137,7 @@ class V3Options {
bool m_oCombine; // main switch: -Ob: common icode packing
bool m_oConst; // main switch: -Oc: constant folding
bool m_oDedupe; // main switch: -Od: logic deduplication
bool m_oAssemble; // main switch: -Om: assign assemble
bool m_oExpand; // main switch: -Ox: expansion of C macros
bool m_oFlopGater; // main switch: -Of: flop gater detection
bool m_oGate; // main switch: -Og: gate wire elimination
@@ -154,7 +154,7 @@ class V3Options {
private:
// METHODS
void addArg(const string& flag);
void addDefine(const string& defline);
void addDefine(const string& defline, bool allowPlus);
void addFuture(const string& flag);
void addIncDirUser(const string& incdir); // User requested
void addIncDirFallback(const string& incdir); // Low priority if not found otherwise
@@ -192,16 +192,18 @@ class V3Options {
bool preprocOnly() const { return m_preprocOnly; }
bool makeDepend() const { return m_makeDepend; }
bool makePhony() const { return m_makePhony; }
bool preprocNoLine() const { return m_preprocNoLine; }
bool underlineZero() const { return m_underlineZero; }
string bin() const { return m_bin; }
string flags() const { return m_flags; }
bool systemC() const { return m_systemC; }
bool systemPerl() const { return m_systemPerl; }
bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); }
bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || coverage()); }
bool usingSystemPerlLibs() const { return !lintOnly() && systemPerl(); }
bool savable() const { return m_savable; }
bool skipIdentical() const { return m_skipIdentical; }
bool stats() const { return m_stats; }
bool statsVars() const { return m_statsVars; }
bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined
bool autoflush() const { return m_autoflush; }
bool bboxSys() const { return m_bboxSys; }
@@ -222,12 +224,10 @@ class V3Options {
bool orderClockDly() const { return m_orderClockDly; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool warnFatal() const { return m_warnFatal; }
bool pinsScUint() const { return m_pinsScUint; }
bool pinsScBigUint() const { return m_pinsScBigUint; }
bool pinsUint8() const { return m_pinsUint8; }
bool profileCFuncs() const { return m_profileCFuncs; }
bool psl() const { return m_psl; }
bool allPublic() const { return m_public; }
bool l2Name() const { return m_l2Name; }
bool lintOnly() const { return m_lintOnly; }
@@ -239,7 +239,6 @@ class V3Options {
int convergeLimit() const { return m_convergeLimit; }
int dumpTree() const { return m_dumpTree; }
int errorLimit() const { return m_errorLimit; }
int ifDepth() const { return m_ifDepth; }
int inlineMult() const { return m_inlineMult; }
int outputSplit() const { return m_outputSplit; }
@@ -280,6 +279,7 @@ class V3Options {
bool oCombine() const { return m_oCombine; }
bool oConst() const { return m_oConst; }
bool oDedupe() const { return m_oDedupe; }
bool oAssemble() const { return m_oAssemble; }
bool oExpand() const { return m_oExpand; }
bool oFlopGater() const { return m_oFlopGater; }
bool oGate() const { return m_oGate; }
+2 -2
View File
@@ -1191,14 +1191,14 @@ void OrderVisitor::processMove() {
while (!m_pomReadyDomScope.empty()) {
// Start with top node on ready list's domain & scope
OrderMoveDomScope* domScopep = m_pomReadyDomScope.begin();
OrderMoveVertex* topVertexp = domScopep->readyVertices().begin();
OrderMoveVertex* topVertexp = domScopep->readyVertices().begin(); // lintok-begin-on-ref
UASSERT(topVertexp, "domScope on ready list without any nodes ready under it");
// Work on all scopes ready inside this domain
while (domScopep) {
UINFO(6," MoveDomain l="<<domScopep->domainp()<<endl);
// Process all nodes ready under same domain & scope
m_pomNewFuncp = NULL;
while (OrderMoveVertex* vertexp = domScopep->readyVertices().begin()) {
while (OrderMoveVertex* vertexp = domScopep->readyVertices().begin()) { // lintok-begin-on-ref
processMoveOne(vertexp, domScopep, 1);
}
// Done with scope/domain pair, pick new scope under same domain, or NULL if none left
+2 -1
View File
@@ -210,7 +210,8 @@ private:
virtual void visit(AstNodeModule* nodep, AstNUser*) {
if (nodep->dead()) {
UINFO(4," MOD-dead. "<<nodep<<endl); // Marked by LinkDot
} else if (nodep->level() <= 2) { // Haven't added top yet, so level 2 is the top
} else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top
|| nodep->castPackage()) { // Likewise haven't done wrapTopPackages yet
// Add request to END of modules left to process
m_todoModps.insert(make_pair(nodep->level(),nodep));
visitModules();
+9 -1
View File
@@ -104,7 +104,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
// of this source file is updated here, in case there have been any
// intervening +<lang>ext+ options since it was first ecountered.
FileLine *modfileline = new FileLine (modfilename, 0);
modfileline->updateLanguage();
modfileline->language(v3Global.opt.fileLanguage(modfilename));
ppPushText((string)"`begin_keywords \""+modfileline->language().ascii()+"\"\n");
}
@@ -123,6 +123,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp";
ofstream* ofp = NULL;
ostream* osp;
bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine();
if (v3Global.opt.preprocOnly()) {
osp = &cout;
} else {
@@ -133,6 +134,13 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
return;
} else {
for (deque<string>::iterator it = m_ppBuffers.begin(); it!=m_ppBuffers.end(); ++it) {
if (noblanks) {
bool blank = true;
for (string::iterator its = it->begin(); its != it->end(); ++its) {
if (!isspace(*its) && *its!='\n') { blank=false; break; }
}
if (blank) continue;
}
*osp << *it;
}
if (ofp) {
+1 -3
View File
@@ -23,6 +23,7 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Global.h"
#include "V3Parse.h"
#include "V3ParseSym.h"
@@ -131,7 +132,6 @@ public:
// Functions called by lex rules:
int yylexThis();
static bool optPsl() { return v3Global.opt.psl(); }
static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
void ppline (const char* text);
@@ -190,8 +190,6 @@ public:
// Interactions with lexer
void lexNew(int debug);
void lexDestroy();
void stateExitPsl(); // Parser -> lexer communication
void statePushVlg(); // Parser -> lexer communication
void statePop(); // Parser -> lexer communication
static int stateVerilogRecent(); // Parser -> lexer communication
int prevLexToken() { return m_prevLexToken; } // Parser -> lexer communication
-9
View File
@@ -47,13 +47,6 @@ public:
V3Lexer() : V3LexerBase(NULL) {}
~V3Lexer() {}
// METHODS
void stateExitPsl() {
if (YY_START != PSL) yyerrorf("Internal error: Exiting PSL state when not in PSL state");
yy_pop_state();
}
void statePushVlg() {
yy_push_state(STATE_VERILOG_RECENT);
}
void statePop() {
yy_pop_state();
}
@@ -65,8 +58,6 @@ public:
}
}
};
void V3ParseImp::stateExitPsl() { parsep()->m_lexerp->stateExitPsl(); }
void V3ParseImp::statePushVlg() { parsep()->m_lexerp->stateExitPsl(); }
void V3ParseImp::statePop() { parsep()->m_lexerp->statePop(); }
void V3ParseImp::unputString(const char* textp, size_t length) { parsep()->m_lexerp->unputString(textp, length); }
+1
View File
@@ -23,6 +23,7 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3Global.h"
#include "V3SymTable.h"
#include <deque>
+3 -4
View File
@@ -31,6 +31,7 @@
#include <stack>
#include "V3Error.h"
#include "V3FileLine.h"
//======================================================================
@@ -166,9 +167,8 @@ class V3PreLex {
// State from lexer
int m_formalLevel; // Parenthesis counting inside def formals
int m_parenLevel; // Parenthesis counting inside def args
int m_pslParenLevel;// PSL Parenthesis (){} counting, so we can find final ;
bool m_pslMoreNeeded;// Next // comment is really psl
bool m_defCmtSlash; // /*...*/ comment in define had \ ending
bool m_defQuote; // Definition value inside quote
string m_defValue; // Definition value being built.
int m_enterExit; // For VL_LINE, the enter/exit level
@@ -181,11 +181,10 @@ class V3PreLex {
m_pedantic = false;
m_formalLevel = 0;
m_parenLevel = 0;
m_defQuote = false;
m_defCmtSlash = false;
m_tokFilelinep = filelinep;
m_enterExit = 0;
m_pslParenLevel = 0;
m_pslMoreNeeded = false;
initFirstBuffer(filelinep);
}
~V3PreLex() {
+20 -51
View File
@@ -42,24 +42,14 @@ void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=siz
// Prevent conflicts from perl version
static void linenoInc() {LEXP->linenoInc();}
static bool optPsl() { return V3PreProc::optPsl(); }
static bool pedantic() { return LEXP->m_pedantic; }
static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t,l); }
static int pslParenLevel() { return LEXP->m_pslParenLevel; }
static void pslParenLevelInc() { LEXP->m_pslParenLevel++; }
static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; }
static bool pslMoreNeeded() { return LEXP->m_pslMoreNeeded; }
static void pslMoreNeeded(bool flag) { LEXP->m_pslMoreNeeded = flag; }
/**********************************************************************/
%}
%x PSLONEM
%x PSLONEE
%x PSLMULM
%x PSLMUL1
%x CMTONEM
%x CMTBEGM
%x CMTMODE
@@ -86,7 +76,6 @@ symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
symbdef ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n`]+)
word [a-zA-Z0-9_]+
drop [\032]
psl [p]sl
/**************************************************************/
%%
@@ -107,7 +96,7 @@ psl [p]sl
/* Optional directives we recognize */
<INITIAL>"`__FILE__" { static string rtnfile;
rtnfile = '"'; rtnfile += LEXP->curFilelinep()->filename().c_str();
rtnfile = '"'; rtnfile += LEXP->curFilelinep()->filename();
rtnfile += '"'; yytext=(char*)rtnfile.c_str(); yyleng = rtnfile.length();
return (VP_STRING); }
<INITIAL>"`__LINE__" { static char buf[10];
@@ -117,7 +106,7 @@ psl [p]sl
<INITIAL>"`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
/* Pass-through strings */
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
<INITIAL>{quote} { yy_push_state(STRMODE); yymore(); }
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
<STRMODE>{word} { yymore(); }
@@ -125,7 +114,7 @@ psl [p]sl
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
<STRMODE>{backslash}. { yymore(); }
<STRMODE>{quote} { yy_pop_state();
if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; }
if (LEXP->m_parenLevel || LEXP->m_defQuote) { LEXP->m_defQuote=false; appendDefValue(yytext,yyleng); yyleng=0; }
else return (VP_STRING); }
/* Stringification */
@@ -162,7 +151,7 @@ psl [p]sl
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Include return so can maintain output line count */
<DEFFORM>{quote} { yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>{tickquote} { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>[{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); }
@@ -179,7 +168,8 @@ psl [p]sl
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Return, AND \ is part of define value */
<DEFVAL>[^\/\*\n\r\\]+ |
<DEFVAL>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); }
<DEFVAL>[^\/\*\n\r\\\"]+ |
<DEFVAL>[\\][^\n\r] |
<DEFVAL>. { appendDefValue(yytext,yyleng); }
@@ -232,57 +222,36 @@ psl [p]sl
<ARGMODE>. { appendDefValue(yytext,yyleng); }
/* One line comments. */
<INITIAL>"//"{ws}*{psl} { if (optPsl()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
else { yy_push_state(CMTONEM); yymore(); } }
<INITIAL>"//"{ws}*{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return (VP_WHITE); }
<INITIAL>"//" { if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
else { yy_push_state(CMTONEM); yymore(); } }
<INITIAL>"//" { yy_push_state(CMTONEM); yymore(); }
<CMTONEM>[^\n\r]* { yy_pop_state(); return (VP_COMMENT); }
/* Psl oneline comments */
<PSLONEM>[{(] { pslParenLevelInc(); return (VP_TEXT); }
<PSLONEM>[})] { pslParenLevelDec(); return (VP_TEXT); }
<PSLONEM>[;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); }
<PSLONEM>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
/* Completed psl oneline comments */
<PSLONEE>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<PSLONEE>{ws}+ { yymore(); }
<PSLONEE>. { yyerrorf("Unexpected text following psl assertion\n"); }
/* C-style comments. */
/**** See also DEFCMT */
/* We distinguish between the start of a comment, and later, so we may find a "psl" prefix */
<INITIAL>"/*" { yy_push_state(optPsl() ? CMTBEGM : CMTMODE); yymore(); }
<CMTBEGM>{psl} { yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); }
/* We distinguish between the start of a comment, and later, to look for prefix comments (deprecated) */
<INITIAL>"/*" { yy_push_state(CMTMODE); yymore(); }
<CMTBEGM>{ws}+ { yymore(); }
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
<CMTBEGM,CMTMODE><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
<CMTMODE>{word} { yymore(); }
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* beginning in comment */
<CMTMODE>. { yymore(); }
/* Psl C-style comments. */
/* EOFs are normal because / * `foo(..) * / hits a unputString EOF */
<PSLMUL1>.|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
<PSLMULM>"*/" { yy_pop_state(); return(VP_COMMENT); }
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
/* Define calls */
/* symbdef prevents normal lex rules from making `\`"foo a symbol {`"foo} instead of a BACKQUOTE */
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef} { return (VP_DEFREF); }
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
<INITIAL>"`"{symbdef} { return (VP_DEFREF); }
<INITIAL>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
/* Generics */
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM><<EOF>> { yyterminate(); } /* A "normal" EOF */
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
<INITIAL,PSLMULM,PSLONEM>{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM>{drop} { }
<INITIAL,PSLMULM,PSLONEM>[\r] { }
<INITIAL,PSLMULM,PSLONEM>. { return (VP_TEXT); }
<INITIAL>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<INITIAL><<EOF>> { yyterminate(); } /* A "normal" EOF */
<INITIAL>{symb} { return (VP_SYMBOL); }
<INITIAL>{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
<INITIAL>{wsn}+ { return (VP_WHITE); }
<INITIAL>{drop} { }
<INITIAL>[\r] { }
<INITIAL>. { return (VP_TEXT); }
%%
void V3PreLex::pushStateDefArg(int level) {
+16 -19
View File
@@ -282,10 +282,6 @@ V3PreProc* V3PreProc::createPreProc(FileLine* fl) {
return preprocp;
}
bool V3PreProc::optPsl() {
return v3Global.opt.psl();
}
//*************************************************************************
// Defines
@@ -483,7 +479,6 @@ const char* V3PreProcImp::tokenName(int tok) {
case VP_IFNDEF : return("IFNDEF");
case VP_INCLUDE : return("INCLUDE");
case VP_LINE : return("LINE");
case VP_PSL : return("PSL");
case VP_STRIFY : return("STRIFY");
case VP_STRING : return("STRING");
case VP_SYMBOL : return("SYMBOL");
@@ -566,7 +561,8 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
bool quote = false;
bool haveDefault = false;
// Note there's a leading ( and trailing ), so parens==1 is the base parsing level
const char* cp=refp->params().c_str();
string params = refp->params(); // Must keep in scope
const char* cp=params.c_str();
if (*cp == '(') cp++;
for (; *cp; cp++) {
//UINFO(4," Parse Paren="<<paren<<" Arg="<<numArgs<<" token='"<<token<<"' Parse="<<cp<<endl);
@@ -1102,7 +1098,7 @@ int V3PreProcImp::getStateToken() {
// Value of building argument is data before the lower defref
// we'll append it when we push the argument.
break;
} else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE || VP_PSL) {
} else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE) {
string rtn; rtn.assign(yyourtext(),yyourleng());
refp->nextarg(refp->nextarg()+rtn);
goto next_tok;
@@ -1339,7 +1335,6 @@ int V3PreProcImp::getStateToken() {
goto next_tok;
case VP_SYMBOL:
case VP_STRING:
case VP_PSL:
case VP_TEXT: {
m_defDepth = 0;
if (!m_off) return tok;
@@ -1367,9 +1362,11 @@ int V3PreProcImp::getFinalToken(string& buf) {
}
int tok = m_finToken;
buf = m_finBuf;
if (0 && debug()>=5) fprintf (stderr,"%d: FIN: %-10s: %s\n",
m_lexp->m_tokFilelinep->lineno(),
tokenName(tok), V3PreLex::cleanDbgStrg(buf).c_str());
if (0 && debug()>=5) {
string bufcln = V3PreLex::cleanDbgStrg(buf);
fprintf (stderr,"%d: FIN: %-10s: %s\n",
m_lexp->m_tokFilelinep->lineno(), tokenName(tok), bufcln.c_str());
}
// Track `line
const char* bufp = buf.c_str();
while (*bufp == '\n') bufp++;
@@ -1400,7 +1397,7 @@ int V3PreProcImp::getFinalToken(string& buf) {
}
}
// Track newlines in prep for next token
for (const char* cp = buf.c_str(); *cp; cp++) {
for (string::iterator cp=buf.begin(); cp!=buf.end(); ++cp) {
if (*cp == '\n') {
m_finAtBol = true;
m_finFilelinep->linenoIncInPlace(); // Increment in place to avoid new/delete calls. It's private data.
@@ -1422,8 +1419,9 @@ string V3PreProcImp::getline() {
string buf;
int tok = getFinalToken(buf/*ref*/);
if (debug()>=5) {
string bufcln = V3PreLex::cleanDbgStrg(buf);
fprintf (stderr,"%d: GETFETC: %-10s: %s\n",
m_lexp->m_tokFilelinep->lineno(), tokenName(tok), V3PreLex::cleanDbgStrg(buf).c_str());
m_lexp->m_tokFilelinep->lineno(), tokenName(tok), bufcln.c_str());
}
if (tok==VP_EOF) {
// Add a final newline, if the user forgot the final \n.
@@ -1432,9 +1430,6 @@ string V3PreProcImp::getline() {
}
gotEof = true;
}
else if (tok==VP_PSL) {
m_lineChars.append(" psl ");
}
else {
m_lineChars.append(buf);
}
@@ -1444,8 +1439,10 @@ string V3PreProcImp::getline() {
int len = rtnp-m_lineChars.c_str()+1;
string theLine(m_lineChars, 0, len);
m_lineChars = m_lineChars.erase(0,len); // Remove returned characters
if (debug()>=4) fprintf (stderr,"%d: GETLINE: %s\n",
m_lexp->m_tokFilelinep->lineno(),
V3PreLex::cleanDbgStrg(theLine).c_str());
if (debug()>=4) {
string lncln = V3PreLex::cleanDbgStrg(theLine);
fprintf (stderr,"%d: GETLINE: %s\n",
m_lexp->m_tokFilelinep->lineno(), lncln.c_str());
}
return theLine;
}
+4 -2
View File
@@ -26,6 +26,7 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include <string>
#include <map>
@@ -71,9 +72,10 @@ public:
// These options control how the parsing proceeds
static int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
static bool keepWhitespace() { return false; }
static bool lineDirectives() { return true; } // Insert `line directives
static bool lineDirectives() { // Insert `line directives
return !(v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine());
}
static bool pedantic() { return false; } // Obey standard; Don't substitute `error
static bool optPsl();
// CALLBACK METHODS
// This probably will want to be overridden for given child users of this class.
+1
View File
@@ -24,6 +24,7 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3FileLine.h"
class V3ParseImp;
class V3InFilter;
+84 -7
View File
@@ -40,6 +40,60 @@
#include "V3Premit.h"
#include "V3Ast.h"
//######################################################################
// Structure for global state
class PremitAssignVisitor : public AstNVisitor {
private:
// NODE STATE
// AstVar::user4() // bool; occurs on LHS of current assignment
AstUser4InUse m_inuser4;
// STATE
bool m_noopt; // Disable optimization of variables in this block
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
//AstNode::user4ClearTree(); // Implied by AstUser4InUse
// LHS first as fewer varrefs
nodep->lhsp()->iterateAndNext(*this);
// Now find vars marked as lhs
nodep->rhsp()->iterateAndNext(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// it's LHS var is used so need a deep temporary
if (nodep->lvalue()) {
nodep->varp()->user4(true);
} else {
if (nodep->varp()->user4()) {
if (!m_noopt) UINFO(4, "Block has LHS+RHS var: "<<nodep<<endl);
m_noopt = true;
}
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTRUCTORS
PremitAssignVisitor(AstNodeAssign* nodep) {
UINFO(4," PremitAssignVisitor on "<<nodep<<endl);
m_noopt = false;
nodep->accept(*this);
}
virtual ~PremitAssignVisitor() {}
bool noOpt() const { return m_noopt; }
};
//######################################################################
// Premit state, as a visitor of each AstNode
@@ -49,6 +103,7 @@ private:
// AstNodeMath::user() -> bool. True if iterated already
// AstShiftL::user2() -> bool. True if converted to conditional
// AstShiftR::user2() -> bool. True if converted to conditional
// *::user4() -> See PremitAssignVisitor
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
@@ -83,7 +138,7 @@ private:
//UINFO(9, " Detail stmtp="<<(m_stmtp?"Y":"N")<<" U="<<(nodep->user1()?"Y":"N")<<" IW "<<(nodep->isWide()?"Y":"N")<<endl);
if (m_stmtp
&& !nodep->user1()) { // Not already done
if (nodep->isWide()) { // Else might be cell interconnect or something
if (nodep->isWide()) {
if (m_assignLhs) {
} else if (nodep->firstAbovep()
&& nodep->firstAbovep()->castNodeAssign()
@@ -93,7 +148,7 @@ private:
&& nodep->firstAbovep()->castArraySel()) { // ArraySel's are pointer refs, ignore
} else {
UINFO(4,"Cre Temp: "<<nodep<<endl);
createDeepTemp(nodep);
createDeepTemp(nodep, false);
}
}
}
@@ -102,7 +157,7 @@ private:
AstVar* getBlockTemp(AstNode* nodep) {
string newvarname = ((string)"__Vtemp"+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname,
VFlagLogicPacked(), nodep->widthMin());
nodep->dtypep());
m_funcp->addInitsp(varp);
return varp;
}
@@ -115,21 +170,24 @@ private:
m_inWhilep->addPrecondsp(newp);
} else if (m_inTracep) {
m_inTracep->addPrecondsp(newp);
} else {
} else if (m_stmtp) {
AstNRelinker linker;
m_stmtp->unlinkFrBack(&linker);
newp->addNext(m_stmtp);
linker.relink(newp);
} else {
newp->v3fatalSrc("No statement insertion point.");
}
}
void createDeepTemp(AstNode* nodep) {
void createDeepTemp(AstNode* nodep, bool noSubst) {
if (debug()>8) nodep->dumpTree(cout,"deepin:");
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstVar* varp = getBlockTemp(nodep);
if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const
// Replace node tree with reference to var
AstVarRef* newp = new AstVarRef (nodep->fileline(), varp, false);
linker.relink(newp);
@@ -174,6 +232,14 @@ private:
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
startStatement(nodep);
{
bool noopt = PremitAssignVisitor(nodep).noOpt();
if (noopt && !nodep->user1()) {
// Need to do this even if not wide, as e.g. a select may be on a wide operator
UINFO(4,"Deep temp for LHS/RHS\n");
createDeepTemp(nodep->rhsp(), false);
}
}
nodep->rhsp()->iterateAndNext(*this);
m_assignLhs = true;
nodep->lhsp()->iterateAndNext(*this);
@@ -272,7 +338,7 @@ private:
&& !nodep->condp()->castVarRef()) {
// We're going to need the expression several times in the expanded code,
// so might as well make it a common expression
createDeepTemp(nodep->condp());
createDeepTemp(nodep->condp(), false);
}
checkNode(nodep);
}
@@ -287,7 +353,7 @@ private:
while (searchp && searchp->castComment()) searchp = searchp->nextp();
if (searchp
&& searchp->castDisplay()
&& nodep->filep()->sameTree(searchp->castDisplay()->filep())) {
&& nodep->filep()->sameGateTree(searchp->castDisplay()->filep())) {
// There's another display next; we can just wait to flush
} else {
UINFO(4,"Autoflush "<<nodep<<endl);
@@ -296,6 +362,17 @@ private:
}
}
}
virtual void visit(AstSFormatF* nodep, AstNUser*) {
nodep->iterateChildren(*this);
// Any strings sent to a display must be var of string data type,
// to avoid passing a pointer to a temporary.
for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) {
if (expp->dtypep()->basicp()->isString()
&& !expp->castVarRef()) {
createDeepTemp(expp, true);
}
}
}
//--------------------
// Default: Just iterate
+7 -2
View File
@@ -241,6 +241,7 @@ private:
if (!nodep->user1p()) {
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
UINFO(6," New scope "<<varscp<<endl);
if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
nodep->user1p(varscp);
if (!m_scopep) nodep->v3fatalSrc("No scope for var");
m_varScopes.insert(make_pair(make_pair(nodep, m_scopep), varscp));
@@ -258,8 +259,8 @@ private:
// the var's referenced package etc might not be created yet.
// So push to a list and post-correct
m_varRefScopes.insert(make_pair(nodep, m_scopep));
}
}
}
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
string prefix = (string)("__DOT__")+m_scopep->name();
@@ -270,6 +271,10 @@ private:
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), prefix));
if (afterp) nodep->scopeAttrp(afterp);
afterp = nodep->scopeEntrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeEntrp(new AstText(nodep->fileline(), prefix));
if (afterp) nodep->scopeEntrp(afterp);
nodep->iterateChildren(*this);
}
virtual void visit(AstScope* nodep, AstNUser*) {
-1
View File
@@ -233,7 +233,6 @@ private:
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
V3Graph m_graph; // Scoreboard of var usages/dependencies
bool m_inDly; // Inside ASSIGNDLY
uint32_t m_stepNum; // Step number we need to ignore a edge in
V3Double0 m_statSplits; // Statistic tracking
// METHODS
+25 -3
View File
@@ -40,6 +40,9 @@
class StatsVisitor : public AstNVisitor {
private:
// NODE STATE/TYPES
typedef map<string,int> NameMap; // Number of times a name appears
// STATE
string m_stage; // Name of the stage we are scanning
bool m_fast; // Counting only fastpath
@@ -54,7 +57,8 @@ private:
V3Double0 m_statPred[AstBranchPred::_ENUM_END]; // Nodes of given type
V3Double0 m_statInstr; // Instruction count
V3Double0 m_statInstrFast; // Instruction count
vector<V3Double0> m_statVarWidths; // Variables of given type
vector<V3Double0> m_statVarWidths; // Variables of given width
vector<NameMap> m_statVarWidthNames; // Var names of given width
V3Double0 m_statVarArray; // Statistic tracking
V3Double0 m_statVarBytes; // Statistic tracking
V3Double0 m_statVarClock; // Statistic tracking
@@ -100,8 +104,18 @@ private:
else m_statVarBytes += nodep->dtypeSkipRefp()->widthTotalBytes();
if (int(m_statVarWidths.size()) <= nodep->width()) {
m_statVarWidths.resize(nodep->width()+5);
if (v3Global.opt.statsVars()) m_statVarWidthNames.resize(nodep->width()+5);
}
++ m_statVarWidths.at(nodep->width());
string pn = nodep->prettyName();
if (v3Global.opt.statsVars()) {
NameMap& nameMapr = m_statVarWidthNames.at(nodep->width());
if (nameMapr.find(pn) != nameMapr.end()) {
nameMapr[pn]++;
} else {
nameMapr[pn]=1;
}
}
}
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
@@ -208,8 +222,16 @@ public:
}
for (unsigned i=0; i<m_statVarWidths.size(); i++) {
if (double count = double(m_statVarWidths.at(i))) {
ostringstream os; os<<"Vars, width "<<setw(4)<<dec<<i;
V3Stats::addStat(m_stage, os.str(), count);
if (v3Global.opt.statsVars()) {
NameMap& nameMapr = m_statVarWidthNames.at(i);
for (NameMap::iterator it=nameMapr.begin(); it!=nameMapr.end(); ++it) {
ostringstream os; os<<"Vars, width "<<setw(5)<<dec<<i<<" "<<it->first;
V3Stats::addStat(m_stage, os.str(), it->second);
}
} else {
ostringstream os; os<<"Vars, width "<<setw(5)<<dec<<i;
V3Stats::addStat(m_stage, os.str(), count);
}
}
}
// Node types
+2 -1
View File
@@ -23,7 +23,8 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
class AstNetlist;
//============================================================================
+7 -4
View File
@@ -258,6 +258,9 @@ private:
return entryp;
}
}
inline bool isSubstVar(AstVar* nodep) {
return nodep->isStatementTemp() && !nodep->noSubst();
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
@@ -266,7 +269,7 @@ private:
nodep->rhsp()->iterateAndNext(*this);
bool hit=false;
if (AstVarRef* varrefp = nodep->lhsp()->castVarRef()) {
if (varrefp->varp()->isStatementTemp()) {
if (isSubstVar(varrefp->varp())) {
SubstVarEntry* entryp = getEntryp(varrefp);
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
@@ -281,7 +284,7 @@ private:
else if (AstWordSel* wordp = nodep->lhsp()->castWordSel()) {
if (AstVarRef* varrefp = wordp->lhsp()->castVarRef()) {
if (wordp->rhsp()->castConst()
&& varrefp->varp()->isStatementTemp()) {
&& isSubstVar(varrefp->varp())) {
int word = wordp->rhsp()->castConst()->toUInt();
SubstVarEntry* entryp = getEntryp(varrefp);
hit = true;
@@ -314,7 +317,7 @@ private:
nodep->rhsp()->accept(*this);
AstVarRef* varrefp = nodep->lhsp()->castVarRef();
AstConst* constp = nodep->rhsp()->castConst();
if (varrefp && varrefp->varp()->isStatementTemp()
if (varrefp && isSubstVar(varrefp->varp())
&& !varrefp->lvalue()
&& constp) {
// Nicely formed lvalues handled in NodeAssign
@@ -344,7 +347,7 @@ private:
nodep->varp()->user2(m_assignStep);
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
}
if (nodep->varp()->isStatementTemp()) {
if (isSubstVar(nodep->varp())) {
SubstVarEntry* entryp = getEntryp (nodep);
if (nodep->lvalue()) {
UINFO(8," ASSIGNcpx "<<nodep<<endl);
+1 -1
View File
@@ -353,7 +353,7 @@ private:
== var2p->dtypep()->arrayUnpackedElements())) {
AstNode* init1p = var1p->valuep()->castInitArray();
AstNode* init2p = var2p->valuep()->castInitArray();
if (init1p->sameTree(init2p)) {
if (init1p->sameGateTree(init2p)) {
UINFO(8," Duplicate table var "<<vsc2p<<" == "<<vsc1p<<endl);
vsc1p->unlinkFrBack()->deleteTree();
return vsc2p;
+10 -7
View File
@@ -43,7 +43,6 @@ private:
// NODE STATE
// STATE
AstNodeModule* m_modp; // Current module
AstScope* m_scopetopp; // Current top scope
AstCFunc* m_initFuncp; // Trace function being built
AstCFunc* m_initSubFuncp; // Trace function being built (under m_init)
@@ -65,15 +64,19 @@ private:
return level;
}
const char* varIgnoreTrace(AstVar* nodep) {
const char* vscIgnoreTrace(AstVarScope* nodep) {
// Return true if this shouldn't be traced
// See also similar rule in V3Coverage::varIgnoreToggle
string prettyName = nodep->prettyName();
if (!nodep->isTrace()) {
AstVar* varp = nodep->varp();
string prettyName = varp->prettyName();
if (!varp->isTrace()) {
return "Verilator trace_off";
}
else if (!nodep->isTrace()) {
return "Verilator cell trace_off";
}
else if (!v3Global.opt.traceUnderscore()) {
if (prettyName.c_str()[0] == '_')
if (prettyName.size()>=1 && prettyName[0] == '_')
return "Leading underscore";
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
@@ -164,8 +167,8 @@ private:
m_traVscp = nodep;
m_traValuep = NULL;
if (varIgnoreTrace(varp)) {
addIgnore(varIgnoreTrace(varp));
if (vscIgnoreTrace(nodep)) {
addIgnore(vscIgnoreTrace(nodep));
} else {
++m_statSigs;
if (nodep->valuep()) m_traValuep = nodep->valuep()->cloneTree(true);
+12 -12
View File
@@ -579,29 +579,29 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->addStmtp(enassp);
// now append this driver to the driver logic.
AstNode* ref1p = new AstVarRef(nodep->fileline(), newlhsp,false);
AstNode* ref2p = new AstVarRef(nodep->fileline(), newenp, false);
andp = new AstAnd(nodep->fileline(), ref1p, ref2p);
AstNode* ref1p = new AstVarRef(refp->fileline(), newlhsp,false);
AstNode* ref2p = new AstVarRef(refp->fileline(), newenp, false);
andp = new AstAnd(refp->fileline(), ref1p, ref2p);
// or this to the others
orp = (!orp) ? andp : new AstOr(nodep->fileline(), orp, andp);
orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp);
if (envarp) {
AstNode* ref3p = new AstVarRef(nodep->fileline(), newenp, false);
AstNode* ref3p = new AstVarRef(refp->fileline(), newenp, false);
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
}
AstNode* tmp = new AstNot(newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, false));
undrivenp = ((!undrivenp) ? tmp
: new AstAnd(nodep->fileline(), tmp, undrivenp));
: new AstAnd(refp->fileline(), tmp, undrivenp));
}
if (!undrivenp) { // No drivers on the bus
V3Number ones(nodep->fileline(), lhsp->width()); ones.setAllBits1();
undrivenp = new AstConst(nodep->fileline(), ones);
V3Number ones(invarp->fileline(), lhsp->width()); ones.setAllBits1();
undrivenp = new AstConst(invarp->fileline(), ones);
}
if (!outvarp) {
// This is the final resolution of the tristate, so we apply
// the pull direction to any undriven pins.
V3Number pull(nodep->fileline(), lhsp->width());
V3Number pull(invarp->fileline(), lhsp->width());
AstPull* pullp = (AstPull*)lhsp->user3p();
if (pullp && pullp->direction() == 1) {
pull.setAllBits1();
@@ -609,9 +609,9 @@ class TristateVisitor : public TristateBaseVisitor {
} else {
pull.setAllBits0(); // default pull direction is down.
}
undrivenp = new AstAnd(nodep->fileline(), undrivenp,
new AstConst(nodep->fileline(), pull));
orp = new AstOr(nodep->fileline(), orp, undrivenp);
undrivenp = new AstAnd(invarp->fileline(), undrivenp,
new AstConst(invarp->fileline(), pull));
orp = new AstOr(invarp->fileline(), orp, undrivenp);
} else {
undrivenp->deleteTree(); undrivenp=NULL;
}
+4 -3
View File
@@ -145,9 +145,10 @@ public:
return isUsedNotDrivenBit(0, m_flags.size()/FLAGS_PER_BIT);
}
bool unusedMatch(AstVar* nodep) {
const char* regexpp = v3Global.opt.unusedRegexp().c_str();
if (!regexpp || !*regexpp) return false;
return VString::wildmatch(nodep->prettyName().c_str(), regexpp);
string regexp = v3Global.opt.unusedRegexp();
if (regexp == "") return false;
string prettyName = nodep->prettyName();
return VString::wildmatch(prettyName.c_str(), regexp.c_str());
}
void reportViolations() {
// Combine bits into overall state
+11 -7
View File
@@ -337,14 +337,14 @@ private:
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
int maxmsb = nodep->fromp()->dtypep()->width()-1;
int maxlsb = maxmsb - nodep->width() + 1;
if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);
V3Number maxmsbnum (nodep->fileline(), nodep->lsbp()->width(), maxmsb);
// See if the condition is constant true
// If (maxmsb >= selected), we're in bound
AstNode* condp = new AstGte (nodep->fileline(),
new AstConst(nodep->fileline(), maxlsbnum),
new AstConst(nodep->fileline(), maxmsbnum),
nodep->lsbp()->cloneTree(false));
// See if the condition is constant true (e.g. always in bound due to constant select)
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
@@ -352,7 +352,7 @@ private:
condp->deleteTree();
}
else if (!lvalue) {
// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
@@ -410,12 +410,16 @@ private:
condp->deleteTree();
}
else if (!lvalue
&& !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension
&& !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
xnum.setAllBitsX();
if (nodep->isString()) {
xnum = V3Number(V3Number::String(), nodep->fileline(), "");
} else {
xnum.setAllBitsX();
}
AstNode* newp = new AstCondBound (nodep->fileline(),
condp,
nodep,
+28 -12
View File
@@ -164,15 +164,27 @@ private:
bool gt = condp->castGt() || condp->castGtS();
bool gte = condp->castGte() || condp->castGteS();
if (!lt && !lte && !gt && !gte)
return cantUnroll(nodep, "condition not <= or <");
AstNodeBiop* condBip = condp->castNodeBiop();
if (!condBip->rhsp()->castVarRef())
return cantUnroll(nodep, "condition not <=, <, >= or >");
AstNodeBiop* cmpInstrp = condp->castNodeBiop();
bool cmpVarLhs;
if (cmpInstrp->lhsp()->castVarRef()
&& cmpInstrp->lhsp()->castVarRef()->varp() == m_forVarp
&& cmpInstrp->lhsp()->castVarRef()->varScopep() == m_forVscp) {
cmpVarLhs = true;
} else if (cmpInstrp->rhsp()->castVarRef()
&& cmpInstrp->rhsp()->castVarRef()->varp() == m_forVarp
&& cmpInstrp->rhsp()->castVarRef()->varScopep() == m_forVscp) {
cmpVarLhs = false;
} else if (!cmpInstrp->rhsp()->castVarRef()) {
return cantUnroll(nodep, "no variable on rhs of condition");
if (condBip->rhsp()->castVarRef()->varp() != m_forVarp
|| condBip->rhsp()->castVarRef()->varScopep() != m_forVscp)
} else {
return cantUnroll(nodep, "different variable in condition");
if (m_generate) V3Const::constifyParamsEdit(condBip->lhsp()); // rhsp may change
AstConst* constStopp = condBip->lhsp()->castConst();
}
if (m_generate) V3Const::constifyParamsEdit(cmpVarLhs ? cmpInstrp->rhsp()
: cmpInstrp->lhsp()); // rhsp/lhsp may change
AstConst* constStopp = (cmpVarLhs ? cmpInstrp->rhsp()->castConst()
: cmpInstrp->lhsp()->castConst());
if (!constStopp) return cantUnroll(nodep, "non-constant final value");
UINFO(8, " Stop expr ok: "<<constStopp<<endl);
//
@@ -217,9 +229,9 @@ private:
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
//
// Finally, we can do it
forUnroller(nodep, initp, precondsp, condp, incp, bodysp,
forUnroller(nodep, initp, precondsp, incp, bodysp,
constInitp->num(),
condBip, constStopp->num(),
cmpInstrp, constStopp->num(), cmpVarLhs,
incInstrp, constIncp->num()); nodep = NULL;
// Cleanup
return true;
@@ -227,10 +239,10 @@ private:
void forUnroller(AstNode* nodep,
AstNode* initp,
AstNode* precondsp, AstNode* condp,
AstNode* precondsp,
AstNode* incp, AstNode* bodysp,
const V3Number& numInit,
AstNodeBiop* cmpInstrp, const V3Number& numStop,
AstNodeBiop* cmpInstrp, const V3Number& numStop, bool cmpVarLhs,
AstNodeBiop* incInstrp, const V3Number& numInc) {
UINFO(4, " Unroll for var="<<numInit<<"; var<"<<numStop<<"; var+="<<numInc<<endl);
UINFO(6, " cmpI "<<cmpInstrp<<endl);
@@ -270,7 +282,11 @@ private:
UINFO(8," Looping "<<loopValue<<endl);
// if loopValue<valStop
V3Number contin (nodep->fileline(), 1);
cmpInstrp->numberOperate(contin, numStop, loopValue);
if (cmpVarLhs) {
cmpInstrp->numberOperate(contin, loopValue, numStop);
} else {
cmpInstrp->numberOperate(contin, numStop, loopValue);
}
if (contin.isEqZero()) {
break; // Done with the loop
} else {
+576 -142
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -72,8 +72,9 @@ class WidthCommitVisitor : public AstNVisitor {
public:
// METHODS
static AstConst* newIfConstCommitSize (AstConst* nodep) {
if ((nodep->dtypep()->width() != nodep->num().width())
|| !nodep->num().sized()) { // Need to force the number rrom unsized to sized
if (((nodep->dtypep()->width() != nodep->num().width())
|| !nodep->num().sized())
&& !nodep->num().isString()) { // Need to force the number rrom unsized to sized
V3Number num (nodep->fileline(), nodep->dtypep()->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
+6 -5
View File
@@ -116,8 +116,8 @@ void V3Global::readFiles() {
V3Parse parser (v3Global.rootp(), &filter, &parseSyms);
// Read top module
for (V3StringList::const_iterator it = v3Global.opt.vFiles().begin();
it != v3Global.opt.vFiles().end(); ++it) {
const V3StringList& vFiles = v3Global.opt.vFiles();
for (V3StringList::const_iterator it = vFiles.begin(); it != vFiles.end(); ++it) {
string filename = *it;
parser.parseFile(new FileLine("COMMAND_LINE",0), filename, false,
"Cannot find file containing module: ");
@@ -126,8 +126,8 @@ void V3Global::readFiles() {
// Read libraries
// To be compatible with other simulators,
// this needs to be done after the top file is read
for (V3StringSet::const_iterator it = v3Global.opt.libraryFiles().begin();
it != v3Global.opt.libraryFiles().end(); ++it) {
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
for (V3StringSet::const_iterator it = libraryFiles.begin(); it != libraryFiles.end(); ++it) {
string filename = *it;
parser.parseFile(new FileLine("COMMAND_LINE",0), filename, true,
"Cannot find file containing library module: ");
@@ -256,6 +256,7 @@ void process () {
// Move assignments from X into MODULE temps.
// (Before flattening, so each new X variable is shared between all scopes of that module.)
V3Unknown::unknownAll(v3Global.rootp());
v3Global.constRemoveXs(true);
V3Global::dumpCheckGlobalTree("unknown.tree");
// Module inlining
@@ -629,7 +630,7 @@ int main(int argc, char** argv, char** env) {
&& !v3Global.opt.lintOnly()
&& !v3Global.opt.xmlOnly()
&& !v3Global.opt.cdc()) {
v3fatal("verilator: Need --cc, --sc, --sp, --cdc, --lint-only, --xml_only or --E option");
v3fatal("verilator: Need --cc, --sc, --cdc, --lint-only, --xml_only or --E option");
}
// Check environment
V3Options::getenvSYSTEMC();
+133
View File
@@ -0,0 +1,133 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Bucket container
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCBUCKET_H_
#define _VLCBUCKET_H_ 1
#include "config_build.h"
#include "verilatedos.h"
//********************************************************************
// VlcBuckets - Container of all coverage point hits for a given test
// This is a bitmap array - we store a single bit to indicate a test
// has hit that point with sufficient coverage.
class VlcBuckets {
private:
// MEMBERS
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
vluint64_t m_dataSize; ///< Current entries in m_datap
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
private:
static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
void allocate(vluint64_t point) {
vluint64_t oldsize = m_dataSize;
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
m_dataSize *= 2;
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<(void*)(m_datap)<<endl);
m_datap = (vluint64_t*)realloc(m_datap, allocSize());
if (!m_datap) {v3fatal("Out of memory increasing buckets"); }
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
}
public:
// CONSTRUCTORS
VlcBuckets() {
m_dataSize = 0;
m_datap = NULL;
m_bucketsCovered = 0;
allocate(1024);
}
~VlcBuckets() {
m_dataSize = 0;
free(m_datap); m_datap=NULL;
}
// ACCESSORS
static vluint64_t sufficient() { return 1; }
vluint64_t bucketsCovered() const { return m_bucketsCovered; }
// METHODS
void addData(vluint64_t point, vluint64_t hits) {
if (hits >= sufficient()) {
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
if (point >= m_dataSize) allocate(point);
m_datap[point/64] |= covBit(point);
m_bucketsCovered++;
}
}
void clearHits(vluint64_t point) const {
if (point >= m_dataSize) {
return;
} else {
m_datap[point/64] &= ~covBit(point);
}
}
bool exists(vluint64_t point) const {
if (point >= m_dataSize) {
return false;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
}
vluint64_t hits(vluint64_t point) const {
if (point >= m_dataSize) {
return 0;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
}
vluint64_t popCount() const {
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) pop++;
}
return pop;
}
vluint64_t dataPopCount(const VlcBuckets& remaining) {
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && remaining.hits(i)) pop++;
}
return pop;
}
void orData(const VlcBuckets& ordata) {
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && ordata.hits(i)) {
clearHits(i);
}
}
}
void dump() const {
cout<<"# ";
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) cout<<","<<i;
}
cout<<endl;
}
};
//######################################################################
#endif // guard
+203
View File
@@ -0,0 +1,203 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: main()
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// Cheat for speed and compile .cpp files into one object
#define _V3ERROR_NO_GLOBAL_ 1
#include "V3Error.cpp"
#include "VlcTop.cpp"
#include "VlcOptions.h"
#include "VlcTop.h"
#include <fstream>
#include <algorithm>
#include <unistd.h>
//######################################################################
// VlcOptions
void VlcOptions::addReadFile(const string& filename) {
if (m_readFiles.find(filename) == m_readFiles.end()) {
m_readFiles.insert(filename);
}
}
string VlcOptions::version() {
string ver = DTVERSION;
ver += " rev "+cvtToStr(DTVERSION_rev);
return ver;
}
bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
// if sw==arg, then return true (found it), and flag=true
// if sw=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false
// else return false
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
if (0==strcmp(sw,arg)) { flag=true; return true; }
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
return false;
}
void VlcOptions::parseOptsList(int argc, char** argv) {
// Parse parameters
// Note argc and argv DO NOT INCLUDE the filename in [0]!!!
// May be called recursively when there are -f files.
#define shift { ++i; }
for (int i=0; i<argc; ) {
UINFO(9, " Option: "<<argv[i]<<endl);
if (argv[i][0]=='-') {
const char *sw = argv[i];
bool flag = true;
// Allow gnu -- switches
if (sw[0]=='-' && sw[1]=='-') ++sw;
if (0) {}
// Single switches
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
// Parameterized switches
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
shift;
m_annotateOut = argv[i];
}
else if ( !strcmp (sw, "-debug") ) {
V3Error::debugDefault(3);
}
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
shift;
V3Error::debugDefault(atoi(argv[i]));
}
else if ( !strcmp (sw, "-V") ) {
showVersion(true);
exit(0);
}
else if ( !strcmp (sw, "-version") ) {
showVersion(false);
exit(0);
}
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
shift;
m_writeFile = argv[i];
}
else {
v3fatal ("Invalid option: "<<argv[i]);
}
shift;
} // - options
else if (1) {
addReadFile(argv[i]);
shift;
}
else {
v3fatal ("Invalid argument: "<<argv[i]);
shift;
}
}
#undef shift
}
void VlcOptions::showVersion(bool verbose) {
cout <<version();
cout <<endl;
if (!verbose) return;
cout <<endl;
cout << "Copyright 2003-2014 by Wilson Snyder. Verilator is free software; you can\n";
cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
cout << "License Version 2.0.\n";
cout <<endl;
cout << "See http://www.veripool.org/verilator for documentation\n";
}
//######################################################################
// File searching
// (TODO: Make a V3Os with these functions and share with Verilator)
string VlcOptions::filenameNonDir (const string& filename) {
string::size_type pos;
if ((pos = filename.rfind("/")) != string::npos) {
return filename.substr(pos+1);
} else {
return filename;
}
}
//######################################################################
int main(int argc, char** argv, char** env) {
// General initialization
ios::sync_with_stdio();
VlcTop top;
// Command option parsing
top.opt.parseOptsList(argc-1, argv+1);
if (top.opt.readFiles().empty()) {
top.opt.addReadFile("vlt_coverage.pl");
}
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
top.readCoverage(filename);
}
if (debug() >= 9) {
top.tests().dump(true);
top.points().dump();
}
V3Error::abortIfWarnings();
if (top.opt.annotateOut() != "") {
top.annotate(top.opt.annotateOut());
}
if (top.opt.rank()) {
top.rank();
top.tests().dump(false);
}
if (top.opt.writeFile() != "") {
top.writeCoverage(top.opt.writeFile());
V3Error::abortIfWarnings();
if (top.opt.unlink()) {
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
unlink(filename.c_str());
}
}
}
// Final writing shouldn't throw warnings, but...
V3Error::abortIfWarnings();
UINFO(1,"Done, Exiting...\n");
}
// Local Variables:
// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
// End:
+87
View File
@@ -0,0 +1,87 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Command line options
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCOPTIONS_H_
#define _VLCOPTIONS_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include <string>
#include <vector>
#include <map>
#include <set>
#include "config_rev.h"
//######################################################################
// V3Options - Command line options
typedef vector<string> VlStringList;
typedef set<string> VlStringSet;
class VlcOptions {
// MEMBERS (general options)
string m_annotateOut; // main switch: --annotate I<output_directory>
bool m_annotateAll; // main switch: --annotate-all
int m_annotateMin; // main switch: --annotate-min I<count>
VlStringSet m_readFiles; // main switch: --read
bool m_rank; // main switch: --rank
bool m_unlink; // main switch: --unlink
string m_writeFile; // main switch: --write
private:
// METHODS
void showVersion(bool verbose);
bool onoff(const char* sw, const char* arg, bool& flag);
public:
// CREATORS
VlcOptions() {
m_annotateAll = false;
m_annotateMin = 10;
m_rank = false;
m_unlink = false;
}
~VlcOptions() {}
void setDebugMode(int level);
// METHODS
void parseOptsList(int argc, char** argv);
void addReadFile(const string& filename);
// ACCESSORS (options)
const VlStringSet& readFiles() const { return m_readFiles; }
string annotateOut() const { return m_annotateOut; }
bool annotateAll() const { return m_annotateAll; }
int annotateMin() const { return m_annotateMin; }
bool rank() const { return m_rank; }
bool unlink() const { return m_unlink; }
string writeFile() const { return m_writeFile; }
// METHODS (from main)
static string version();
// METHODS (file searching)
static string filenameNonDir(const string& filename);
};
//######################################################################
#endif // guard
+152
View File
@@ -0,0 +1,152 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Coverage points
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCPOINT_H_
#define _VLCPOINT_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "verilated_cov_key.h"
#include <map>
#include <vector>
#include <iomanip>
//********************************************************************
// VlcPoint - A coverage point (across all tests)
class VlcPoint {
private:
// MEMBERS
string m_name; //< Name of the point
vluint64_t m_pointNum; //< Point number
vluint64_t m_testsCovering;//< Number tests with non-zero coverage of this point
vluint64_t m_count; //< Count of hits across all tests
public:
// CONSTRUCTORS
VlcPoint(const string& name, int pointNum) {
m_name = name;
m_pointNum = pointNum;
m_testsCovering = 0;
m_count = 0;
}
~VlcPoint() {}
// ACCESSORS
const string& name() const { return m_name; }
vluint64_t pointNum() const { return m_pointNum; }
vluint64_t testsCovering() const { return m_testsCovering; }
void countInc(vluint64_t inc) { m_count += inc; }
vluint64_t count() const { return m_count; }
void testsCoveringInc() { m_testsCovering++; }
// KEY ACCESSORS
string filename() const { return keyExtract(VL_CIK_FILENAME); }
string comment() const { return keyExtract(VL_CIK_COMMENT); }
string type() const { return keyExtract(VL_CIK_TYPE); }
string thresh() const { return keyExtract(VL_CIK_THRESH); } // string as maybe ""
int lineno() const { return atoi(keyExtract(VL_CIK_LINENO).c_str()); }
int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
// METHODS
string keyExtract(const char* shortKey) const {
// Hot function
size_t shortLen = strlen(shortKey);
const string namestr = name();
for (const char* cp = namestr.c_str(); *cp; ++cp) {
if (*cp == '\001') {
if (0==strncmp(cp+1, shortKey, shortLen)
&& cp[shortLen+1] == '\002') {
cp += shortLen+2; // Skip \001+short+\002
const char* ep = cp;
while (*ep && *ep != '\001') ++ep;
return string(cp, ep-cp);
}
}
}
return "";
}
static void dumpHeader() {
cout<<"Points:\n";
cout<<" Num, TestsCover, Count, Name"<<endl;
}
void dump() const {
cout<<" "<<setw(8)<<setfill('0')<<pointNum()
<<", "<<setw(7)<<setfill(' ')<<testsCovering()
<<", "<<setw(7)<<setfill(' ')<<count()
<<", \""<<name()<<"\""<<endl;
}
};
//********************************************************************
// VlcPoints - Container of all points
class VlcPoints {
private:
// MEMBERS
typedef std::map<string,vluint64_t> NameMap;
NameMap m_nameMap; //< Name to point-number
vector<VlcPoint> m_points; //< List of all points
vluint64_t m_numPoints; //< Total unique points
public:
// ITERATORS
typedef NameMap ByName;
typedef ByName::iterator iterator;
ByName::iterator begin() { return m_nameMap.begin(); }
ByName::iterator end() { return m_nameMap.end(); }
public:
// CONSTRUCTORS
VlcPoints() {
m_numPoints = 0;
}
~VlcPoints() {}
// METHODS
void dump() {
UINFO(2,"dumpPoints...\n");
VlcPoint::dumpHeader();
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
const VlcPoint& point = pointNumber(it->second);
point.dump();
}
}
VlcPoint& pointNumber(vluint64_t num) {
return m_points[num];
}
vluint64_t findAddPoint(const string& name, vluint64_t count) {
vluint64_t pointnum;
NameMap::iterator iter = m_nameMap.find(name);
if (iter != m_nameMap.end()) {
pointnum = iter->second;
m_points[pointnum].countInc(count);
}
else {
pointnum = m_numPoints++;
VlcPoint point (name, pointnum);
point.countInc(count);
m_points.push_back(point);
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
}
return pointnum;
}
};
//######################################################################
#endif // guard
+145
View File
@@ -0,0 +1,145 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Source file to annotate with line coverage
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCSOURCE_H_
#define _VLCSOURCE_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include <map>
#include <vector>
//********************************************************************
// VlcColumnCount - count at specific source file, line and column
class VlcSourceCount {
private:
// MEMBERS
int m_lineno; ///< Line number
int m_column; ///< Column number
vluint64_t m_count; ///< Count
bool m_ok; ///< Coverage is above threshold
public:
// CONSTRUCTORS
VlcSourceCount(int lineno, int column) {
m_lineno = lineno;
m_column = column;
m_count = 0;
m_ok = false;
}
~VlcSourceCount() {}
// ACCESSORS
int lineno() const { return m_lineno; }
int column() const { return m_column; }
vluint64_t count() const { return m_count; }
bool ok() const { return m_ok; }
// METHODS
void incCount(vluint64_t count, bool ok) {
m_count += count;
if (ok) m_ok = true;
}
};
//********************************************************************
// VlcSource - source file to annotate
class VlcSource {
public:
// TYPES
typedef map<int,VlcSourceCount> ColumnMap; // Map of {column}
typedef map<int,ColumnMap> LinenoMap; // Map of {lineno}{column}
private:
// MEMBERS
string m_name; //< Name of the source file
bool m_needed; //< Need to annotate; has low coverage
LinenoMap m_lines; //< Map of each annotated line
public:
// CONSTRUCTORS
VlcSource(const string& name) {
m_name = name;
m_needed = false;
}
~VlcSource() {}
// ACCESSORS
const string& name() const { return m_name; }
void needed(bool flag) { m_needed = flag; }
bool needed() const { return m_needed; }
LinenoMap& lines() { return m_lines; }
// METHODS
void incCount(int lineno, int column, vluint64_t count, bool ok) {
LinenoMap::iterator lit = m_lines.find(lineno);
if (lit == m_lines.end()) {
lit = m_lines.insert(make_pair(lineno,ColumnMap())).first;
}
ColumnMap& cmap = lit->second;
ColumnMap::iterator cit = cmap.find(column);
if (cit == cmap.end()) {
cit = cmap.insert(make_pair(column,VlcSourceCount(lineno, column))).first;
}
VlcSourceCount& sc = cit->second;
sc.incCount(count,ok);
}
};
//********************************************************************
// VlcSources - Container of all source files
class VlcSources {
public:
// TYPES
typedef map<string,VlcSource> NameMap;
private:
// MEMBERS
NameMap m_sources; //< List of all sources
public:
// ITERATORS
typedef NameMap::iterator iterator;
NameMap::iterator begin() { return m_sources.begin(); }
NameMap::iterator end() { return m_sources.end(); }
public:
// CONSTRUCTORS
VlcSources() {}
~VlcSources() {}
// METHODS
VlcSource& findNewSource(const string& name) {
NameMap::iterator iter = m_sources.find(name);
if (iter != m_sources.end()) {
return iter->second;
}
else {
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
return iter->second;
}
}
};
//######################################################################
#endif // Guard
+137
View File
@@ -0,0 +1,137 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Test/coverage file container
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCTEST_H_
#define _VLCTEST_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "VlcPoint.h"
#include "VlcBucket.h"
#include <map>
#include <vector>
//********************************************************************
// VlcTest - a single testrun i.e. a file containing coverage data
class VlcTest {
private:
// MEMBERS
string m_name; //< Name of the test
double m_computrons; //< Runtime for the test
vluint64_t m_testrun; //< Test run number, for database use
vluint64_t m_rank; //< Execution rank suggestion
vluint64_t m_rankPoints; //< Ranked additional points
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
VlcBuckets m_buckets; //< Coverage data for each coverage point
public:
// CONSTRUCTORS
VlcTest(const string& name, vluint64_t testrun, double comp) {
m_name = name;
m_computrons = comp;
m_testrun = testrun;
m_rank = 0;
m_rankPoints = 0;
m_user = 0;
}
~VlcTest() {}
// ACCESSORS
const string& name() const { return m_name; }
double computrons() const { return m_computrons; }
vluint64_t testrun() const { return m_testrun; }
VlcBuckets& buckets() { return m_buckets; }
vluint64_t bucketsCovered() const { return m_buckets.bucketsCovered(); }
vluint64_t rank() const { return m_rank; }
void rank(vluint64_t flag) { m_rank = flag; }
vluint64_t rankPoints() const { return m_rankPoints; }
void rankPoints(vluint64_t flag) { m_rankPoints = flag; }
vluint64_t user() const { return m_user; }
void user(vluint64_t flag) { m_user = flag; }
// METHODS
static void dumpHeader() {
cout<<"Tests:\n";
//cout<<" Testrun, Computrons,"; // Currently not loaded
cout<<" Covered, Rank, RankPts, Filename"<<endl;
}
void dump(bool bucketsToo) {
if (testrun() || computrons()) {
cout<<" "<<setw(8)<<setfill('0')<<testrun()
<<", "<<setw(7)<<setfill(' ')<<computrons()<<",";
}
cout<<" "<<setw(7)<<setfill(' ')<<bucketsCovered()
<<", "<<setw(7)<<setfill(' ')<<rank()
<<", "<<setw(7)<<setfill(' ')<<rankPoints()
<<", \""<<name()<<"\""<<endl;
if (bucketsToo) m_buckets.dump();
}
};
//********************************************************************
// VlcTests - Container of all tests
class VlcTests {
public:
// TYPES
typedef vector<VlcTest*> ByName;
private:
// MEMBERS
ByName m_tests; //< List of all tests
public:
// ITERATORS
typedef ByName::iterator iterator;
ByName::iterator begin() { return m_tests.begin(); }
ByName::iterator end() { return m_tests.end(); }
public:
// CONSTRUCTORS
VlcTests() {}
~VlcTests() {
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
delete *it; *it=NULL;
}
}
// METHODS
void dump(bool bucketsToo) {
UINFO(2,"dumpTests...\n");
VlcTest::dumpHeader();
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
(*it)->dump(bucketsToo);
}
}
VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
VlcTest* testp = new VlcTest(name, testrun, comp);
m_tests.push_back(testp);
return testp;
}
void clearUser() {
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
(*it)->user(0);
}
}
};
//######################################################################
#endif // Guard
+263
View File
@@ -0,0 +1,263 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: top implementation
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// Cheat for speed and compile .cpp files into one object
#include "V3Error.h"
#include "VlcOptions.h"
#include "VlcTop.h"
#include <sys/stat.h>
#include <fstream>
#include <algorithm>
//######################################################################
void VlcTop::readCoverage(const string& filename, bool nonfatal) {
UINFO(2,"readCoverage "<<filename<<endl);
ifstream is (filename.c_str());
if (!is) {
if (!nonfatal) v3fatal("Can't read "<<filename);
return;
}
// Testrun and computrons argument unsupported as yet
VlcTest* testp = tests().newTest(filename, 0, 0);
while (!is.eof()) {
string line;
getline(is, line);
//UINFO(9," got "<<line<<endl);
if (line[0] == 'C') {
string::size_type secspace=3;
for (; secspace<line.length(); secspace++) {
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
}
string point = line.substr(3,secspace-3);
vluint64_t hits = atoll(line.c_str()+secspace+1);
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
vluint64_t pointnum = points().findAddPoint(point, hits);
if (pointnum) {} // Prevent unused
if (opt.rank()) { // Only if ranking - uses a lot of memory
if (hits >= VlcBuckets::sufficient()) {
points().pointNumber(pointnum).testsCoveringInc();
testp->buckets().addData(pointnum, hits);
}
}
}
}
}
void VlcTop::writeCoverage(const string& filename) {
UINFO(2,"writeCoverage "<<filename<<endl);
ofstream os (filename.c_str());
if (!os) {
v3fatal("Can't write "<<filename);
return;
}
os << "# SystemC::Coverage-3" << endl;
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
const VlcPoint& point = m_points.pointNumber(it->second);
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
}
}
//********************************************************************
struct CmpComputrons {
inline bool operator () (const VlcTest* lhsp, const VlcTest* rhsp) const {
if (lhsp->computrons() != rhsp->computrons()) {
return lhsp->computrons() < rhsp->computrons();
}
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
}
};
void VlcTop::rank() {
UINFO(2,"rank...\n");
vluint64_t nextrank=1;
// Sort by computrons, so fast tests get selected first
vector<VlcTest*> bytime;
for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
VlcTest* testp = *it;
if (testp->bucketsCovered()) { // else no points, so can't help us
bytime.push_back(*it);
}
}
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
VlcBuckets remaining;
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
VlcPoint* pointp = &points().pointNumber(it->second);
// If any tests hit this point, then we'll need to cover it.
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
}
// Additional Greedy algorithm
// O(n^2) Ouch. Probably the thing to do is randomize the order of data
// then hierarchically solve a small subset of tests, and take resulting
// solution and move up to larger subset of tests. (Aka quick sort.)
while (1) {
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
VlcTest* bestTestp = NULL;
vluint64_t bestRemain = 0;
for (vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
VlcTest* testp = *it;
if (!testp->rank()) {
vluint64_t remain = testp->buckets().dataPopCount(remaining);
if (remain > bestRemain) {
bestTestp = testp;
bestRemain = remain;
}
}
}
if (VlcTest* testp = bestTestp) {
testp->rank(nextrank++);
testp->rankPoints(bestRemain);
remaining.orData(bestTestp->buckets());
} else {
break; // No test covering more stuff found
}
}
}
//######################################################################
void VlcTop::annotateCalc() {
// Calculate per-line information into filedata structure
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
const VlcPoint& point = m_points.pointNumber(it->second);
string filename = point.filename();
int lineno = point.lineno();
if (filename!="" && lineno!=0) {
int column = point.column();
VlcSource& source = sources().findNewSource(filename);
string threshStr = point.thresh();
unsigned thresh = (threshStr!="") ? atoi(threshStr.c_str()) : opt.annotateMin();
bool ok = (point.count() >= thresh);
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
source.incCount(lineno, column, point.count(), ok);
}
}
}
void VlcTop::annotateCalcNeeded() {
// Compute which files are needed. A file isn't needed if it has appropriate
// coverage in all categories
int totCases = 0;
int totOk = 0;
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
VlcSource& source = sit->second;
//UINFO(1,"Source "<<source.name()<<endl);
if (opt.annotateAll()) source.needed(true);
VlcSource::LinenoMap& lines = source.lines();
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
++totCases;
if (col.ok()) {
++totOk;
} else {
source.needed(true);
}
}
}
}
float pct = totCases ? (100*totOk / totCases) : 0;
cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
<<fixed<<setw(3)<<setprecision(2)<<pct<<"%"<<endl;
if (totOk != totCases) cout<<"See lines with '%00' in "<<opt.annotateOut()<<endl;
}
void VlcTop::annotateOutputFiles(const string& dirname) {
// Create if uncreated, ignore errors
mkdir(dirname.c_str(), 0777);
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
VlcSource& source = sit->second;
if (!source.needed()) continue;
string filename = source.name();
string outfilename = dirname+"/"+VlcOptions::filenameNonDir(filename);
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
ifstream is (filename.c_str());
if (!is) {
v3error("Can't read "<<filename);
return;
}
ofstream os (outfilename.c_str());
if (!os) {
v3fatal("Can't write "<<outfilename);
return;
}
os << "\t// verilator_coverage annotation"<<endl;
int lineno = 0;
while (!is.eof()) {
lineno++;
string line;
getline(is, line);
bool first = true;
VlcSource::LinenoMap& lines = source.lines();
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
if (lit != lines.end()) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
os<<(col.ok()?" ":"%")
<<setfill('0')<<setw(6)<<col.count()
<<"\t"<<line<<endl;
if (first) {
first = false;
// Multiple columns on same line; print line just once
string indent = "";
for (const char* cp=line.c_str(); isspace(*cp); ++cp) {
indent += *cp;
}
line = indent + "verilator_coverage: (next point on previous line)\n";
}
}
}
if (first) {
os<<"\t"<<line<<endl;
}
}
}
}
void VlcTop::annotate(const string& dirname) {
// Calculate per-line information into filedata structure
annotateCalc();
annotateCalcNeeded();
annotateOutputFiles(dirname);
}

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