mirror of
https://github.com/verilator/verilator.git
synced 2026-10-05 17:43:31 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a3378e0f5 | ||
|
|
5c3eee34a1 | ||
|
|
2b5017e610 | ||
|
|
e755c7fdcc | ||
|
|
8d463b33cd | ||
|
|
7d9b21a874 | ||
|
|
a118921b21 | ||
|
|
a1aefd2330 | ||
|
|
8b511379ac | ||
|
|
c1593f856d | ||
|
|
93f1d7643d | ||
|
|
ce4dfb4296 | ||
|
|
2e5f5010f7 | ||
|
|
7c588c2e30 | ||
|
|
43be4cf2b5 | ||
|
|
8b457b9b66 | ||
|
|
25efee2e62 | ||
|
|
546c91a940 | ||
|
|
85ebc5f7bd | ||
|
|
e002b0e25f | ||
|
|
4944383769 | ||
|
|
68c6f0ff07 | ||
|
|
5078152292 | ||
|
|
9837b40330 | ||
|
|
cb645c9a74 | ||
|
|
87573a9fef | ||
|
|
7c486e27ba | ||
|
|
4a3bdc340d | ||
|
|
903ee0622d | ||
|
|
d33ad7600b | ||
|
|
9ec35a2348 | ||
|
|
6da13c6486 | ||
|
|
87a47a5ca0 | ||
|
|
c682f1c16a | ||
|
|
591075a8ed | ||
|
|
41701673a0 | ||
|
|
55f0d4ddd8 | ||
|
|
6d66fcaa57 | ||
|
|
26e79ca889 | ||
|
|
62eb247c1e | ||
|
|
c5fd583b2c | ||
|
|
117db3e11c | ||
|
|
3f82fd2f37 | ||
|
|
e9c46afcf7 | ||
|
|
3234fa15ef | ||
|
|
7ef84df852 | ||
|
|
4e2884b509 | ||
|
|
03100020ab | ||
|
|
8bfb5cc5e9 | ||
|
|
cf6d07aafa | ||
|
|
85c3179dbd | ||
|
|
bfbca34eb0 | ||
|
|
b73edc0564 | ||
|
|
6ba90e3a50 | ||
|
|
e8edbad18c | ||
|
|
c86fec5307 | ||
|
|
6e476255ca | ||
|
|
27af9b6b06 | ||
|
|
f8208fa961 | ||
|
|
87b9cb49ad | ||
|
|
b2da0772e6 | ||
|
|
4f73e0850e | ||
|
|
b6a39db627 | ||
|
|
3a83b06572 | ||
|
|
fe5bf01b25 | ||
|
|
5559ec903b | ||
|
|
18750028b2 | ||
|
|
6b88648c67 | ||
|
|
58ee803cb4 | ||
|
|
894ff73c7d | ||
|
|
8031f0ed7f | ||
|
|
3a56b5da47 | ||
|
|
fedcb6d26a | ||
|
|
eed3c5e543 | ||
|
|
e26ab67e25 | ||
|
|
e77b7427b4 | ||
|
|
475e4207cc | ||
|
|
71b2eed32c | ||
|
|
6cf50e6579 | ||
|
|
69468708e2 | ||
|
|
5da5678e64 | ||
|
|
a428e7f618 | ||
|
|
0eb5a0a539 | ||
|
|
a1c1ff9981 | ||
|
|
2029ade18c | ||
|
|
5f8f474c0c | ||
|
|
f705f9b275 | ||
|
|
91e706ec1f | ||
|
|
dcf351f847 | ||
|
|
06744b664a | ||
|
|
d3049d9c89 | ||
|
|
1f2abb9c0f | ||
|
|
9f0d7e50a5 | ||
|
|
5f262a8f11 | ||
|
|
f62bc6a2e5 | ||
|
|
d7e4bc1379 | ||
|
|
cd2d6575c6 |
@@ -23,3 +23,4 @@ gdbrun*
|
||||
internals.txt
|
||||
verilator.txt
|
||||
verilator_bin*
|
||||
verilator_coverage_bin*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -28,6 +28,7 @@ config.status$
|
||||
verilator.log
|
||||
verilator.tex
|
||||
verilator_bin.*
|
||||
verilator_coverage_bin.*
|
||||
.vcsmx_rebuild$
|
||||
autom4te\.cache/
|
||||
nodist/
|
||||
|
||||
+22
-17
@@ -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 \
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
|
||||
Executable
+291
@@ -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
|
||||
|
||||
######################################################################
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
######################################################################
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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, ...);
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief SystemPerl Tracing in VCD Format
|
||||
/// \brief Verilator tracing in VCD Format
|
||||
///
|
||||
/// AUTHOR: Wilson Snyder
|
||||
///
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief SystemPerl tracing in VCD format
|
||||
/// \brief Verilator tracing in VCD format
|
||||
///
|
||||
/// AUTHOR: Wilson Snyder
|
||||
///
|
||||
|
||||
+19
-26
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+41
-6
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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*) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "verilatedos.h"
|
||||
#include <string>
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
||||
+157
-10
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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() { }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
|
||||
class V3ParseImp;
|
||||
class V3InFilter;
|
||||
|
||||
+84
-7
@@ -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
@@ -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*) {
|
||||
|
||||
@@ -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
@@ -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
@@ -23,7 +23,8 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
+7
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user