mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +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 |
@@ -23,3 +23,4 @@ gdbrun*
|
||||
internals.txt
|
||||
verilator.txt
|
||||
verilator_bin*
|
||||
verilator_coverage_bin*
|
||||
|
||||
@@ -3,6 +3,58 @@ 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]
|
||||
|
||||
@@ -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?)
|
||||
|
||||
+61
-81
@@ -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
|
||||
@@ -316,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
|
||||
@@ -452,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
|
||||
|
||||
@@ -572,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
|
||||
|
||||
@@ -590,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>
|
||||
|
||||
@@ -613,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
|
||||
|
||||
@@ -963,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
|
||||
@@ -1285,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
|
||||
@@ -1320,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
|
||||
|
||||
@@ -1359,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
|
||||
@@ -1417,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.
|
||||
@@ -1444,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
|
||||
@@ -1523,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.
|
||||
@@ -2174,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*/
|
||||
|
||||
@@ -2249,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
|
||||
@@ -2336,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
|
||||
|
||||
@@ -2620,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
|
||||
|
||||
@@ -3443,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) {
|
||||
@@ -3469,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
|
||||
@@ -3521,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?)
|
||||
@@ -3828,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"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[3.864 2014-09-21])
|
||||
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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -343,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': {
|
||||
@@ -762,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 = "";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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))
|
||||
|
||||
@@ -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, ...);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
@@ -444,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);
|
||||
@@ -522,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';
|
||||
@@ -530,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';
|
||||
|
||||
@@ -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
|
||||
///
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+1
-21
@@ -131,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,
|
||||
@@ -309,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;
|
||||
@@ -339,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) {
|
||||
|
||||
+8
-36
@@ -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))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+31
-8
@@ -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;
|
||||
@@ -1259,8 +1274,9 @@ public:
|
||||
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; }
|
||||
@@ -1283,8 +1299,9 @@ public:
|
||||
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; }
|
||||
@@ -1564,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; }
|
||||
@@ -1616,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
|
||||
@@ -1672,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;
|
||||
@@ -1879,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()); }
|
||||
@@ -1886,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()); }
|
||||
|
||||
|
||||
+12
-2
@@ -737,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) {
|
||||
@@ -819,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]";
|
||||
@@ -846,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<<")";
|
||||
}
|
||||
|
||||
+198
-91
@@ -49,6 +49,8 @@ public:
|
||||
,m_num(num) {
|
||||
if (m_num.isDouble()) {
|
||||
dtypeSetDouble();
|
||||
} else if (m_num.isString()) {
|
||||
dtypeSetString();
|
||||
} else {
|
||||
dtypeSetLogicSized(m_num.width(), m_num.sized()?0:m_num.widthMin(),
|
||||
m_num.isSigned() ? AstNumeric::SIGNED
|
||||
@@ -74,6 +76,10 @@ public:
|
||||
AstConst(FileLine* fl, RealDouble, double num)
|
||||
:AstNodeMath(fl)
|
||||
,m_num(V3Number(fl,64)) { m_num.setDouble(num); dtypeSetDouble(); }
|
||||
class String {}; // for creator type-overload selection
|
||||
AstConst(FileLine* fl, String, const string& num)
|
||||
:AstNodeMath(fl)
|
||||
,m_num(V3Number(V3Number::String(), fl, num)) { dtypeSetString(); }
|
||||
class LogicFalse {};
|
||||
AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, know the dtype should be a logic of size 1
|
||||
:AstNodeMath(fl)
|
||||
@@ -100,34 +106,6 @@ public:
|
||||
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMin()); }
|
||||
};
|
||||
|
||||
class AstConstString : public AstNodeMath {
|
||||
// A constant string
|
||||
private:
|
||||
string m_name;
|
||||
public:
|
||||
AstConstString(FileLine* fl, const string& name)
|
||||
: AstNodeMath(fl), m_name(name) {
|
||||
rewidth();
|
||||
}
|
||||
void rewidth() {
|
||||
if (m_name.length()==0) {
|
||||
dtypeSetLogicSized(1,1,AstNumeric::UNSIGNED); // 0 width isn't allowed due to historic special cases
|
||||
} else {
|
||||
dtypeSetLogicSized(((int)m_name.length())*8, ((int)m_name.length())*8, AstNumeric::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ConstString, CONSTSTRING)
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(name()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return name()==samep->castConstString()->name(); }
|
||||
virtual int instrCount() const { return 2; } // C just loads a pointer
|
||||
virtual string name() const { return m_name; }
|
||||
void name(const string& flag) { m_name = flag; rewidth(); }
|
||||
};
|
||||
|
||||
class AstRange : public AstNode {
|
||||
// Range specification, for use under variables and cells
|
||||
private:
|
||||
@@ -183,22 +161,30 @@ public:
|
||||
class AstTypedef : public AstNode {
|
||||
private:
|
||||
string m_name;
|
||||
bool m_attrPublic;
|
||||
public:
|
||||
AstTypedef(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
||||
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, AstNodeDType* dtp)
|
||||
: AstNode(fl), m_name(name) {
|
||||
childDTypep(dtp); // Only for parser
|
||||
addAttrsp(attrsp);
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
m_attrPublic = false;
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Typedef, TYPEDEF)
|
||||
virtual void dump(ostream& str);
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
AstNode* attrsp() const { return op4p()->castNode(); } // op4 = Attributes during early parse
|
||||
// METHODS
|
||||
virtual string name() const { return m_name; }
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
virtual bool hasDType() const { return true; }
|
||||
void name(const string& flag) { m_name = flag; }
|
||||
bool attrPublic() const { return m_attrPublic; }
|
||||
void attrPublic(bool flag) { m_attrPublic = flag; }
|
||||
};
|
||||
|
||||
class AstTypedefFwd : public AstNode {
|
||||
@@ -242,6 +228,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 dtypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
|
||||
virtual string name() const { return m_name; }
|
||||
@@ -384,12 +371,14 @@ public:
|
||||
virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (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; // (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,...
|
||||
AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead
|
||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||
bool isDouble() const { return keyword().isDouble(); }
|
||||
bool isOpaque() const { return keyword().isOpaque(); }
|
||||
bool isString() const { return keyword().isString(); }
|
||||
bool isSloppy() const { return keyword().isSloppy(); }
|
||||
bool isZeroInit() const { return keyword().isZeroInit(); }
|
||||
bool isRanged() const { return rangep() || m.m_nrange.ranged(); }
|
||||
@@ -445,6 +434,7 @@ public:
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
|
||||
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
};
|
||||
@@ -474,6 +464,7 @@ public:
|
||||
virtual AstBasicDType* basicp() const { return NULL; }
|
||||
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 1; }
|
||||
virtual int widthTotalBytes() const { return 1; }
|
||||
string cellName() const { return m_cellName; }
|
||||
@@ -528,6 +519,10 @@ public:
|
||||
if (defp()) return defp()->skipRefToConstp();
|
||||
else { v3fatalSrc("Typedef not linked"); return NULL; }
|
||||
}
|
||||
virtual AstNodeDType* skipRefToEnump() const {
|
||||
if (defp()) return defp()->skipRefToEnump();
|
||||
else { v3fatalSrc("Typedef not linked"); return NULL; }
|
||||
}
|
||||
virtual int widthAlignBytes() const { return dtypeSkipRefp()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
|
||||
void name(const string& flag) { m_name = flag; }
|
||||
@@ -599,6 +594,7 @@ public:
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
// METHODS
|
||||
@@ -688,6 +684,7 @@ public:
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
|
||||
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
};
|
||||
@@ -884,6 +881,32 @@ public:
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
};
|
||||
|
||||
class AstMethodSel : public AstNode {
|
||||
// A reference to a member task (or function)
|
||||
// We do not support generic member calls yet, so this is only enough to make built-in methods work
|
||||
private:
|
||||
string m_name; // Name of variable
|
||||
public:
|
||||
AstMethodSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp)
|
||||
: AstNode(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
AstMethodSel(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
|
||||
:AstNode(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(MethodSel, METHODSEL)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* pinsp() const { return op2p()->castNode(); } // op2 = Pin interconnection list
|
||||
void addPinsp(AstNode* nodep) { addOp2p(nodep); }
|
||||
};
|
||||
|
||||
class AstVar : public AstNode {
|
||||
// A variable (in/out/wire/reg/param) inside a module
|
||||
private:
|
||||
@@ -917,6 +940,7 @@ private:
|
||||
bool m_isPulldown:1; // Tri0
|
||||
bool m_isPullup:1; // Tri1
|
||||
bool m_isIfaceParent:1; // dtype is reference to interface present in this module
|
||||
bool m_noSubst:1; // Do not substitute out references
|
||||
bool m_trace:1; // Trace this variable
|
||||
|
||||
void init() {
|
||||
@@ -929,6 +953,7 @@ private:
|
||||
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false;
|
||||
m_isIfaceParent=false;
|
||||
m_noSubst=false;
|
||||
m_trace=false;
|
||||
}
|
||||
public:
|
||||
@@ -1021,7 +1046,9 @@ public:
|
||||
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
|
||||
void funcLocal(bool flag) { m_funcLocal = flag; }
|
||||
void funcReturn(bool flag) { m_funcReturn = flag; }
|
||||
void trace(bool flag) { m_trace=flag; }
|
||||
void noSubst(bool flag) { m_noSubst=flag; }
|
||||
bool noSubst() const { return m_noSubst; }
|
||||
void trace(bool flag) { m_trace=flag; }
|
||||
// METHODS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual string directionName() const { return (isInout() ? "inout" : isInput() ? "input"
|
||||
@@ -1201,11 +1228,13 @@ private:
|
||||
AstScope* m_scopep; // Scope variable is underneath
|
||||
AstVar* m_varp; // [AfterLink] Pointer to variable itself
|
||||
bool m_circular:1; // Used in circular ordering dependency, need change detect
|
||||
bool m_trace:1; // Tracing is turned on for this scope
|
||||
public:
|
||||
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
|
||||
:AstNode(fl)
|
||||
, m_scopep(scopep), m_varp(varp) {
|
||||
m_circular = false;
|
||||
m_trace = true;
|
||||
dtypeFrom(varp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(VarScope, VARSCOPE)
|
||||
@@ -1226,6 +1255,8 @@ public:
|
||||
void valuep(AstNode* valuep) { addOp1p(valuep); }
|
||||
bool isCircular() const { return m_circular; }
|
||||
void circular(bool flag) { m_circular = flag; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
void trace(bool flag) { m_trace = flag; }
|
||||
};
|
||||
|
||||
class AstVarRef : public AstNodeVarRef {
|
||||
@@ -1483,13 +1514,14 @@ private:
|
||||
string m_origName; // Original name before dot addition
|
||||
string m_modName; // Module the cell instances
|
||||
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
|
||||
bool m_hasIfaceVar; // True if a Var has been created for this cell
|
||||
bool m_hasIfaceVar:1; // True if a Var has been created for this cell
|
||||
bool m_trace:1; // Trace this cell
|
||||
public:
|
||||
AstCell(FileLine* fl, const string& instName, const string& modName,
|
||||
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
|
||||
: AstNode(fl)
|
||||
, m_name(instName), m_origName(instName), m_modName(modName)
|
||||
, m_modp(NULL), m_hasIfaceVar(false) {
|
||||
, m_modp(NULL), m_hasIfaceVar(false), m_trace(true) {
|
||||
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
|
||||
ASTNODE_NODE_FUNCS(Cell, CELL)
|
||||
// No cloneRelink, we presume cloneee's want the same module linkages
|
||||
@@ -1512,6 +1544,8 @@ public:
|
||||
void modp(AstNodeModule* nodep) { m_modp = nodep; }
|
||||
bool hasIfaceVar() const { return m_hasIfaceVar; }
|
||||
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
|
||||
void trace(bool flag) { m_trace=flag; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
};
|
||||
|
||||
class AstCellInline : public AstNode {
|
||||
@@ -3496,10 +3530,10 @@ public:
|
||||
};
|
||||
|
||||
class AstCvtPackString : public AstNodeUniop {
|
||||
// Convert to Verilator Packed Pack (aka Pack)
|
||||
// Convert to Verilator Packed String (aka verilog "string")
|
||||
public:
|
||||
AstCvtPackString(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetUInt64(); } // Really, width should be dtypep -> STRING
|
||||
dtypeSetString(); } // Really, width should be dtypep -> STRING
|
||||
ASTNODE_NODE_FUNCS(CvtPackString, CVTPACKSTRING)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
|
||||
virtual string emitVerilog() { return "%f$_CAST(%l)"; }
|
||||
@@ -3769,6 +3803,21 @@ public:
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
class AstEqN : public AstNodeBiCom {
|
||||
public:
|
||||
AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(EqN, EQN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f== %r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return "=="; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstNeq : public AstNodeBiCom {
|
||||
public:
|
||||
AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
|
||||
@@ -3797,6 +3846,21 @@ public:
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
class AstNeqN : public AstNodeBiCom {
|
||||
public:
|
||||
AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(NeqN, NEQN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f!= %r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return "!="; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstLt : public AstNodeBiop {
|
||||
public:
|
||||
AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
@@ -3839,6 +3903,21 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual bool signedFlavor() const { return true; }
|
||||
};
|
||||
class AstLtN : public AstNodeBiop {
|
||||
public:
|
||||
AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(LtN, LTN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f< %r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return "<"; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstGt : public AstNodeBiop {
|
||||
public:
|
||||
AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
@@ -3881,6 +3960,21 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual bool signedFlavor() const { return true; }
|
||||
};
|
||||
class AstGtN : public AstNodeBiop {
|
||||
public:
|
||||
AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(GtN, GTN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f> %r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return ">"; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstGte : public AstNodeBiop {
|
||||
public:
|
||||
AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
@@ -3924,6 +4018,21 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual bool signedFlavor() const { return true; }
|
||||
};
|
||||
class AstGteN : public AstNodeBiop {
|
||||
public:
|
||||
AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(GteN, GTEN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f>= %r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return ">="; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstLte : public AstNodeBiop {
|
||||
public:
|
||||
AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
@@ -3967,6 +4076,21 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual bool signedFlavor() const { return true; }
|
||||
};
|
||||
class AstLteN : public AstNodeBiop {
|
||||
public:
|
||||
AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(LteN, LTEN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f<= %r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return "<="; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstShiftL : public AstNodeBiop {
|
||||
public:
|
||||
AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0)
|
||||
@@ -4327,6 +4451,22 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*2; }
|
||||
};
|
||||
class AstConcatN : public AstNodeBiop {
|
||||
// String concatenate
|
||||
public:
|
||||
AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
dtypeSetString();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ConcatN, CONCATN)
|
||||
virtual string emitVerilog() { return "%f{%l, %k%r}"; }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opConcatN(lhs,rhs); }
|
||||
virtual string emitC() { return "VL_CONCATN_NNN(%li, %ri)"; }
|
||||
virtual bool cleanOut() {return true;}
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstReplicate : public AstNodeBiop {
|
||||
// Also used as a "Uniop" flavor of Concat, e.g. "{a}"
|
||||
// Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp()
|
||||
@@ -4352,6 +4492,25 @@ public:
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*2; }
|
||||
};
|
||||
class AstReplicateN : public AstNodeBiop {
|
||||
// String replicate
|
||||
private:
|
||||
void init() { dtypeSetString(); }
|
||||
public:
|
||||
AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: AstNodeBiop(fl, lhsp, rhsp) { init(); }
|
||||
AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount)
|
||||
: AstNodeBiop(fl, lhsp, new AstConst(fl, repCount)) { init(); }
|
||||
ASTNODE_NODE_FUNCS(ReplicateN, REPLICATEN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opReplN(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%f{%r{%k%l}}"; }
|
||||
virtual string emitC() { return "VL_REPLICATEN_NN%rq(0,0,%rw, %li, %ri)"; }
|
||||
virtual bool cleanOut() {return false;}
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*2; }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstStreamL : public AstNodeStream {
|
||||
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
|
||||
public:
|
||||
@@ -4495,19 +4654,6 @@ public:
|
||||
//======================================================================
|
||||
// PSL
|
||||
|
||||
class AstPslDefClock : public AstNode {
|
||||
// Set default PSL clock
|
||||
// Parents: MODULE
|
||||
// Children: SENITEM
|
||||
public:
|
||||
AstPslDefClock(FileLine* fl, AstNodeSenItem* sensesp)
|
||||
: AstNode(fl) {
|
||||
addNOp1p(sensesp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(PslDefClock, PSLDEFCLOCK)
|
||||
AstNodeSenItem* sensesp() const { return op1p()->castNodeSenItem(); } // op1 = Sensitivity list
|
||||
};
|
||||
|
||||
class AstPslClocked : public AstNode {
|
||||
// A clocked property
|
||||
// Parents: ASSERT|COVER (property)
|
||||
@@ -4526,27 +4672,6 @@ public:
|
||||
AstNode* propp() const { return op3p(); } // op3 = property
|
||||
};
|
||||
|
||||
class AstPslAssert : public AstNodeStmt {
|
||||
// Psl Assertion
|
||||
// Parents: {statement list}
|
||||
// Children: expression, report string
|
||||
private:
|
||||
string m_name; // Name to report
|
||||
public:
|
||||
AstPslAssert(FileLine* fl, AstNode* propp, const string& name="")
|
||||
: AstNodeStmt(fl)
|
||||
, m_name(name) {
|
||||
addOp1p(propp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(PslAssert, PSLASSERT)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual V3Hash sameHash() const { return V3Hash(name()); }
|
||||
virtual bool same(AstNode* samep) const { return samep->name() == name(); }
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
|
||||
};
|
||||
|
||||
class AstPslCover : public AstNodeStmt {
|
||||
// Psl Cover
|
||||
// Parents: {statement list}
|
||||
@@ -4573,29 +4698,6 @@ public:
|
||||
AstNode* stmtsp() const { return op4p(); } // op4 = statements
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// PSL Expressions
|
||||
|
||||
class AstPslBool : public AstNode {
|
||||
// Separates PSL Sere/sequences from the normal expression boolean layer below.
|
||||
// Note this excludes next() and similar functions; they are time domain, so not under AstPslBool.
|
||||
// Parents: Sequences, etc.
|
||||
// Children: math
|
||||
public:
|
||||
AstPslBool(FileLine* fileline, AstNode* exprp)
|
||||
: AstNode(fileline) {
|
||||
addOp1p(exprp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(PslBool, PSLBOOL)
|
||||
AstNode* exprp() const { return op1p()->castNode(); } // op1= expression
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual bool isGateOptimizable() const { return false; } // Not relevant
|
||||
virtual bool isPredictOptimizable() const { return false; } // Not relevant
|
||||
virtual int instrCount() const { return 0; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// Text based nodes
|
||||
|
||||
@@ -4731,6 +4833,7 @@ private:
|
||||
bool m_formCallTree:1; // Make a global function to call entire tree of functions
|
||||
bool m_slow:1; // Slow routine, called once or just at init time
|
||||
bool m_funcPublic:1; // From user public task/function
|
||||
bool m_isInline:1; // Inline function
|
||||
bool m_isStatic:1; // Function is declared static (no this)
|
||||
bool m_symProlog:1; // Setup symbol table for later instructions
|
||||
bool m_entryPoint:1; // User may call into this top level function
|
||||
@@ -4751,6 +4854,7 @@ public:
|
||||
m_formCallTree = false;
|
||||
m_slow = false;
|
||||
m_funcPublic = false;
|
||||
m_isInline = false;
|
||||
m_isStatic = true; // Note defaults to static, later we see where thisp is needed
|
||||
m_symProlog = false;
|
||||
m_entryPoint = false;
|
||||
@@ -4780,6 +4884,7 @@ public:
|
||||
string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); }
|
||||
bool dontCombine() const { return m_dontCombine || funcType()!=AstCFuncType::FT_NORMAL; }
|
||||
void dontCombine(bool flag) { m_dontCombine = flag; }
|
||||
bool dontInline() const { return dontCombine() || slow() || skipDecl() || funcPublic(); }
|
||||
bool skipDecl() const { return m_skipDecl; }
|
||||
void skipDecl(bool flag) { m_skipDecl = flag; }
|
||||
bool declPrivate() const { return m_declPrivate; }
|
||||
@@ -4794,6 +4899,8 @@ public:
|
||||
string argTypes() const { return m_argTypes; }
|
||||
void funcType(AstCFuncType flag) { m_funcType = flag; }
|
||||
AstCFuncType funcType() const { return m_funcType; }
|
||||
bool isInline() const { return m_isInline; }
|
||||
void isInline(bool flag) { m_isInline = flag; }
|
||||
bool isStatic() const { return m_isStatic; }
|
||||
void isStatic(bool flag) { m_isStatic = flag; }
|
||||
bool symProlog() const { return m_symProlog; }
|
||||
|
||||
+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() {}
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
||||
+151
-7
@@ -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)
|
||||
@@ -418,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;
|
||||
@@ -439,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) {
|
||||
@@ -450,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.
|
||||
@@ -531,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);
|
||||
@@ -668,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
|
||||
@@ -792,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
|
||||
@@ -1325,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)) {
|
||||
@@ -1539,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
|
||||
@@ -1910,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)");
|
||||
@@ -2008,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)");
|
||||
@@ -2064,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)");
|
||||
@@ -2076,6 +2219,7 @@ private:
|
||||
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;
|
||||
|
||||
+59
-16
@@ -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());
|
||||
@@ -588,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())));
|
||||
@@ -648,9 +684,6 @@ public:
|
||||
emitConstant(nodep, NULL, "");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConstString* nodep, AstNUser*) {
|
||||
putsQuoted(nodep->name());
|
||||
}
|
||||
|
||||
// Just iterate
|
||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||
@@ -663,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
|
||||
@@ -670,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");
|
||||
@@ -797,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");
|
||||
@@ -1135,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;
|
||||
@@ -1198,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();
|
||||
@@ -1205,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();
|
||||
}
|
||||
@@ -1255,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();
|
||||
@@ -1295,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;
|
||||
@@ -1312,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;
|
||||
}
|
||||
@@ -1351,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
|
||||
@@ -1372,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
|
||||
@@ -1476,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.
|
||||
@@ -1485,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");
|
||||
@@ -1795,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
|
||||
@@ -1845,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");
|
||||
|
||||
+3
-3
@@ -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()) {
|
||||
|
||||
+1
-5
@@ -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*) {
|
||||
|
||||
+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
-278
@@ -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,270 +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;
|
||||
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
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3Error class functions
|
||||
|
||||
@@ -354,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()) {
|
||||
@@ -423,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;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-143
@@ -30,8 +30,6 @@
|
||||
#include <set>
|
||||
#include <deque>
|
||||
|
||||
#include "V3LangCode.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3ErrorCode {
|
||||
@@ -191,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
|
||||
@@ -210,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; }
|
||||
@@ -243,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.
|
||||
@@ -285,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
|
||||
|
||||
+1
-1
@@ -757,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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+130
-1
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1009,7 +1013,6 @@ private:
|
||||
lvertexp->user(true);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1063,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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
+68
-1
@@ -34,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
|
||||
@@ -365,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";
|
||||
}
|
||||
@@ -404,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)) {
|
||||
@@ -418,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;
|
||||
}
|
||||
@@ -473,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;
|
||||
@@ -581,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++;
|
||||
@@ -1626,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());
|
||||
}
|
||||
|
||||
+24
-3
@@ -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; }
|
||||
@@ -115,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);
|
||||
@@ -154,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; }
|
||||
@@ -164,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;}
|
||||
@@ -293,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>
|
||||
|
||||
+34
-24
@@ -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;
|
||||
}
|
||||
|
||||
@@ -668,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+"))));
|
||||
@@ -744,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; }
|
||||
@@ -774,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;
|
||||
@@ -802,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);
|
||||
@@ -822,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"))));
|
||||
@@ -936,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-");
|
||||
@@ -1210,16 +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_preprocNoLine = false;
|
||||
m_psl = 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;
|
||||
@@ -1234,7 +1244,6 @@ V3Options::V3Options() {
|
||||
|
||||
m_convergeLimit = 100;
|
||||
m_dumpTree = 0;
|
||||
m_errorLimit = 50;
|
||||
m_ifDepth = 0;
|
||||
m_inlineMult = 2000;
|
||||
m_outputSplit = 0;
|
||||
@@ -1319,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
|
||||
|
||||
+6
-8
@@ -77,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
|
||||
@@ -101,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
|
||||
@@ -139,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
|
||||
@@ -155,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
|
||||
@@ -200,10 +199,11 @@ class V3Options {
|
||||
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; }
|
||||
@@ -224,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; }
|
||||
@@ -241,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; }
|
||||
@@ -282,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; }
|
||||
|
||||
+1
-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");
|
||||
}
|
||||
|
||||
|
||||
+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() {
|
||||
|
||||
+19
-50
@@ -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
|
||||
|
||||
/**************************************************************/
|
||||
%%
|
||||
@@ -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) {
|
||||
|
||||
+1
-10
@@ -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");
|
||||
@@ -1103,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;
|
||||
@@ -1340,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;
|
||||
@@ -1436,9 +1430,6 @@ string V3PreProcImp::getline() {
|
||||
}
|
||||
gotEof = true;
|
||||
}
|
||||
else if (tok==VP_PSL) {
|
||||
m_lineChars.append(" psl ");
|
||||
}
|
||||
else {
|
||||
m_lineChars.append(buf);
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,6 +26,7 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
@@ -75,7 +76,6 @@ public:
|
||||
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;
|
||||
|
||||
+19
-7
@@ -138,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()
|
||||
@@ -148,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,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;
|
||||
}
|
||||
@@ -180,13 +180,14 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -236,7 +237,7 @@ private:
|
||||
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());
|
||||
createDeepTemp(nodep->rhsp(), false);
|
||||
}
|
||||
}
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
@@ -337,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);
|
||||
}
|
||||
@@ -352,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);
|
||||
@@ -361,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
|
||||
|
||||
+3
-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();
|
||||
|
||||
+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;
|
||||
|
||||
+9
-5
@@ -64,13 +64,17 @@ 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.size()>=1 && prettyName[0] == '_')
|
||||
return "Leading underscore";
|
||||
@@ -163,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);
|
||||
|
||||
+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 {
|
||||
|
||||
+393
-66
@@ -77,6 +77,7 @@
|
||||
#include "V3Width.h"
|
||||
#include "V3Number.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Task.h"
|
||||
|
||||
// More code; this file was getting too large; see actions there
|
||||
@@ -154,6 +155,10 @@ ostream& operator<<(ostream& str, const WidthVP* vup) {
|
||||
|
||||
class WidthVisitor : public AstNVisitor {
|
||||
private:
|
||||
// TYPES
|
||||
typedef map<pair<AstNodeDType*,AstAttrType>, AstVar*> TableMap;
|
||||
typedef map<int,AstPatMember*> PatVecMap;
|
||||
|
||||
// STATE
|
||||
bool m_paramsOnly; // Computing parameter value; limit operation
|
||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||
@@ -162,9 +167,7 @@ private:
|
||||
AstAttrOf* m_attrp; // Current attribute
|
||||
bool m_doGenerate; // Do errors later inside generate statement
|
||||
int m_dtTables; // Number of created data type tables
|
||||
|
||||
// TYPES
|
||||
typedef map<int,AstPatMember*> PatVecMap;
|
||||
TableMap m_tableMap; // Created tables so can remove duplicates
|
||||
|
||||
// ENUMS
|
||||
enum ExtendRule {
|
||||
@@ -189,7 +192,6 @@ private:
|
||||
|
||||
// Widths: 1 bit out, lhs 1 bit; Real: converts via compare with 0
|
||||
virtual void visit(AstLogNot* nodep, AstNUser* vup) { visit_log_not(nodep,vup); }
|
||||
virtual void visit(AstPslBool* nodep, AstNUser* vup) { visit_log_not(nodep,vup); }
|
||||
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0
|
||||
virtual void visit(AstLogAnd* nodep, AstNUser* vup) { visit_log_and_or(nodep,vup); }
|
||||
virtual void visit(AstLogOr* nodep, AstNUser* vup) { visit_log_and_or(nodep,vup); }
|
||||
@@ -230,6 +232,13 @@ private:
|
||||
virtual void visit(AstLteD* nodep, AstNUser* vup) { visit_cmp_real(nodep,vup); }
|
||||
virtual void visit(AstGtD* nodep, AstNUser* vup) { visit_cmp_real(nodep,vup); }
|
||||
virtual void visit(AstGteD* nodep, AstNUser* vup) { visit_cmp_real(nodep,vup); }
|
||||
// ... String compares
|
||||
virtual void visit(AstEqN* nodep, AstNUser* vup) { visit_cmp_string(nodep,vup); }
|
||||
virtual void visit(AstNeqN* nodep, AstNUser* vup) { visit_cmp_string(nodep,vup); }
|
||||
virtual void visit(AstLtN* nodep, AstNUser* vup) { visit_cmp_string(nodep,vup); }
|
||||
virtual void visit(AstLteN* nodep, AstNUser* vup) { visit_cmp_string(nodep,vup); }
|
||||
virtual void visit(AstGtN* nodep, AstNUser* vup) { visit_cmp_string(nodep,vup); }
|
||||
virtual void visit(AstGteN* nodep, AstNUser* vup) { visit_cmp_string(nodep,vup); }
|
||||
|
||||
// Widths: out width = lhs width = rhs width
|
||||
// Signed: Output signed iff LHS & RHS signed.
|
||||
@@ -369,6 +378,29 @@ private:
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (nodep->lhsp()->isString()
|
||||
|| nodep->rhsp()->isString()) {
|
||||
AstNode* newp = new AstConcatN (nodep->fileline(),nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (vup->c()->final()) {
|
||||
if (!nodep->dtypep()->widthSized()) {
|
||||
// See also error in V3Number
|
||||
nodep->v3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in concatenations.");
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConcatN* nodep, AstNUser* vup) {
|
||||
// String concatenate.
|
||||
// Already did AstConcat simplifications
|
||||
if (vup->c()->prelim()) {
|
||||
iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
|
||||
iterateCheckString(nodep,"RHS",nodep->rhsp(),BOTH);
|
||||
nodep->dtypeSetString();
|
||||
}
|
||||
if (vup->c()->final()) {
|
||||
if (!nodep->dtypep()->widthSized()) {
|
||||
@@ -391,9 +423,38 @@ private:
|
||||
if (times==0 && !nodep->backp()->castConcat()) { // Concat Visitor will clean it up.
|
||||
nodep->v3error("Replication value of 0 is only legal under a concatenation."); times=1;
|
||||
}
|
||||
nodep->dtypeSetLogicSized((nodep->lhsp()->width() * times),
|
||||
(nodep->lhsp()->widthMin() * times),
|
||||
AstNumeric::UNSIGNED);
|
||||
if (nodep->lhsp()->isString()) {
|
||||
AstNode* newp = new AstReplicateN(nodep->fileline(),nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
return;
|
||||
} else {
|
||||
nodep->dtypeSetLogicSized((nodep->lhsp()->width() * times),
|
||||
(nodep->lhsp()->widthMin() * times),
|
||||
AstNumeric::UNSIGNED);
|
||||
}
|
||||
}
|
||||
if (vup->c()->final()) {
|
||||
if (!nodep->dtypep()->widthSized()) {
|
||||
// See also error in V3Number
|
||||
nodep->v3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in replications.");
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstReplicateN* nodep, AstNUser* vup) {
|
||||
// Replicate with string
|
||||
if (vup->c()->prelim()) {
|
||||
iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
|
||||
iterateCheckSizedSelf(nodep,"RHS",nodep->rhsp(),SELF,BOTH);
|
||||
V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
|
||||
AstConst* constp = nodep->rhsp()->castConst();
|
||||
if (!constp) { nodep->v3error("Replication value isn't a constant."); return; }
|
||||
uint32_t times = constp->toUInt();
|
||||
if (times==0 && !nodep->backp()->castConcat()) { // Concat Visitor will clean it up.
|
||||
nodep->v3error("Replication value of 0 is only legal under a concatenation."); times=1;
|
||||
}
|
||||
nodep->dtypeSetString();
|
||||
}
|
||||
if (vup->c()->final()) {
|
||||
if (!nodep->dtypep()->widthSized()) {
|
||||
@@ -650,7 +711,9 @@ private:
|
||||
// However a later operation may have changed the node->signed w/o changing
|
||||
// the number's sign. So we don't: nodep->dtypeChgSigned(nodep->num().isSigned());
|
||||
if (vup && vup->c()->prelim()) {
|
||||
if (nodep->num().sized()) {
|
||||
if (nodep->num().isString()) {
|
||||
nodep->dtypeSetString();
|
||||
} else if (nodep->num().sized()) {
|
||||
nodep->dtypeChgWidth(nodep->num().width(), nodep->num().width());
|
||||
} else {
|
||||
nodep->dtypeChgWidth(nodep->num().width(), nodep->num().widthMin());
|
||||
@@ -659,9 +722,6 @@ private:
|
||||
// We don't size the constant until we commit the widths, as need parameters
|
||||
// to remain unsized, and numbers to remain unsized to avoid backp() warnings
|
||||
}
|
||||
virtual void visit(AstConstString* nodep, AstNUser* vup) {
|
||||
nodep->rewidth();
|
||||
}
|
||||
virtual void visit(AstRand* nodep, AstNUser* vup) {
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->dtypeSetSigned32(); // Says the spec
|
||||
@@ -763,45 +823,55 @@ private:
|
||||
m_attrp = nodep;
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(SELF,BOTH).p());
|
||||
// Don't iterate children, don't want to lose VarRef.
|
||||
if (nodep->attrType()==AstAttrType::VAR_BASE) {
|
||||
switch (nodep->attrType()) {
|
||||
case AstAttrType::VAR_BASE:
|
||||
// Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
|
||||
} else if (nodep->attrType()==AstAttrType::MEMBER_BASE) {
|
||||
break;
|
||||
case AstAttrType::MEMBER_BASE:
|
||||
// Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
|
||||
} else if (nodep->attrType()==AstAttrType::DIM_DIMENSIONS
|
||||
|| nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS) {
|
||||
break;
|
||||
case AstAttrType::DIM_DIMENSIONS:
|
||||
case AstAttrType::DIM_UNPK_DIMENSIONS: {
|
||||
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
|
||||
pair<uint32_t,uint32_t> dim = nodep->fromp()->dtypep()->dimensions(true);
|
||||
int val = (nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS
|
||||
? dim.second : (dim.first+dim.second));
|
||||
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); nodep->deleteTree(); nodep=NULL;
|
||||
} else if (nodep->attrType()==AstAttrType::DIM_BITS
|
||||
|| nodep->attrType()==AstAttrType::DIM_HIGH
|
||||
|| nodep->attrType()==AstAttrType::DIM_INCREMENT
|
||||
|| nodep->attrType()==AstAttrType::DIM_LEFT
|
||||
|| nodep->attrType()==AstAttrType::DIM_LOW
|
||||
|| nodep->attrType()==AstAttrType::DIM_RIGHT
|
||||
|| nodep->attrType()==AstAttrType::DIM_SIZE) {
|
||||
break;
|
||||
}
|
||||
case AstAttrType::DIM_BITS:
|
||||
case AstAttrType::DIM_HIGH:
|
||||
case AstAttrType::DIM_INCREMENT:
|
||||
case AstAttrType::DIM_LEFT:
|
||||
case AstAttrType::DIM_LOW:
|
||||
case AstAttrType::DIM_RIGHT:
|
||||
case AstAttrType::DIM_SIZE: {
|
||||
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
|
||||
pair<uint32_t,uint32_t> dim = nodep->fromp()->dtypep()->skipRefp()->dimensions(true);
|
||||
uint32_t maxdim = dim.first+dim.second;
|
||||
if (!nodep->dimp() || nodep->dimp()->castConst() || maxdim<1) {
|
||||
uint32_t msbdim = dim.first+dim.second;
|
||||
if (!nodep->dimp() || nodep->dimp()->castConst() || msbdim<1) {
|
||||
int dim = !nodep->dimp() ? 1 : nodep->dimp()->castConst()->toSInt();
|
||||
int val = dimensionValue(nodep->fromp()->dtypep(), nodep->attrType(), dim);
|
||||
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); nodep->deleteTree(); nodep=NULL;
|
||||
AstConst* newp = dimensionValue(nodep->fromp()->dtypep(), nodep->attrType(), dim);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else { // Need a runtime lookup table. Yuk.
|
||||
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
|
||||
AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType());
|
||||
AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim);
|
||||
AstNode* dimp = nodep->dimp()->unlinkFrBack();
|
||||
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
} else { // Everything else resolved earlier
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Everything else resolved earlier
|
||||
nodep->dtypeSetLogicSized(32,1,AstNumeric::UNSIGNED); // Approximation, unsized 32
|
||||
UINFO(1,"Missing ATTR type case node: "<<nodep<<endl);
|
||||
nodep->v3fatalSrc("Missing ATTR type case");
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_attrp = oldAttr;
|
||||
}
|
||||
@@ -931,7 +1001,7 @@ private:
|
||||
: nodep->findBitDType(width, width, underDtp->numeric()));
|
||||
nodep->dtypep(newDtp);
|
||||
// We ignore warnings as that is sort of the point of a cast
|
||||
iterateCheck(nodep,"Cast LHS",nodep->lhsp(),SELF,FINAL,newDtp,EXTEND_EXP,false);
|
||||
iterateCheck(nodep,"Cast LHS",nodep->lhsp(),CONTEXT,FINAL,newDtp,EXTEND_EXP,false);
|
||||
}
|
||||
if (vup->c()->final()) {
|
||||
// CastSize not needed once sizes determined
|
||||
@@ -1244,21 +1314,29 @@ private:
|
||||
if (debug()>=9) nodep->dumpTree("-ms-in-");
|
||||
nodep->iterateChildren(*this,WidthVP(SELF,BOTH).p());
|
||||
// Find the fromp dtype - should be a class
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp();
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
AstNodeClassDType* fromClassp = fromDtp->castNodeClassDType();
|
||||
AstMemberDType* memberp = NULL; // NULL=error below
|
||||
if (!fromClassp) {
|
||||
nodep->v3error("Member selection of non-struct/union object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
else {
|
||||
// No need to width-resolve the fromClassp, as it was done when we did the child
|
||||
memberp = fromClassp->findMember(nodep->name());
|
||||
if (AstNodeClassDType* adtypep = fromDtp->castNodeClassDType()) {
|
||||
// No need to width-resolve the class, as it was done when we did the child
|
||||
memberp = adtypep->findMember(nodep->name());
|
||||
if (!memberp) {
|
||||
nodep->v3error("Member '"<<nodep->prettyName()<<"' not found in structure");
|
||||
}
|
||||
}
|
||||
else if (fromDtp->castEnumDType()) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
// Convert this into a method call, and let that visitor figure out what to do next
|
||||
AstNode* newp = new AstMethodSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), NULL);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
newp->accept(*this,vup);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Member selection of non-struct/union object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
if (memberp) {
|
||||
if (m_attrp) { // Looking for the base of the attribute
|
||||
nodep->dtypep(memberp);
|
||||
@@ -1280,6 +1358,94 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstMethodSel* nodep, AstNUser* vup) {
|
||||
UINFO(5," METHODSEL "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree("-ms-in-");
|
||||
// Should check types the method requires, but at present we don't do much
|
||||
nodep->fromp()->accept(*this,WidthVP(SELF,BOTH).p());
|
||||
for (AstArg* argp = nodep->pinsp()->castArg(); argp; argp = argp->nextp()->castArg()) {
|
||||
if (argp->exprp()) argp->exprp()->accept(*this,WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
// Find the fromp dtype - should be a class
|
||||
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
if (AstEnumDType* adtypep = fromDtp->castEnumDType()) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
// Convert this into a method call, and let that visitor figure out what to do next
|
||||
if (adtypep) {}
|
||||
if (nodep->name() == "num"
|
||||
|| nodep->name() == "first"
|
||||
|| nodep->name() == "last") {
|
||||
// Constant value
|
||||
AstConst* newp = NULL;
|
||||
if (nodep->pinsp()) nodep->v3error("Arguments passed to enum.num method, but it does not take arguments");
|
||||
if (nodep->name() == "num") {
|
||||
int items = 0;
|
||||
for (AstNode* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()) ++items;
|
||||
newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items);
|
||||
} else if (nodep->name() == "first") {
|
||||
AstEnumItem* itemp = adtypep->itemsp();
|
||||
if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); // Spec doesn't say what to do
|
||||
else newp = itemp->valuep()->cloneTree(false)->castConst(); // A const
|
||||
} else if (nodep->name() == "last") {
|
||||
AstEnumItem* itemp = adtypep->itemsp();
|
||||
while (itemp && itemp->nextp()) itemp = itemp->nextp()->castEnumItem();
|
||||
if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); // Spec doesn't say what to do
|
||||
else newp = itemp->valuep()->cloneTree(false)->castConst(); // A const
|
||||
}
|
||||
if (!newp) nodep->v3fatalSrc("Enum method (perhaps enum item) not const");
|
||||
newp->fileline(nodep->fileline()); // Use method's filename/line number to be clearer; may have warning disables
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else if (nodep->name() == "name"
|
||||
|| nodep->name() == "next"
|
||||
|| nodep->name() == "prev") {
|
||||
AstAttrType attrType;
|
||||
if (nodep->name() == "name") attrType = AstAttrType::ENUM_NAME;
|
||||
else if (nodep->name() == "next") attrType = AstAttrType::ENUM_NEXT;
|
||||
else if (nodep->name() == "prev") attrType = AstAttrType::ENUM_PREV;
|
||||
else nodep->v3fatalSrc("Bad case");
|
||||
|
||||
if (nodep->pinsp() && nodep->name() == "name") {
|
||||
nodep->v3error("Arguments passed to enum.name method, but it does not take arguments");
|
||||
} else if (nodep->pinsp() && !(nodep->pinsp()->castArg()->exprp()->castConst()
|
||||
&& nodep->pinsp()->castArg()->exprp()->castConst()->toUInt()==1
|
||||
&& !nodep->pinsp()->nextp())) {
|
||||
nodep->v3error("Unsupported: Arguments passed to enum.next method");
|
||||
}
|
||||
// Need a runtime lookup table. Yuk.
|
||||
// Ideally we would have a fast algorithm when a number is
|
||||
// of small width and complete and so can use an array, and
|
||||
// a map for when the value is many bits and sparse.
|
||||
uint64_t msbdim = 0;
|
||||
{
|
||||
for (AstEnumItem* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()->castEnumItem()) {
|
||||
AstConst* vconstp = itemp->valuep()->castConst();
|
||||
if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
|
||||
if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad();
|
||||
}
|
||||
if (adtypep->itemsp()->width() > 64 || msbdim >= 1024) {
|
||||
nodep->v3error("Unsupported; enum next/prev method on enum with > 10 bits");
|
||||
return;
|
||||
}
|
||||
}
|
||||
AstVar* varp = enumVarp(adtypep, attrType, msbdim);
|
||||
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, nodep->fromp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
} else {
|
||||
nodep->v3error("Unknown built-in enum method '"<<nodep->fromp()->prettyTypeName()<<"'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Unsupported: Member call on non-enum object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPattern* nodep, AstNUser* vup) {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
UINFO(9,"PATTERN "<<nodep<<endl);
|
||||
@@ -1702,6 +1868,13 @@ private:
|
||||
if (argp) argp=argp->nextp();
|
||||
break;
|
||||
}
|
||||
case 's': { // Convert string to pack string
|
||||
if (argp && argp->dtypep()->basicp()->isString()) { // Convert it
|
||||
ch = '@';
|
||||
}
|
||||
if (argp) argp=argp->nextp();
|
||||
break;
|
||||
}
|
||||
default: { // Most operators, just move to next argument
|
||||
if (argp) argp=argp->nextp();
|
||||
break;
|
||||
@@ -1810,10 +1983,6 @@ private:
|
||||
iterateCheckBool(nodep,"Property",nodep->propp(),BOTH); // it's like an if() condition.
|
||||
nodep->stmtsp()->iterateAndNext(*this);
|
||||
}
|
||||
virtual void visit(AstPslAssert* nodep, AstNUser* vup) {
|
||||
assertAtStatement(nodep,vup);
|
||||
iterateCheckBool(nodep,"Property",nodep->propp(),BOTH); // it's like an if() condition.
|
||||
}
|
||||
virtual void visit(AstVAssert* nodep, AstNUser* vup) {
|
||||
assertAtStatement(nodep,vup);
|
||||
iterateCheckBool(nodep,"Property",nodep->propp(),BOTH); // it's like an if() condition.
|
||||
@@ -2131,8 +2300,7 @@ private:
|
||||
}
|
||||
|
||||
void visit_log_not(AstNode* nodep, AstNUser* vup) {
|
||||
// CALLER: LogNot, PslBool
|
||||
// Note AstPslBool isn't a AstNodeUniop, or we'd only allow that here
|
||||
// CALLER: LogNot
|
||||
// Width-check: lhs 1 bit
|
||||
// Real: Allowed; implicitly compares with zero
|
||||
// We calculate the width of the UNDER expression.
|
||||
@@ -2207,6 +2375,12 @@ private:
|
||||
iterateCheckReal(nodep,"LHS",nodep->lhsp(),FINAL);
|
||||
iterateCheckReal(nodep,"RHS",nodep->rhsp(),FINAL);
|
||||
}
|
||||
} else if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) {
|
||||
if (AstNodeBiop* newp=replaceWithNVersion(nodep)) { nodep=NULL;
|
||||
nodep = newp; // Process new node instead
|
||||
iterateCheckString(nodep,"LHS",nodep->lhsp(),FINAL);
|
||||
iterateCheckString(nodep,"RHS",nodep->rhsp(),FINAL);
|
||||
}
|
||||
} else {
|
||||
bool signedFl = nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned();
|
||||
if (AstNodeBiop* newp=replaceWithUOrSVersion(nodep, signedFl)) { nodep=NULL;
|
||||
@@ -2236,6 +2410,19 @@ private:
|
||||
nodep->dtypeSetLogicBool();
|
||||
}
|
||||
}
|
||||
void visit_cmp_string(AstNodeBiop* nodep, AstNUser* vup) {
|
||||
// CALLER: EqN, LtN
|
||||
// Widths: 1 bit out, lhs width == rhs width
|
||||
// String compare (not output)
|
||||
// Real if and only if real_allow set
|
||||
if (!nodep->rhsp()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
// See similar handling in visit_cmp_eq_gt where created
|
||||
iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
|
||||
iterateCheckString(nodep,"RHS",nodep->rhsp(),BOTH);
|
||||
nodep->dtypeSetLogicBool();
|
||||
}
|
||||
}
|
||||
|
||||
void visit_negate_not(AstNodeUniop* nodep, AstNUser* vup, bool real_ok) {
|
||||
// CALLER: (real_ok=false) Not
|
||||
@@ -2602,6 +2789,15 @@ private:
|
||||
underp = iterateCheck(nodep,side,underp,SELF,FINAL,expDTypep,EXTEND_EXP);
|
||||
}
|
||||
}
|
||||
void iterateCheckString (AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
|
||||
if (stage & PRELIM) {
|
||||
underp = underp->acceptSubtreeReturnEdits(*this,WidthVP(SELF,PRELIM).p());
|
||||
}
|
||||
if (stage & FINAL) {
|
||||
AstNodeDType* expDTypep = nodep->findStringDType();
|
||||
underp = iterateCheck(nodep,side,underp,SELF,FINAL,expDTypep,EXTEND_EXP);
|
||||
}
|
||||
}
|
||||
void iterateCheckSizedSelf (AstNode* nodep, const char* side, AstNode* underp,
|
||||
Determ determ, Stage stage) {
|
||||
// Coerce child to any sized-number data type; child is self-determined i.e. isolated from expected type.
|
||||
@@ -2685,6 +2881,9 @@ private:
|
||||
} else if (!expDTypep->isDouble() && underp->isDouble()) {
|
||||
underp = spliceCvtS(underp, true); // Round RHS
|
||||
underp = underp->acceptSubtreeReturnEdits(*this,WidthVP(SELF,FINAL).p());
|
||||
} else if (expDTypep->isString() && !underp->dtypep()->isString()) {
|
||||
underp = spliceCvtString(underp);
|
||||
underp = underp->acceptSubtreeReturnEdits(*this,WidthVP(SELF,FINAL).p());
|
||||
} else {
|
||||
AstBasicDType* expBasicp = expDTypep->basicp();
|
||||
AstBasicDType* underBasicp = underp->dtypep()->basicp();
|
||||
@@ -2828,6 +3027,20 @@ private:
|
||||
return nodep;
|
||||
}
|
||||
}
|
||||
AstNode* spliceCvtString(AstNode* nodep) {
|
||||
// IEEE-2012 11.8.1: Signed: Type coercion creates signed
|
||||
// 11.8.2: Argument to convert is self-determined
|
||||
if (nodep && !nodep->dtypep()->basicp()->isString()) {
|
||||
UINFO(6," spliceCvtString: "<<nodep<<endl);
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = new AstCvtPackString(nodep->fileline(), nodep);
|
||||
linker.relink(newp);
|
||||
return newp;
|
||||
} else {
|
||||
return nodep;
|
||||
}
|
||||
}
|
||||
AstNodeBiop* replaceWithUOrSVersion(AstNodeBiop* nodep, bool signedFlavorNeeded) {
|
||||
// Given a signed/unsigned node type, create the opposite type
|
||||
// Return new node or NULL if nothing
|
||||
@@ -2910,6 +3123,34 @@ private:
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
return newp;
|
||||
}
|
||||
AstNodeBiop* replaceWithNVersion(AstNodeBiop* nodep) {
|
||||
// Given a signed/unsigned node type, replace with string version
|
||||
// Return new node or NULL if nothing
|
||||
if (nodep->stringFlavor()) {
|
||||
return NULL;
|
||||
}
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* newp = NULL;
|
||||
// No width change on output;... // All below have bool or double outputs
|
||||
switch (nodep->type()) {
|
||||
case AstType::atEQ: case AstType::atEQCASE: newp = new AstEqN (fl,lhsp,rhsp); break;
|
||||
case AstType::atNEQ: case AstType::atNEQCASE: newp = new AstNeqN (fl,lhsp,rhsp); break;
|
||||
case AstType::atGT: case AstType::atGTS: newp = new AstGtN (fl,lhsp,rhsp); break;
|
||||
case AstType::atGTE: case AstType::atGTES: newp = new AstGteN (fl,lhsp,rhsp); break;
|
||||
case AstType::atLT: case AstType::atLTS: newp = new AstLtN (fl,lhsp,rhsp); break;
|
||||
case AstType::atLTE: case AstType::atLTES: newp = new AstLteN (fl,lhsp,rhsp); break;
|
||||
default:
|
||||
nodep->v3fatalSrc("Node needs conversion to string, but bad case: "<<nodep<<endl);
|
||||
break;
|
||||
}
|
||||
UINFO(6," ReplaceWithNVersion: "<<nodep<<" w/ "<<newp<<endl);
|
||||
nodep->replaceWith(newp);
|
||||
// No width change; the default created type (bool or string) is correct
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
return newp;
|
||||
}
|
||||
AstNodeUniop* replaceWithDVersion(AstNodeUniop* nodep) {
|
||||
// Given a signed/unsigned node type, create the opposite type
|
||||
// Return new node or NULL if nothing
|
||||
@@ -2960,7 +3201,7 @@ private:
|
||||
return nodep;
|
||||
}
|
||||
|
||||
int dimensionValue(AstNodeDType* nodep, AstAttrType attrType, int dim) {
|
||||
AstConst* dimensionValue(AstNodeDType* nodep, AstAttrType attrType, int dim) {
|
||||
// Return the dimension value for the specified attribute and constant dimension
|
||||
AstNodeDType* dtypep = nodep->skipRefp();
|
||||
VNumRange declRange; // ranged() set false
|
||||
@@ -2981,8 +3222,10 @@ private:
|
||||
}
|
||||
break;
|
||||
}
|
||||
AstConst* valp = NULL; // If NULL, construct from val
|
||||
int val = 0;
|
||||
if (attrType==AstAttrType::DIM_BITS) {
|
||||
switch (attrType) {
|
||||
case AstAttrType::DIM_BITS: {
|
||||
int bits = 1;
|
||||
while (dtypep) {
|
||||
//UINFO(9, " bits at "<<bits<<" "<<dtypep<<endl);
|
||||
@@ -3006,36 +3249,46 @@ private:
|
||||
} else {
|
||||
val = bits;
|
||||
}
|
||||
} else if (attrType==AstAttrType::DIM_HIGH) {
|
||||
break; }
|
||||
case AstAttrType::DIM_HIGH:
|
||||
val = !declRange.ranged() ? 0 : declRange.hi();
|
||||
} else if (attrType==AstAttrType::DIM_LEFT) {
|
||||
break;
|
||||
case AstAttrType::DIM_LEFT:
|
||||
val = !declRange.ranged() ? 0 : declRange.left();
|
||||
} else if (attrType==AstAttrType::DIM_LOW) {
|
||||
break;
|
||||
case AstAttrType::DIM_LOW:
|
||||
val = !declRange.ranged() ? 0 : declRange.lo();
|
||||
} else if (attrType==AstAttrType::DIM_RIGHT) {
|
||||
break;
|
||||
case AstAttrType::DIM_RIGHT:
|
||||
val = !declRange.ranged() ? 0 : declRange.right();
|
||||
} else if (attrType==AstAttrType::DIM_INCREMENT) {
|
||||
break;
|
||||
case AstAttrType::DIM_INCREMENT:
|
||||
val = (declRange.ranged() && declRange.littleEndian()) ? -1 : 1;
|
||||
} else if (attrType==AstAttrType::DIM_SIZE) {
|
||||
break;
|
||||
case AstAttrType::DIM_SIZE:
|
||||
val = !declRange.ranged() ? 0 : declRange.elements();
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
nodep->v3fatalSrc("Missing DIM ATTR type case");
|
||||
break;
|
||||
}
|
||||
UINFO(9," $dimension "<<attrType.ascii()<<"("<<((void*)dtypep)<<","<<dim<<")="<<val<<endl);
|
||||
return val;
|
||||
if (!valp) valp = new AstConst(nodep->fileline(), AstConst::Signed32(), val);
|
||||
UINFO(9," $dimension "<<attrType.ascii()<<"("<<((void*)dtypep)<<","<<dim<<")="<<valp<<endl);
|
||||
return valp;
|
||||
}
|
||||
AstVar* dimensionVarp(AstNodeDType* nodep, AstAttrType attrType) {
|
||||
AstVar* dimensionVarp(AstNodeDType* nodep, AstAttrType attrType, uint32_t msbdim) {
|
||||
// Return a variable table which has specified dimension properties for this variable
|
||||
pair<uint32_t,uint32_t> dim = nodep->skipRefp()->dimensions(true);
|
||||
uint32_t maxdim = dim.first+dim.second;
|
||||
//
|
||||
TableMap::iterator pos = m_tableMap.find(make_pair(nodep,attrType));
|
||||
if (pos != m_tableMap.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
AstNodeArrayDType* vardtypep = new AstUnpackArrayDType(nodep->fileline(),
|
||||
nodep->findSigned32DType(),
|
||||
new AstRange(nodep->fileline(), maxdim, 0));
|
||||
new AstRange(nodep->fileline(), msbdim, 0));
|
||||
AstInitArray* initp = new AstInitArray (nodep->fileline(), vardtypep, NULL);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__Vdimtable" + cvtToStr(m_dtTables++),
|
||||
"__Vdimtab_" + VString::downcase(attrType.ascii()) + cvtToStr(m_dtTables++),
|
||||
vardtypep);
|
||||
varp->isConst(true);
|
||||
varp->isStatic(true);
|
||||
@@ -3043,13 +3296,87 @@ private:
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
|
||||
// Element 0 is a non-index and has speced values
|
||||
initp->addInitsp(new AstConst(nodep->fileline(), AstConst::Signed32(),
|
||||
dimensionValue(nodep, attrType, 0)));
|
||||
for (unsigned i=1; i<maxdim+1; ++i) {
|
||||
initp->addInitsp(new AstConst(nodep->fileline(), AstConst::Signed32(),
|
||||
dimensionValue(nodep, attrType, i)));
|
||||
initp->addInitsp(dimensionValue(nodep, attrType, 0));
|
||||
for (unsigned i=1; i<msbdim+1; ++i) {
|
||||
initp->addInitsp(dimensionValue(nodep, attrType, i));
|
||||
}
|
||||
varp->iterate(*this); // May have already done $unit so must do this var
|
||||
m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
|
||||
return varp;
|
||||
}
|
||||
AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t msbdim) {
|
||||
// Return a variable table which has specified dimension properties for this variable
|
||||
TableMap::iterator pos = m_tableMap.find(make_pair(nodep,attrType));
|
||||
if (pos != m_tableMap.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
UINFO(9, "Construct Venumtab attr="<<attrType.ascii()<<" max="<<msbdim<<" for "<<nodep<<endl);
|
||||
AstNodeDType* basep;
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
basep = nodep->findStringDType();
|
||||
} else {
|
||||
basep = nodep->findSigned32DType();
|
||||
}
|
||||
AstNodeArrayDType* vardtypep = new AstUnpackArrayDType(nodep->fileline(),
|
||||
basep,
|
||||
new AstRange(nodep->fileline(), msbdim, 0));
|
||||
AstInitArray* initp = new AstInitArray (nodep->fileline(), vardtypep, NULL);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__Venumtab_" + VString::downcase(attrType.ascii()) + cvtToStr(m_dtTables++),
|
||||
vardtypep);
|
||||
varp->isConst(true);
|
||||
varp->isStatic(true);
|
||||
varp->valuep(initp);
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
|
||||
|
||||
// Find valid values and populate
|
||||
if (!nodep->itemsp()) nodep->v3fatalSrc("enum without items");
|
||||
vector<AstNode*> values;
|
||||
values.reserve(msbdim+1);
|
||||
for (unsigned i=0; i<(msbdim+1); ++i) {
|
||||
values[i] = NULL;
|
||||
}
|
||||
{
|
||||
AstEnumItem* firstp = nodep->itemsp();
|
||||
AstEnumItem* prevp = firstp; // Prev must start with last item
|
||||
while (prevp->nextp()) prevp = prevp->nextp()->castEnumItem();
|
||||
for (AstEnumItem* itemp = firstp; itemp;) {
|
||||
AstEnumItem* nextp = itemp->nextp()->castEnumItem();
|
||||
AstConst* vconstp = itemp->valuep()->castConst();
|
||||
if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
|
||||
uint32_t i = vconstp->toUInt();
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
values[i] = new AstConst(nodep->fileline(), AstConst::String(), itemp->name());
|
||||
} else if (attrType == AstAttrType::ENUM_NEXT) {
|
||||
values[i] = (nextp ? nextp : firstp)->valuep()->cloneTree(false); // A const
|
||||
} else if (attrType == AstAttrType::ENUM_PREV) {
|
||||
values[i] = prevp->valuep()->cloneTree(false); // A const
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
prevp = itemp;
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
// Fill in all unspecified values and add to table
|
||||
for (unsigned i=0; i<(msbdim+1); ++i) {
|
||||
AstNode* valp = values[i];
|
||||
if (!valp) {
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
valp = new AstConst(nodep->fileline(), AstConst::String(), "");
|
||||
} else if (attrType == AstAttrType::ENUM_NEXT
|
||||
|| attrType == AstAttrType::ENUM_PREV) {
|
||||
valp = new AstConst(nodep->fileline(), V3Number(nodep->fileline(), nodep->width(), 0));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
}
|
||||
initp->addInitsp(valp);
|
||||
}
|
||||
varp->iterate(*this); // May have already done $unit so must do this var
|
||||
m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
|
||||
return varp;
|
||||
}
|
||||
|
||||
|
||||
+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());
|
||||
|
||||
+1
-1
@@ -630,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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: verilator_coverage: Top global 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 _VLCTOP_H_
|
||||
#define _VLCTOP_H_ 1
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "VlcOptions.h"
|
||||
#include "VlcTest.h"
|
||||
#include "VlcPoint.h"
|
||||
#include "VlcSource.h"
|
||||
|
||||
//######################################################################
|
||||
// VlcTop - Top level options container
|
||||
|
||||
class VlcTop {
|
||||
public:
|
||||
// PUBLIC MEMBERS
|
||||
VlcOptions opt; //< Runtime options
|
||||
private:
|
||||
// MEMBERS
|
||||
VlcTests m_tests; //< List of all tests (all coverage files)
|
||||
VlcPoints m_points; //< List of all points
|
||||
VlcSources m_sources; //< List of all source files to annotate
|
||||
|
||||
// METHODS
|
||||
void annotateCalc();
|
||||
void annotateCalcNeeded();
|
||||
void annotateOutputFiles(const string& dirname);
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcTop() {}
|
||||
~VlcTop() {}
|
||||
|
||||
// ACCESSORS
|
||||
VlcTests& tests() { return m_tests; }
|
||||
VlcPoints& points() { return m_points; }
|
||||
VlcSources& sources() { return m_sources; }
|
||||
|
||||
// METHODS
|
||||
void annotate(const string& dirname);
|
||||
void readCoverage(const string& filename, bool nonfatal=false);
|
||||
void writeCoverage(const string& filename);
|
||||
|
||||
void rank();
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // guard
|
||||
+2
-6
@@ -19,8 +19,8 @@ my @Opt_Cpt;
|
||||
my @Opt_I;
|
||||
Getopt::Long::config ("pass_through", "no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"help" => \&report,
|
||||
"debug" => \&debug,
|
||||
"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"classes!" => \$opt_classes,
|
||||
"report!" => \$opt_report,
|
||||
"<>" => \¶meter,
|
||||
@@ -54,10 +54,6 @@ sub usage {
|
||||
exit (1);
|
||||
}
|
||||
|
||||
sub debug {
|
||||
$Debug = 1;
|
||||
}
|
||||
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if ($param =~ /^-+I(\S+)/) {
|
||||
|
||||
+28
-144
@@ -103,8 +103,6 @@ void V3ParseImp::verilatorCmtBad(const char* textp) {
|
||||
}
|
||||
|
||||
// See V3Read.cpp
|
||||
//void V3ParseImp::stateExitPsl() { BEGIN VLG; }
|
||||
//void V3ParseImp::statePushVlg() { yy_push_state(VLG); }
|
||||
//void V3ParseImp::statePop() { yy_pop_state(); }
|
||||
|
||||
//======================================================================
|
||||
@@ -138,7 +136,7 @@ void yyerrorf(const char* format, ...) {
|
||||
|
||||
%s V95 V01 V05 S05 S09 S12
|
||||
%s STRING ATTRMODE TABLE
|
||||
%s VA5 SAX PSL VLT
|
||||
%s VA5 SAX VLT
|
||||
%s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
|
||||
%s IGNORE
|
||||
|
||||
@@ -179,7 +177,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
|
||||
/************************************************************************/
|
||||
/* Verilog 1995 */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
{ws} { } /* otherwise ignore white-space */
|
||||
{crnl} { NEXTLINE(); } /* Count line numbers */
|
||||
/* Extensions to Verilog set, some specified by PSL */
|
||||
@@ -352,7 +350,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
}
|
||||
|
||||
/* Verilog 2001 */
|
||||
<V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
<V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
/* System Tasks */
|
||||
"$signed" { FL; return yD_SIGNED; }
|
||||
"$unsigned" { FL; return yD_UNSIGNED; }
|
||||
@@ -383,13 +381,13 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
}
|
||||
|
||||
/* Verilog 2005 */
|
||||
<V05,S05,S09,S12,SAX,PSL>{
|
||||
<V05,S05,S09,S12,SAX>{
|
||||
/* Keywords */
|
||||
"uwire" { FL; return yWIRE; }
|
||||
}
|
||||
|
||||
/* System Verilog 2005 */
|
||||
<S05,S09,S12,SAX,PSL>{
|
||||
<S05,S09,S12,SAX>{
|
||||
/* System Tasks */
|
||||
"$bits" { FL; return yD_BITS; }
|
||||
"$clog2" { FL; return yD_CLOG2; }
|
||||
@@ -414,18 +412,21 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"always_comb" { FL; return yALWAYS_COMB; }
|
||||
"always_ff" { FL; return yALWAYS_FF; }
|
||||
"always_latch" { FL; return yALWAYS_LATCH; }
|
||||
"assert" { FL; return yASSERT; }
|
||||
"bind" { FL; return yBIND; }
|
||||
"bit" { FL; return yBIT; }
|
||||
"break" { FL; return yBREAK; }
|
||||
"byte" { FL; return yBYTE; }
|
||||
"chandle" { FL; return yCHANDLE; }
|
||||
"clocking" { FL; return yCLOCKING; }
|
||||
"const" { FL; return yCONST__LEX; }
|
||||
"context" { FL; return yCONTEXT; }
|
||||
"continue" { FL; return yCONTINUE; }
|
||||
"cover" { FL; return yCOVER; }
|
||||
"do" { FL; return yDO; }
|
||||
"endclocking" { FL; return yENDCLOCKING; }
|
||||
"endpackage" { FL; return yENDPACKAGE; }
|
||||
"endinterface" { FL; return yENDINTERFACE; }
|
||||
"endpackage" { FL; return yENDPACKAGE; }
|
||||
"endprogram" { FL; return yENDPROGRAM; }
|
||||
"endproperty" { FL; return yENDPROPERTY; }
|
||||
"enum" { FL; return yENUM; }
|
||||
@@ -434,8 +435,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"iff" { FL; return yIFF; }
|
||||
"import" { FL; return yIMPORT; }
|
||||
"inside" { FL; return yINSIDE; }
|
||||
"interface" { FL; return yINTERFACE; }
|
||||
"int" { FL; return yINT; }
|
||||
"interface" { FL; return yINTERFACE; }
|
||||
"logic" { FL; return yLOGIC; }
|
||||
"longint" { FL; return yLONGINT; }
|
||||
"modport" { FL; return yMODPORT; }
|
||||
@@ -443,6 +444,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"packed" { FL; return yPACKED; }
|
||||
"priority" { FL; return yPRIORITY; }
|
||||
"program" { FL; return yPROGRAM; }
|
||||
"property" { FL; return yPROPERTY; }
|
||||
"pure" { FL; return yPURE; }
|
||||
"rand" { FL; return yRAND; }
|
||||
"randc" { FL; return yRANDC; }
|
||||
@@ -454,6 +456,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"timeprecision" { FL; return yTIMEPRECISION; }
|
||||
"timeunit" { FL; return yTIMEUNIT; }
|
||||
"typedef" { FL; return yTYPEDEF; }
|
||||
"union" { FL; return yUNION; }
|
||||
"unique" { FL; return yUNIQUE; }
|
||||
"var" { FL; return yVAR; }
|
||||
"void" { FL; return yVOID; }
|
||||
@@ -461,6 +464,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
/* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
|
||||
"$root" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"alias" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"assume" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"before" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
@@ -492,6 +497,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"randomize" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"sequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"super" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
@@ -503,25 +509,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"wait_order" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"wildcard" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"with" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
}
|
||||
|
||||
/* SystemVerilog 2005 ONLY not PSL; different rules for PSL as specified below */
|
||||
<S05,S09,S12,SAX>{
|
||||
/* Keywords */
|
||||
"assert" { FL; return yASSERT; }
|
||||
"const" { FL; return yCONST__LEX; }
|
||||
"cover" { FL; return yCOVER; }
|
||||
"property" { FL; return yPROPERTY; }
|
||||
"union" { FL; return yUNION; }
|
||||
/* Generic unsupported warnings */
|
||||
"assume" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"before" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"sequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"within" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"within" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
}
|
||||
|
||||
/* SystemVerilog 2009 */
|
||||
<S09,S12,SAX,PSL>{
|
||||
<S09,S12,SAX>{
|
||||
/* Keywords */
|
||||
"global" { FL; return yGLOBAL__LEX; }
|
||||
"unique0" { FL; return yUNIQUE0; }
|
||||
@@ -550,7 +542,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
}
|
||||
|
||||
/* System Verilog 2012 */
|
||||
<S12,SAX,PSL>{
|
||||
<S12,SAX>{
|
||||
/* Keywords */
|
||||
"implements" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
|
||||
"interconnect" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
|
||||
@@ -559,7 +551,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
}
|
||||
|
||||
/* Default PLI rule */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { string str (yytext,yyleng);
|
||||
yylval.strp = PARSEP->newString(AstNode::encodeName(str));
|
||||
// Lookup unencoded name including the $, to avoid hitting normal signals
|
||||
@@ -662,100 +654,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"zi_zp" { yyerrorf("Unsupported: AMS reserved word not implemented: %s",yytext); }
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* PSL */
|
||||
|
||||
/*Entry into PSL; mode change */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"psl" { yy_push_state(PSL); FL; return yPSL; }
|
||||
}
|
||||
|
||||
<PSL>{
|
||||
/* Special things */
|
||||
"psl" { ; } // 'psl' may occur in middle of statement, so easier just to suppress
|
||||
/* Keywords */
|
||||
"assert" { FL; return yPSL_ASSERT; }
|
||||
"assume" { FL; return yPSL_ASSERT; } //==assert
|
||||
"before_!" { yyerrorf("Illegal syntax, use before!_ instead of %s",yytext); }
|
||||
"clock" { FL; return yPSL_CLOCK; }
|
||||
"countones" { FL; return yD_COUNTONES; }
|
||||
"cover" { FL; return yPSL_COVER; }
|
||||
"isunknown" { FL; return yD_ISUNKNOWN; }
|
||||
"onehot" { FL; return yD_ONEHOT; }
|
||||
"onehot0" { FL; return yD_ONEHOT0; }
|
||||
"until_!" { yyerrorf("Illegal syntax, use until!_ instead of %s",yytext); }
|
||||
"report" { FL; return yPSL_REPORT; }
|
||||
"true" { FL; return yTRUE; }
|
||||
/* Generic unsupported warnings */
|
||||
/*"A" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"AF" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"AG" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"AX" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"E" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"EF" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"EG" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"EX" { yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
|
||||
/*"F" { FL; return yEVENTUALLYB; } */
|
||||
/*"G" { FL; return yALWAYS; } */
|
||||
/*"U" { FL; return yUNTILB; } */
|
||||
/*"W" { FL; return yUNTIL; } */
|
||||
/*"X" { FL; return yNEXT; } */
|
||||
/*"X!" { FL; return yNEXTB; } */
|
||||
/*"restrict" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } S09 instead */
|
||||
/*"strong" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } S09 instead */
|
||||
/*"until" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } S09 instead */
|
||||
"%for" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"%if" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"abort" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"assume_guarantee" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"before" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"before!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"before!_" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"before_" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"boolean" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"const" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"endpoint" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"eventually!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"fairness" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"fell" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"forall" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"in" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"inf" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"inherit" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"never" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_a" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_a!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_e" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_e!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_event" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_event!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_event_a" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_event_a!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_event_e" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"next_event_e!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"prev" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"property" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"restrict_guarantee" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"rose" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"sequence" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"stable" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"union" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"until!" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"until!_" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"until_" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"vmode" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"vprop" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
|
||||
"vunit" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
"within" { yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* Meta comments */
|
||||
|
||||
/* Converted from //{cmt}verilator ...{cmt} by preprocessor */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"/*verilator"{ws}*"*/" {} /* Ignore empty comments, may be `endif // verilator */
|
||||
"/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; }
|
||||
"/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; }
|
||||
@@ -793,8 +696,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"{" { FL; return yytext[0]; }
|
||||
"}" { FL; return yytext[0]; }
|
||||
}
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
"!" { FL; return yytext[0]; }
|
||||
"#" { FL; return yytext[0]; }
|
||||
"$" { FL; return yytext[0]; }
|
||||
@@ -826,7 +727,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
/* Operators and multi-character symbols */
|
||||
|
||||
/* Verilog 1995 Operators */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"&&" { FL; return yP_ANDAND; }
|
||||
"||" { FL; return yP_OROR; }
|
||||
"<=" { FL; return yP_LTE; }
|
||||
@@ -848,7 +749,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
}
|
||||
|
||||
/* Verilog 2001 Operators */
|
||||
<V01,V05,VA5,S05,S09,S12,SAX,PSL>{
|
||||
<V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"<<<" { FL; return yP_SLEFT; }
|
||||
">>>" { FL; return yP_SSRIGHT; }
|
||||
"**" { FL; return yP_POW; }
|
||||
@@ -891,23 +792,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"["{ws}*"->" { FL; return yP_BRAMINUSGT; }
|
||||
}
|
||||
|
||||
/* PSL Operators */
|
||||
<PSL>{
|
||||
"{" { FL; return yPSL_BRA; } // Avoid parser hitting concatenate.
|
||||
"}" { FL; return yPSL_KET; } // Avoid parser hitting concatenate.
|
||||
"<->" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } //Unsup in other tools
|
||||
"[*" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_STAR
|
||||
"[*]" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_STAR_KET
|
||||
"[+]" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_PLUS_KET
|
||||
"[->" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_MINUS_GT
|
||||
"[->]" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_MINUS_GT_KET
|
||||
"[=" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_EQ
|
||||
"|->" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_ORMINUSGT
|
||||
"|=>" { yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_OREQGT
|
||||
}
|
||||
|
||||
/* Identifiers and numbers */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,VLT>{
|
||||
{escid} { FL; yylval.strp = PARSEP->newString
|
||||
(AstNode::encodeName(string(yytext+1))); // +1 to skip the backslash
|
||||
return yaID__LEX;
|
||||
@@ -997,7 +883,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
/* Preprocessor */
|
||||
/* Common for all SYSC header states */
|
||||
/* OPTIMIZE: we return one per line, make it one for the entire block */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
|
||||
"`accelerate" { } // Verilog-XL compatibility
|
||||
"`autoexpand_vectornets" { } // Verilog-XL compatibility
|
||||
"`celldefine" { PARSEP->inCellDefine(true); }
|
||||
@@ -1026,7 +912,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"`portcoerce" { }
|
||||
"`pragma"{ws}+[^\n\r]* { } // Verilog 2005
|
||||
"`protect" { }
|
||||
"`psl" { if (PARSEP->optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
|
||||
"`remove_gatenames" { } // Verilog-XL compatibility
|
||||
"`remove_netnames" { } // Verilog-XL compatibility
|
||||
"`resetall" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,true); } // Rest handled by preproc
|
||||
@@ -1073,7 +958,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
/************************************************************************/
|
||||
/* Default rules - leave last */
|
||||
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT>{
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX,VLT>{
|
||||
"`"[a-zA-Z_0-9]+ { FL; yyerrorf("Define or directive not defined: %s",yytext); }
|
||||
"//"[^\n]* { } /* throw away single line comments */
|
||||
. { FL; return yytext[0]; } /* return single char ops. */
|
||||
@@ -1087,15 +972,14 @@ int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; }
|
||||
double V3ParseImp::parseDouble(const char* textp, size_t length) {
|
||||
char* strgp = new char[length+1];
|
||||
char* dp=strgp;
|
||||
for (const char* sp=textp; sp<(textp+length);) {
|
||||
if (*sp != '_') *dp++ = *sp++;
|
||||
else sp++;
|
||||
for (const char* sp=textp; sp<(textp+length); ++sp) {
|
||||
if (*sp != '_') *dp++ = *sp;
|
||||
}
|
||||
*dp++ = '\0';
|
||||
char* endp = strgp;
|
||||
double d = strtod(strgp, &endp);
|
||||
size_t parsed_len = endp-strgp;
|
||||
if (parsed_len != length) { yyerrorf("Syntax error parsing real: %s",strgp); }
|
||||
if (parsed_len != strlen(strgp)) { yyerrorf("Syntax error parsing real: %s",strgp); }
|
||||
delete strgp;
|
||||
return d;
|
||||
}
|
||||
|
||||
+46
-97
@@ -62,6 +62,7 @@ public:
|
||||
int m_pinNum; // Pin number currently parsing
|
||||
string m_instModule; // Name of module referenced for instantiations
|
||||
AstPin* m_instParamp; // Parameters for instantiations
|
||||
bool m_tracingParse; // Tracing disable for parser
|
||||
|
||||
static int s_modTypeImpNum; // Implicit type number, incremented each module
|
||||
|
||||
@@ -78,6 +79,7 @@ public:
|
||||
m_instParamp = NULL;
|
||||
m_varAttrp = NULL;
|
||||
m_caseAttrp = NULL;
|
||||
m_tracingParse = true;
|
||||
}
|
||||
static V3ParseGrammar* singletonp() {
|
||||
static V3ParseGrammar singleton;
|
||||
@@ -86,6 +88,9 @@ public:
|
||||
|
||||
// METHODS
|
||||
void argWrapList(AstNodeFTaskRef* nodep);
|
||||
bool allTracingOn(FileLine* fl) {
|
||||
return v3Global.opt.trace() && m_tracingParse && fl->tracingOn();
|
||||
}
|
||||
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
|
||||
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
|
||||
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
||||
@@ -483,12 +488,6 @@ class AstSenTree;
|
||||
%token<fl> yD_WARNING "$warning"
|
||||
%token<fl> yD_WRITE "$write"
|
||||
|
||||
%token<fl> yPSL "psl"
|
||||
%token<fl> yPSL_ASSERT "PSL assert"
|
||||
%token<fl> yPSL_CLOCK "PSL clock"
|
||||
%token<fl> yPSL_COVER "PSL cover"
|
||||
%token<fl> yPSL_REPORT "PSL report"
|
||||
|
||||
%token<fl> yVL_CLOCK "/*verilator sc_clock*/"
|
||||
%token<fl> yVL_CLOCK_ENABLE "/*verilator clock_enable*/"
|
||||
%token<fl> yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/"
|
||||
@@ -561,8 +560,6 @@ class AstSenTree;
|
||||
%token<fl> yP_SRIGHTEQ ">>="
|
||||
%token<fl> yP_SSRIGHTEQ ">>>="
|
||||
|
||||
%token<fl> yPSL_BRA "{"
|
||||
%token<fl> yPSL_KET "}"
|
||||
%token<fl> yP_LOGIFF
|
||||
|
||||
// [* is not a operator, as "[ * ]" is legal
|
||||
@@ -573,7 +570,6 @@ class AstSenTree;
|
||||
// PSL op precedence
|
||||
%right yP_MINUSGT yP_LOGIFF
|
||||
%right yP_ORMINUSGT yP_OREQGT
|
||||
%left<fl> prPSLCLK
|
||||
|
||||
// Verilog op precedence
|
||||
%right '?' ':'
|
||||
@@ -632,20 +628,6 @@ class AstSenTree;
|
||||
%start source_text
|
||||
|
||||
%%
|
||||
//**********************************************************************
|
||||
// Feedback to the Lexer
|
||||
// Note we read a parenthesis ahead, so this may not change the lexer at the right point.
|
||||
|
||||
stateExitPsl: // For PSL lexing, return from PSL state
|
||||
/* empty */ { PARSEP->stateExitPsl(); }
|
||||
;
|
||||
statePushVlg: // For PSL lexing, escape current state into Verilog state
|
||||
/* empty */ { PARSEP->statePushVlg(); }
|
||||
;
|
||||
statePop: // Return to previous lexing state
|
||||
/* empty */ { PARSEP->statePop(); }
|
||||
;
|
||||
|
||||
//**********************************************************************
|
||||
// Files
|
||||
|
||||
@@ -685,7 +667,7 @@ timeunits_declaration<nodep>: // ==IEEE: timeunits_declaration
|
||||
|
||||
package_declaration: // ==IEEE: package_declaration
|
||||
packageFront package_itemListE yENDPACKAGE endLabelE
|
||||
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
|
||||
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
|
||||
if ($2) $1->addStmtp($2);
|
||||
SYMP->popScope($1);
|
||||
GRAMMARP->endLabel($<fl>4,$1,$4); }
|
||||
@@ -695,7 +677,7 @@ packageFront<modulep>:
|
||||
yPACKAGE idAny ';'
|
||||
{ $$ = new AstPackage($1,*$2);
|
||||
$$->inLibrary(true); // packages are always libraries; don't want to make them a "top"
|
||||
$$->modTrace(v3Global.opt.trace());
|
||||
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
|
||||
PARSEP->rootp()->addModulep($$);
|
||||
SYMP->pushNew($$); }
|
||||
;
|
||||
@@ -768,7 +750,7 @@ module_declaration: // ==IEEE: module_declaration
|
||||
// // IEEE: module_nonansi_header + module_ansi_header
|
||||
modFront importsAndParametersE portsStarE ';'
|
||||
module_itemListE yENDMODULE endLabelE
|
||||
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
|
||||
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
|
||||
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
|
||||
if ($5) $1->addStmtp($5);
|
||||
SYMP->popScope($1);
|
||||
@@ -778,6 +760,7 @@ module_declaration: // ==IEEE: module_declaration
|
||||
{ $1->modTrace(false); // Stash for implicit wires, etc
|
||||
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
|
||||
if ($5) $1->addStmtp($5);
|
||||
GRAMMARP->m_tracingParse = true;
|
||||
SYMP->popScope($1);
|
||||
GRAMMARP->endLabel($<fl>7,$1,$7); }
|
||||
//
|
||||
@@ -790,7 +773,7 @@ modFront<modulep>:
|
||||
// // any formal arguments, as the arguments must land in the new scope.
|
||||
yMODULE lifetimeE idAny
|
||||
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
|
||||
$$->modTrace(v3Global.opt.trace());
|
||||
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
|
||||
PARSEP->rootp()->addModulep($$);
|
||||
SYMP->pushNew($$); }
|
||||
;
|
||||
@@ -806,7 +789,7 @@ udpFront<modulep>:
|
||||
{ $$ = new AstPrimitive($1,*$3); $$->inLibrary(true);
|
||||
$$->modTrace(false);
|
||||
$$->addStmtp(new AstPragma($1,AstPragmaType::INLINE_MODULE));
|
||||
PARSEP->fileline()->tracingOn(false);
|
||||
GRAMMARP->m_tracingParse = false;
|
||||
PARSEP->rootp()->addModulep($$);
|
||||
SYMP->pushNew($$); }
|
||||
;
|
||||
@@ -988,7 +971,8 @@ interface_itemList<nodep>:
|
||||
interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
|
||||
port_declaration ';' { $$ = $1; }
|
||||
// // IEEE: non_port_interface_item
|
||||
//UNSUP generate_region { $$ = $1; }
|
||||
// // IEEE: generate_region
|
||||
| interface_generate_region { $$ = $1; }
|
||||
| interface_or_generate_item { $$ = $1; }
|
||||
//UNSUP program_declaration { $$ = $1; }
|
||||
//UNSUP interface_declaration { $$ = $1; }
|
||||
@@ -997,6 +981,11 @@ interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
|
||||
| module_common_item { $$ = $1; }
|
||||
;
|
||||
|
||||
interface_generate_region<nodep>: // ==IEEE: generate_region
|
||||
yGENERATE interface_itemList yENDGENERATE { $$ = new AstGenerate($1, $2); }
|
||||
| yGENERATE yENDGENERATE { $$ = NULL; }
|
||||
;
|
||||
|
||||
interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item
|
||||
// // module_common_item in interface_item, as otherwise duplicated
|
||||
// // with module_or_generate_item's module_common_item
|
||||
@@ -1011,7 +1000,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr
|
||||
// // timeunits_delcarationE is instead in program_item
|
||||
pgmFront parameter_port_listE portsStarE ';'
|
||||
program_itemListE yENDPROGRAM endLabelE
|
||||
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
|
||||
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
|
||||
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
|
||||
if ($5) $1->addStmtp($5);
|
||||
SYMP->popScope($1);
|
||||
@@ -1023,7 +1012,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr
|
||||
pgmFront<modulep>:
|
||||
yPROGRAM lifetimeE idAny/*new_program*/
|
||||
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
|
||||
$$->modTrace(v3Global.opt.trace());
|
||||
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
|
||||
PARSEP->rootp()->addModulep($$);
|
||||
SYMP->pushNew($$); }
|
||||
;
|
||||
@@ -1594,8 +1583,9 @@ implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
|
||||
|
||||
type_declaration<nodep>: // ==IEEE: type_declaration
|
||||
// // Use idAny, as we can redeclare a typedef on an existing typedef
|
||||
yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
|
||||
SYMP->reinsert($$); }
|
||||
yTYPEDEF data_type idAny variable_dimensionListE dtypeAttrListE ';'
|
||||
/**/ { $$ = new AstTypedef($<fl>1, *$3, $5, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
|
||||
SYMP->reinsert($$); }
|
||||
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
|
||||
// // Combines into above "data_type id" rule
|
||||
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
|
||||
@@ -1606,6 +1596,20 @@ type_declaration<nodep>: // ==IEEE: type_declaration
|
||||
//UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
;
|
||||
|
||||
dtypeAttrListE<nodep>:
|
||||
/* empty */ { $$ = NULL; }
|
||||
| dtypeAttrList { $$ = $1; }
|
||||
;
|
||||
|
||||
dtypeAttrList<nodep>:
|
||||
dtypeAttr { $$ = $1; }
|
||||
| dtypeAttrList dtypeAttr { $$ = $1->addNextNull($2); }
|
||||
;
|
||||
|
||||
dtypeAttr<nodep>:
|
||||
yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::DT_PUBLIC); }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
// Module Items
|
||||
|
||||
@@ -1677,8 +1681,6 @@ module_common_item<nodep>: // ==IEEE: module_common_item
|
||||
| yALWAYS_LATCH event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); }
|
||||
| loop_generate_construct { $$ = $1; }
|
||||
| conditional_generate_construct { $$ = $1; }
|
||||
// // Verilator only
|
||||
| pslStmt { $$ = $1; }
|
||||
//
|
||||
| error ';' { $$ = NULL; }
|
||||
;
|
||||
@@ -2017,9 +2019,11 @@ instnameList<nodep>:
|
||||
| instnameList ',' instnameParen { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
||||
instnameParen<nodep>:
|
||||
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2); }
|
||||
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2); }
|
||||
instnameParen<cellp>:
|
||||
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2);
|
||||
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
|
||||
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2);
|
||||
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
|
||||
//UNSUP instRangeE '(' cellpinList ')' { UNSUP } // UDP
|
||||
// // Adding above and switching to the Verilog-Perl syntax
|
||||
// // causes a shift conflict due to use of idClassSel inside exprScope.
|
||||
@@ -2964,7 +2968,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
||||
| ~noPar__IGNORE~'(' expr ')' { $$ = $2; }
|
||||
//UNSUP ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' { $$ = $4; }
|
||||
// // PSL rule
|
||||
| '_' '(' statePushVlg expr statePop ')' { $$ = $4; } // Arbitrary Verilog inside PSL
|
||||
| '_' '(' expr ')' { $$ = $3; } // Arbitrary Verilog inside PSL
|
||||
//
|
||||
// // IEEE: cast/constant_cast
|
||||
| casting_type yP_TICK '(' expr ')' { $$ = new AstCast($2,$4,$1); }
|
||||
@@ -3064,11 +3068,6 @@ fexprScope<nodep>: // exprScope, For use as first part of statement (disambigua
|
||||
BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied}
|
||||
;
|
||||
|
||||
// Psl excludes {}'s by lexer converting to different token
|
||||
exprPsl<nodep>:
|
||||
expr { $$ = $1; }
|
||||
;
|
||||
|
||||
// PLI calls exclude "" as integers, they're strings
|
||||
// For $c("foo","bar") we want "bar" as a string, not a Verilog integer.
|
||||
exprStrText<nodep>:
|
||||
@@ -3491,7 +3490,7 @@ str<strp>: // yaSTRING but with \{escapes} need decoded
|
||||
;
|
||||
|
||||
strAsInt<nodep>:
|
||||
yaSTRING { $$ = new AstConst($<fl>1,V3Number(V3Number::VerilogString(),$<fl>1,GRAMMARP->deQuote($<fl>1,*$1)));}
|
||||
yaSTRING { $$ = new AstConst($<fl>1,V3Number(V3Number::VerilogStringLiteral(),$<fl>1,GRAMMARP->deQuote($<fl>1,*$1)));}
|
||||
;
|
||||
|
||||
strAsIntIgnore<nodep>: // strAsInt, but never matches for when expr shouldn't parse strings
|
||||
@@ -3599,56 +3598,6 @@ package_scopeIdFollows<packagep>: // IEEE: package_scope
|
||||
//UNSUP /*cont*/ yP_COLONCOLON { UNSUP }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
// PSL Statements
|
||||
|
||||
pslStmt<nodep>:
|
||||
yPSL pslDir stateExitPsl { $$ = $2; }
|
||||
| yPSL pslDecl stateExitPsl { $$ = $2; }
|
||||
;
|
||||
|
||||
pslDir<nodep>:
|
||||
id ':' pslDirOne { $$ = $3; }
|
||||
| pslDirOne { $$ = $1; }
|
||||
;
|
||||
|
||||
pslDirOne<nodep>:
|
||||
yPSL_ASSERT pslProp ';' { $$ = new AstPslAssert($1,$2); }
|
||||
| yPSL_ASSERT pslProp yPSL_REPORT yaSTRING ';' { $$ = new AstPslAssert($1,$2,*$4); }
|
||||
| yPSL_COVER pslProp ';' { $$ = new AstPslCover($1,$2,NULL); }
|
||||
| yPSL_COVER pslProp yPSL_REPORT yaSTRING ';' { $$ = new AstPslCover($1,$2,NULL,*$4); }
|
||||
;
|
||||
|
||||
pslDecl<nodep>:
|
||||
yDEFAULT yPSL_CLOCK '=' senitemEdge ';' { $$ = new AstPslDefClock($3, $4); }
|
||||
| yDEFAULT yPSL_CLOCK '=' '(' senitemEdge ')' ';' { $$ = new AstPslDefClock($3, $5); }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
// PSL Properties, Sequences and SEREs
|
||||
// Don't use '{' or '}'; in PSL they're yPSL_BRA and yPSL_KET to avoid expr concatenates
|
||||
|
||||
pslProp<nodep>:
|
||||
pslSequence { $$ = $1; }
|
||||
| pslSequence '@' %prec prPSLCLK '(' senitemEdge ')' { $$ = new AstPslClocked($2,$4,NULL,$1); } // or pslSequence @ ...?
|
||||
;
|
||||
|
||||
pslSequence<nodep>:
|
||||
yPSL_BRA pslSere yPSL_KET { $$ = $2; }
|
||||
;
|
||||
|
||||
pslSere<nodep>:
|
||||
pslExpr { $$ = $1; }
|
||||
| pslSequence { $$ = $1; } // Sequence containing sequence
|
||||
;
|
||||
|
||||
// Undocumented PSL rule is that {} is always a SERE; concatenation is not allowed.
|
||||
// This can be bypassed with the _(...) embedding of any arbitrary expression.
|
||||
pslExpr<nodep>:
|
||||
exprPsl { $$ = new AstPslBool($1->fileline(), $1); }
|
||||
| yTRUE { $$ = new AstPslBool($1, new AstConst($1, AstConst::LogicTrue())); }
|
||||
;
|
||||
|
||||
//**********************************************************************
|
||||
// VLT Files
|
||||
|
||||
@@ -3783,7 +3732,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
|
||||
// Propagate from current module tracing state
|
||||
if (nodep->isGenVar()) nodep->trace(false);
|
||||
else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false);
|
||||
else nodep->trace(v3Global.opt.trace() && nodep->fileline()->tracingOn());
|
||||
else nodep->trace(allTracingOn(nodep->fileline()));
|
||||
|
||||
// Remember the last variable created, so we can attach attributes to it in later parsing
|
||||
GRAMMARP->m_varAttrp = nodep;
|
||||
@@ -3792,7 +3741,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
|
||||
|
||||
string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
|
||||
// Fix up the quoted strings the user put in, for example "\"" becomes "
|
||||
// Reverse is AstNode::quoteName(...)
|
||||
// Reverse is V3Number::quoteNameControls(...)
|
||||
bool quoted = false;
|
||||
string newtext;
|
||||
unsigned char octal_val = 0;
|
||||
|
||||
Executable
+173
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
#require 5.006_001;
|
||||
use Getopt::Long;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug);
|
||||
|
||||
our @Items;
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
$Debug = 0;
|
||||
my $Opt_Srcdir = ".";
|
||||
Getopt::Long::config ("pass_through", "no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"srcdir=s" => \$Opt_Srcdir,
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
|
||||
)) {
|
||||
usage();
|
||||
}
|
||||
|
||||
read_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
|
||||
lint();
|
||||
write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub read_keys {
|
||||
my $filename = shift;
|
||||
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
|
||||
while (defined (my $line = $fh->getline())) {
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
|
||||
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
|
||||
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
|
||||
my @data;
|
||||
my $code = "\@data = ($1);";
|
||||
eval $code;
|
||||
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
|
||||
push @Items, {@data};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub lint {
|
||||
my %shorts;
|
||||
my $ok = 1;
|
||||
foreach my $itemref (@Items) {
|
||||
if ($shorts{$itemref->{short}}) {
|
||||
warn "%Error: Duplicate short code: $itemref->{short},";
|
||||
$ok = 0;
|
||||
}
|
||||
$shorts{$itemref->{short}} = 1;
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
|
||||
sub write_keys {
|
||||
my $filename = shift;
|
||||
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
|
||||
|
||||
my @in;
|
||||
my @out;
|
||||
my $deleting;
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
push @in, $line;
|
||||
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
|
||||
$deleting = 1;
|
||||
push @out, $line;
|
||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
|
||||
uc $keyref->{name}, $keyref->{short});
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
|
||||
$deleting = 1;
|
||||
push @out, $line;
|
||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||
push @out, sprintf("\tif (key == \"%s\") return VL_CIK_%s;\n",
|
||||
$keyref->{name}, uc $keyref->{name});
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
|
||||
$deleting = 0;
|
||||
push @out, $line;
|
||||
}
|
||||
elsif ($deleting) {
|
||||
}
|
||||
else {
|
||||
push @out, $line;
|
||||
}
|
||||
}
|
||||
$fh->close;
|
||||
|
||||
my $ok = join("", @out) eq join("", @in);
|
||||
if (!$ok) {
|
||||
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
|
||||
$fh->print(join "", @out);
|
||||
$fh->close;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
vlcovgen - Generate verilated_cov headers to reduce C++ code duplication
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
(called from make rules)
|
||||
vlcovgen
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Generates several files for Verilator compilations.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2002-2014 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
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.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "./vlcovgen --srcdir ."
|
||||
### End:
|
||||
@@ -52,7 +52,7 @@ endif
|
||||
|
||||
#Our own compile rules; Faster compile, all in one file
|
||||
$(VM_PREFIX)__ALLboth.cpp: $(VK_CLASSES_CPP) $(VK_SUPPORT_CPP)
|
||||
$(SP_INCLUDER) $^ > $@
|
||||
$(VERILATOR_INCLUDER) -DVL_INLINE_OPT=inline $^ > $@
|
||||
|
||||
$(VM_PREFIX)__ALLboth.o: $(VM_PREFIX)__ALLboth.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
|
||||
@@ -115,9 +115,15 @@ if ($#opt_tests<0) {
|
||||
foreach my $dir (@Test_Dirs) {
|
||||
my @stats = stat($dir); # Uniquify by inode, so different paths to same place get combined
|
||||
next if !$stats[1] || $uniq{$stats[1]}++;
|
||||
push @opt_tests, glob ("${dir}/t_*.pl");
|
||||
push @opt_tests, sort(glob ("${dir}/t_*.pl"));
|
||||
}
|
||||
}
|
||||
if ($#opt_tests>=2 && $opt_jobs>=2) {
|
||||
# Without this tests such as t_debug_sigsegv_bt_bad.pl will occasionally
|
||||
# block on input and cause a SIGSTOP, then a "fg" was needed to resume testing.
|
||||
print STDERR "== Many jobs; redirecting STDIN\n";
|
||||
open(STDIN, "+>/dev/null");
|
||||
}
|
||||
|
||||
mkdir "obj_dir";
|
||||
|
||||
@@ -388,7 +394,7 @@ sub new {
|
||||
$self->{stats} ||= "$self->{obj_dir}/V".$self->{name}."__stats.txt";
|
||||
$self->{status_filename} ||= "$self->{obj_dir}/V".$self->{name}.".status";
|
||||
$self->{run_log_filename} ||= "$self->{obj_dir}/vlt_sim.log";
|
||||
$self->{coverage_filename} ||= "$self->{obj_dir}/vlt_coverage.pl";
|
||||
$self->{coverage_filename} ||= "$self->{obj_dir}/coverage.dat";
|
||||
$self->{vcd_filename} ||= "$self->{obj_dir}/sim.vcd";
|
||||
$self->{main_filename} ||= "$self->{obj_dir}/$self->{VM_PREFIX}__main.cpp";
|
||||
($self->{top_filename} = $self->{pl_filename}) =~ s/\.pl$//;
|
||||
@@ -633,10 +639,6 @@ sub compile {
|
||||
$self->skip("Test requires SystemC; ignore error since not installed\n");
|
||||
return 1;
|
||||
}
|
||||
elsif ($self->{coverage} && !$Have_System_Perl) {
|
||||
$self->skip("Test requires SystemPerl; ignore error since not installed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!$param{fails} && $param{verilator_make_gcc}
|
||||
&& $param{make_main}) {
|
||||
@@ -1143,7 +1145,7 @@ sub _make_main {
|
||||
|
||||
if ($self->{coverage}) {
|
||||
$fh->print("#if VM_COVERAGE\n");
|
||||
$fh->print(" SpCoverage::write(\"",$self->{coverage_filename},"\");\n");
|
||||
$fh->print(" VerilatedCov::write(\"",$self->{coverage_filename},"\");\n");
|
||||
$fh->print("#endif //VM_COVERAGE\n");
|
||||
}
|
||||
if ($self->{trace}) {
|
||||
|
||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
top_filename("t/t_assert_basic.v");
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ['--assert --sp --coverage-user'],
|
||||
verilator_flags2 => ['--assert --cc --coverage-user'],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
top_filename("t/t_assert_cover.v");
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ['--assert --sp --coverage-user'],
|
||||
verilator_flags2 => ['--assert --cc --coverage-user'],
|
||||
nc_flags2 => ["+nccovoverwrite +nccoverage+all +nccovtest+$Self->{name}"]
|
||||
);
|
||||
|
||||
|
||||
@@ -10,13 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Comple time only test
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
# expect=>
|
||||
# TBD better error message, bug509
|
||||
#'.*
|
||||
#%Error: Exiting due to.*',
|
||||
);
|
||||
verilator_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
'.*%Error: t/t_bitsel_wire_array_bad.v:\d+: Illegal assignment of constant to unpacked array
|
||||
%Error: Exiting due to.*',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -2,24 +2,22 @@
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003 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.
|
||||
|
||||
top_filename("t/t_trace_ena.v");
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ['-notrace -sp'],
|
||||
v_flags2 => ["--stats"],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
);
|
||||
|
||||
if ($Self->{vlt}) {
|
||||
!-r "$Self->{obj_dir}/simx.vcd" or $Self->error("Tracing should be off\n");
|
||||
}
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
|
||||
};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,100 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2014 by Jie Xu.
|
||||
//
|
||||
|
||||
// change these two parameters to see the speed differences
|
||||
`define DATA_WIDTH 8
|
||||
`define REP_COUNT4 `DATA_WIDTH/4
|
||||
`define REP_COUNT2 `DATA_WIDTH/2
|
||||
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
reg [3:0] count4 = 0;
|
||||
reg [1:0] count2 = 0;
|
||||
|
||||
reg [`DATA_WIDTH-1:0] a = {`REP_COUNT4{4'b0000}};
|
||||
reg [`DATA_WIDTH-1:0] b = {`REP_COUNT4{4'b1111}};
|
||||
reg [`DATA_WIDTH-1:0] c = {`REP_COUNT4{4'b1111}};
|
||||
reg [`DATA_WIDTH-1:0] d = {`REP_COUNT4{4'b1111}};
|
||||
reg [`DATA_WIDTH-1:0] res1;
|
||||
reg [`DATA_WIDTH-1:0] res2;
|
||||
reg [`DATA_WIDTH-1:0] res3;
|
||||
reg [`DATA_WIDTH-1:0] res4;
|
||||
|
||||
drv1 t_drv1 [`DATA_WIDTH-1:0] (.colSelA(a), .datao(res1));
|
||||
drv2 t_drv2 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .datao(res2));
|
||||
drv3 t_drv3 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .colSelC(c), .datao(res3));
|
||||
drv4 t_drv4 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .colSelC(c), .colSelD(d), .datao(res4));
|
||||
|
||||
always@(posedge clk)
|
||||
begin
|
||||
count2 <= count2 + 1;
|
||||
count4 <= count4 + 1;
|
||||
a <= {`REP_COUNT4{count4}};
|
||||
b <= {`REP_COUNT4{count4}};
|
||||
c <= {`REP_COUNT2{count2}};
|
||||
d <= {`REP_COUNT2{count2}};
|
||||
|
||||
if (res1 != (a)) begin
|
||||
$stop;
|
||||
end
|
||||
if (res2 != (a&b)) begin
|
||||
$stop;
|
||||
end
|
||||
if (res3 != (a&b&c)) begin
|
||||
$stop;
|
||||
end
|
||||
if (res4 != (a&b&c&d)) begin
|
||||
$stop;
|
||||
end
|
||||
|
||||
if (count4 > 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
||||
module drv1
|
||||
(input colSelA,
|
||||
output datao
|
||||
);
|
||||
assign datao = colSelA;
|
||||
endmodule
|
||||
|
||||
module drv2
|
||||
(input colSelA,
|
||||
input colSelB,
|
||||
output datao
|
||||
);
|
||||
assign datao = colSelB & colSelA;
|
||||
endmodule
|
||||
|
||||
module drv3
|
||||
(input colSelA,
|
||||
input colSelB,
|
||||
input colSelC,
|
||||
output datao
|
||||
);
|
||||
assign datao = colSelB & colSelA & colSelC;
|
||||
|
||||
endmodule
|
||||
|
||||
module drv4
|
||||
(input colSelA,
|
||||
input colSelB,
|
||||
input colSelC,
|
||||
input colSelD,
|
||||
output datao
|
||||
);
|
||||
assign datao = colSelB & colSelA & colSelC & colSelD;
|
||||
|
||||
endmodule
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2004 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,71 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2004 by Jie Xu.
|
||||
//
|
||||
// The test was added together with the concat optimization.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
integer cyc; initial cyc=1;
|
||||
|
||||
reg [31:0] in_a;
|
||||
reg [31:0] in_b;
|
||||
reg [31:0] in_c;
|
||||
reg [31:0] in_d;
|
||||
reg [31:0] in_e;
|
||||
reg [15:0] in_f;
|
||||
wire [31:0] in_g;
|
||||
|
||||
assign in_g = in_a << 4;
|
||||
|
||||
reg [31:0] out_x;
|
||||
reg [31:0] out_y;
|
||||
reg [31:0] out_z;
|
||||
reg [31:0] out_o;
|
||||
reg [31:0] out_p;
|
||||
reg [31:0] out_q;
|
||||
|
||||
assign out_x = {in_a[31:16] & in_f, in_a[15:0] & in_f};
|
||||
assign out_y = {in_a[31:18] & in_b[31:18], in_a[17:0] & in_b[17:0]};
|
||||
assign out_z = {in_c[31:14] & in_d[31:14] & in_e[31:14], in_c[13:0] & in_d[13:0] & in_e[13:0]};
|
||||
assign out_o = out_z | out_y;
|
||||
assign out_p = {in_a[31:16] & in_f | in_e[31:16], in_a[15:0] & in_f | in_e[15:0]};
|
||||
assign out_q = {{in_a[31:25] ^ in_g[31:25], in_a[24:16] ^ in_g[24:16]}, {in_a[15:5] ^ in_g[15:5], in_a[4:0] ^ in_g[4:0]}};
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
in_a <= cyc;
|
||||
in_b <= cyc + 1;
|
||||
in_c <= cyc + 3;
|
||||
in_d <= cyc + 8;
|
||||
in_e <= cyc;
|
||||
in_f <= cyc[15:0];
|
||||
|
||||
if (out_x != (in_a & {2{in_f}}))
|
||||
$stop;
|
||||
if (out_y != (in_a&in_b))
|
||||
$stop;
|
||||
if (out_z != (in_e&in_d&in_c))
|
||||
$stop;
|
||||
if (out_o != (((in_a&in_b)|(in_c&in_e&in_d))))
|
||||
$stop;
|
||||
if (out_p != (in_a & {2{in_f}} | in_e))
|
||||
$stop;
|
||||
if (out_q != (in_a ^ in_g))
|
||||
$stop;
|
||||
|
||||
if (cyc==100) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user